diff --git a/.config/taplo.toml b/.config/taplo.toml index f5d0b7021ba898ea3ab96323fa3fbc4efdd7b307..2c6ccfb2b34440686764c39ed6db1c73ed940f06 100644 --- a/.config/taplo.toml +++ b/.config/taplo.toml @@ -2,10 +2,12 @@ # ignore zombienet as they do some deliberate custom toml stuff exclude = [ + "bridges/testing/**", "cumulus/zombienet/**", "polkadot/node/malus/integrationtests/**", "polkadot/zombienet_tests/**", "substrate/zombienet/**", + "target/**", ] # global rules diff --git a/.github/scripts/check-prdoc.py b/.github/scripts/check-prdoc.py new file mode 100644 index 0000000000000000000000000000000000000000..42b063f2885da148033986dfa49740f2b0416460 --- /dev/null +++ b/.github/scripts/check-prdoc.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +''' +Ensure that the prdoc files are valid. + +# Example + +```sh +python3 -m pip install cargo-workspace +python3 .github/scripts/check-prdoc.py Cargo.toml prdoc/*.prdoc +``` + +Produces example output: +```pre +🔎 Reading workspace polkadot-sdk/Cargo.toml +📦 Checking 32 prdocs against 493 crates. +✅ All prdocs are valid +``` +''' + +import os +import yaml +import argparse +import cargo_workspace + +def check_prdoc_crate_names(root, paths): + ''' + Check that all crates of the `crates` section of each prdoc is present in the workspace. + ''' + + print(f'🔎 Reading workspace {root}.') + workspace = cargo_workspace.Workspace.from_path(root) + crate_names = [crate.name for crate in workspace.crates] + + print(f'📦 Checking {len(paths)} prdocs against {len(crate_names)} crates.') + faulty = {} + + for path in paths: + with open(path, 'r') as f: + prdoc = yaml.safe_load(f) + + for crate in prdoc.get('crates', []): + crate = crate['name'] + if crate in crate_names: + continue + + faulty.setdefault(path, []).append(crate) + + if len(faulty) == 0: + print('✅ All prdocs are valid.') + else: + print('❌ Some prdocs are invalid.') + for path, crates in faulty.items(): + print(f'💥 {path} lists invalid crate: {", ".join(crates)}') + exit(1) + +def parse_args(): + parser = argparse.ArgumentParser(description='Check prdoc files') + parser.add_argument('root', help='The cargo workspace manifest', metavar='root', type=str, nargs=1) + parser.add_argument('prdoc', help='The prdoc files', metavar='prdoc', type=str, nargs='*') + args = parser.parse_args() + + if len(args.prdoc) == 0: + print('❌ Need at least one prdoc file as argument.') + exit(1) + + return { 'root': os.path.abspath(args.root[0]), 'prdocs': args.prdoc } + +if __name__ == '__main__': + args = parse_args() + check_prdoc_crate_names(args['root'], args['prdocs']) diff --git a/.github/scripts/check-workspace.py b/.github/scripts/check-workspace.py index d200122fee9f7035dce8c811e7c24c003d9545a4..1f8f103e4e157a8c1c804a618652741193ca5a00 100644 --- a/.github/scripts/check-workspace.py +++ b/.github/scripts/check-workspace.py @@ -18,7 +18,7 @@ def parse_args(): parser.add_argument('workspace_dir', help='The directory to check', metavar='workspace_dir', type=str, nargs=1) parser.add_argument('--exclude', help='Exclude crate paths from the check', metavar='exclude', type=str, nargs='*', default=[]) - + args = parser.parse_args() return (args.workspace_dir[0], args.exclude) @@ -26,7 +26,7 @@ def main(root, exclude): workspace_crates = get_members(root, exclude) all_crates = get_crates(root, exclude) print(f'📦 Found {len(all_crates)} crates in total') - + check_duplicates(workspace_crates) check_missing(workspace_crates, all_crates) check_links(all_crates) @@ -48,14 +48,14 @@ def get_members(workspace_dir, exclude): if not 'members' in root_manifest['workspace']: return [] - + members = [] for member in root_manifest['workspace']['members']: if member in exclude: print(f'❌ Excluded member should not appear in the workspace {member}') sys.exit(1) members.append(member) - + return members # List all members of the workspace. @@ -74,12 +74,12 @@ def get_crates(workspace_dir, exclude_crates) -> dict: with open(path, "r") as f: content = f.read() manifest = toml.loads(content) - + if 'workspace' in manifest: if root != workspace_dir: print("⏩ Excluded recursive workspace at %s" % path) continue - + # Cut off the root path and the trailing /Cargo.toml. path = path[len(workspace_dir)+1:-11] name = manifest['package']['name'] @@ -87,7 +87,7 @@ def get_crates(workspace_dir, exclude_crates) -> dict: print("⏩ Excluded crate %s at %s" % (name, path)) continue crates[name] = (path, manifest) - + return crates # Check that there are no duplicate entries in the workspace. @@ -138,23 +138,23 @@ def check_links(all_crates): if not 'path' in deps[dep]: broken.append((name, dep_name, "crate must be linked via `path`")) return - + def check_crate(deps): to_checks = ['dependencies', 'dev-dependencies', 'build-dependencies'] for to_check in to_checks: if to_check in deps: check_deps(deps[to_check]) - + # There could possibly target dependant deps: if 'target' in manifest: # Target dependant deps can only have one level of nesting: for _, target in manifest['target'].items(): check_crate(target) - + check_crate(manifest) - + links.sort() broken.sort() diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index bd12d9c6e6ff773f8513189a381d725243e53eb5..29dc269ffd23b1f51e1eb2b87a61544de0cbb57f 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -237,6 +237,61 @@ fetch_release_artifacts() { popd > /dev/null } +# Fetch the release artifacts like binary and sigantures from S3. Assumes the ENV are set: +# - RELEASE_ID +# - GITHUB_TOKEN +# - REPO in the form paritytech/polkadot +fetch_release_artifacts_from_s3() { + echo "Version : $VERSION" + echo "Repo : $REPO" + echo "Binary : $BINARY" + OUTPUT_DIR=${OUTPUT_DIR:-"./release-artifacts/${BINARY}"} + echo "OUTPUT_DIR : $OUTPUT_DIR" + + URL_BASE=$(get_s3_url_base $BINARY) + echo "URL_BASE=$URL_BASE" + + URL_BINARY=$URL_BASE/$VERSION/$BINARY + URL_SHA=$URL_BASE/$VERSION/$BINARY.sha256 + URL_ASC=$URL_BASE/$VERSION/$BINARY.asc + + # Fetch artifacts + mkdir -p "$OUTPUT_DIR" + pushd "$OUTPUT_DIR" > /dev/null + + echo "Fetching artifacts..." + for URL in $URL_BINARY $URL_SHA $URL_ASC; do + echo "Fetching %s" "$URL" + curl --progress-bar -LO "$URL" || echo "Missing $URL" + done + + pwd + ls -al --color + popd > /dev/null + +} + +# Pass the name of the binary as input, it will +# return the s3 base url +function get_s3_url_base() { + name=$1 + case $name in + polkadot | polkadot-execute-worker | polkadot-prepare-worker | staking-miner) + printf "https://releases.parity.io/polkadot" + ;; + + polkadot-parachain) + printf "https://releases.parity.io/cumulus" + ;; + + *) + printf "UNSUPPORTED BINARY $name" + exit 1 + ;; + esac +} + + # Check the checksum for a given binary function check_sha256() { echo "Checking SHA256 for $1" @@ -248,13 +303,11 @@ function check_sha256() { function import_gpg_keys() { GPG_KEYSERVER=${GPG_KEYSERVER:-"keyserver.ubuntu.com"} SEC="9D4B2B6EB8F97156D19669A9FF0812D491B96798" - WILL="2835EAF92072BC01D188AF2C4A092B93E97CE1E2" EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3" - MARA="533C920F40E73A21EEB7E9EBF27AEA7E7594C9CF" MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF" echo "Importing GPG keys from $GPG_KEYSERVER in parallel" - for key in $SEC $WILL $EGOR $MARA $MORGAN; do + for key in $SEC $EGOR $MORGAN; do ( echo "Importing GPG key $key" gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key @@ -344,3 +397,40 @@ function find_runtimes() { done echo $JSON } + +# Filter the version matches the particular pattern and return it. +# input: version (v1.8.0 or v1.8.0-rc1) +# 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]+)$" + + 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 + else + echo "Invalid version: $version" + exit 1 + fi + +} + +# Check if the release_id is valid number +# input: release_id +# output: release_id or exit 1 +check_release_id() { + input=$1 + + release_id=$(echo "$input" | sed 's/[^0-9]//g') + + if [[ $release_id =~ ^[0-9]+$ ]]; then + echo "$release_id" + else + echo "Invalid release_id from input: $input" + exit 1 + fi + +} diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index 97562f0da09569931582864bd764e6724900d619..1d1a8770058d33ba5e449c6a2e8b307e0ff02eb7 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -9,14 +9,6 @@ jobs: check-labels: runs-on: ubuntu-latest steps: - - name: Skip merge queue - if: ${{ contains(github.ref, 'gh-readonly-queue') }} - run: exit 0 - - name: Pull image - env: - IMAGE: paritytech/ruled_labels:0.4.0 - run: docker pull $IMAGE - - name: Check labels env: IMAGE: paritytech/ruled_labels:0.4.0 @@ -28,6 +20,16 @@ jobs: RULES_PATH: labels/ruled_labels CHECK_SPECS: "specs_polkadot-sdk.yaml" run: | + if [ ${{ github.ref }} == "refs/heads/master" ]; then + echo "Skipping master" + exit 0 + fi + if [ $(echo ${{ github.ref }} | grep -c "gh-readonly-queue") -eq 1 ]; then + echo "Skipping merge queue" + exit 0 + fi + + docker pull $IMAGE echo "REPO: ${REPO}" echo "GITHUB_PR: ${GITHUB_PR}" diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index e1e92d288ceae235d23fa36c31d592092fe8b0ba..c32b6fcf89e06bb56cefc0517e1dcab1d1ef0f37 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -42,5 +42,4 @@ jobs: shopt -s globstar npx @paritytech/license-scanner scan \ --ensure-licenses ${{ env.LICENSES }} \ - --exclude ./substrate/bin/node-template \ -- ./substrate/**/*.rs diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index f47404744a49b86735b584e5c0f84bda3fe3078e..c31dee06ec54a0154efc3ad46ff24c79de4d0d7b 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -17,31 +17,25 @@ env: jobs: check-prdoc: runs-on: ubuntu-latest + if: github.event.pull_request.number != '' steps: + - name: Checkout repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 # we cannot show the version in this step (ie before checking out the repo) # due to https://github.com/paritytech/prdoc/issues/15 - - name: Skip merge queue - if: ${{ contains(github.ref, 'gh-readonly-queue') }} - run: exit 0 - - name: Pull image + - name: Check if PRdoc is required + id: get-labels run: | echo "Pulling $IMAGE" $ENGINE pull $IMAGE - - name: Check if PRdoc is required - id: get-labels - run: | # Fetch the labels for the PR under test echo "Fetch the labels for $API_BASE/${REPO}/pulls/${GITHUB_PR}" labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") echo "Labels: ${labels}" echo "labels=${labels}" >> "$GITHUB_OUTPUT" - - name: Checkout repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 - - - name: Check PRDoc version - run: | + echo "Checking PRdoc version" $ENGINE run --rm -v $PWD:/repo $IMAGE --version - name: Early exit if PR is silent @@ -62,4 +56,12 @@ jobs: run: | echo "Checking for PR#${GITHUB_PR}" echo "You can find more information about PRDoc at $PRDOC_DOC" - $ENGINE run --rm -v $PWD:/repo $IMAGE check -n ${GITHUB_PR} + $ENGINE run --rm -v $PWD:/repo -e RUST_LOG=info $IMAGE check -n ${GITHUB_PR} + + - name: Validate prdoc for PR#${{ github.event.pull_request.number }} + if: ${{ !contains(steps.get-labels.outputs.labels, 'R0') }} + run: | + echo "Validating PR#${GITHUB_PR}" + python3 --version + python3 -m pip install cargo-workspace==1.2.1 + python3 .github/scripts/check-prdoc.py Cargo.toml prdoc/pr_${GITHUB_PR}.prdoc diff --git a/.github/workflows/check-workspace.yml b/.github/workflows/check-workspace.yml index 3dd812d7d9b3743062553b700adba9d6abd93c50..81ec311ccce8153d7a28f68ff801cc917c8d1fd9 100644 --- a/.github/workflows/check-workspace.yml +++ b/.github/workflows/check-workspace.yml @@ -2,8 +2,6 @@ name: Check workspace on: pull_request: - paths: - - "*.toml" merge_group: jobs: @@ -19,5 +17,5 @@ jobs: run: > python3 .github/scripts/check-workspace.py . --exclude - "substrate/frame/contracts/fixtures/build" + "substrate/frame/contracts/fixtures/build" "substrate/frame/contracts/fixtures/contracts/common" diff --git a/.github/workflows/gitspiegel-trigger.yml b/.github/workflows/gitspiegel-trigger.yml index b338f7a3f6254b9db628f8b2b45c88b8094ef390..01058ad74d0b71385a8096964ea6c779fc6f4869 100644 --- a/.github/workflows/gitspiegel-trigger.yml +++ b/.github/workflows/gitspiegel-trigger.yml @@ -13,14 +13,15 @@ on: - unlocked - ready_for_review - reopened + # doesn't work as intended, triggers "workflow_run" webhook in any case # the job doesn't check out any code, so it is relatively safe to run it on any event - pull_request_target: - types: - - opened - - synchronize - - unlocked - - ready_for_review - - reopened + # pull_request_target: + # types: + # - opened + # - synchronize + # - unlocked + # - ready_for_review + # - reopened merge_group: # drop all permissions for GITHUB_TOKEN diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index ecbac01cd3a5b2aaed679cfaf2ade0b04900531a..67e93ee96574de1f1e3e29f1bf6d90085865100d 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -36,7 +36,7 @@ on: -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/$OWNER/$REPO/releases | \ jq '.[] | { name: .name, id: .id }' required: true - type: string + type: number registry: description: Container registry @@ -61,7 +61,6 @@ permissions: contents: write env: - RELEASE_ID: ${{ inputs.release_id }} ENGINE: docker REGISTRY: ${{ inputs.registry }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -71,6 +70,7 @@ env: # EVENT_ACTION: ${{ github.event.action }} EVENT_NAME: ${{ github.event_name }} IMAGE_TYPE: ${{ inputs.image_type }} + VERSION: ${{ inputs.version }} jobs: fetch-artifacts: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build @@ -95,13 +95,16 @@ jobs: # chmod a+x $BINARY # ls -al - - name: Fetch rc artifacts or release artifacts based on release id + - 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' }} run: | . ./.github/scripts/common/lib.sh - fetch_release_artifacts + VERSION=$(filter_version_from_input "${{ inputs.version }}") + echo "VERSION=${VERSION}" >> $GITHUB_ENV + + fetch_release_artifacts_from_s3 - name: Cache the artifacts uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 @@ -147,7 +150,10 @@ jobs: if: ${{ env.IMAGE_TYPE == 'rc' }} id: fetch_rc_refs run: | - release=release-${{ inputs.release_id }} && \ + . ./.github/scripts/common/lib.sh + + RELEASE_ID=$(check_release_id "${{ inputs.release_id }}") + release=release-$RELEASE_ID && \ echo "release=${release}" >> $GITHUB_OUTPUT commit=$(git rev-parse --short HEAD) && \ diff --git a/.github/workflows/release-99_notif-published.yml b/.github/workflows/release-99_notif-published.yml index b35120ca4e128beaa37047b0ac3f21b02f4da663..05c9d6a47f551860c51e318b01b495ca662e902e 100644 --- a/.github/workflows/release-99_notif-published.yml +++ b/.github/workflows/release-99_notif-published.yml @@ -8,22 +8,14 @@ on: jobs: ping_matrix: runs-on: ubuntu-latest + environment: release strategy: matrix: channel: # Internal - - name: 'RelEng: Cumulus Release Coordination' - room: '!NAEMyPAHWOiOQHsvus:parity.io' - pre-releases: true - name: "RelEng: Polkadot Release Coordination" room: '!cqAmzdIcbOFwrdrubV:parity.io' pre-release: true - - name: 'General: Rust, Polkadot, Substrate' - room: '!aJymqQYtCjjqImFLSb:parity.io' - pre-release: false - - name: 'Team: DevOps' - room: '!lUslSijLMgNcEKcAiE:parity.io' - pre-release: true # External - name: 'Ledger <> Polkadot Coordination' @@ -31,18 +23,15 @@ jobs: pre-release: true # Public - # - name: '#KusamaValidatorLounge:polkadot.builders' - # room: '!LhjZccBOqFNYKLdmbb:polkadot.builders' - # pre-releases: false - # - name: '#kusama-announcements:matrix.parity.io' - # room: '!FMwxpQnYhRCNDRsYGI:matrix.parity.io' - # pre-release: false - # - name: '#polkadotvalidatorlounge:web3.foundation' - # room: '!NZrbtteFeqYKCUGQtr:matrix.parity.io' - # pre-release: false - # - name: '#polkadot-announcements:matrix.parity.io' - # room: '!UqHPWiCBGZWxrmYBkF:matrix.parity.io' - # pre-release: false + - name: '#polkadotvalidatorlounge:web3.foundation' + room: '!NZrbtteFeqYKCUGQtr:matrix.parity.io' + pre-releases: false + - name: '#polkadot-announcements:parity.io' + room: '!UqHPWiCBGZWxrmYBkF:matrix.parity.io' + pre-releases: false + - name: '#kusama-announce:parity.io' + room: '!FMwxpQnYhRCNDRsYGI:matrix.parity.io' + pre-releases: false steps: - name: Matrix notification to ${{ matrix.channel.name }} @@ -53,7 +42,9 @@ jobs: access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} server: m.parity.io message: | - A (pre)release has been ${{github.event.action}} in **${{github.event.repository.full_name}}:**
+ @room + + A new node release has been ${{github.event.action}} in **${{github.event.repository.full_name}}:**
Release version: [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) ----- diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c90a6c8e6e27a932c421378a333321f69f90ad0a..7f8796ca51248acb8be92fcb9f76e280b18e605e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -121,9 +121,8 @@ default: before_script: - 'curl --header "PRIVATE-TOKEN: $FL_CI_GROUP_TOKEN" -o forklift -L "${CI_API_V4_URL}/projects/676/packages/generic/forklift/${FL_FORKLIFT_VERSION}/forklift_${FL_FORKLIFT_VERSION}_linux_amd64"' - chmod +x forklift - - mkdir .forklift - - cp $FL_FORKLIFT_CONFIG .forklift/config.toml - - export FORKLIFT_PACKAGE_SUFFIX=${CI_JOB_NAME/ [0-9 \/]*} + - mkdir ~/.forklift + - cp $FL_FORKLIFT_CONFIG ~/.forklift/config.toml - shopt -s expand_aliases - export PATH=$PATH:$(pwd) - | @@ -131,11 +130,8 @@ default: echo "FORKLIFT_BYPASS not set, creating alias cargo='forklift cargo'" alias cargo="forklift cargo" fi - - ls -al - - rm -f forklift.sock # - echo "FL_FORKLIFT_VERSION ${FL_FORKLIFT_VERSION}" - - echo "FORKLIFT_PACKAGE_SUFFIX $FORKLIFT_PACKAGE_SUFFIX" .common-refs: rules: diff --git a/.gitlab/check-each-crate.py b/.gitlab/check-each-crate.py index da2eaad36c522e5ebfdc0d43e78c38507807e1a6..9b654f8071ac7237fe9c7c943540e8e020cebd6e 100755 --- a/.gitlab/check-each-crate.py +++ b/.gitlab/check-each-crate.py @@ -55,7 +55,7 @@ for i in range(0, crates_per_group + overflow_crates): print(f"Checking {crates[crate][0]}", file=sys.stderr) - res = subprocess.run(["cargo", "check", "--locked"], cwd = crates[crate][1]) + res = subprocess.run(["forklift", "cargo", "check", "--locked"], cwd = crates[crate][1]) if res.returncode != 0: sys.exit(1) diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index d9c67af7efdba49eaf533cc3665d6de5d45b7bce..f8de6135572565d9d16465e68aa3f0bace915cc5 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -91,7 +91,7 @@ build-rustdoc: - .run-immediately variables: SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "" + RUSTDOCFLAGS: "--default-theme=ayu --html-in-header ./docs/sdk/headers/header.html --extend-css ./docs/sdk/headers/theme.css" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success @@ -314,8 +314,9 @@ 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] script: - - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release -p staging-node-cli + - time WASM_BUILD_NO_COLOR=1 cargo build --locked --release -p staging-node-cli - mv $CARGO_TARGET_DIR/release/substrate-node ./artifacts/substrate/substrate - echo -n "Substrate version = " - if [ "${CI_COMMIT_TAG}" ]; then @@ -334,8 +335,9 @@ build-runtimes-polkavm: extends: - .docker-env - .common-refs + - .run-immediately script: - - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p minimal-runtime + - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p minimal-template-runtime - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p westend-runtime - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p rococo-runtime - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p polkadot-test-runtime @@ -352,9 +354,10 @@ build-runtimes-polkavm: CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" before_script: - mkdir -p ./artifacts/subkey + - !reference [.forklift-cache, before_script] script: - cd ./substrate/bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --locked --release + - time SKIP_WASM_BUILD=1 cargo build --locked --release # - cd - # - mv $CARGO_TARGET_DIR/release/subkey ./artifacts/subkey/. # - echo -n "Subkey version = " @@ -393,3 +396,18 @@ build-subkey-linux: # after_script: [""] # tags: # - osx + +# bridges + +# we need some non-binary artifacts in our bridges+zombienet image +prepare-bridges-zombienet-artifacts: + stage: build + extends: + - .docker-env + - .common-refs + - .run-immediately + - .collect-artifacts + before_script: + - mkdir -p ./artifacts/bridges-polkadot-sdk/bridges + script: + - cp -r bridges/testing ./artifacts/bridges-polkadot-sdk/bridges/testing diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 1ed12e68c2ce19b67dd5aca03cec85702351c039..52da33550508ede16c9577346e6985d869b5e8ae 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -108,8 +108,10 @@ check-toml-format: export RUST_LOG=remote-ext=debug,runtime=debug echo "---------- Downloading try-runtime CLI ----------" - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.0/try-runtime-x86_64-unknown-linux-musl -o try-runtime + curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.4/try-runtime-x86_64-unknown-linux-musl -o try-runtime chmod +x ./try-runtime + echo "Using try-runtime-cli version:" + ./try-runtime --version echo "---------- Building ${PACKAGE} runtime ----------" time cargo build --release --locked -p "$PACKAGE" --features try-runtime @@ -133,6 +135,7 @@ check-runtime-migration-westend: WASM: "westend_runtime.compact.compressed.wasm" URI: "wss://westend-try-runtime-node.parity-chains.parity.io:443" SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" + allow_failure: true check-runtime-migration-rococo: stage: check @@ -256,3 +259,19 @@ find-fail-ci-phrase: echo "No $ASSERT_REGEX was found, exiting with 0"; exit 0; fi + +check-core-crypto-features: + stage: check + extends: + - .docker-env + - .common-refs + script: + - pushd substrate/primitives/core + - ./check-features-variants.sh + - popd + - pushd substrate/primitives/application-crypto + - ./check-features-variants.sh + - popd + - pushd substrate/primitives/keyring + - ./check-features-variants.sh + - popd diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index 3b77f5363f627070984be057fb105d45c290be6e..b73acb560f67f93e540826b95fcf075374189846 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -66,6 +66,8 @@ publish-rustdoc: # note: images are used not only in zombienet but also in rococo, wococo and versi .build-push-image: image: $BUILDAH_IMAGE + extends: + - .zombienet-refs variables: DOCKERFILE: "" # docker/path-to.Dockerfile IMAGE_NAME: "" # docker.io/paritypr/image_name @@ -77,6 +79,7 @@ publish-rustdoc: --build-arg VCS_REF="${CI_COMMIT_SHA}" --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" --build-arg IMAGE_NAME="${IMAGE_NAME}" + --build-arg ZOMBIENET_IMAGE="${ZOMBIENET_IMAGE}" --tag "$IMAGE_NAME:${DOCKER_IMAGES_VERSION}" --file ${DOCKERFILE} . - echo "$PARITYPR_PASS" | @@ -163,3 +166,22 @@ build-push-image-substrate-pr: variables: DOCKERFILE: "docker/dockerfiles/substrate_injected.Dockerfile" IMAGE_NAME: "docker.io/paritypr/substrate" + +# 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: + stage: publish + extends: + - .kubernetes-env + - .common-refs + - .build-push-image + needs: + - job: build-linux-stable + artifacts: true + - job: build-linux-stable-cumulus + artifacts: true + - job: prepare-bridges-zombienet-artifacts + artifacts: true + variables: + DOCKERFILE: "docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile" + IMAGE_NAME: "docker.io/paritypr/bridges-zombienet-tests" diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index e75700ffddc468a918b216875294e362571754f5..5c41a3e6e08fae521c41a66735ac54df51e39057 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -25,6 +25,7 @@ test-linux-stable: # "upgrade_version_checks_should_work" is currently failing - | time cargo nextest run \ + --filter-expr 'not deps(/polkadot-subsystem-bench/)' \ --workspace \ --locked \ --release \ @@ -48,6 +49,7 @@ test-linux-stable: - target/nextest/default/junit.xml reports: junit: target/nextest/default/junit.xml + timeout: 90m test-linux-oldkernel-stable: extends: test-linux-stable @@ -68,7 +70,7 @@ test-linux-stable-runtime-benchmarks: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - - time cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet + - time cargo nextest run --filter-expr 'not deps(/polkadot-subsystem-bench/)' --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet # can be used to run all tests # test-linux-stable-all: @@ -224,6 +226,7 @@ cargo-check-benches: git merge --verbose --no-edit FETCH_HEAD; fi fi' + - !reference [.forklift-cache, before_script] parallel: 2 script: - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index a1d4db580cca734918c78bbb850cefcf3d06010e..55120e66d0e53c740b16a7ee6276230f42c172ef 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -10,3 +10,5 @@ include: - .gitlab/pipeline/zombienet/cumulus.yml # polkadot tests - .gitlab/pipeline/zombienet/polkadot.yml + # bridges tests + - .gitlab/pipeline/zombienet/bridges.yml diff --git a/.gitlab/pipeline/zombienet/bridges.yml b/.gitlab/pipeline/zombienet/bridges.yml new file mode 100644 index 0000000000000000000000000000000000000000..4278f59b1e9a2e33f32bf255436d6af5d31b30fb --- /dev/null +++ b/.gitlab/pipeline/zombienet/bridges.yml @@ -0,0 +1,63 @@ +# This file is part of .gitlab-ci.yml +# Here are all jobs that are executed during "zombienet" stage for bridges + +# common settings for all zombienet jobs +.zombienet-bridges-common: + extends: + - .kubernetes-env + - .zombienet-refs + rules: + # Docker images have different tag in merge queues + - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ + variables: + DOCKER_IMAGES_VERSION: ${CI_COMMIT_SHORT_SHA} + - !reference [.build-refs, rules] + before_script: + - echo "Zombienet Tests Config" + - echo "${ZOMBIENET_IMAGE}" + - echo "${GH_DIR}" + - echo "${LOCAL_DIR}" + - ls "${LOCAL_DIR}" + - export DEBUG=zombie,zombie::network-node + - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${BRIDGES_ZOMBIENET_TESTS_IMAGE}":${BRIDGES_ZOMBIENET_TESTS_IMAGE_TAG} + - echo "${ZOMBIENET_INTEGRATION_TEST_IMAGE}" + stage: zombienet + image: "${BRIDGES_ZOMBIENET_TESTS_IMAGE}:${BRIDGES_ZOMBIENET_TESTS_IMAGE_TAG}" + needs: + - job: build-push-image-bridges-zombienet-tests + artifacts: true + variables: + BRIDGES_ZOMBIENET_TESTS_IMAGE_TAG: ${DOCKER_IMAGES_VERSION} + BRIDGES_ZOMBIENET_TESTS_IMAGE: "docker.io/paritypr/bridges-zombienet-tests" + GH_DIR: "https://github.com/paritytech/polkadot-sdk/tree/${CI_COMMIT_SHA}/bridges/testing" + LOCAL_DIR: "/builds/parity/mirrors/polkadot-sdk/bridges/testing" + FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 + RUN_IN_CONTAINER: "1" + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}_zombienet_bridge_tests" + when: always + expire_in: 2 days + paths: + - ./zombienet-logs + after_script: + - mkdir -p ./zombienet-logs + # copy general logs + - cp -r /tmp/bridges-tests-run-*/logs/* ./zombienet-logs/ + # copy logs of rococo nodes + - cp -r /tmp/bridges-tests-run-*/bridge_hub_rococo_local_network/*.log ./zombienet-logs/ + # copy logs of westend nodes + - cp -r /tmp/bridges-tests-run-*/bridge_hub_westend_local_network/*.log ./zombienet-logs/ + +zombienet-bridges-0001-asset-transfer-works: + extends: + - .zombienet-bridges-common + script: + - /home/nonroot/bridges-polkadot-sdk/bridges/testing/run-new-test.sh 0001-asset-transfer --docker + - echo "Done" + +zombienet-bridges-0002-mandatory-headers-synced-while-idle: + extends: + - .zombienet-bridges-common + script: + - /home/nonroot/bridges-polkadot-sdk/bridges/testing/run-new-test.sh 0002-mandatory-headers-synced-while-idle --docker + - echo "Done" diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 54eb6db48cae63d9cfb08cf7da61125028904371..97572f029d0020f090a8fd16839028ac9f088cf9 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -158,6 +158,14 @@ zombienet-polkadot-functional-0011-async-backing-6-seconds-rate: --local-dir="${LOCAL_DIR}/functional" --test="0011-async-backing-6-seconds-rate.zndsl" +zombienet-polkadot-functional-0012-elastic-scaling-mvp: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0012-elastic-scaling-mvp.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common diff --git a/Cargo.lock b/Cargo.lock index 27a1efc38098cdbb2837fc10e1e79bab3877a70a..37c5a5177c0427703e1161433a76f5588d0299e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,16 +86,16 @@ dependencies = [ [[package]] name = "aes-gcm" -version = "0.9.4" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" dependencies = [ "aead 0.4.3", "aes 0.7.5", "cipher 0.3.0", - "ctr 0.8.0", + "ctr 0.7.0", "ghash 0.4.4", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -109,14 +109,14 @@ dependencies = [ "cipher 0.4.4", "ctr 0.9.2", "ghash 0.5.0", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom 0.2.10", "once_cell", @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" dependencies = [ "cfg-if", "getrandom 0.2.10", @@ -191,7 +191,7 @@ checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -206,7 +206,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "syn-solidity", "tiny-keccak", ] @@ -322,6 +322,20 @@ dependencies = [ "num-traits", ] +[[package]] +name = "aquamarine" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "aquamarine" version = "0.5.0" @@ -333,7 +347,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -730,12 +744,6 @@ dependencies = [ "nodrop", ] -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.4" @@ -1050,11 +1058,11 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", - "pallet-asset-conversion", "pallet-assets", "pallet-balances", "pallet-collator-selection", "pallet-session", + "pallet-timestamp", "pallet-xcm", "pallet-xcm-bridge-hub-router", "parachains-common", @@ -1099,7 +1107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] @@ -1109,7 +1117,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" dependencies = [ - "async-lock", + "async-lock 2.8.0", "async-task", "concurrent-queue", "fastrand 1.9.0", @@ -1123,7 +1131,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "blocking", "futures-lite", @@ -1135,7 +1143,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", @@ -1155,7 +1163,18 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy", + "pin-project-lite 0.2.12", ] [[package]] @@ -1177,11 +1196,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" dependencies = [ "async-io", - "async-lock", + "async-lock 2.8.0", "autocfg", "blocking", "cfg-if", - "event-listener", + "event-listener 2.5.3", "futures-lite", "rustix 0.37.23", "signal-hook", @@ -1207,7 +1226,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1224,7 +1243,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1309,7 +1328,7 @@ dependencies = [ "ark-std 0.4.0", "dleq_vrf", "fflonk", - "merlin 3.0.0", + "merlin", "rand_chacha 0.3.1", "rand_core 0.6.4", "ring 0.1.0", @@ -1406,7 +1425,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1415,9 +1434,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ - "bitcoin_hashes", - "rand", - "rand_core 0.6.4", + "bitcoin_hashes 0.11.0", "serde", "unicode-normalization", ] @@ -1437,12 +1454,28 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + [[package]] name = "bitcoin_hashes" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1534,18 +1567,6 @@ dependencies = [ "constant_time_eq 0.3.0", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -1564,15 +1585,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - [[package]] name = "blocking" version = "1.3.1" @@ -1580,7 +1592,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" dependencies = [ "async-channel", - "async-lock", + "async-lock 2.8.0", "async-task", "atomic-waker", "fastrand 1.9.0", @@ -2089,6 +2101,7 @@ dependencies = [ "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", + "pallet-timestamp", "pallet-utility", "parachains-common", "parachains-runtimes-test-utils", @@ -2591,40 +2604,40 @@ dependencies = [ "clap_lex 0.2.4", "indexmap 1.9.3", "once_cell", - "strsim", + "strsim 0.10.0", "termcolor", "textwrap", ] [[package]] name = "clap" -version = "4.4.18" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", - "clap_derive 4.4.7", + "clap_derive 4.5.0", ] [[package]] name = "clap-num" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488557e97528174edaa2ee268b23a809e0c598213a4bbcb4f34575a46fda147e" +checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" dependencies = [ "num-traits", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", - "clap_lex 0.6.0", - "strsim", + "clap_lex 0.7.0", + "strsim 0.11.0", "terminal_size", ] @@ -2634,7 +2647,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", ] [[package]] @@ -2652,14 +2665,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2673,9 +2686,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "coarsetime" @@ -2828,11 +2841,10 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", "windows-sys 0.48.0", ] @@ -2860,7 +2872,7 @@ dependencies = [ "ark-std 0.4.0", "fflonk", "getrandom_or_panic", - "merlin 3.0.0", + "merlin", "rand_chacha 0.3.1", ] @@ -3099,7 +3111,6 @@ dependencies = [ "pallet-xcm-benchmarks", "parachains-common", "parity-scale-codec", - "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", "rococo-runtime-constants", @@ -3150,11 +3161,11 @@ dependencies = [ "pallet-aura", "pallet-authorship", "pallet-balances", + "pallet-broker", "pallet-collator-selection", "pallet-message-queue", "pallet-multisig", "pallet-session", - "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -3163,7 +3174,6 @@ dependencies = [ "pallet-xcm-benchmarks", "parachains-common", "parity-scale-codec", - "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", "scale-info", @@ -3371,7 +3381,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.18", + "clap 4.5.1", "criterion-plot", "futures", "is-terminal", @@ -3467,7 +3477,7 @@ checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle 2.4.1", + "subtle 2.5.0", "zeroize", ] @@ -3499,24 +3509,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.7", - "subtle 2.4.1", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array 0.14.7", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] name = "ctr" -version = "0.8.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" dependencies = [ "cipher 0.3.0", ] @@ -3534,7 +3534,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3864,6 +3864,7 @@ dependencies = [ "pallet-message-queue", "parity-scale-codec", "polkadot-parachain-primitives", + "polkadot-runtime-common", "polkadot-runtime-parachains", "rand", "sc-client-api", @@ -3892,7 +3893,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4037,6 +4038,27 @@ dependencies = [ "sp-trie", ] +[[package]] +name = "cumulus-primitives-storage-weight-reclaim" +version = "1.0.0" +dependencies = [ + "cumulus-primitives-core", + "cumulus-primitives-proof-size-hostfunction", + "cumulus-test-runtime", + "docify 0.2.7", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0", + "sp-trie", +] + [[package]] name = "cumulus-primitives-timestamp" version = "0.7.0" @@ -4057,7 +4079,6 @@ dependencies = [ "frame-support", "log", "pallet-asset-conversion", - "pallet-xcm-benchmarks", "parity-scale-codec", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -4137,6 +4158,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-primitives", + "polkadot-service", "sc-authority-discovery", "sc-client-api", "sc-network", @@ -4199,6 +4221,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", + "cumulus-primitives-storage-weight-reclaim", "cumulus-test-relay-sproof-builder", "cumulus-test-runtime", "cumulus-test-service", @@ -4243,6 +4266,7 @@ version = "0.1.0" dependencies = [ "cumulus-pallet-parachain-system", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "frame-executive", "frame-support", "frame-system", @@ -4275,7 +4299,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.18", + "clap 4.5.1", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -4285,6 +4309,7 @@ dependencies = [ "cumulus-client-service", "cumulus-pallet-parachain-system", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", @@ -4347,19 +4372,6 @@ dependencies = [ "url", ] -[[package]] -name = "curve25519-dalek" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" -dependencies = [ - "byteorder", - "digest 0.8.1", - "rand_core 0.5.1", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -4369,15 +4381,15 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.4.1", + "subtle 2.5.0", "zeroize", ] [[package]] name = "curve25519-dalek" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" dependencies = [ "cfg-if", "cpufeatures", @@ -4386,7 +4398,7 @@ dependencies = [ "fiat-crypto", "platforms", "rustc_version 0.4.0", - "subtle 2.4.1", + "subtle 2.5.0", "zeroize", ] @@ -4398,7 +4410,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4438,7 +4450,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4455,7 +4467,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4610,7 +4622,7 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -4663,7 +4675,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4703,13 +4715,39 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "docify" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1b04e6ef3d21119d3eb7b032bca17f99fe041e9c072f30f32cc0e1a2b1f3c4" +dependencies = [ + "docify_macros 0.1.16", +] + [[package]] name = "docify" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cc4fd38aaa9fb98ac70794c82a00360d1e165a87fbf96a8a91f9dfc602aaee2" dependencies = [ - "docify_macros", + "docify_macros 0.2.7", +] + +[[package]] +name = "docify_macros" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5610df7f2acf89a1bb5d1a66ae56b1c7fcdcfe3948856fb3ace3f644d70eb7" +dependencies = [ + "common-path", + "derive-syn-parse", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "syn 2.0.50", + "termcolor", + "walkdir", ] [[package]] @@ -4724,7 +4762,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.48", + "syn 2.0.50", "termcolor", "toml 0.8.8", "walkdir", @@ -4791,6 +4829,7 @@ dependencies = [ "digest 0.10.7", "elliptic-curve", "rfc6979", + "serdect", "signature", "spki", ] @@ -4811,12 +4850,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.1.2", "ed25519", "rand_core 0.6.4", "serde", "sha2 0.10.7", - "subtle 2.4.1", + "subtle 2.5.0", "zeroize", ] @@ -4840,7 +4879,7 @@ version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.1.2", "ed25519", "hashbrown 0.14.3", "hex", @@ -4857,9 +4896,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" -version = "0.13.5" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", @@ -4870,7 +4909,8 @@ dependencies = [ "pkcs8", "rand_core 0.6.4", "sec1", - "subtle 2.4.1", + "serdect", + "subtle 2.5.0", "zeroize", ] @@ -4895,10 +4935,10 @@ dependencies = [ "paste", "polkadot-primitives", "polkadot-runtime-parachains", - "polkadot-service", "sc-consensus-grandpa", "sp-authority-discovery", "sp-consensus-babe", + "sp-consensus-beefy", "sp-core", "sp-runtime", "staging-xcm", @@ -4949,7 +4989,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4960,7 +5000,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5098,6 +5138,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite 0.2.12", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite 0.2.12", +] + [[package]] name = "exit-future" version = "0.2.0" @@ -5129,7 +5190,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5142,12 +5203,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fallible-iterator" version = "0.2.0" @@ -5244,7 +5299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core 0.6.4", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -5257,7 +5312,7 @@ dependencies = [ "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", - "merlin 3.0.0", + "merlin", ] [[package]] @@ -5397,7 +5452,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" name = "frame" version = "0.0.1-dev" dependencies = [ - "docify", + "docify 0.2.7", "frame-executive", "frame-support", "frame-system", @@ -5406,7 +5461,6 @@ dependencies = [ "pallet-examples", "parity-scale-codec", "scale-info", - "simple-mermaid", "sp-api", "sp-arithmetic", "sp-block-builder", @@ -5457,7 +5511,7 @@ dependencies = [ "Inflector", "array-bytes 6.1.0", "chrono", - "clap 4.4.18", + "clap 4.5.1", "comfy-table", "frame-benchmarking", "frame-support", @@ -5523,7 +5577,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.48", + "syn 2.0.50", "trybuild", ] @@ -5549,7 +5603,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5566,6 +5620,7 @@ dependencies = [ name = "frame-executive" version = "28.0.0" dependencies = [ + "aquamarine 0.3.3", "array-bytes 6.1.0", "frame-support", "frame-system", @@ -5622,11 +5677,11 @@ dependencies = [ name = "frame-support" version = "28.0.0" dependencies = [ - "aquamarine", + "aquamarine 0.5.0", "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", - "docify", + "docify 0.2.7", "environmental", "frame-metadata", "frame-support-procedural", @@ -5656,6 +5711,7 @@ dependencies = [ "sp-staking", "sp-state-machine", "sp-std 14.0.0", + "sp-timestamp", "sp-tracing 16.0.0", "sp-weights", "static_assertions", @@ -5678,7 +5734,7 @@ dependencies = [ "quote", "regex", "sp-crypto-hashing", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5689,7 +5745,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5698,7 +5754,7 @@ version = "11.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5769,7 +5825,7 @@ version = "28.0.0" dependencies = [ "cfg-if", "criterion 0.4.0", - "docify", + "docify 0.2.7", "frame-support", "log", "parity-scale-codec", @@ -5843,7 +5899,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", ] @@ -5861,9 +5917,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -5892,9 +5948,9 @@ checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -5931,7 +5987,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -6158,6 +6214,24 @@ dependencies = [ "testnet-parachains-constants", ] +[[package]] +name = "governor" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4" +dependencies = [ + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot 0.12.1", + "quanta", + "rand", + "smallvec", +] + [[package]] name = "group" version = "0.13.0" @@ -6166,7 +6240,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -6181,7 +6255,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.0.0", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -6196,9 +6270,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.3.7" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d" +checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" dependencies = [ "log", "pest", @@ -6229,7 +6303,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] @@ -6238,7 +6312,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", ] [[package]] @@ -6247,7 +6321,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "allocator-api2", "serde", ] @@ -6288,6 +6362,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + [[package]] name = "hex-literal" version = "0.4.1" @@ -6313,16 +6393,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.12.1" @@ -6447,9 +6517,9 @@ dependencies = [ "hyper", "log", "rustls 0.21.6", - "rustls-native-certs", + "rustls-native-certs 0.6.3", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", ] [[package]] @@ -6612,9 +6682,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -6714,7 +6784,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.2", - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -6777,9 +6847,9 @@ checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] name = "jsonrpsee" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" +checksum = "4a95f7cc23d5fab0cdeeaf6bad8c8f5e7a3aa7f0d211957ea78232b327ab27b0" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -6793,19 +6863,20 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b005c793122d03217da09af68ba9383363caa950b90d3436106df8cabce935" +checksum = "6b1736cfa3845fd9f8f43751f2b8e0e83f7b6081e754502f7d63b6587692cc83" dependencies = [ "futures-util", "http", "jsonrpsee-core", "pin-project", - "rustls-native-certs", + "rustls-native-certs 0.7.0", + "rustls-pki-types", "soketto", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", "tokio-util", "tracing", "url", @@ -6813,12 +6884,12 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +checksum = "82030d038658974732103e623ba2e0abec03bbbe175b39c0a2fafbada60c5868" dependencies = [ "anyhow", - "async-lock", + "async-lock 3.3.0", "async-trait", "beef", "futures-timer", @@ -6826,21 +6897,22 @@ dependencies = [ "hyper", "jsonrpsee-types", "parking_lot 0.12.1", + "pin-project", "rand", "rustc-hash", "serde", "serde_json", - "soketto", "thiserror", "tokio", + "tokio-stream", "tracing", ] [[package]] name = "jsonrpsee-http-client" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" +checksum = "36a06ef0de060005fddf772d54597bb6a8b0413da47dcffd304b0306147b9678" dependencies = [ "async-trait", "hyper", @@ -6858,12 +6930,12 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" +checksum = "69fc56131589f82e57805f7338b87023db4aafef813555708b159787e34ad6bc" dependencies = [ "heck", - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.0.0", "proc-macro2", "quote", "syn 1.0.109", @@ -6871,15 +6943,16 @@ dependencies = [ [[package]] name = "jsonrpsee-server" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" +checksum = "d85be77fe5b2a94589e3164fb780017f7aff7d646b49278c0d0346af16975c8e" dependencies = [ "futures-util", "http", "hyper", "jsonrpsee-core", "jsonrpsee-types", + "pin-project", "route-recognizer", "serde", "serde_json", @@ -6894,23 +6967,22 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" +checksum = "9a48fdc1202eafc51c63e00406575e59493284ace8b8b61aa16f3a6db5d64f1a" dependencies = [ "anyhow", "beef", "serde", "serde_json", "thiserror", - "tracing", ] [[package]] name = "jsonrpsee-ws-client" -version = "0.20.3" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca9cb3933ccae417eb6b08c3448eb1cb46e39834e5b503e395e5e5bd08546c0" +checksum = "c5ce25d70a8e4d3cc574bbc3cad0137c326ad64b194793d5e7bbdd3fa4504181" dependencies = [ "http", "jsonrpsee-client-transport", @@ -6921,14 +6993,15 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", "once_cell", + "serdect", "sha2 0.10.7", ] @@ -7008,6 +7081,7 @@ dependencies = [ "pallet-lottery", "pallet-membership", "pallet-message-queue", + "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", @@ -7020,6 +7094,7 @@ dependencies = [ "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", + "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", @@ -7638,7 +7713,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -7717,9 +7792,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" @@ -7833,6 +7908,15 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + [[package]] name = "macro_magic" version = "0.5.0" @@ -7842,7 +7926,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -7856,7 +7940,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -7867,7 +7951,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -7878,7 +7962,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -7996,18 +8080,6 @@ dependencies = [ "hash-db", ] -[[package]] -name = "merlin" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.5.1", - "zeroize", -] - [[package]] name = "merlin" version = "3.0.0" @@ -8044,15 +8116,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "minimal-node" -version = "4.0.0-dev" +name = "minimal-template-node" +version = "0.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "frame", "futures", "futures-timer", "jsonrpsee", - "minimal-runtime", + "minimal-template-runtime", "sc-basic-authorship", "sc-cli", "sc-client-api", @@ -8079,12 +8151,12 @@ dependencies = [ ] [[package]] -name = "minimal-runtime" -version = "0.1.0" +name = "minimal-template-runtime" +version = "0.0.0" dependencies = [ "frame", - "frame-support", "pallet-balances", + "pallet-minimal-template", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -8106,9 +8178,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -8126,7 +8198,7 @@ dependencies = [ "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.1.2", "either", "hashlink", "lioness", @@ -8135,7 +8207,7 @@ dependencies = [ "rand", "rand_chacha 0.3.1", "rand_distr", - "subtle 2.4.1", + "subtle 2.5.0", "thiserror", "zeroize", ] @@ -8499,6 +8571,12 @@ dependencies = [ "libc", ] +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + [[package]] name = "no-std-net" version = "0.6.0" @@ -8510,7 +8588,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes 6.1.0", - "clap 4.4.18", + "clap 4.5.1", "derive_more", "fs_extra", "futures", @@ -8587,114 +8665,31 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "generate-bags", "kitchensink-runtime", ] [[package]] -name = "node-template" -version = "4.0.0-dev" +name = "node-template-release" +version = "3.0.0" +dependencies = [ + "clap 4.5.1", + "flate2", + "fs_extra", + "glob", + "itertools 0.10.5", + "tar", + "tempfile", + "toml_edit 0.19.15", +] + +[[package]] +name = "node-testing" +version = "3.0.0-dev" dependencies = [ - "clap 4.4.18", - "frame-benchmarking", - "frame-benchmarking-cli", "frame-system", - "futures", - "jsonrpsee", - "node-template-runtime", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc", - "sc-basic-authorship", - "sc-cli", - "sc-client-api", - "sc-consensus", - "sc-consensus-aura", - "sc-consensus-grandpa", - "sc-executor", - "sc-network", - "sc-offchain", - "sc-rpc-api", - "sc-service", - "sc-telemetry", - "sc-transaction-pool", - "sc-transaction-pool-api", - "serde_json", - "sp-api", - "sp-block-builder", - "sp-blockchain", - "sp-consensus-aura", - "sp-consensus-grandpa", - "sp-core", - "sp-inherents", - "sp-io", - "sp-keyring", - "sp-runtime", - "sp-timestamp", - "substrate-build-script-utils", - "substrate-frame-rpc-system", - "try-runtime-cli", -] - -[[package]] -name = "node-template-release" -version = "3.0.0" -dependencies = [ - "clap 4.4.18", - "flate2", - "fs_extra", - "glob", - "itertools 0.10.5", - "tar", - "tempfile", - "toml_edit 0.19.15", -] - -[[package]] -name = "node-template-runtime" -version = "4.0.0-dev" -dependencies = [ - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "pallet-aura", - "pallet-balances", - "pallet-grandpa", - "pallet-sudo", - "pallet-template", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec", - "scale-info", - "serde_json", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-consensus-grandpa", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std 14.0.0", - "sp-storage 19.0.0", - "sp-transaction-pool", - "sp-version", - "substrate-wasm-builder", -] - -[[package]] -name = "node-testing" -version = "3.0.0-dev" -dependencies = [ - "frame-system", - "fs_extra", + "fs_extra", "futures", "kitchensink-runtime", "log", @@ -8749,6 +8744,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -8900,9 +8901,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -8958,7 +8959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eedb646674596266dc9bb2b5c7eea7c36b32ecc7777eba0d510196972d72c4fd" dependencies = [ "expander 2.0.0", - "indexmap 2.0.0", + "indexmap 2.2.3", "itertools 0.11.0", "petgraph", "proc-macro-crate 1.3.1", @@ -9039,6 +9040,7 @@ dependencies = [ name = "pallet-asset-conversion-tx-payment" version = "10.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-asset-conversion", @@ -9206,8 +9208,8 @@ dependencies = [ name = "pallet-bags-list" version = "27.0.0" dependencies = [ - "aquamarine", - "docify", + "aquamarine 0.5.0", + "docify 0.2.7", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -9255,7 +9257,7 @@ dependencies = [ name = "pallet-balances" version = "28.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -9576,7 +9578,6 @@ dependencies = [ "tempfile", "toml 0.8.8", "twox-hash", - "wat", ] [[package]] @@ -9623,7 +9624,7 @@ version = "18.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -9735,6 +9736,7 @@ dependencies = [ "pallet-bags-list", "pallet-balances", "pallet-election-provider-multi-phase", + "pallet-nomination-pools", "pallet-session", "pallet-staking", "pallet-timestamp", @@ -9869,6 +9871,26 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-example-single-block-migrations" +version = "0.0.1" +dependencies = [ + "docify 0.2.7", + "frame-executive", + "frame-support", + "frame-system", + "frame-try-runtime", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0", + "sp-version", +] + [[package]] name = "pallet-example-split" version = "10.0.0" @@ -9910,6 +9932,7 @@ dependencies = [ "pallet-example-frame-crate", "pallet-example-kitchensink", "pallet-example-offchain-worker", + "pallet-example-single-block-migrations", "pallet-example-split", "pallet-example-tasks", ] @@ -9918,7 +9941,7 @@ dependencies = [ name = "pallet-fast-unstake" version = "27.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -10115,6 +10138,39 @@ dependencies = [ "sp-weights", ] +[[package]] +name = "pallet-migrations" +version = "1.0.0" +dependencies = [ + "docify 0.1.16", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "pretty_assertions", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0", + "sp-tracing 16.0.0", + "sp-version", +] + +[[package]] +name = "pallet-minimal-template" +version = "0.0.0" +dependencies = [ + "frame", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "pallet-mixnet" version = "0.4.0" @@ -10390,7 +10446,7 @@ dependencies = [ name = "pallet-paged-list" version = "0.6.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -10416,17 +10472,36 @@ dependencies = [ [[package]] name = "pallet-parachain-template" -version = "0.7.0" +version = "0.0.0" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "parity-scale-codec", "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + +[[package]] +name = "pallet-parameters" +version = "0.0.1" +dependencies = [ + "docify 0.2.7", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-example-basic", + "parity-scale-codec", + "paste", + "scale-info", "serde", "sp-core", "sp-io", "sp-runtime", + "sp-std 14.0.0", ] [[package]] @@ -10574,7 +10649,7 @@ dependencies = [ name = "pallet-safe-mode" version = "9.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -10631,7 +10706,7 @@ dependencies = [ name = "pallet-scheduler" version = "29.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -10777,7 +10852,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -10844,7 +10919,7 @@ dependencies = [ name = "pallet-sudo" version = "28.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -10858,7 +10933,7 @@ dependencies = [ [[package]] name = "pallet-template" -version = "4.0.0-dev" +version = "0.0.0" dependencies = [ "frame-benchmarking", "frame-support", @@ -10868,14 +10943,13 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0", ] [[package]] name = "pallet-timestamp" version = "27.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -10915,6 +10989,7 @@ dependencies = [ name = "pallet-transaction-payment" version = "28.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-balances", @@ -10979,7 +11054,7 @@ dependencies = [ name = "pallet-treasury" version = "27.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -10999,7 +11074,7 @@ dependencies = [ name = "pallet-tx-pause" version = "9.0.0" dependencies = [ - "docify", + "docify 0.2.7", "frame-benchmarking", "frame-support", "frame-system", @@ -11181,9 +11256,9 @@ dependencies = [ [[package]] name = "parachain-template-node" -version = "0.1.0" +version = "0.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11239,7 +11314,7 @@ dependencies = [ [[package]] name = "parachain-template-runtime" -version = "0.7.0" +version = "0.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", @@ -11247,6 +11322,7 @@ dependencies = [ "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -11339,6 +11415,7 @@ dependencies = [ "pallet-balances", "pallet-collator-selection", "pallet-session", + "pallet-timestamp", "pallet-xcm", "parity-scale-codec", "polkadot-parachain-primitives", @@ -11354,6 +11431,19 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "parity-bip39" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" +dependencies = [ + "bitcoin_hashes 0.13.0", + "rand", + "rand_core 0.6.4", + "serde", + "unicode-normalization", +] + [[package]] name = "parity-bytes" version = "0.1.2" @@ -11509,19 +11599,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156" [[package]] -name = "paste" -version = "1.0.14" +name = "password-hash" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle 2.5.0", +] [[package]] -name = "pbkdf2" -version = "0.8.0" +name = "paste" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" -dependencies = [ - "crypto-mac 0.11.1", -] +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pbkdf2" @@ -11530,6 +11622,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", + "password-hash", ] [[package]] @@ -11620,7 +11713,6 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", - "testnet-parachains-constants", ] [[package]] @@ -11857,7 +11949,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -11878,7 +11970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.0", + "indexmap 2.2.3", ] [[package]] @@ -11898,7 +11990,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -12064,6 +12156,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "polkadot-subsystem-bench", "rand", "sc-network", "schnellru", @@ -12095,6 +12188,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "polkadot-subsystem-bench", "rand", "sc-network", "schnellru", @@ -12111,7 +12205,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.4.18", + "clap 4.5.1", "frame-benchmarking-cli", "futures", "log", @@ -12130,6 +12224,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-maybe-compressed-blob", + "sp-runtime", "substrate-build-script-utils", "thiserror", "try-runtime-cli", @@ -12187,7 +12282,7 @@ dependencies = [ "fatality", "futures", "futures-timer", - "indexmap 2.0.0", + "indexmap 2.2.3", "lazy_static", "parity-scale-codec", "polkadot-erasure-coding", @@ -12232,6 +12327,7 @@ dependencies = [ "futures", "futures-timer", "lazy_static", + "parking_lot 0.12.1", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -12318,7 +12414,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "log", - "merlin 3.0.0", + "merlin", "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-jaeger", @@ -12393,7 +12489,9 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-statement-table", + "rstest", "sc-keystore", + "schnellru", "sp-application-crypto", "sp-core", "sp-keyring", @@ -12545,6 +12643,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "rstest", "sc-keystore", "sp-application-crypto", "sp-core", @@ -12568,6 +12667,8 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "rstest", + "schnellru", "sp-application-crypto", "sp-keystore", "thiserror", @@ -12954,7 +13055,7 @@ dependencies = [ "async-trait", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.4.18", + "clap 4.5.1", "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", @@ -13063,6 +13164,7 @@ version = "7.0.0" dependencies = [ "bitvec", "hex-literal", + "log", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", @@ -13155,7 +13257,6 @@ dependencies = [ "pallet-transaction-payment", "pallet-treasury", "pallet-vesting", - "pallet-xcm-benchmarks", "parity-scale-codec", "polkadot-primitives", "polkadot-primitives-test-helpers", @@ -13229,6 +13330,7 @@ dependencies = [ "polkadot-runtime-metrics", "rand", "rand_chacha 0.3.1", + "rstest", "rustc-hex", "sc-keystore", "scale-info", @@ -13260,13 +13362,28 @@ version = "0.0.1" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", - "docify", + "docify 0.2.7", "frame", + "frame-executive", + "frame-support", + "frame-system", "kitchensink-runtime", + "pallet-assets", "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collective", "pallet-default-config-example", + "pallet-democracy", + "pallet-example-offchain-worker", + "pallet-example-single-block-migrations", "pallet-examples", + "pallet-multisig", + "pallet-proxy", + "pallet-scheduler", "pallet-timestamp", + "pallet-transaction-payment", + "pallet-utility", "parity-scale-codec", "sc-cli", "sc-client-db", @@ -13285,10 +13402,13 @@ dependencies = [ "sp-core", "sp-io", "sp-keyring", + "sp-offchain", "sp-runtime", + "sp-version", "staging-chain-spec-builder", "staging-node-cli", "staging-parachain-info", + "staging-xcm", "subkey", "substrate-wasm-builder", ] @@ -13299,6 +13419,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "async-trait", + "bitvec", "env_logger 0.9.3", "frame-benchmarking", "frame-benchmarking-cli", @@ -13429,7 +13550,7 @@ dependencies = [ "fatality", "futures", "futures-timer", - "indexmap 2.0.0", + "indexmap 2.2.3", "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -13459,6 +13580,7 @@ dependencies = [ "parity-scale-codec", "polkadot-primitives", "sp-core", + "tracing-gum", ] [[package]] @@ -13469,7 +13591,7 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.4.18", + "clap 4.5.1", "clap-num", "color-eyre", "colored", @@ -13511,7 +13633,7 @@ dependencies = [ "sc-keystore", "sc-network", "sc-service", - "schnorrkel 0.9.1", + "schnorrkel 0.11.4", "serde", "serde_yaml", "sha1", @@ -13563,7 +13685,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.18", + "clap 4.5.1", "color-eyre", "futures", "futures-timer", @@ -13710,12 +13832,34 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "generate-bags", "sp-io", "westend-runtime", ] +[[package]] +name = "polkavm" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3693e5efdb2bf74e449cd25fd777a28bd7ed87e41f5d5da75eb31b4de48b94" +dependencies = [ + "libc", + "log", + "polkavm-assembler", + "polkavm-common 0.9.0", + "polkavm-linux-raw", +] + +[[package]] +name = "polkavm-assembler" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa96d6d868243acc12de813dd48e756cbadcc8e13964c70d272753266deadc1" +dependencies = [ + "log", +] + [[package]] name = "polkavm-common" version = "0.5.0" @@ -13724,9 +13868,12 @@ checksum = "88b4e215c80fe876147f3d58158d5dfeae7dabdd6047e175af77095b78d0035c" [[package]] name = "polkavm-common" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c99f7eee94e7be43ba37eef65ad0ee8cbaf89b7c00001c3f6d2be985cb1817" +checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92" +dependencies = [ + "log", +] [[package]] name = "polkavm-derive" @@ -13735,14 +13882,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6380dbe1fb03ecc74ad55d841cfc75480222d153ba69ddcb00977866cbdabdb8" dependencies = [ "polkavm-derive-impl 0.5.0", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "polkavm-derive" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79fa916f7962348bd1bb1a65a83401675e6fc86c51a0fdbcf92a3108e58e6125" +checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606" dependencies = [ "polkavm-derive-impl-macro", ] @@ -13756,29 +13903,29 @@ dependencies = [ "polkavm-common 0.5.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "polkavm-derive-impl" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c10b2654a8a10a83c260bfb93e97b262cf0017494ab94a65d389e0eda6de6c9c" +checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ - "polkavm-common 0.8.0", + "polkavm-common 0.9.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "polkavm-derive-impl-macro" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" +checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ - "polkavm-derive-impl 0.8.0", - "syn 2.0.48", + "polkavm-derive-impl 0.9.0", + "syn 2.0.50", ] [[package]] @@ -13798,19 +13945,25 @@ dependencies = [ [[package]] name = "polkavm-linker" -version = "0.8.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdec1451cb18261d5d01de82acc15305e417fb59588cdcb3127d3dcc9672b925" +checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" dependencies = [ "gimli 0.28.0", "hashbrown 0.14.3", "log", "object 0.32.2", - "polkavm-common 0.8.0", + "polkavm-common 0.9.0", "regalloc2 0.9.3", "rustc-demangle", ] +[[package]] +name = "polkavm-linux-raw" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" + [[package]] name = "polling" version = "2.8.0" @@ -13835,7 +13988,7 @@ checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", - "universal-hash 0.4.1", + "universal-hash 0.4.0", ] [[package]] @@ -13858,7 +14011,7 @@ dependencies = [ "cfg-if", "cpufeatures", "opaque-debug 0.3.0", - "universal-hash 0.4.1", + "universal-hash 0.4.0", ] [[package]] @@ -13983,7 +14136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -14074,7 +14227,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -14098,7 +14251,7 @@ dependencies = [ "hex", "lazy_static", "procfs-core", - "rustix 0.38.21", + "rustix 0.38.25", ] [[package]] @@ -14146,7 +14299,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -14246,7 +14399,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -14297,6 +14450,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "quanta" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +dependencies = [ + "crossbeam-utils", + "libc", + "mach2", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -14454,7 +14623,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.6.4", +] + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", ] [[package]] @@ -14564,7 +14742,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -14642,11 +14820,17 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "relative-path" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" + [[package]] name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -14681,12 +14865,12 @@ dependencies = [ "percent-encoding", "pin-project-lite 0.2.12", "rustls 0.21.6", - "rustls-pemfile", + "rustls-pemfile 1.0.3", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -14713,7 +14897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac 0.12.1", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -14729,7 +14913,7 @@ dependencies = [ "blake2 0.10.6", "common", "fflonk", - "merlin 3.0.0", + "merlin", ] [[package]] @@ -15024,6 +15208,35 @@ dependencies = [ "winapi", ] +[[package]] +name = "rstest" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version 0.4.0", +] + +[[package]] +name = "rstest_macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" +dependencies = [ + "cfg-if", + "glob", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version 0.4.0", + "syn 2.0.50", + "unicode-ident", +] + [[package]] name = "rtnetlink" version = "0.10.1" @@ -15163,14 +15376,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.4.0", "errno", "libc", - "linux-raw-sys 0.4.10", + "linux-raw-sys 0.4.11", "windows-sys 0.48.0", ] @@ -15194,10 +15407,24 @@ checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" dependencies = [ "log", "ring 0.16.20", - "rustls-webpki", + "rustls-webpki 0.101.4", "sct", ] +[[package]] +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-pki-types", + "rustls-webpki 0.102.2", + "subtle 2.5.0", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -15205,7 +15432,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.3", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.0.0", + "rustls-pki-types", "schannel", "security-framework", ] @@ -15219,6 +15459,22 @@ dependencies = [ "base64 0.21.2", ] +[[package]] +name = "rustls-pemfile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +dependencies = [ + "base64 0.21.2", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" + [[package]] name = "rustls-webpki" version = "0.101.4" @@ -15229,6 +15485,17 @@ dependencies = [ "untrusted 0.7.1", ] +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring 0.17.7", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -15389,7 +15656,7 @@ name = "sc-chain-spec" version = "27.0.0" dependencies = [ "array-bytes 6.1.0", - "docify", + "docify 0.2.7", "log", "memmap2 0.9.3", "parity-scale-codec", @@ -15420,7 +15687,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -15428,9 +15695,8 @@ name = "sc-cli" version = "0.36.0" dependencies = [ "array-bytes 6.1.0", - "bip39", "chrono", - "clap 4.4.18", + "clap 4.5.1", "fdlimit", "futures", "futures-timer", @@ -15438,6 +15704,7 @@ dependencies = [ "libp2p-identity", "log", "names", + "parity-bip39", "parity-scale-codec", "rand", "regex", @@ -15741,7 +16008,7 @@ dependencies = [ name = "sc-consensus-grandpa" version = "0.19.0" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "array-bytes 6.1.0", "assert_matches", "async-trait", @@ -15909,6 +16176,7 @@ dependencies = [ "paste", "regex", "sc-executor-common", + "sc-executor-polkavm", "sc-executor-wasmtime", "sc-runtime-test", "sc-tracing", @@ -15938,6 +16206,7 @@ dependencies = [ name = "sc-executor-common" version = "0.29.0" dependencies = [ + "polkavm", "sc-allocator", "sp-maybe-compressed-blob", "sp-wasm-interface 20.0.0", @@ -15945,6 +16214,16 @@ dependencies = [ "wasm-instrument", ] +[[package]] +name = "sc-executor-polkavm" +version = "0.29.0" +dependencies = [ + "log", + "polkavm", + "sc-executor-common", + "sp-wasm-interface 20.0.0", +] + [[package]] name = "sc-executor-wasmtime" version = "0.29.0" @@ -16127,7 +16406,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.34.0" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "async-trait", "futures", "futures-timer", @@ -16386,7 +16665,10 @@ dependencies = [ name = "sc-rpc-server" version = "11.0.0" dependencies = [ + "futures", + "governor", "http", + "hyper", "jsonrpsee", "log", "serde_json", @@ -16410,11 +16692,13 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "pretty_assertions", + "rand", "sc-block-builder", "sc-chain-spec", "sc-client-api", "sc-rpc", "sc-service", + "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "serde", @@ -16430,6 +16714,7 @@ dependencies = [ "sp-version", "substrate-test-runtime", "substrate-test-runtime-client", + "substrate-test-runtime-transaction-pool", "thiserror", "tokio", "tokio-stream", @@ -16484,6 +16769,7 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", + "schnellru", "serde", "serde_json", "sp-api", @@ -16581,7 +16867,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "fs4", "log", "sp-core", @@ -16683,7 +16969,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -16816,27 +17102,11 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "cfg-if", "hashbrown 0.13.2", ] -[[package]] -name = "schnorrkel" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "curve25519-dalek 2.1.3", - "merlin 2.0.1", - "rand_core 0.5.1", - "sha2 0.8.2", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "schnorrkel" version = "0.10.2" @@ -16846,7 +17116,7 @@ dependencies = [ "arrayref", "arrayvec 0.7.4", "curve25519-dalek-ng", - "merlin 3.0.0", + "merlin", "rand_core 0.6.4", "sha2 0.9.9", "subtle-ng", @@ -16862,13 +17132,13 @@ dependencies = [ "aead 0.5.2", "arrayref", "arrayvec 0.7.4", - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.1.2", "getrandom_or_panic", - "merlin 3.0.0", + "merlin", "rand_core 0.6.4", "serde_bytes", "sha2 0.10.7", - "subtle 2.4.1", + "subtle 2.5.0", "zeroize", ] @@ -16910,7 +17180,8 @@ dependencies = [ "der", "generic-array 0.14.7", "pkcs8", - "subtle 2.4.1", + "serdect", + "subtle 2.5.0", "zeroize", ] @@ -17067,9 +17338,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -17094,13 +17365,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -17125,9 +17396,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -17157,17 +17428,27 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.30" +version = "0.9.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" +checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.3", "itoa", "ryu", "serde", "unsafe-libyaml", ] +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "serial_test" version = "2.0.0" @@ -17190,7 +17471,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -17228,18 +17509,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - [[package]] name = "sha2" version = "0.9.9" @@ -17370,8 +17639,9 @@ dependencies = [ [[package]] name = "simple-mermaid" -version = "0.1.0" -source = "git+https://github.com/kianenigma/simple-mermaid.git?rev=e48b187bcfd5cc75111acd9d241f1bd36604344b#e48b187bcfd5cc75111acd9d241f1bd36604344b" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "620a1d43d70e142b1d46a929af51d44f383db9c7a2ec122de2cd992ccfcf3c18" [[package]] name = "siphasher" @@ -17430,7 +17700,7 @@ dependencies = [ "async-executor", "async-fs", "async-io", - "async-lock", + "async-lock 2.8.0", "async-net", "async-process", "blocking", @@ -17453,7 +17723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ "arrayvec 0.7.4", - "async-lock", + "async-lock 2.8.0", "atomic-take", "base64 0.21.2", "bip39", @@ -17464,7 +17734,7 @@ dependencies = [ "derive_more", "ed25519-zebra 4.0.3", "either", - "event-listener", + "event-listener 2.5.3", "fnv", "futures-lite", "futures-util", @@ -17473,13 +17743,13 @@ dependencies = [ "hmac 0.12.1", "itertools 0.11.0", "libsecp256k1", - "merlin 3.0.0", + "merlin", "no-std-net", "nom", "num-bigint", "num-rational", "num-traits", - "pbkdf2 0.12.2", + "pbkdf2", "pin-project", "poly1305 0.8.0", "rand", @@ -17507,12 +17777,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ "async-channel", - "async-lock", + "async-lock 2.8.0", "base64 0.21.2", "blake2-rfc", "derive_more", "either", - "event-listener", + "event-listener 2.5.3", "fnv", "futures-channel", "futures-lite", @@ -17548,15 +17818,15 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" dependencies = [ - "aes-gcm 0.9.4", + "aes-gcm 0.9.2", "blake2 0.10.6", "chacha20poly1305", - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.1.2", "rand_core 0.6.4", "ring 0.16.20", "rustc_version 0.4.0", "sha2 0.10.7", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -17571,7 +17841,7 @@ dependencies = [ [[package]] name = "snowbridge-beacon-primitives" -version = "0.0.0" +version = "0.2.0" dependencies = [ "byte-slice-cast", "frame-support", @@ -17595,7 +17865,7 @@ dependencies = [ [[package]] name = "snowbridge-core" -version = "0.0.0" +version = "0.2.0" dependencies = [ "ethabi-decode", "frame-support", @@ -17618,7 +17888,7 @@ dependencies = [ [[package]] name = "snowbridge-ethereum" -version = "0.1.0" +version = "0.3.0" dependencies = [ "ethabi-decode", "ethbloom", @@ -17657,7 +17927,7 @@ dependencies = [ [[package]] name = "snowbridge-outbound-queue-merkle-tree" -version = "0.1.1" +version = "0.3.0" dependencies = [ "array-bytes 4.2.0", "env_logger 0.9.3", @@ -17672,7 +17942,7 @@ dependencies = [ [[package]] name = "snowbridge-outbound-queue-runtime-api" -version = "0.0.0" +version = "0.2.0" dependencies = [ "frame-support", "parity-scale-codec", @@ -17686,7 +17956,7 @@ dependencies = [ [[package]] name = "snowbridge-pallet-ethereum-client" -version = "0.0.0" +version = "0.2.0" dependencies = [ "bp-runtime", "byte-slice-cast", @@ -17732,7 +18002,7 @@ dependencies = [ [[package]] name = "snowbridge-pallet-inbound-queue" -version = "0.0.0" +version = "0.2.0" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -17765,7 +18035,7 @@ dependencies = [ [[package]] name = "snowbridge-pallet-inbound-queue-fixtures" -version = "0.9.0" +version = "0.10.0" dependencies = [ "frame-benchmarking", "frame-support", @@ -17779,7 +18049,7 @@ dependencies = [ [[package]] name = "snowbridge-pallet-outbound-queue" -version = "0.0.0" +version = "0.2.0" dependencies = [ "bridge-hub-common", "ethabi-decode", @@ -17804,7 +18074,7 @@ dependencies = [ [[package]] name = "snowbridge-pallet-system" -version = "0.0.0" +version = "0.2.0" dependencies = [ "ethabi-decode", "frame-benchmarking", @@ -17832,7 +18102,7 @@ dependencies = [ [[package]] name = "snowbridge-router-primitives" -version = "0.0.0" +version = "0.9.0" dependencies = [ "ethabi-decode", "frame-support", @@ -17855,7 +18125,7 @@ dependencies = [ [[package]] name = "snowbridge-runtime-common" -version = "0.0.0" +version = "0.2.0" dependencies = [ "frame-support", "frame-system", @@ -17871,7 +18141,7 @@ dependencies = [ [[package]] name = "snowbridge-runtime-test-common" -version = "0.0.0" +version = "0.2.0" dependencies = [ "assets-common", "bridge-hub-test-utils", @@ -17948,7 +18218,7 @@ dependencies = [ [[package]] name = "snowbridge-system-runtime-api" -version = "0.0.0" +version = "0.2.0" dependencies = [ "parity-scale-codec", "snowbridge-core", @@ -17995,6 +18265,87 @@ dependencies = [ "sha-1 0.9.8", ] +[[package]] +name = "solochain-template-node" +version = "0.0.0" +dependencies = [ + "clap 4.5.1", + "frame-benchmarking-cli", + "frame-system", + "futures", + "jsonrpsee", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc", + "sc-basic-authorship", + "sc-cli", + "sc-client-api", + "sc-consensus", + "sc-consensus-aura", + "sc-consensus-grandpa", + "sc-executor", + "sc-network", + "sc-offchain", + "sc-rpc-api", + "sc-service", + "sc-telemetry", + "sc-transaction-pool", + "sc-transaction-pool-api", + "serde_json", + "solochain-template-runtime", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-consensus-aura", + "sp-consensus-grandpa", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keyring", + "sp-runtime", + "sp-timestamp", + "substrate-build-script-utils", + "substrate-frame-rpc-system", + "try-runtime-cli", +] + +[[package]] +name = "solochain-template-runtime" +version = "0.0.0" +dependencies = [ + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "pallet-aura", + "pallet-balances", + "pallet-grandpa", + "pallet-sudo", + "pallet-template", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-consensus-grandpa", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 14.0.0", + "sp-storage 19.0.0", + "sp-transaction-pool", + "sp-version", + "substrate-wasm-builder", +] + [[package]] name = "sp-api" version = "26.0.0" @@ -18028,7 +18379,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -18225,6 +18576,7 @@ dependencies = [ "sp-core", "sp-crypto-hashing", "sp-io", + "sp-keystore", "sp-mmr-primitives", "sp-runtime", "sp-std 14.0.0", @@ -18292,7 +18644,6 @@ version = "28.0.0" dependencies = [ "array-bytes 6.1.0", "bandersnatch_vrfs", - "bip39", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", @@ -18305,10 +18656,12 @@ dependencies = [ "hash256-std-hasher", "impl-serde", "itertools 0.10.5", + "k256", "lazy_static", "libsecp256k1", "log", - "merlin 3.0.0", + "merlin", + "parity-bip39", "parity-scale-codec", "parking_lot 0.12.1", "paste", @@ -18362,7 +18715,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", @@ -18420,7 +18773,7 @@ version = "0.0.0" dependencies = [ "quote", "sp-crypto-hashing", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -18438,7 +18791,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -18447,7 +18800,7 @@ version = "14.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -18504,6 +18857,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", + "polkavm-derive 0.9.1", "rustversion", "secp256k1", "sp-core", @@ -18538,7 +18892,6 @@ dependencies = [ "rand_chacha 0.2.2", "sp-core", "sp-externalities 0.25.0", - "thiserror", ] [[package]] @@ -18607,7 +18960,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "honggfuzz", "rand", "sp-npos-elections", @@ -18646,7 +18999,7 @@ dependencies = [ name = "sp-runtime" version = "31.0.1" dependencies = [ - "docify", + "docify 0.2.7", "either", "hash256-std-hasher", "impl-trait-for-tuples", @@ -18668,6 +19021,7 @@ dependencies = [ "sp-tracing 16.0.0", "sp-weights", "substrate-test-runtime-client", + "tuplex", "zstd 0.12.4", ] @@ -18696,7 +19050,7 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive 0.8.0", + "polkavm-derive 0.9.1", "primitive-types", "rustversion", "sp-core", @@ -18716,13 +19070,13 @@ dependencies = [ [[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", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -18734,7 +19088,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -18831,7 +19185,7 @@ name = "sp-statement-store" version = "10.0.0" dependencies = [ "aes-gcm 0.10.3", - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.1.2", "ed25519-dalek", "hkdf", "parity-scale-codec", @@ -18958,7 +19312,7 @@ dependencies = [ name = "sp-trie" version = "29.0.0" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "array-bytes 6.1.0", "criterion 0.4.0", "hash-db", @@ -19006,7 +19360,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -19130,7 +19484,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "2.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "log", "sc-chain-spec", "serde_json", @@ -19143,7 +19497,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes 6.1.0", "assert_cmd", - "clap 4.4.18", + "clap 4.5.1", "clap_complete", "criterion 0.4.0", "frame-benchmarking", @@ -19253,7 +19607,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -19397,7 +19751,7 @@ dependencies = [ "bitflags 1.3.2", "byteorder", "keccak", - "subtle 2.4.1", + "subtle 2.5.0", "zeroize", ] @@ -19407,6 +19761,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "strum" version = "0.24.1" @@ -19445,27 +19805,27 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "sc-cli", ] [[package]] name = "substrate-bip39" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e620c7098893ba667438b47169c00aacdd9e7c10e042250ce2b60b087ec97328" +version = "0.4.7" dependencies = [ - "hmac 0.11.0", - "pbkdf2 0.8.0", - "schnorrkel 0.9.1", - "sha2 0.9.9", + "bip39", + "hmac 0.12.1", + "pbkdf2", + "rustc-hex", + "schnorrkel 0.11.4", + "sha2 0.10.7", "zeroize", ] @@ -19494,7 +19854,7 @@ dependencies = [ name = "substrate-frame-cli" version = "32.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "frame-support", "frame-system", "sc-cli", @@ -19712,7 +20072,7 @@ dependencies = [ "console", "filetime", "parity-wasm", - "polkavm-linker 0.8.2", + "polkavm-linker 0.9.2", "sp-maybe-compressed-blob", "strum 0.24.1", "tempfile", @@ -19729,9 +20089,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "subtle-ng" @@ -19843,9 +20203,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -19861,7 +20221,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -19929,7 +20289,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.0", "redox_syscall 0.4.1", - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -19948,7 +20308,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", ] @@ -19975,7 +20335,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "futures", "futures-timer", "log", @@ -20023,7 +20383,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.1", "futures", "futures-timer", "log", @@ -20126,7 +20486,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -20287,7 +20647,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -20311,6 +20671,17 @@ 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.2", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -20399,7 +20770,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.3", "toml_datetime", "winnow", ] @@ -20410,7 +20781,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.3", "serde", "serde_spanned", "toml_datetime", @@ -20483,7 +20854,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -20525,7 +20896,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -20707,7 +21078,7 @@ version = "0.38.0" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.18", + "clap 4.5.1", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -20783,6 +21154,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tuplex" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "676ac81d5454c4dcf37955d34fa8626ede3490f744b86ca14a7b90168d2a08aa" + [[package]] name = "twox-hash" version = "1.6.3" @@ -20860,12 +21237,12 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" dependencies = [ "generic-array 0.14.7", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -20875,7 +21252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle 2.4.1", + "subtle 2.5.0", ] [[package]] @@ -21090,7 +21467,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-shared", ] @@ -21124,7 +21501,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -22043,7 +22420,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.1.2", "rand_core 0.6.4", "serde", "zeroize", @@ -22119,10 +22496,12 @@ dependencies = [ "pallet-transaction-payment", "pallet-xcm", "parity-scale-codec", + "polkadot-service", "polkadot-test-client", "polkadot-test-runtime", "polkadot-test-service", "sp-consensus", + "sp-core", "sp-keyring", "sp-runtime", "sp-state-machine", @@ -22139,7 +22518,7 @@ dependencies = [ "proc-macro2", "quote", "staging-xcm", - "syn 2.0.48", + "syn 2.0.50", "trybuild", ] @@ -22192,8 +22571,10 @@ name = "xcm-simulator-fuzzer" version = "1.0.0" dependencies = [ "arbitrary", + "frame-executive", "frame-support", "frame-system", + "frame-try-runtime", "honggfuzz", "pallet-balances", "pallet-message-queue", @@ -22259,14 +22640,14 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -22279,7 +22660,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8cbfc7a23fed6130e2af818ccc931ca58137c1bc..f256d02808a8f4475eeb4d0c7ac35d305cfe05ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ authors = ["Parity Technologies "] edition = "2021" repository = "https://github.com/paritytech/polkadot-sdk.git" license = "GPL-3.0-only" +homepage = "https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html" [workspace] resolver = "2" @@ -74,9 +75,6 @@ members = [ "cumulus/pallets/solo-to-para", "cumulus/pallets/xcm", "cumulus/pallets/xcmp-queue", - "cumulus/parachain-template/node", - "cumulus/parachain-template/pallets/template", - "cumulus/parachain-template/runtime", "cumulus/parachains/common", "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend", @@ -127,6 +125,7 @@ members = [ "cumulus/primitives/core", "cumulus/primitives/parachain-inherent", "cumulus/primitives/proof-size-hostfunction", + "cumulus/primitives/storage-weight-reclaim", "cumulus/primitives/timestamp", "cumulus/primitives/utility", "cumulus/test/client", @@ -218,11 +217,6 @@ members = [ "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", - "substrate/bin/minimal/node", - "substrate/bin/minimal/runtime", - "substrate/bin/node-template/node", - "substrate/bin/node-template/pallets/template", - "substrate/bin/node-template/runtime", "substrate/bin/node/bench", "substrate/bin/node/cli", "substrate/bin/node/inspect", @@ -255,6 +249,7 @@ members = [ "substrate/client/db", "substrate/client/executor", "substrate/client/executor/common", + "substrate/client/executor/polkavm", "substrate/client/executor/runtime-test", "substrate/client/executor/wasmtime", "substrate/client/informant", @@ -336,6 +331,7 @@ members = [ "substrate/frame/examples/frame-crate", "substrate/frame/examples/kitchensink", "substrate/frame/examples/offchain-worker", + "substrate/frame/examples/single-block-migrations", "substrate/frame/examples/split", "substrate/frame/examples/tasks", "substrate/frame/executive", @@ -350,6 +346,7 @@ members = [ "substrate/frame/membership", "substrate/frame/merkle-mountain-range", "substrate/frame/message-queue", + "substrate/frame/migrations", "substrate/frame/mixnet", "substrate/frame/multisig", "substrate/frame/nft-fractionalization", @@ -366,6 +363,7 @@ members = [ "substrate/frame/offences/benchmarking", "substrate/frame/paged-list", "substrate/frame/paged-list/fuzzer", + "substrate/frame/parameters", "substrate/frame/preimage", "substrate/frame/proxy", "substrate/frame/ranked-collective", @@ -499,7 +497,20 @@ members = [ "substrate/utils/frame/rpc/system", "substrate/utils/frame/try-runtime/cli", "substrate/utils/prometheus", + "substrate/utils/substrate-bip39", "substrate/utils/wasm-builder", + + "templates/minimal/node", + "templates/minimal/pallets/template", + "templates/minimal/runtime", + + "templates/solochain/node", + "templates/solochain/pallets/template", + "templates/solochain/runtime", + + "templates/parachain/node", + "templates/parachain/pallets/template", + "templates/parachain/runtime", ] default-members = ["polkadot", "substrate/bin/node/cli"] @@ -533,8 +544,18 @@ extra-unused-type-parameters = { level = "allow", priority = 2 } # stylistic default_constructed_unit_structs = { level = "allow", priority = 2 } # stylistic [workspace.dependencies] -polkavm-linker = "0.8.2" -polkavm-derive = "0.8.0" +polkavm = "0.9.3" +polkavm-linker = "0.9.2" +polkavm-derive = "0.9.1" +log = { version = "0.4.20", default-features = false } +quote = { version = "1.0.33" } +serde = { version = "1.0.197", default-features = false } +serde-big-array = { version = "0.3.2" } +serde_derive = { version = "1.0.117" } +serde_json = { version = "1.0.114", default-features = false } +serde_yaml = { version = "0.9" } +syn = { version = "2.0.50" } +thiserror = { version = "1.0.48" } [profile.release] # Polkadot runtime requires unwinding. diff --git a/README.md b/README.md index 93f9539a94a1de5771f04106b11ba18f27010aad..63743a456f4c8f8561bbeee8c59d63b88d352285 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ way. The Polkadot SDK comprises three main pieces of software: [![Polkadot-license](https://img.shields.io/badge/License-GPL3-blue)](./polkadot/LICENSE) Implementation of a node for the https://polkadot.network in Rust, using the Substrate framework. This directory -currently contains runtimes for the Polkadot, Kusama, Westend, and Rococo networks. In the future, these will be -relocated to the [`runtimes`](https://github.com/polkadot-fellows/runtimes/) repository. +currently contains runtimes for the Westend and Rococo test networks. Polkadot, Kusama and their system chain runtimes +are located in the [`runtimes`](https://github.com/polkadot-fellows/runtimes/) repository maintained by +[the Polkadot Technical Fellowship](https://polkadot-fellows.github.io/dashboard/#/overview). ## [Substrate](./substrate/) [![SubstrateRustDocs](https://img.shields.io/badge/Rust_Docs-Substrate-24CC85?logo=rust)](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/substrate/index.html) diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index c0072064507331848beaaec3a56a8324296dd1f4..ee54f15f38b4c0a2e9faae3a157874898701ba2a 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } @@ -93,6 +93,7 @@ runtime-benchmarks = [ "pallet-bridge-messages/runtime-benchmarks", "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index 2722f6f1c6d14f09ab215f8f020f2c449eda4d4b..035077408c40bd42c9e941c19af868989d66e362 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -105,43 +105,48 @@ 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::TransactionExtensionBase for BridgeRejectObsoleteHeadersAndMessages { const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages"; - type AccountId = $account_id; - type Call = $call; - type AdditionalSigned = (); + type Implicit = (); + } + impl sp_runtime::traits::TransactionExtension<$call, Context> for BridgeRejectObsoleteHeadersAndMessages { type Pre = (); - - fn additional_signed(&self) -> sp_std::result::Result< - (), - sp_runtime::transaction_validity::TransactionValidityError, - > { - Ok(()) - } + type Val = (); 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 { - let valid = sp_runtime::transaction_validity::ValidTransaction::default(); + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl codec::Encode, + ) -> Result< + ( + sp_runtime::transaction_validity::ValidTransaction, + Self::Val, + <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, + ), sp_runtime::transaction_validity::TransactionValidityError + > { + let tx_validity = sp_runtime::transaction_validity::ValidTransaction::default(); $( - let valid = valid - .combine_with(<$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?); + let call_filter_validity = <$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?; + let tx_validity = tx_validity.combine_with(call_filter_validity); )* - Ok(valid) + Ok((tx_validity, (), origin)) } - fn pre_dispatch( + fn prepare( self, - who: &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, + _context: &Context, ) -> Result { - self.validate(who, call, info, len).map(drop) + Ok(()) } } }; @@ -150,12 +155,14 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { #[cfg(test)] mod tests { use crate::BridgeRuntimeFilterCall; - use frame_support::{assert_err, assert_ok}; + use codec::Encode; + use frame_support::assert_err; use sp_runtime::{ - traits::SignedExtension, + traits::DispatchTransaction, transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, }; + #[derive(Encode)] pub struct MockCall { data: u32, } @@ -206,17 +213,20 @@ mod tests { ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 1 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate_only((), &MockCall { data: 1 }, &(), 0), InvalidTransaction::Custom(1) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 2 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate_only((), &MockCall { data: 2 }, &(), 0), InvalidTransaction::Custom(2) ); - assert_ok!( - BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 3 }, &(), 0), + assert_eq!( + BridgeRejectObsoleteHeadersAndMessages + .validate_only((), &MockCall { data: 3 }, &(), 0) + .unwrap() + .0, ValidTransaction { priority: 3, ..Default::default() } ) } diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 8877a4fd95ce33150824b78674f38860616cf820..f147f1404f06fb60c608d4ad049502c6e184a85f 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -164,6 +164,7 @@ impl pallet_balances::Config for TestRuntime { type AccountStore = System; } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for TestRuntime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; @@ -176,7 +177,6 @@ impl pallet_transaction_payment::Config for TestRuntime { MinimumMultiplier, MaximumMultiplier, >; - type RuntimeEvent = RuntimeEvent; } impl pallet_bridge_grandpa::Config for TestRuntime { diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index a597fb9e2f49289360acfd7ee305b44eb7874a3e..0c53018330ea0ebc2fbacb32808e01a9ec88960f 100644 --- a/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/priority_calculator.rs @@ -169,12 +169,15 @@ mod integrity_tests { // 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() + let messages_proof_size = >::WeightInfo::expected_extra_storage_proof_size() .saturating_mul(2) .saturating_div(3) .saturating_add(estimated_message_size) @@ -182,7 +185,7 @@ mod integrity_tests { // 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), diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index bfcb82ad166c3a2a60891c1e18f2ad22e085cb1b..b912f8445ac1b455e95110d41347ac8e55afaa7c 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -48,9 +48,12 @@ use pallet_transaction_payment::{Config as TransactionPaymentConfig, OnChargeTra use pallet_utility::{Call as UtilityCall, Config as UtilityConfig, Pallet as UtilityPallet}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, SignedExtension, Zero}, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, + TransactionExtension, TransactionExtensionBase, ValidateResult, Zero, + }, transaction_validity::{ - TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, + InvalidTransaction, TransactionPriority, TransactionValidityError, ValidTransactionBuilder, }, DispatchResult, FixedPointOperand, RuntimeDebug, }; @@ -239,8 +242,8 @@ pub enum RelayerAccountAction { Slash(AccountId, RewardsAccountParams), } -/// Everything common among our refund signed extensions. -pub trait RefundSignedExtension: +/// Everything common among our refund transaction extensions. +pub trait RefundTransactionExtension: 'static + Clone + Codec + sp_std::fmt::Debug + Default + Eq + PartialEq + Send + Sync + TypeInfo where >::BridgedChain: @@ -456,8 +459,8 @@ where } } -/// Adapter that allow implementing `sp_runtime::traits::SignedExtension` for any -/// `RefundSignedExtension`. +/// Adapter that allow implementing `sp_runtime::traits::TransactionExtension` for any +/// `RefundTransactionExtension`. #[derive( DefaultNoBound, CloneNoBound, @@ -468,12 +471,13 @@ where RuntimeDebugNoBound, TypeInfo, )] -pub struct RefundSignedExtensionAdapter(T) +pub struct RefundTransactionExtensionAdapter(T) where >::BridgedChain: Chain; -impl SignedExtension for RefundSignedExtensionAdapter +impl TransactionExtensionBase + for RefundTransactionExtensionAdapter where >::BridgedChain: Chain, @@ -483,22 +487,35 @@ where + MessagesCallSubType::Instance>, { const IDENTIFIER: &'static str = T::Id::STR; - type AccountId = AccountIdOf; - type Call = CallOf; - type AdditionalSigned = (); - type Pre = Option>>; + type Implicit = (); +} - fn additional_signed(&self) -> Result<(), TransactionValidityError> { - Ok(()) - } +impl TransactionExtension, Context> + for RefundTransactionExtensionAdapter +where + >::BridgedChain: + Chain, + CallOf: Dispatchable + + IsSubType, T::Runtime>> + + GrandpaCallSubType + + MessagesCallSubType::Instance>, + as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner> + Clone, +{ + type Pre = Option>>; + type Val = Option; fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: as Dispatchable>::RuntimeOrigin, + call: &CallOf, + _info: &DispatchInfoOf>, _len: usize, - ) -> TransactionValidity { + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> ValidateResult> { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; // this is the only relevant line of code for the `pre_dispatch` // // we're not calling `validate` from `pre_dispatch` directly because of performance @@ -511,12 +528,12 @@ where // we only boost priority of presumably correct message delivery transactions let bundled_messages = match T::bundled_messages_for_priority_boost(parsed_call.as_ref()) { Some(bundled_messages) => bundled_messages, - None => return Ok(Default::default()), + None => return Ok((Default::default(), parsed_call, origin)), }; // we only boost priority if relayer has staked required balance if !RelayersPallet::::is_registration_active(who) { - return Ok(Default::default()) + return Ok((Default::default(), parsed_call, origin)) } // compute priority boost @@ -535,20 +552,21 @@ where priority_boost, ); - valid_transaction.build() + let validity = valid_transaction.build()?; + Ok((validity, parsed_call, origin)) } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + val: Self::Val, + origin: & as Dispatchable>::RuntimeOrigin, + _call: &CallOf, + _info: &DispatchInfoOf>, _len: usize, + _context: &Context, ) -> Result { - // this is a relevant piece of `validate` that we need here (in `pre_dispatch`) - let parsed_call = T::parse_and_check_for_obsolete_call(call)?; - - Ok(parsed_call.map(|call_info| { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + Ok(val.map(|call_info| { log::trace!( target: "runtime::bridge", "{} via {:?} parsed bridge transaction in pre-dispatch: {:?}", @@ -561,13 +579,14 @@ where } fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Self::Pre, + info: &DispatchInfoOf>, + post_info: &PostDispatchInfoOf>, len: usize, result: &DispatchResult, + _context: &Context, ) -> Result<(), TransactionValidityError> { - let call_result = T::analyze_call_result(pre, info, post_info, len, result); + let call_result = T::analyze_call_result(Some(pre), info, post_info, len, result); match call_result { RelayerAccountAction::None => (), @@ -595,7 +614,7 @@ where } } -/// Signed extension that refunds a relayer for new messages coming from a parachain. +/// Transaction extension that refunds a relayer for new messages coming from a parachain. /// /// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) /// with message delivery transaction. Batch may deliver either both relay chain header and @@ -636,7 +655,7 @@ pub struct RefundBridgedParachainMessages, ); -impl RefundSignedExtension +impl RefundTransactionExtension for RefundBridgedParachainMessages where Self: 'static + Send + Sync, @@ -730,13 +749,13 @@ where } } -/// Signed extension that refunds a relayer for new messages coming from a standalone (GRANDPA) +/// Transaction extension that refunds a relayer for new messages coming from a standalone (GRANDPA) /// chain. /// /// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) /// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages -/// proof verification. +/// parachain head, or just parachain head. Corresponding headers must be used in messages proof +/// verification. /// /// Extension does not refund transaction tip due to security reasons. #[derive( @@ -771,7 +790,7 @@ pub struct RefundBridgedGrandpaMessages, ); -impl RefundSignedExtension +impl RefundTransactionExtension for RefundBridgedGrandpaMessages where Self: 'static + Send + Sync, @@ -869,8 +888,8 @@ mod tests { Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, }; use sp_runtime::{ - traits::{ConstU64, Header as HeaderT}, - transaction_validity::{InvalidTransaction, ValidTransaction}, + traits::{ConstU64, DispatchTransaction, Header as HeaderT}, + transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, DispatchError, }; @@ -899,7 +918,7 @@ mod tests { ConstU64<1>, StrTestExtension, >; - type TestGrandpaExtension = RefundSignedExtensionAdapter; + type TestGrandpaExtension = RefundTransactionExtensionAdapter; type TestExtensionProvider = RefundBridgedParachainMessages< TestRuntime, DefaultRefundableParachainId<(), TestParachain>, @@ -908,7 +927,7 @@ mod tests { ConstU64<1>, StrTestExtension, >; - type TestExtension = RefundSignedExtensionAdapter; + type TestExtension = RefundTransactionExtensionAdapter; fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { let test_stake: ThisChainBalance = TestStake::get(); @@ -1407,14 +1426,28 @@ mod tests { fn run_validate(call: RuntimeCall) -> TransactionValidity { let extension: TestExtension = - RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + RefundTransactionExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|res| res.0) } fn run_grandpa_validate(call: RuntimeCall) -> TransactionValidity { let extension: TestGrandpaExtension = - RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + RefundTransactionExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|res| res.0) } fn run_validate_ignore_priority(call: RuntimeCall) -> TransactionValidity { @@ -1428,16 +1461,30 @@ mod tests { call: RuntimeCall, ) -> Result>, TransactionValidityError> { let extension: TestExtension = - RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + RefundTransactionExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|(pre, _)| pre) } fn run_grandpa_pre_dispatch( call: RuntimeCall, ) -> Result>, TransactionValidityError> { let extension: TestGrandpaExtension = - RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + RefundTransactionExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|(pre, _)| pre) } fn dispatch_info() -> DispatchInfo { @@ -1460,11 +1507,12 @@ mod tests { dispatch_result: DispatchResult, ) { let post_dispatch_result = TestExtension::post_dispatch( - Some(pre_dispatch_data), + pre_dispatch_data, &dispatch_info(), &post_dispatch_info(), 1024, &dispatch_result, + &(), ); assert_eq!(post_dispatch_result, Ok(())); } diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 562a6e43e0271dadcf68f77f0a74bba887c862f5..dccd7b3bdca3533cda4fec82ed0266d0b221b7a7 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 224aad7b36a2fd217fa910bbb49ed4474046b30e..173d6f1c16448517b7051cfba2f96625ff3d525a 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } num-traits = { version = "0.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 41aeca4b3bc5c608915783d2603ef0157aef54bb..e454a6f2888fa169a0b0795101172b2f260b4020 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 35017ebbd30361ae5c6184cfdbbdd7a42e9d59bb..b78da5cbeeca65a4f448cbc38928894d51e8f7b4 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index ff33b19a5811e2de96c276920fc8e354ca73ec19..20f8ff4407b2ad9882c64b334fa557a6c7dc4ef2 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 89e261dc6d79cd41d3afda77b37e4b48f4563c36..e10119e864953f1777c43151092ae43a5e594b8c 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs index c49aa4b856397d28746d017fd8333ae3ad10655e..f186f6427ae7d5cbac37c0dea528665ea474803e 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/primitives/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, }; @@ -164,7 +164,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/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index c4e697fbe9526b85c7f10cf739c6893d50190fe9..992ef1bd7a10f5fd95d1a5b4ec1a1267543ce615 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -107,5 +107,5 @@ frame_support::parameter_types! { /// 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_complex_message_confirmation_transaction` + `33%`) - pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 5_380_829_647; + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 5_380_904_835; } diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index e3b4d0520f61c858b54d78dfa4a45f57bac411fb..253a1010e83df928cceae91a18c309959c33d94e 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -59,8 +59,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/primitives/chain-polkadot-bulletin/src/lib.rs b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs index f2eebf9312470a42e1d3a1c7d67ab8b7a38af189..73dd122bd153869b937ed65f8e7ea7f4dde79c7c 100644 --- a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/primitives/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, }; @@ -37,7 +37,12 @@ use frame_support::{ }; use frame_system::limits; use scale_info::TypeInfo; -use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill}; +use sp_runtime::{ + impl_tx_ext_default, + traits::{Dispatchable, TransactionExtensionBase}, + transaction_validity::TransactionValidityError, + Perbill, +}; // This chain reuses most of Polkadot primitives. pub use bp_polkadot_core::{ @@ -71,10 +76,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, @@ -87,34 +92,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 TransactionExtensionBase for TransactionExtension { 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) } +} - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } +impl sp_runtime::traits::TransactionExtension for TransactionExtension +where + C: Dispatchable, +{ + type Pre = (); + type Val = (); + + impl_tx_ext_default!(C; Context; validate prepare); } -impl SignedExtension { +impl TransactionExtension { /// Create signed extension from its components. pub fn from_params( spec_version: u32, @@ -123,7 +124,7 @@ impl SignedExtension { genesis_hash: Hash, nonce: Nonce, ) -> Self { - Self(GenericSignedExtension::new( + Self(GenericTransactionExtension::new( ( ( (), // non-zero sender diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index fc5e10308a8e33463a74c041f157daaef09cc9c8..e5e2e7c3a042abddd8fb3dbd6f1decf62529cfe3 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -61,8 +61,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/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs index f1b256f0f090f048cc8db3a16c112ed8b938f6ce..267c6b2b1f0292b64ca8aaf969845129dae64dd8 100644 --- a/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -59,8 +59,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/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index f03fd2160a700eb3817a6feb629e9d366cc366aa..afa02e8ee541e5e2912b4b9a216feb633a07b617 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -59,8 +59,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/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index 828b567bb947d851e5d0f8dac03dadebf120e614..205b593365ef8216a2e501e5751303185d4f7537 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 54aae4a2f76a425046860835ccd2a66cc29cf135..8aa6b4b05e5efb2427a8548e91ec5f47ab494968 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } -serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index e667c283a07937ab88053c064fb7b8cfb380f765..c0dae684b5f2f3b7b9be096a808fc67d15dadfcf 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Bridge Dependencies diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index df2836495bbe131e9cf810c43eb4af5eefaf43b7..d59b99db4b586dde7b2d645ff44c34b94f865f24 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/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 6786bf8f21ced12e2424ecc17ff0c4ce96fd96d7..22206fb2c376ce53fee9dc8ff806baaef3ce7c28 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -13,10 +13,10 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } hash-db = { version = "0.16.0", default-features = false } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.19", default-features = false } +log = { workspace = true } num-traits = { version = "0.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +serde = { features = ["alloc", "derive"], workspace = true } # Substrate Dependencies diff --git a/bridges/primitives/runtime/src/extensions.rs b/bridges/primitives/runtime/src/extensions.rs index d896bc92efffc4e8fcb427ffa7057dece6f17241..a31e7b5bb47a64ec2333bbaba3e9c520aa53ef5a 100644 --- a/bridges/primitives/runtime/src/extensions.rs +++ b/bridges/primitives/runtime/src/extensions.rs @@ -20,135 +20,138 @@ 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, TransactionExtensionBase}, 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 TransactionExtensionBase for GenericTransactionExtension where - S: SignedExtensionSchema, + 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), - ), - ) + )) } +} +impl TransactionExtension for GenericTransactionExtension +where + C: Dispatchable, + S: TransactionExtensionSchema, + S::Payload: Send + Sync, + S::Implicit: Send + Sync, +{ + 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; Context; validate prepare); } diff --git a/bridges/primitives/test-utils/src/lib.rs b/bridges/primitives/test-utils/src/lib.rs index f23ddd1a10d3681900b024999aef279ea6fcb91d..1d80890779bf8310b393d585749e96f9577196a1 100644 --- a/bridges/primitives/test-utils/src/lib.rs +++ b/bridges/primitives/test-utils/src/lib.rs @@ -129,7 +129,7 @@ pub fn make_justification_for_header( votes_ancestries.push(child.clone()); } - // The header we need to use when pre-commiting is the one at the highest height + // The header we need to use when pre-committing is the one at the highest height // on our chain. let precommit_candidate = chain.last().map(|h| (h.hash(), *h.number())).unwrap(); unsigned_precommits.push(precommit_candidate); diff --git a/bridges/snowbridge/README.md b/bridges/snowbridge/README.md index 49b9c2eaf553780176897a770bad9579d53bfaa9..6561df401120e9c5c5d6ee2762eb1423b5d6daaf 100644 --- a/bridges/snowbridge/README.md +++ b/bridges/snowbridge/README.md @@ -1,32 +1,40 @@ -# Snowbridge -[![codecov](https://codecov.io/gh/Snowfork/snowbridge/branch/main/graph/badge.svg?token=9hvgSws4rN)](https://codecov.io/gh/Snowfork/snowbridge) +# Snowbridge · +[![codecov](https://codecov.io/gh/Snowfork/polkadot-sdk/branch/snowbridge/graph/badge.svg?token=9hvgSws4rN)](https://codecov.io/gh/Snowfork/polkadot-sdk) ![GitHub](https://img.shields.io/github/license/Snowfork/snowbridge) Snowbridge is a trustless bridge between Polkadot and Ethereum. For documentation, visit https://docs.snowbridge.network. ## Components +The Snowbridge project lives in two repositories: + +- [Snowfork/Polkadot-sdk](https://github.com/Snowfork/polkadot-sdk): The Snowbridge parachain and pallets live in +a fork of the Polkadot SDK. Changes are eventually contributed back to +[paritytech/Polkadot-sdk](https://github.com/paritytech/polkadot-sdk) +- [Snowfork/snowbridge](https://github.com/Snowfork/snowbridge): The rest of the Snowbridge components, like contracts, +off-chain relayer, end-to-end tests and test-net setup code. + ### Parachain -Polkadot parachain and our pallets. See [parachain/README.md](https://github.com/Snowfork/snowbridge/blob/main/parachain/README.md). +Polkadot parachain and our pallets. See [README.md](https://github.com/Snowfork/polkadot-sdk/blob/snowbridge/bridges/snowbridge/README.md). ### Contracts -Ethereum contracts and unit tests. See [contracts/README.md](https://github.com/Snowfork/snowbridge/blob/main/contracts/README.md) +Ethereum contracts and unit tests. See [Snowfork/snowbridge/contracts/README.md](https://github.com/Snowfork/snowbridge/blob/main/contracts/README.md) ### Relayer Off-chain relayer services for relaying messages between Polkadot and Ethereum. See -[relayer/README.md](https://github.com/Snowfork/snowbridge/blob/main/relayer/README.md) +[Snowfork/snowbridge/relayer/README.md](https://github.com/Snowfork/snowbridge/blob/main/relayer/README.md) ### Local Testnet Scripts to provision a local testnet, running the above services to bridge between local deployments of Polkadot and -Ethereum. See [web/packages/test/README.md](https://github.com/Snowfork/snowbridge/blob/main/web/packages/test/README.md). +Ethereum. See [Snowfork/snowbridge/web/packages/test/README.md](https://github.com/Snowfork/snowbridge/blob/main/web/packages/test/README.md). ### Smoke Tests -Integration tests for our local testnet. See [smoketest/README.md](https://github.com/Snowfork/snowbridge/blob/main/smoketest/README.md). +Integration tests for our local testnet. See [Snowfork/snowbridge/smoketest/README.md](https://github.com/Snowfork/snowbridge/blob/main/smoketest/README.md). ## Development @@ -83,7 +91,7 @@ direnv allow ### Upgrading the Rust toolchain -Sometimes we would like to upgrade rust toolchain. First update `parachain/rust-toolchain.toml` as required and then +Sometimes we would like to upgrade rust toolchain. First update `rust-toolchain.toml` as required and then update `flake.lock` running ```sh nix flake lock --update-input rust-overlay diff --git a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml index 2f76d5b8357985c65cdc09c86257bc6ddd766250..c8999633c97abb00174e38e16ed5618e7baf0b59 100644 --- a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-pallet-ethereum-client" description = "Snowbridge Ethereum Client Pallet" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -15,8 +15,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.195", optional = true } -serde_json = { version = "1.0.111", optional = true } +serde = { optional = true, workspace = true, default-features = true } +serde_json = { optional = true, workspace = true, default-features = true } codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } ssz_rs = { version = "0.9.0", default-features = false } @@ -24,7 +24,7 @@ ssz_rs_derive = { version = "0.9.0", default-features = false } byte-slice-cast = { version = "1.2.1", default-features = false } rlp = { version = "0.5.2", default-features = false } hex-literal = { version = "0.4.1", optional = true } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../../substrate/frame/support", default-features = false } @@ -45,12 +45,12 @@ pallet-timestamp = { path = "../../../../substrate/frame/timestamp", default-fea [dev-dependencies] rand = "0.8.5" sp-keyring = { path = "../../../../substrate/primitives/keyring" } -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } hex-literal = "0.4.1" pallet-timestamp = { path = "../../../../substrate/frame/timestamp" } snowbridge-pallet-ethereum-client-fixtures = { path = "./fixtures" } sp-io = { path = "../../../../substrate/primitives/io" } -serde = "1.0.195" +serde = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml index 1081b162ddaec58037863a65028db4dffd03b438..b850496cd4e14cd906565d488450b339a29f463f 100644 --- a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-pallet-inbound-queue" description = "Snowbridge Inbound Queue Pallet" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -15,11 +15,11 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } alloy-primitives = { version = "0.4.2", default-features = false, features = ["rlp"] } alloy-sol-types = { version = "0.4.2", default-features = false } alloy-rlp = { version = "0.3.3", default-features = false, features = ["derive"] } diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml index 61f1421e056773c4f078390f9c48f7b8fa0420d3..64605a42f0d383d838429eb9b82b5f6cf238ab09 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-pallet-inbound-queue-fixtures" description = "Snowbridge Inbound Queue Test Fixtures" -version = "0.9.0" +version = "0.10.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 110f611c6766020039bd1f73def900914da8cae2..749fb0367f332d743b01ad9d56238106ced36e72 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -3,7 +3,7 @@ use super::*; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU128, ConstU32, Everything}, weights::IdentityFee, }; @@ -47,10 +47,9 @@ parameter_types! { type Balance = u128; +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeTask = RuntimeTask; @@ -60,16 +59,8 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; type Nonce = u64; type Block = Block; } diff --git a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml index ae52fb3e5c49d5d35558d78a38b7f00b0d01ac8f..f16a28cb1e457d9ebfb7804fa013e5b57858f79e 100644 --- a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-pallet-outbound-queue" description = "Snowbridge Outbound Queue Pallet" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.195", features = ["alloc", "derive"], default-features = false } +serde = { features = ["alloc", "derive"], workspace = true } codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index c185d5af7062045f40946fcbd3c45cb62b932216..0606e9de33056c9dffae50befcc1da5e865dca44 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-outbound-queue-merkle-tree" description = "Snowbridge Outbound Queue Merkle Tree" -version = "0.1.1" +version = "0.3.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true diff --git a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml index 347b3bae493b7491790854be7a28f82386d2ee4b..cb68fd0a250a92e7f6a6693f3aebf1c8553308aa 100644 --- a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-outbound-queue-runtime-api" description = "Snowbridge Outbound Queue Runtime API" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs index dd8fee4e2ed08ec0f3090b765fa882b063a98300..6e78fb4467210e3cb5e1eb581b377cbbfeac74ad 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs @@ -3,7 +3,7 @@ use super::*; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{Everything, Hooks}, weights::IdentityFee, }; @@ -37,10 +37,9 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeTask = RuntimeTask; @@ -50,16 +49,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; type Nonce = u64; type Block = Block; } diff --git a/bridges/snowbridge/pallets/system/Cargo.toml b/bridges/snowbridge/pallets/system/Cargo.toml index aa600511633bb7d5fef36f8d4ae6cec847c4e6c4..5ad04290de044a2c8ed13aa092f5ea033aaafb97 100644 --- a/bridges/snowbridge/pallets/system/Cargo.toml +++ b/bridges/snowbridge/pallets/system/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-pallet-system" description = "Snowbridge System Pallet" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -22,7 +22,7 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive" frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } sp-core = { path = "../../../../substrate/primitives/core", default-features = false } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } diff --git a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml index 355d2d29147f3cd84ae013363db874c9b9739b8e..eb02ae1db529730f51743e79a322e54db44fee51 100644 --- a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-system-runtime-api" description = "Snowbridge System Runtime API" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs index b7f38fb753d31bd67acb78174e175f90fc711175..6e5ceb5e9b1d42796567c3da5e549b2af3cfd4de 100644 --- a/bridges/snowbridge/pallets/system/src/lib.rs +++ b/bridges/snowbridge/pallets/system/src/lib.rs @@ -37,8 +37,6 @@ //! `force_update_channel` and extrinsics to manage agents and channels for system parachains. #![cfg_attr(not(feature = "std"), no_std)] -pub use pallet::*; - #[cfg(test)] mod mock; @@ -79,6 +77,8 @@ use xcm_executor::traits::ConvertLocation; #[cfg(feature = "runtime-benchmarks")] use frame_support::traits::OriginTrait; +pub use pallet::*; + pub type BalanceOf = <::Token as Inspect<::AccountId>>::Balance; pub type AccountIdOf = ::AccountId; diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs index edc3f141b0735d7439b120c51da836fb8a77bd04..de2970dd550ba75fe42de08dc4d297cd5cccdf1f 100644 --- a/bridges/snowbridge/pallets/system/src/mock.rs +++ b/bridges/snowbridge/pallets/system/src/mock.rs @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: 2023 Snowfork use crate as snowbridge_system; use frame_support::{ - parameter_types, - traits::{tokens::fungible::Mutate, ConstU128, ConstU16, ConstU64, ConstU8}, + derive_impl, parameter_types, + traits::{tokens::fungible::Mutate, ConstU128, ConstU64, ConstU8}, weights::IdentityFee, PalletId, }; @@ -95,11 +95,9 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeTask = RuntimeTask; @@ -109,15 +107,8 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; - type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; type Nonce = u64; type Block = Block; } diff --git a/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs b/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..77b5c1aa631db89a986837f258ee7dea45a580d0 --- /dev/null +++ b/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +use crate as ethereum_beacon_client; +use frame_support::parameter_types; +use pallet_timestamp; +use primitives::{Fork, ForkVersions}; +use sp_core::H256; +use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; + +#[cfg(not(feature = "beacon-spec-mainnet"))] +pub mod minimal { + use super::*; + + use crate::config; + use frame_support::derive_impl; + use hex_literal::hex; + use primitives::CompactExecutionHeader; + use snowbridge_core::inbound::{Log, Proof}; + use sp_runtime::BuildStorage; + use std::{fs::File, path::PathBuf}; + + type Block = frame_system::mocking::MockBlock; + + frame_support::construct_runtime!( + pub enum Test { + System: frame_system::{Pallet, Call, Storage, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + EthereumBeaconClient: ethereum_beacon_client::{Pallet, Call, Storage, Event}, + } + ); + + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; + } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type PalletInfo = PalletInfo; + type SS58Prefix = SS58Prefix; + type Nonce = u64; + type Block = Block; + } + + impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = (); + type WeightInfo = (); + } + + parameter_types! { + pub const ExecutionHeadersPruneThreshold: u32 = 10; + pub const ChainForkVersions: ForkVersions = ForkVersions{ + genesis: Fork { + version: [0, 0, 0, 1], // 0x00000001 + epoch: 0, + }, + altair: Fork { + version: [1, 0, 0, 1], // 0x01000001 + epoch: 0, + }, + bellatrix: Fork { + version: [2, 0, 0, 1], // 0x02000001 + epoch: 0, + }, + capella: Fork { + version: [3, 0, 0, 1], // 0x03000001 + epoch: 0, + }, + }; + } + + impl ethereum_beacon_client::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ForkVersions = ChainForkVersions; + type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; + type WeightInfo = (); + } + + // Build genesis storage according to the mock runtime. + pub fn new_tester() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + let _ = ext.execute_with(|| Timestamp::set(RuntimeOrigin::signed(1), 30_000)); + ext + } + + fn load_fixture(basename: &str) -> Result + where + T: for<'de> serde::Deserialize<'de>, + { + let filepath: PathBuf = + [env!("CARGO_MANIFEST_DIR"), "tests", "fixtures", basename].iter().collect(); + serde_json::from_reader(File::open(filepath).unwrap()) + } + + pub fn load_execution_header_update_fixture() -> primitives::ExecutionHeaderUpdate { + load_fixture("execution-header-update.minimal.json").unwrap() + } + + pub fn load_checkpoint_update_fixture( + ) -> primitives::CheckpointUpdate<{ config::SYNC_COMMITTEE_SIZE }> { + load_fixture("initial-checkpoint.minimal.json").unwrap() + } + + pub fn load_sync_committee_update_fixture( + ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { + load_fixture("sync-committee-update.minimal.json").unwrap() + } + + pub fn load_finalized_header_update_fixture( + ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { + load_fixture("finalized-header-update.minimal.json").unwrap() + } + + pub fn load_next_sync_committee_update_fixture( + ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { + load_fixture("next-sync-committee-update.minimal.json").unwrap() + } + + pub fn load_next_finalized_header_update_fixture( + ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { + load_fixture("next-finalized-header-update.minimal.json").unwrap() + } + + pub fn get_message_verification_payload() -> (Log, Proof) { + ( + Log { + address: hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into(), + topics: vec![ + hex!("1b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ad").into(), + hex!("00000000000000000000000000000000000000000000000000000000000003e8").into(), + hex!("0000000000000000000000000000000000000000000000000000000000000001").into(), + ], + data: hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000").into(), + }, + Proof { + block_hash: hex!("05aaa60b0f27cce9e71909508527264b77ee14da7b5bf915fcc4e32715333213").into(), + tx_index: 0, + data: (vec![ + hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb").to_vec(), + hex!("d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c185510").to_vec(), + hex!("b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646").to_vec(), + ], vec![ + hex!("f90131a0b601337b3aa10a671caa724eba641e759399979856141d3aea6b6b4ac59b889ba00c7d5dd48be9060221a02fb8fa213860b4c50d47046c8fa65ffaba5737d569e0a094601b62a1086cd9c9cb71a7ebff9e718f3217fd6e837efe4246733c0a196f63a06a4b0dd0aefc37b3c77828c8f07d1b7a2455ceb5dbfd3c77d7d6aeeddc2f7e8ca0d6e8e23142cdd8ec219e1f5d8b56aa18e456702b195deeaa210327284d42ade4a08a313d4c87023005d1ab631bbfe3f5de1e405d0e66d0bef3e033f1e5711b5521a0bf09a5d9a48b10ade82b8d6a5362a15921c8b5228a3487479b467db97411d82fa0f95cccae2a7c572ef3c566503e30bac2b2feb2d2f26eebf6d870dcf7f8cf59cea0d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c1855108080808080808080").to_vec(), + hex!("f851a0b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646a060a634b9280e3a23fb63375e7bbdd9ab07fd379ab6a67e2312bbc112195fa358808080808080808080808080808080").to_vec(), + hex!("f9030820b9030402f90300018301d6e2b9010000000000000800000000000020040008000000000000000000000000400000008000000000000000000000000000000000000000000000000000000000042010000000001000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000002000000000000000000000000200000000000000200000000000100000000040000001000200008000000000000200000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000f901f5f87a942ffa5ecdbe006d30397c7636d3e015eee251369ff842a0c965575a00553e094ca7c5d14f02e107c258dda06867cbf9e0e69f80e71bbcc1a000000000000000000000000000000000000000000000000000000000000003e8a000000000000000000000000000000000000000000000000000000000000003e8f9011c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000001b8a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000f858948cf6147918a5cbb672703f879f385036f8793a24e1a01449abf21e49fd025f33495e77f7b1461caefdd3d4bb646424a3f445c4576a5ba0000000000000000000000000440edffa1352b13227e8ee646f3ea37456dec701").to_vec(), + ]), + } + ) + } + + pub fn get_message_verification_header() -> CompactExecutionHeader { + CompactExecutionHeader { + parent_hash: hex!("04a7f6ab8282203562c62f38b0ab41d32aaebe2c7ea687702b463148a6429e04") + .into(), + block_number: 55, + state_root: hex!("894d968712976d613519f973a317cb0781c7b039c89f27ea2b7ca193f7befdb3") + .into(), + receipts_root: hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb") + .into(), + } + } +} + +#[cfg(feature = "beacon-spec-mainnet")] +pub mod mainnet { + use super::*; + use frame_support::derive_impl; + + type Block = frame_system::mocking::MockBlock; + use sp_runtime::BuildStorage; + + frame_support::construct_runtime!( + pub enum Test { + System: frame_system::{Pallet, Call, Storage, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + EthereumBeaconClient: ethereum_beacon_client::{Pallet, Call, Storage, Event}, + } + ); + + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; + } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type PalletInfo = PalletInfo; + type SS58Prefix = SS58Prefix; + type Nonce = u64; + type Block = Block; + } + + impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = (); + type WeightInfo = (); + } + + parameter_types! { + pub const ChainForkVersions: ForkVersions = ForkVersions{ + genesis: Fork { + version: [0, 0, 16, 32], // 0x00001020 + epoch: 0, + }, + altair: Fork { + version: [1, 0, 16, 32], // 0x01001020 + epoch: 36660, + }, + bellatrix: Fork { + version: [2, 0, 16, 32], // 0x02001020 + epoch: 112260, + }, + capella: Fork { + version: [3, 0, 16, 32], // 0x03001020 + epoch: 162304, + }, + }; + pub const ExecutionHeadersPruneThreshold: u32 = 10; + } + + impl ethereum_beacon_client::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ForkVersions = ChainForkVersions; + type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; + type WeightInfo = (); + } + + // Build genesis storage according to the mock runtime. + pub fn new_tester() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + let _ = ext.execute_with(|| Timestamp::set(RuntimeOrigin::signed(1), 30_000)); + ext + } +} diff --git a/bridges/snowbridge/primitives/beacon/Cargo.toml b/bridges/snowbridge/primitives/beacon/Cargo.toml index b59e5191b418753fc3eb1a2342194af4efc311c3..d181fa1d3945a704a3d1e1e28fea67b7dea0ee15 100644 --- a/bridges/snowbridge/primitives/beacon/Cargo.toml +++ b/bridges/snowbridge/primitives/beacon/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-beacon-primitives" description = "Snowbridge Beacon Primitives" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -12,7 +12,7 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } hex = { version = "0.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } diff --git a/bridges/snowbridge/primitives/core/Cargo.toml b/bridges/snowbridge/primitives/core/Cargo.toml index f735d01a848fb15ced0f086b8b7117e6e771c688..9a299ad0ae92326a6d0bb0391baf81e6e5bad663 100644 --- a/bridges/snowbridge/primitives/core/Cargo.toml +++ b/bridges/snowbridge/primitives/core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-core" description = "Snowbridge Core" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -12,7 +12,7 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -serde = { version = "1.0.195", optional = true, features = ["alloc", "derive"], default-features = false } +serde = { optional = true, features = ["alloc", "derive"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } diff --git a/bridges/snowbridge/primitives/ethereum/Cargo.toml b/bridges/snowbridge/primitives/ethereum/Cargo.toml index 047ebdd56695b1b42768da7108c75ce4c15b4fb4..9fa725a6c0565a5f42847d89149878f8997d07a0 100644 --- a/bridges/snowbridge/primitives/ethereum/Cargo.toml +++ b/bridges/snowbridge/primitives/ethereum/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-ethereum" description = "Snowbridge Ethereum" -version = "0.1.0" +version = "0.3.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -12,8 +12,8 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -serde = { version = "1.0.195", optional = true, features = ["derive"] } -serde-big-array = { version = "0.3.2", optional = true, features = ["const-generics"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +serde-big-array = { optional = true, features = ["const-generics"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } ethbloom = { version = "0.13.0", default-features = false } @@ -33,7 +33,7 @@ ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = fals [dev-dependencies] wasm-bindgen-test = "0.3.19" rand = "0.8.5" -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/primitives/router/Cargo.toml b/bridges/snowbridge/primitives/router/Cargo.toml index 712c60c2148f60f12e2be246e32242b67188bdaf..ded773e0d38917b7834679b3e521dfbe9539e51b 100644 --- a/bridges/snowbridge/primitives/router/Cargo.toml +++ b/bridges/snowbridge/primitives/router/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-router-primitives" description = "Snowbridge Router Primitives" -version = "0.0.0" +version = "0.9.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -12,10 +12,10 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system", default-features = false } diff --git a/bridges/snowbridge/runtime/runtime-common/Cargo.toml b/bridges/snowbridge/runtime/runtime-common/Cargo.toml index f5b44b25585aaccdc434d93cb039e24b4712aebc..bf5e9a8832dcf48113d5f74a92a060687da2fe4e 100644 --- a/bridges/snowbridge/runtime/runtime-common/Cargo.toml +++ b/bridges/snowbridge/runtime/runtime-common/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-runtime-common" description = "Snowbridge Runtime Common" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition.workspace = true repository.workspace = true @@ -12,7 +12,7 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -log = { version = "0.4.20", default-features = false } +log = { workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system", default-features = false } diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index a2994e618913416214cb7eb21d1a56c23c2d1094..5f169e82f49346742bd97028da583105bf02335d 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "snowbridge-runtime-test-common" description = "Snowbridge Runtime Tests" -version = "0.0.0" +version = "0.2.0" authors = ["Snowfork "] edition = "2021" license = "Apache-2.0" @@ -13,9 +13,9 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } smallvec = "1.11.0" # Substrate @@ -181,6 +181,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/runtime-benchmarks", diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs index c9bbce98e575d5e55015aa7814d8cd57a5c3a966..7455adf76170acefd50f06e8a40ef1c79028f49f 100644 --- a/bridges/snowbridge/runtime/test-common/src/lib.rs +++ b/bridges/snowbridge/runtime/test-common/src/lib.rs @@ -13,9 +13,9 @@ use parachains_runtimes_test_utils::{ }; use snowbridge_core::{ChannelId, ParaId}; use snowbridge_pallet_ethereum_client_fixtures::*; -use sp_core::H160; +use sp_core::{H160, U256}; use sp_keyring::AccountKeyring::*; -use sp_runtime::{traits::Header, AccountId32, SaturatedConversion, Saturating}; +use sp_runtime::{traits::Header, AccountId32, DigestItem, SaturatedConversion, Saturating}; use xcm::{ latest::prelude::*, v3::Error::{self, Barrier}, @@ -40,6 +40,7 @@ where } pub fn send_transfer_token_message( + ethereum_chain_id: u64, assethub_parachain_id: u32, weth_contract_address: H160, destination_address: H160, @@ -53,7 +54,8 @@ where + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config - + snowbridge_pallet_outbound_queue::Config, + + snowbridge_pallet_outbound_queue::Config + + pallet_timestamp::Config, XcmConfig: xcm_executor::Config, { let assethub_parachain_location = Location::new(1, Parachain(assethub_parachain_id)); @@ -88,7 +90,7 @@ where WithdrawAsset(Assets::from(vec![fee.clone()])), BuyExecution { fees: fee, weight_limit: Unlimited }, ExportMessage { - network: Ethereum { chain_id: 11155111 }, + network: Ethereum { chain_id: ethereum_chain_id }, destination: Here, xcm: inner_xcm, }, @@ -106,6 +108,7 @@ where } pub fn send_transfer_token_message_success( + ethereum_chain_id: u64, collator_session_key: CollatorSessionKeys, runtime_para_id: u32, assethub_parachain_id: u32, @@ -125,7 +128,8 @@ pub fn send_transfer_token_message_success( + pallet_message_queue::Config + cumulus_pallet_parachain_system::Config + snowbridge_pallet_outbound_queue::Config - + snowbridge_pallet_system::Config, + + snowbridge_pallet_system::Config + + pallet_timestamp::Config, XcmConfig: xcm_executor::Config, ValidatorIdOf: From>, ::AccountId: From + AsRef<[u8]>, @@ -147,6 +151,7 @@ pub fn send_transfer_token_message_success( initial_fund::(assethub_parachain_id, 5_000_000_000_000); let outcome = send_transfer_token_message::( + ethereum_chain_id, assethub_parachain_id, weth_contract_address, destination_address, @@ -193,13 +198,104 @@ pub fn send_transfer_token_message_success( let digest = included_head.digest(); - //let digest = frame_system::Pallet::::digest(); let digest_items = digest.logs(); assert!(digest_items.len() == 1 && digest_items[0].as_other().is_some()); }); } +pub fn ethereum_outbound_queue_processes_messages_before_message_queue_works< + Runtime, + XcmConfig, + AllPalletsWithoutSystem, +>( + ethereum_chain_id: u64, + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + assethub_parachain_id: u32, + weth_contract_address: H160, + destination_address: H160, + fee_amount: u128, + snowbridge_pallet_outbound_queue: Box< + dyn Fn(Vec) -> Option>, + >, +) where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + pallet_message_queue::Config + + cumulus_pallet_parachain_system::Config + + snowbridge_pallet_outbound_queue::Config + + snowbridge_pallet_system::Config + + pallet_timestamp::Config, + XcmConfig: xcm_executor::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + ValidatorIdOf: From>, + ::AccountId: From + AsRef<[u8]>, +{ + ExtBuilder::::default() + .with_collators(collator_session_key.collators()) + .with_session_keys(collator_session_key.session_keys()) + .with_para_id(runtime_para_id.into()) + .with_tracing() + .build() + .execute_with(|| { + >::initialize( + runtime_para_id.into(), + assethub_parachain_id.into(), + ) + .unwrap(); + + // fund asset hub sovereign account enough so it can pay fees + initial_fund::(assethub_parachain_id, 5_000_000_000_000); + + let outcome = send_transfer_token_message::( + ethereum_chain_id, + assethub_parachain_id, + weth_contract_address, + destination_address, + fee_amount, + ); + + assert_ok!(outcome.ensure_complete()); + + // check events + let mut events = >::events() + .into_iter() + .filter_map(|e| snowbridge_pallet_outbound_queue(e.event.encode())); + assert!(events.any(|e| matches!( + e, + snowbridge_pallet_outbound_queue::Event::MessageQueued { .. } + ))); + + let next_block_number: U256 = >::block_number() + .saturating_add(BlockNumberFor::::from(1u32)) + .into(); + + let included_head = + RuntimeHelper::::run_to_block_with_finalize( + next_block_number.as_u32(), + ); + let digest = included_head.digest(); + let digest_items = digest.logs(); + + let mut found_outbound_digest = false; + for digest_item in digest_items { + match digest_item { + DigestItem::Other(_) => found_outbound_digest = true, + _ => {}, + } + } + + assert_eq!(found_outbound_digest, true); + }); +} + pub fn send_unpaid_transfer_token_message( + ethereum_chain_id: u64, collator_session_key: CollatorSessionKeys, runtime_para_id: u32, assethub_parachain_id: u32, @@ -213,7 +309,8 @@ pub fn send_unpaid_transfer_token_message( + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config - + snowbridge_pallet_outbound_queue::Config, + + snowbridge_pallet_outbound_queue::Config + + pallet_timestamp::Config, XcmConfig: xcm_executor::Config, ValidatorIdOf: From>, { @@ -262,7 +359,7 @@ pub fn send_unpaid_transfer_token_message( let xcm = Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, ExportMessage { - network: Ethereum { chain_id: 11155111 }, + network: Ethereum { chain_id: ethereum_chain_id }, destination: Here, xcm: inner_xcm, }, @@ -284,6 +381,7 @@ pub fn send_unpaid_transfer_token_message( #[allow(clippy::too_many_arguments)] pub fn send_transfer_token_message_failure( + ethereum_chain_id: u64, collator_session_key: CollatorSessionKeys, runtime_para_id: u32, assethub_parachain_id: u32, @@ -301,7 +399,8 @@ pub fn send_transfer_token_message_failure( + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config + snowbridge_pallet_outbound_queue::Config - + snowbridge_pallet_system::Config, + + snowbridge_pallet_system::Config + + pallet_timestamp::Config, XcmConfig: xcm_executor::Config, ValidatorIdOf: From>, { @@ -322,6 +421,7 @@ pub fn send_transfer_token_message_failure( initial_fund::(assethub_parachain_id, initial_amount); let outcome = send_transfer_token_message::( + ethereum_chain_id, assethub_parachain_id, weth_contract_address, destination_address, @@ -349,7 +449,8 @@ pub fn ethereum_extrinsic( + cumulus_pallet_parachain_system::Config + snowbridge_pallet_outbound_queue::Config + snowbridge_pallet_system::Config - + snowbridge_pallet_ethereum_client::Config, + + snowbridge_pallet_ethereum_client::Config + + pallet_timestamp::Config, ValidatorIdOf: From>, ::RuntimeCall: From>, @@ -430,7 +531,8 @@ pub fn ethereum_to_polkadot_message_extrinsics_work( + cumulus_pallet_parachain_system::Config + snowbridge_pallet_outbound_queue::Config + snowbridge_pallet_system::Config - + snowbridge_pallet_ethereum_client::Config, + + snowbridge_pallet_ethereum_client::Config + + pallet_timestamp::Config, ValidatorIdOf: From>, ::RuntimeCall: From>, diff --git a/bridges/snowbridge/scripts/contribute-upstream.sh b/bridges/snowbridge/scripts/contribute-upstream.sh new file mode 100755 index 0000000000000000000000000000000000000000..32005b770ecf44cb9af18c61f830243ed5287e68 --- /dev/null +++ b/bridges/snowbridge/scripts/contribute-upstream.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +# A script to cleanup the Snowfork fork of the polkadot-sdk to contribute it upstream back to parity/polkadot-sdk +# ./bridges/snowbridge/scripts/contribute-upstream.sh + +# show CLI help +function show_help() { + set +x + echo " " + echo Error: $1 + echo "Usage:" + echo " ./bridges/snowbridge/scripts/contribute-upstream.sh Exit with code 0 if pallets code is well decoupled from the other code in the repo" + exit 1 +} + +if [[ -z "$1" ]]; then + echo "Please provide a branch name you would like your upstream branch to be named" + exit 1 +fi + +branch_name=$1 + +set -eux + +# let's avoid any restrictions on where this script can be called for - snowbridge repo may be +# plugged into any other repo folder. So the script (and other stuff that needs to be removed) +# may be located either in call dir, or one of it subdirs. +SNOWBRIDGE_FOLDER="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/../" + +# Get the current Git branch name +current_branch=$(git rev-parse --abbrev-ref HEAD) + +if [ "$current_branch" = "$branch_name" ] || git branch | grep -q "$branch_name"; then + echo "Already on requested branch or branch exists, not creating." +else + git branch "$branch_name" +fi + +git checkout "$branch_name" + +# remove everything we think is not required for our needs +rm -rf rust-toolchain.toml +rm -rf codecov.yml +rm -rf $SNOWBRIDGE_FOLDER/.cargo +rm -rf $SNOWBRIDGE_FOLDER/.github +rm -rf $SNOWBRIDGE_FOLDER/SECURITY.md +rm -rf $SNOWBRIDGE_FOLDER/.gitignore +rm -rf $SNOWBRIDGE_FOLDER/rustfmt.toml +rm -rf $SNOWBRIDGE_FOLDER/templates +rm -rf $SNOWBRIDGE_FOLDER/pallets/ethereum-client/fuzz + +pushd $SNOWBRIDGE_FOLDER + +# let's test if everything we need compiles +cargo check -p snowbridge-pallet-ethereum-client +cargo check -p snowbridge-pallet-ethereum-client --features runtime-benchmarks +cargo check -p snowbridge-pallet-ethereum-client --features try-runtime +cargo check -p snowbridge-pallet-inbound-queue +cargo check -p snowbridge-pallet-inbound-queue --features runtime-benchmarks +cargo check -p snowbridge-pallet-inbound-queue --features try-runtime +cargo check -p snowbridge-pallet-outbound-queue +cargo check -p snowbridge-pallet-outbound-queue --features runtime-benchmarks +cargo check -p snowbridge-pallet-outbound-queue --features try-runtime +cargo check -p snowbridge-pallet-system +cargo check -p snowbridge-pallet-system --features runtime-benchmarks +cargo check -p snowbridge-pallet-system --features try-runtime + +# we're removing lock file after all checks are done. Otherwise we may use different +# Substrate/Polkadot/Cumulus commits and our checks will fail +rm -f $SNOWBRIDGE_FOLDER/Cargo.toml +rm -f $SNOWBRIDGE_FOLDER/Cargo.lock + +popd + +# Replace Parity's CI files, that we have overwritten in our fork, to run our own CI +rm -rf .github +git remote -v | grep -w parity || git remote add parity https://github.com/paritytech/polkadot-sdk +git fetch parity master +git checkout parity/master -- .github +git add -- .github + +echo "OK" diff --git a/bridges/snowbridge/scripts/verify-pallets-build.sh b/bridges/snowbridge/scripts/verify-pallets-build.sh deleted file mode 100755 index a62f48c84d4fd34731c20365a20097e086aa2c99..0000000000000000000000000000000000000000 --- a/bridges/snowbridge/scripts/verify-pallets-build.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/bin/bash - -# A script to remove everything from snowbridge repository/subtree, except: -# -# - parachain -# - readme -# - license - -set -eu - -# show CLI help -function show_help() { - set +x - echo " " - echo Error: $1 - echo "Usage:" - echo " ./scripts/verify-pallets-build.sh Exit with code 0 if pallets code is well decoupled from the other code in the repo" - echo "Options:" - echo " --no-revert Leaves only runtime code on exit" - echo " --ignore-git-state Ignores git actual state" - exit 1 -} - -# parse CLI args -NO_REVERT= -IGNORE_GIT_STATE= -for i in "$@" -do - case $i in - --no-revert) - NO_REVERT=true - shift - ;; - --ignore-git-state) - IGNORE_GIT_STATE=true - shift - ;; - *) - show_help "Unknown option: $i" - ;; - esac -done - -# the script is able to work only on clean git copy, unless we want to ignore this check -[[ ! -z "${IGNORE_GIT_STATE}" ]] || [[ -z "$(git status --porcelain)" ]] || { echo >&2 "The git copy must be clean"; exit 1; } - -# let's avoid any restrictions on where this script can be called for - snowbridge repo may be -# plugged into any other repo folder. So the script (and other stuff that needs to be removed) -# may be located either in call dir, or one of it subdirs. -SNOWBRIDGE_FOLDER="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/../.." - -# remove everything we think is not required for our needs -rm -rf $SNOWBRIDGE_FOLDER/.cargo -rm -rf $SNOWBRIDGE_FOLDER/.github -rm -rf $SNOWBRIDGE_FOLDER/contracts -rm -rf $SNOWBRIDGE_FOLDER/codecov.yml -rm -rf $SNOWBRIDGE_FOLDER/docs -rm -rf $SNOWBRIDGE_FOLDER/hooks -rm -rf $SNOWBRIDGE_FOLDER/relayer -rm -rf $SNOWBRIDGE_FOLDER/scripts -rm -rf $SNOWBRIDGE_FOLDER/SECURITY.md -rm -rf $SNOWBRIDGE_FOLDER/smoketest -rm -rf $SNOWBRIDGE_FOLDER/web -rm -rf $SNOWBRIDGE_FOLDER/.envrc-example -rm -rf $SNOWBRIDGE_FOLDER/.gitbook.yaml -rm -rf $SNOWBRIDGE_FOLDER/.gitignore -rm -rf $SNOWBRIDGE_FOLDER/.gitmodules -rm -rf $SNOWBRIDGE_FOLDER/_typos.toml -rm -rf $SNOWBRIDGE_FOLDER/_codecov.yml -rm -rf $SNOWBRIDGE_FOLDER/flake.lock -rm -rf $SNOWBRIDGE_FOLDER/flake.nix -rm -rf $SNOWBRIDGE_FOLDER/go.work -rm -rf $SNOWBRIDGE_FOLDER/go.work.sum -rm -rf $SNOWBRIDGE_FOLDER/polkadot-sdk -rm -rf $SNOWBRIDGE_FOLDER/rust-toolchain.toml -rm -rf $SNOWBRIDGE_FOLDER/parachain/rustfmt.toml -rm -rf $SNOWBRIDGE_FOLDER/parachain/.gitignore -rm -rf $SNOWBRIDGE_FOLDER/parachain/templates -rm -rf $SNOWBRIDGE_FOLDER/parachain/.cargo -rm -rf $SNOWBRIDGE_FOLDER/parachain/.config -rm -rf $SNOWBRIDGE_FOLDER/parachain/pallets/ethereum-client/fuzz - -cd bridges/snowbridge/parachain - -# fix polkadot-sdk paths in Cargo.toml files -find "." -name 'Cargo.toml' | while read -r file; do - replace=$(printf '../../' ) - if [[ "$(uname)" = "Darwin" ]] || [[ "$(uname)" = *BSD ]]; then - sed -i '' "s|polkadot-sdk/|$replace|g" "$file" - else - sed -i "s|polkadot-sdk/|$replace|g" "$file" - fi -done - -# let's test if everything we need compiles -cargo check -p snowbridge-pallet-ethereum-client -cargo check -p snowbridge-pallet-ethereum-client --features runtime-benchmarks -cargo check -p snowbridge-pallet-ethereum-client --features try-runtime -cargo check -p snowbridge-pallet-inbound-queue -cargo check -p snowbridge-pallet-inbound-queue --features runtime-benchmarks -cargo check -p snowbridge-pallet-inbound-queue --features try-runtime -cargo check -p snowbridge-pallet-outbound-queue -cargo check -p snowbridge-pallet-outbound-queue --features runtime-benchmarks -cargo check -p snowbridge-pallet-outbound-queue --features try-runtime -cargo check -p snowbridge-pallet-system -cargo check -p snowbridge-pallet-system --features runtime-benchmarks -cargo check -p snowbridge-pallet-system --features try-runtime - -cd - - -# we're removing lock file after all checks are done. Otherwise we may use different -# Substrate/Polkadot/Cumulus commits and our checks will fail -rm -f $SNOWBRIDGE_FOLDER/parachain/Cargo.toml -rm -f $SNOWBRIDGE_FOLDER/parachain/Cargo.lock - -echo "OK" diff --git a/bridges/zombienet/README.md b/bridges/testing/README.md similarity index 94% rename from bridges/zombienet/README.md rename to bridges/testing/README.md index b601154b624ce69ed921ea6c2453d17c4d37b6c8..bd467a410d013c363913a8e4b2be8ca7b184e2dc 100644 --- a/bridges/zombienet/README.md +++ b/bridges/testing/README.md @@ -23,7 +23,7 @@ To start those tests, you need to: - copy fresh `substrate-relay` binary, built in previous point, to the `~/local_bridge_testing/bin/substrate-relay`; -- change the `POLKADOT_SDK_FOLDER` and `ZOMBIENET_BINARY_PATH` (and ensure that the nearby variables +- change the `POLKADOT_SDK_PATH` and `ZOMBIENET_BINARY_PATH` (and ensure that the nearby variables have correct values) in the `./run-tests.sh`. After that, you could run tests with the `./run-tests.sh` command. Hopefully, it'll show the diff --git a/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml b/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml similarity index 82% rename from cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml rename to bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml index 99a7d0035b511c57ccf5c10fa94165933c495ba9..52271f9442131923f8a758b16df7610e73813d15 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +++ b/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml @@ -2,7 +2,7 @@ node_spawn_timeout = 240 [relaychain] -default_command = "{{POLKADOT_BINARY_PATH}}" +default_command = "{{POLKADOT_BINARY}}" default_args = [ "-lparachain=debug,xcm=trace" ] chain = "rococo-local" @@ -36,24 +36,22 @@ cumulus_based = true [[parachains.collators]] name = "bridge-hub-rococo-collator1" validator = true - command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" rpc_port = 8933 ws_port = 8943 args = [ - "-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring" + "-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" ] # run bob as parachain collator [[parachains.collators]] name = "bridge-hub-rococo-collator2" validator = true - command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" rpc_port = 8934 ws_port = 8944 args = [ - "-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring" + "-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" ] [[parachains]] @@ -65,14 +63,14 @@ cumulus_based = true name = "asset-hub-rococo-collator1" rpc_port = 9911 ws_port = 9910 - command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] [[parachains.collators]] name = "asset-hub-rococo-collator2" - command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] diff --git a/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml b/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml similarity index 84% rename from cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml rename to bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml index 1919d1c63f25f154e4676599afb8a2969598c10b..f2550bcc9959638b21ea78043cca3bc12d3d23ea 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml +++ b/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml @@ -2,7 +2,7 @@ node_spawn_timeout = 240 [relaychain] -default_command = "{{POLKADOT_BINARY_PATH}}" +default_command = "{{POLKADOT_BINARY}}" default_args = [ "-lparachain=debug,xcm=trace" ] chain = "westend-local" @@ -36,24 +36,22 @@ cumulus_based = true [[parachains.collators]] name = "bridge-hub-westend-collator1" validator = true - command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" rpc_port = 8935 ws_port = 8945 args = [ - "-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring" + "-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" ] # run bob as parachain collator [[parachains.collators]] name = "bridge-hub-westend-collator2" validator = true - command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" rpc_port = 8936 ws_port = 8946 args = [ - "-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", - "--force-authoring" + "-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" ] [[parachains]] @@ -65,14 +63,14 @@ cumulus_based = true name = "asset-hub-westend-collator1" rpc_port = 9011 ws_port = 9010 - command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] [[parachains.collators]] name = "asset-hub-westend-collator2" - command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND}}" + command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" ] diff --git a/cumulus/scripts/bridges_rococo_westend.sh b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh similarity index 97% rename from cumulus/scripts/bridges_rococo_westend.sh rename to bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh index 3b6f8e892858ad034a9db23a717b4290f9024bde..479ab833abfc38dd978c7b7d3abdd4c1fe37ad64 100755 --- a/cumulus/scripts/bridges_rococo_westend.sh +++ b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh @@ -1,7 +1,7 @@ #!/bin/bash # import common functions -source "$(dirname "$0")"/bridges_common.sh +source "$FRAMEWORK_PATH/utils/bridges.sh" # Expected sovereign accounts. # @@ -185,8 +185,8 @@ function run_relay() { case "$1" in run-relay) - init_ro_wnd init_wnd_ro + init_ro_wnd run_relay ;; init-asset-hub-rococo-local) @@ -319,6 +319,7 @@ case "$1" in $XCM_VERSION ;; reserve-transfer-assets-from-asset-hub-rococo-local) + amount=$2 ensure_polkadot_js_api # send ROCs to Alice account on AHW limited_reserve_transfer_assets \ @@ -326,11 +327,12 @@ case "$1" in "//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": 5000000000000 } } ] }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; withdraw-reserve-assets-from-asset-hub-rococo-local) + amount=$2 ensure_polkadot_js_api # send back only 100000000000 wrappedWNDs to Alice account on AHW limited_reserve_transfer_assets \ @@ -338,11 +340,12 @@ case "$1" in "//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": 3000000000000 } } ] }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; reserve-transfer-assets-from-asset-hub-westend-local) + amount=$2 ensure_polkadot_js_api # send WNDs to Alice account on AHR limited_reserve_transfer_assets \ @@ -350,11 +353,12 @@ case "$1" in "//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": 5000000000000 } } ] }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; withdraw-reserve-assets-from-asset-hub-westend-local) + amount=$2 ensure_polkadot_js_api # send back only 100000000000 wrappedROCs to Alice account on AHR limited_reserve_transfer_assets \ @@ -362,7 +366,7 @@ case "$1" in "//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": 3000000000000 } } ] }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; diff --git a/bridges/testing/environments/rococo-westend/helper.sh b/bridges/testing/environments/rococo-westend/helper.sh new file mode 100755 index 0000000000000000000000000000000000000000..0a13ded213f5d3a0920cb466fc974c129e9ad79a --- /dev/null +++ b/bridges/testing/environments/rococo-westend/helper.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +$ENV_PATH/bridges_rococo_westend.sh "$@" diff --git a/bridges/testing/environments/rococo-westend/rococo-init.zndsl b/bridges/testing/environments/rococo-westend/rococo-init.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..c913e4db31f49184eb8214fda4d525c3594b358b --- /dev/null +++ b/bridges/testing/environments/rococo-westend/rococo-init.zndsl @@ -0,0 +1,8 @@ +Description: Check if the HRMP channel between Rococo BH and Rococo AH was opened successfully +Network: ./bridge_hub_rococo_local_network.toml +Creds: config + +# ensure that initialization has completed +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wait-hrmp-channel-opened.js with "1013" within 300 seconds + + diff --git a/bridges/testing/environments/rococo-westend/rococo.zndsl b/bridges/testing/environments/rococo-westend/rococo.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..5b49c7c632fa4dd0ce77134858a2f697acbfff16 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/rococo.zndsl @@ -0,0 +1,7 @@ +Description: Check if the with-Westend GRANPDA pallet was initialized at Rococo BH +Network: ./bridge_hub_rococo_local_network.toml +Creds: config + +# relay is already started - let's wait until with-Westend GRANPDA pallet is initialized at Rococo +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Westend,0" within 400 seconds + diff --git a/bridges/testing/environments/rococo-westend/spawn.sh b/bridges/testing/environments/rococo-westend/spawn.sh new file mode 100755 index 0000000000000000000000000000000000000000..cbd0b1bc623ab77876ed5ce3beefd7ab72db2d37 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/spawn.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +set -e + +trap "trap - SIGTERM && kill -9 -$$" SIGINT SIGTERM EXIT + +source "$FRAMEWORK_PATH/utils/zombienet.sh" + +# whether to init the chains (open HRMP channels, set XCM version, create reserve assets, etc) +init=0 +start_relayer=0 +while [ $# -ne 0 ] +do + arg="$1" + case "$arg" in + --init) + init=1 + ;; + --start-relayer) + start_relayer=1 + ;; + esac + shift +done + +logs_dir=$TEST_DIR/logs +helper_script="${BASH_SOURCE%/*}/helper.sh" + +rococo_def=${BASH_SOURCE%/*}/bridge_hub_rococo_local_network.toml +start_zombienet $TEST_DIR $rococo_def rococo_dir rococo_pid +echo + +westend_def=${BASH_SOURCE%/*}/bridge_hub_westend_local_network.toml +start_zombienet $TEST_DIR $westend_def westend_dir westend_pid +echo + +if [[ $init -eq 1 ]]; then + 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" + + $helper_script init-asset-hub-rococo-local >> $rococo_init_log 2>&1 & + rococo_init_pid=$! + $helper_script init-asset-hub-westend-local >> $westend_init_log 2>&1 & + 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 & + westend_init_pid=$! + wait -n $rococo_init_pid $westend_init_pid + + run_zndsl ${BASH_SOURCE%/*}/rococo-init.zndsl $rococo_dir + run_zndsl ${BASH_SOURCE%/*}/westend-init.zndsl $westend_dir +fi + +if [[ $start_relayer -eq 1 ]]; then + ${BASH_SOURCE%/*}/start_relayer.sh $rococo_dir $westend_dir relayer_pid +fi + +echo $rococo_dir > $TEST_DIR/rococo.env +echo $westend_dir > $TEST_DIR/westend.env +echo + +wait -n $rococo_pid $westend_pid $relayer_pid +kill -9 -$$ diff --git a/bridges/testing/environments/rococo-westend/start_relayer.sh b/bridges/testing/environments/rococo-westend/start_relayer.sh new file mode 100755 index 0000000000000000000000000000000000000000..7ddd312d395aa8733d2afea59277b48721c8a36b --- /dev/null +++ b/bridges/testing/environments/rococo-westend/start_relayer.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +source "$FRAMEWORK_PATH/utils/common.sh" +source "$FRAMEWORK_PATH/utils/zombienet.sh" + +rococo_dir=$1 +westend_dir=$2 +__relayer_pid=$3 + +logs_dir=$TEST_DIR/logs +helper_script="${BASH_SOURCE%/*}/helper.sh" + +relayer_log=$logs_dir/relayer.log +echo -e "Starting rococo-westend relayer. Logs available at: $relayer_log\n" +start_background_process "$helper_script run-relay" $relayer_log relayer_pid + +run_zndsl ${BASH_SOURCE%/*}/rococo.zndsl $rococo_dir +run_zndsl ${BASH_SOURCE%/*}/westend.zndsl $westend_dir + +eval $__relayer_pid="'$relayer_pid'" + diff --git a/bridges/testing/environments/rococo-westend/westend-init.zndsl b/bridges/testing/environments/rococo-westend/westend-init.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..0f5428eed3b01c042f8aad3b3df51c3a800a9b72 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/westend-init.zndsl @@ -0,0 +1,7 @@ +Description: Check if the HRMP channel between Westend BH and Westend AH was opened successfully +Network: ./bridge_hub_westend_local_network.toml +Creds: config + +# ensure that initialization has completed +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wait-hrmp-channel-opened.js with "1002" within 600 seconds + diff --git a/bridges/testing/environments/rococo-westend/westend.zndsl b/bridges/testing/environments/rococo-westend/westend.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..07968838852f7c0a00131db3080c460c07d08206 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/westend.zndsl @@ -0,0 +1,6 @@ +Description: Check if the with-Rococo GRANPDA pallet was initialized at Westend BH +Network: ./bridge_hub_westend_local_network.toml +Creds: config + +# relay is already started - let's wait until with-Rococo GRANPDA pallet is initialized at Westend +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds diff --git a/bridges/zombienet/helpers/best-finalized-header-at-bridged-chain.js b/bridges/testing/framework/js-helpers/best-finalized-header-at-bridged-chain.js similarity index 94% rename from bridges/zombienet/helpers/best-finalized-header-at-bridged-chain.js rename to bridges/testing/framework/js-helpers/best-finalized-header-at-bridged-chain.js index f7e1eefc84b3fa3e799d7111608cfc39783f5e21..af4f18aee9b2710612ed142c50b28caf8313326d 100644 --- a/bridges/zombienet/helpers/best-finalized-header-at-bridged-chain.js +++ b/bridges/testing/framework/js-helpers/best-finalized-header-at-bridged-chain.js @@ -18,7 +18,7 @@ async function run(nodeName, networkInfo, args) { } // else sleep and retry - await new Promise((resolve) => setTimeout(resolve, 12000)); + await new Promise((resolve) => setTimeout(resolve, 6000)); } } diff --git a/bridges/zombienet/helpers/chains/rococo-at-westend.js b/bridges/testing/framework/js-helpers/chains/rococo-at-westend.js similarity index 100% rename from bridges/zombienet/helpers/chains/rococo-at-westend.js rename to bridges/testing/framework/js-helpers/chains/rococo-at-westend.js diff --git a/bridges/zombienet/helpers/chains/westend-at-rococo.js b/bridges/testing/framework/js-helpers/chains/westend-at-rococo.js similarity index 100% rename from bridges/zombienet/helpers/chains/westend-at-rococo.js rename to bridges/testing/framework/js-helpers/chains/westend-at-rococo.js diff --git a/bridges/zombienet/helpers/native-assets-balance-increased.js b/bridges/testing/framework/js-helpers/native-assets-balance-increased.js similarity index 74% rename from bridges/zombienet/helpers/native-assets-balance-increased.js rename to bridges/testing/framework/js-helpers/native-assets-balance-increased.js index 9ee1a769e9f2807ed7b73ca9c6aa4b89d5c135f9..749c3e2fec32ac0af4d244c53cb4ac1c6237817a 100644 --- a/bridges/zombienet/helpers/native-assets-balance-increased.js +++ b/bridges/testing/framework/js-helpers/native-assets-balance-increased.js @@ -3,18 +3,19 @@ async function run(nodeName, networkInfo, args) { const api = await zombie.connect(wsUri, userDefinedTypes); const accountAddress = args[0]; + const expectedIncrease = BigInt(args[1]); const initialAccountData = await api.query.system.account(accountAddress); const initialAccountBalance = initialAccountData.data['free']; while (true) { const accountData = await api.query.system.account(accountAddress); const accountBalance = accountData.data['free']; - if (accountBalance > initialAccountBalance) { + if (accountBalance > initialAccountBalance + expectedIncrease) { return accountBalance; } // else sleep and retry - await new Promise((resolve) => setTimeout(resolve, 12000)); + await new Promise((resolve) => setTimeout(resolve, 6000)); } } -module.exports = { run } +module.exports = {run} diff --git a/bridges/zombienet/helpers/only-mandatory-headers-synced-when-idle.js b/bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js similarity index 88% rename from bridges/zombienet/helpers/only-mandatory-headers-synced-when-idle.js rename to bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js index 3a3432cfaf38da93f3ea0e65657f266b66f84d74..979179245ebe9f5b250efca6f2e6199ef0ac86d7 100644 --- a/bridges/zombienet/helpers/only-mandatory-headers-synced-when-idle.js +++ b/bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js @@ -10,7 +10,7 @@ async function run(nodeName, networkInfo, args) { // start listening to new blocks let totalGrandpaHeaders = 0; - let totalParachainHeaders = 0; + let initialParachainHeaderImported = false; api.rpc.chain.subscribeNewHeads(async function (header) { const apiAtParent = await api.at(header.parentHash); const apiAtCurrent = await api.at(header.hash); @@ -22,7 +22,7 @@ async function run(nodeName, networkInfo, args) { apiAtCurrent, currentEvents, ); - totalParachainHeaders += await utils.ensureOnlyInitialParachainHeaderImported( + initialParachainHeaderImported = await utils.ensureOnlyInitialParachainHeaderImported( bridgedChain, apiAtParent, apiAtCurrent, @@ -36,7 +36,7 @@ async function run(nodeName, networkInfo, args) { if (totalGrandpaHeaders == 0) { throw new Error("No bridged relay chain headers imported"); } - if (totalParachainHeaders == 0) { + if (!initialParachainHeaderImported) { throw new Error("No bridged parachain headers imported"); } } diff --git a/bridges/zombienet/helpers/only-required-headers-synced-when-idle.js b/bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js similarity index 100% rename from bridges/zombienet/helpers/only-required-headers-synced-when-idle.js rename to bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js diff --git a/bridges/zombienet/helpers/relayer-rewards.js b/bridges/testing/framework/js-helpers/relayer-rewards.js similarity index 93% rename from bridges/zombienet/helpers/relayer-rewards.js rename to bridges/testing/framework/js-helpers/relayer-rewards.js index a5f567db797722e04d3bfae90745a728ff1abdff..5347c649604fc209042725c9cf269c9d3ca0290f 100644 --- a/bridges/zombienet/helpers/relayer-rewards.js +++ b/bridges/testing/framework/js-helpers/relayer-rewards.js @@ -21,7 +21,7 @@ async function run(nodeName, networkInfo, args) { } // else sleep and retry - await new Promise((resolve) => setTimeout(resolve, 12000)); + await new Promise((resolve) => setTimeout(resolve, 6000)); } } diff --git a/bridges/zombienet/helpers/utils.js b/bridges/testing/framework/js-helpers/utils.js similarity index 98% rename from bridges/zombienet/helpers/utils.js rename to bridges/testing/framework/js-helpers/utils.js index 5a5542b56dfc215a082fc6fbb8c1b9aa018de83e..f6e9f5623b47b3cb3c642245e86654ae9f65358a 100644 --- a/bridges/zombienet/helpers/utils.js +++ b/bridges/testing/framework/js-helpers/utils.js @@ -98,6 +98,6 @@ module.exports = { throw new Error("Unexpected parachain header import: " + newParachainHeaders + " / " + maxNewParachainHeaders); } - return newParachainHeaders; + return hasBestBridgedParachainHeader; }, } diff --git a/bridges/zombienet/helpers/wait-hrmp-channel-opened.js b/bridges/testing/framework/js-helpers/wait-hrmp-channel-opened.js similarity index 91% rename from bridges/zombienet/helpers/wait-hrmp-channel-opened.js rename to bridges/testing/framework/js-helpers/wait-hrmp-channel-opened.js index e700cab1d7481d77631e55492e4b0032f4382028..765d48cc49848ab7a4389f6e0d9b9b3b8cb38f2b 100644 --- a/bridges/zombienet/helpers/wait-hrmp-channel-opened.js +++ b/bridges/testing/framework/js-helpers/wait-hrmp-channel-opened.js @@ -15,7 +15,7 @@ async function run(nodeName, networkInfo, args) { } // else sleep and retry - await new Promise((resolve) => setTimeout(resolve, 12000)); + await new Promise((resolve) => setTimeout(resolve, 6000)); } } diff --git a/bridges/zombienet/helpers/wrapped-assets-balance.js b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js similarity index 93% rename from bridges/zombienet/helpers/wrapped-assets-balance.js rename to bridges/testing/framework/js-helpers/wrapped-assets-balance.js index bb3cea8858a850e551ba0380b1557ccad0761717..27287118547f702b3e94eb635f9e3855d1cab535 100644 --- a/bridges/zombienet/helpers/wrapped-assets-balance.js +++ b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js @@ -19,7 +19,7 @@ async function run(nodeName, networkInfo, args) { } // else sleep and retry - await new Promise((resolve) => setTimeout(resolve, 12000)); + await new Promise((resolve) => setTimeout(resolve, 6000)); } } diff --git a/cumulus/scripts/bridges_common.sh b/bridges/testing/framework/utils/bridges.sh similarity index 97% rename from cumulus/scripts/bridges_common.sh rename to bridges/testing/framework/utils/bridges.sh index 029d4cd4ff74a5c88165913a48b2b369c0f185b8..7c8399461584a85e4e8eedf5f347d9d74725f1c9 100755 --- a/cumulus/scripts/bridges_common.sh +++ b/bridges/testing/framework/utils/bridges.sh @@ -2,7 +2,7 @@ function relayer_path() { local default_path=~/local_bridge_testing/bin/substrate-relay - local path="${SUBSTRATE_RELAY_PATH:-$default_path}" + local path="${SUBSTRATE_RELAY_BINARY:-$default_path}" echo "$path" } @@ -41,8 +41,8 @@ function ensure_polkadot_js_api() { echo "" echo "" echo "-------------------" - echo "Installing (nodejs) sub module: $(dirname "$0")/generate_hex_encoded_call" - pushd $(dirname "$0")/generate_hex_encoded_call + echo "Installing (nodejs) sub module: ${BASH_SOURCE%/*}/generate_hex_encoded_call" + pushd ${BASH_SOURCE%/*}/generate_hex_encoded_call npm install popd fi @@ -65,7 +65,7 @@ function generate_hex_encoded_call_data() { shift echo "Input params: $@" - node $(dirname "$0")/generate_hex_encoded_call "$type" "$endpoint" "$output" "$@" + node ${BASH_SOURCE%/*}/../utils/generate_hex_encoded_call "$type" "$endpoint" "$output" "$@" local retVal=$? if [ $type != "check" ]; then diff --git a/bridges/testing/framework/utils/common.sh b/bridges/testing/framework/utils/common.sh new file mode 100644 index 0000000000000000000000000000000000000000..06f41320be1353720fccc76b7b76e69ba56a3b94 --- /dev/null +++ b/bridges/testing/framework/utils/common.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +function start_background_process() { + local command=$1 + local log_file=$2 + local __pid=$3 + + $command > $log_file 2>&1 & + eval $__pid="'$!'" +} + +function wait_for_process_file() { + local pid=$1 + local file=$2 + local timeout=$3 + local __found=$4 + + local time=0 + until [ -e $file ]; do + if ! kill -0 $pid; then + echo "Process finished unsuccessfully" + return + fi + if (( time++ >= timeout )); then + echo "Timeout waiting for file $file: $timeout seconds" + eval $__found=0 + return + fi + sleep 1 + done + + echo "File $file found after $time seconds" + eval $__found=1 +} + +function ensure_process_file() { + local pid=$1 + local file=$2 + local timeout=$3 + + wait_for_process_file $pid $file $timeout file_found + if [ "$file_found" != "1" ]; then + exit 1 + fi +} diff --git a/cumulus/scripts/generate_hex_encoded_call/index.js b/bridges/testing/framework/utils/generate_hex_encoded_call/index.js similarity index 100% rename from cumulus/scripts/generate_hex_encoded_call/index.js rename to bridges/testing/framework/utils/generate_hex_encoded_call/index.js diff --git a/cumulus/scripts/generate_hex_encoded_call/package-lock.json b/bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json similarity index 100% rename from cumulus/scripts/generate_hex_encoded_call/package-lock.json rename to bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json diff --git a/cumulus/scripts/generate_hex_encoded_call/package.json b/bridges/testing/framework/utils/generate_hex_encoded_call/package.json similarity index 100% rename from cumulus/scripts/generate_hex_encoded_call/package.json rename to bridges/testing/framework/utils/generate_hex_encoded_call/package.json diff --git a/bridges/testing/framework/utils/zombienet.sh b/bridges/testing/framework/utils/zombienet.sh new file mode 100644 index 0000000000000000000000000000000000000000..bbcd1a30620252d8740473c3924e0988e5bff4d6 --- /dev/null +++ b/bridges/testing/framework/utils/zombienet.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +source "${BASH_SOURCE%/*}/common.sh" + +function start_zombienet() { + local test_dir=$1 + local definition_path=$2 + local __zombienet_dir=$3 + local __zombienet_pid=$4 + + local zombienet_name=`basename $definition_path .toml` + local zombienet_dir=$test_dir/$zombienet_name + eval $__zombienet_dir="'$zombienet_dir'" + mkdir -p $zombienet_dir + rm -rf $zombienet_dir + + local logs_dir=$test_dir/logs + mkdir -p $logs_dir + local zombienet_log=$logs_dir/$zombienet_name.log + + echo "Starting $zombienet_name zombienet. Logs available at: $zombienet_log" + start_background_process \ + "$ZOMBIENET_BINARY spawn --dir $zombienet_dir --provider native $definition_path" \ + "$zombienet_log" zombienet_pid + + ensure_process_file $zombienet_pid "$zombienet_dir/zombie.json" 180 + echo "$zombienet_name zombienet started successfully" + + eval $__zombienet_pid="'$zombienet_pid'" +} + +function run_zndsl() { + local zndsl_file=$1 + local zombienet_dir=$2 + + echo "Running $zndsl_file." + $ZOMBIENET_BINARY test --dir $zombienet_dir --provider native $zndsl_file $zombienet_dir/zombie.json + echo +} diff --git a/bridges/testing/run-new-test.sh b/bridges/testing/run-new-test.sh new file mode 100755 index 0000000000000000000000000000000000000000..7c84a69aa47de84439091cb7b908233d02238175 --- /dev/null +++ b/bridges/testing/run-new-test.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -e + +trap 'kill -9 -$$ || echo "Environment already teared down"' SIGINT SIGTERM EXIT + +test=$1 +shift + +# whether to use paths for zombienet+bridges tests container or for local testing +ZOMBIENET_DOCKER_PATHS=0 +while [ $# -ne 0 ] +do + arg="$1" + case "$arg" in + --docker) + ZOMBIENET_DOCKER_PATHS=1 + ;; + esac + shift +done + +export POLKADOT_SDK_PATH=`realpath ${BASH_SOURCE%/*}/../..` +export FRAMEWORK_PATH=`realpath ${BASH_SOURCE%/*}/framework` + +# set path to binaries +if [ "$ZOMBIENET_DOCKER_PATHS" -eq 1 ]; then + # otherwise zombienet uses some hardcoded paths + unset RUN_IN_CONTAINER + unset ZOMBIENET_IMAGE + + export POLKADOT_BINARY=/usr/local/bin/polkadot + export POLKADOT_PARACHAIN_BINARY=/usr/local/bin/polkadot-parachain + + export ZOMBIENET_BINARY=/usr/local/bin/zombie + export SUBSTRATE_RELAY_BINARY=/usr/local/bin/substrate-relay +else + export POLKADOT_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot + export POLKADOT_PARACHAIN_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot-parachain + + export ZOMBIENET_BINARY=~/local_bridge_testing/bin/zombienet-linux-x64 + export SUBSTRATE_RELAY_BINARY=~/local_bridge_testing/bin/substrate-relay +fi + +export TEST_DIR=`mktemp -d /tmp/bridges-tests-run-XXXXX` +echo -e "Test folder: $TEST_DIR\n" + +${BASH_SOURCE%/*}/tests/$test/run.sh diff --git a/bridges/zombienet/run-tests.sh b/bridges/testing/run-tests.sh similarity index 77% rename from bridges/zombienet/run-tests.sh rename to bridges/testing/run-tests.sh index cf3b529e6a9d9823f875938d8603b363c6079136..6149d9912653c79968a0229759c8f1bf46f68a9f 100755 --- a/bridges/zombienet/run-tests.sh +++ b/bridges/testing/run-tests.sh @@ -27,34 +27,27 @@ done # assuming that we'll be using native provide && all processes will be executing locally # (we need absolute paths here, because they're used when scripts are called by zombienet from tmp folders) -export POLKADOT_SDK_FOLDER=`realpath $(dirname "$0")/../..` -export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_FOLDER/bridges/zombienet/tests +export POLKADOT_SDK_PATH=`realpath $(dirname "$0")/../..` +export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_PATH/bridges/testing/tests # set pathc to binaries if [ "$ZOMBIENET_DOCKER_PATHS" -eq 1 ]; then - export POLKADOT_BINARY_PATH=/usr/local/bin/polkadot - export POLKADOT_PARACHAIN_BINARY_PATH=/usr/local/bin/polkadot-parachain - export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO=/usr/local/bin/polkadot-parachain - export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND=/usr/local/bin/polkadot-parachain + export POLKADOT_BINARY=/usr/local/bin/polkadot + export POLKADOT_PARACHAIN_BINARY=/usr/local/bin/polkadot-parachain - export SUBSTRATE_RELAY_PATH=/usr/local/bin/substrate-relay + export SUBSTRATE_RELAY_BINARY=/usr/local/bin/substrate-relay export ZOMBIENET_BINARY_PATH=/usr/local/bin/zombie else - export POLKADOT_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot - export POLKADOT_PARACHAIN_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot-parachain - export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO=$POLKADOT_PARACHAIN_BINARY_PATH - export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND=$POLKADOT_PARACHAIN_BINARY_PATH + export POLKADOT_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot + export POLKADOT_PARACHAIN_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot-parachain - export SUBSTRATE_RELAY_PATH=~/local_bridge_testing/bin/substrate-relay + export SUBSTRATE_RELAY_BINARY=~/local_bridge_testing/bin/substrate-relay export ZOMBIENET_BINARY_PATH=~/local_bridge_testing/bin/zombienet-linux fi # check if `wait` supports -p flag if [ `printf "$BASH_VERSION\n5.1" | sort -V | head -n 1` = "5.1" ]; then IS_BASH_5_1=1; else IS_BASH_5_1=0; fi -# check if `wait` supports -p flag -if [ `printf "$BASH_VERSION\n5.1" | sort -V | head -n 1` = "5.1" ]; then IS_BASH_5_1=1; else IS_BASH_5_1=0; fi - # bridge configuration export LANE_ID="00000002" diff --git a/bridges/zombienet/scripts/invoke-script.sh b/bridges/testing/scripts/invoke-script.sh similarity index 62% rename from bridges/zombienet/scripts/invoke-script.sh rename to bridges/testing/scripts/invoke-script.sh index 835b4fe500f01ea2968bcb8bff538491ec7149bc..cd0557b071bbadc41e056a2e50c9f1aa0b677312 100755 --- a/bridges/zombienet/scripts/invoke-script.sh +++ b/bridges/testing/scripts/invoke-script.sh @@ -2,6 +2,6 @@ INVOKE_LOG=`mktemp -p $TEST_FOLDER invoke.XXXXX` -pushd $POLKADOT_SDK_FOLDER/cumulus/scripts +pushd $POLKADOT_SDK_PATH/bridges/testing/environments/rococo-westend ./bridges_rococo_westend.sh $1 >$INVOKE_LOG 2>&1 popd diff --git a/bridges/zombienet/scripts/start-relayer.sh b/bridges/testing/scripts/start-relayer.sh similarity index 63% rename from bridges/zombienet/scripts/start-relayer.sh rename to bridges/testing/scripts/start-relayer.sh index 2f72b5ee556bcc8a89b2de4c5d3c53db8ac072b1..38ea62fad524486c40cf88943c48a2e4df4b86e8 100755 --- a/bridges/zombienet/scripts/start-relayer.sh +++ b/bridges/testing/scripts/start-relayer.sh @@ -2,6 +2,6 @@ RELAY_LOG=`mktemp -p $TEST_FOLDER relay.XXXXX` -pushd $POLKADOT_SDK_FOLDER/cumulus/scripts +pushd $POLKADOT_SDK_PATH/bridges/testing/environments/rococo-westend ./bridges_rococo_westend.sh run-relay >$RELAY_LOG 2>&1& popd diff --git a/bridges/zombienet/scripts/sync-exit.sh b/bridges/testing/scripts/sync-exit.sh similarity index 100% rename from bridges/zombienet/scripts/sync-exit.sh rename to bridges/testing/scripts/sync-exit.sh diff --git a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..a58520ccea65b50dd0db1f67a72f6f8a4c5cdb38 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl @@ -0,0 +1,12 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# send 5 ROC to //Alice from Rococo AH to Westend AH +asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "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 300 seconds + +# check that the relayer //Charlie is rewarded by Westend AH +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x6268726F,ThisChain,0" within 30 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/run.sh b/bridges/testing/tests/0001-asset-transfer/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..a7bb122919b40187c49e89c489d2271d646bff40 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/run.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +source "${BASH_SOURCE%/*}/../../framework/utils/common.sh" +source "${BASH_SOURCE%/*}/../../framework/utils/zombienet.sh" + +export ENV_PATH=`realpath ${BASH_SOURCE%/*}/../../environments/rococo-westend` + +$ENV_PATH/spawn.sh --init --start-relayer & +env_pid=$! + +ensure_process_file $env_pid $TEST_DIR/rococo.env 600 +rococo_dir=`cat $TEST_DIR/rococo.env` +echo + +ensure_process_file $env_pid $TEST_DIR/westend.env 300 +westend_dir=`cat $TEST_DIR/westend.env` +echo + +run_zndsl ${BASH_SOURCE%/*}/roc-reaches-westend.zndsl $westend_dir +run_zndsl ${BASH_SOURCE%/*}/wnd-reaches-rococo.zndsl $rococo_dir + +run_zndsl ${BASH_SOURCE%/*}/wroc-reaches-rococo.zndsl $rococo_dir +run_zndsl ${BASH_SOURCE%/*}/wwnd-reaches-westend.zndsl $westend_dir diff --git a/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..fedb78cc2103555a1d15c446dd2f08fca94643e1 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl @@ -0,0 +1,12 @@ +Description: User is able to transfer WND from Westend Asset Hub to Rococo Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_rococo_local_network.toml +Creds: config + +# send 5 WND to //Alice from Westend AH to Rococo AH +asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "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 300 seconds + +# check that the relayer //Charlie is rewarded by Rococo AH +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x62687764,ThisChain,0" within 30 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl b/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..68b888b6858e86b8fe846b887bc101e221b2f21d --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl @@ -0,0 +1,10 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# send 3 wROC back to Alice from Westend AH to Rococo AH +asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-assets-from-asset-hub-westend-local 3000000000000" within 120 seconds + +# check that //Alice received at least 2.8 wROC on Rococo AH +# (we wait until //Alice account increases here - there are no other transactions that may increase it) +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 300 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..1a8a161819542e281094aed0681d52167aaea8e6 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl @@ -0,0 +1,10 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# send 3 wWND back to Alice from Rococo AH to Westend AH +asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-assets-from-asset-hub-rococo-local 3000000000000" within 120 seconds + +# check that //Alice received at least 2.8 wWND on Westend AH +# (we wait until //Alice account increases here - there are no other transactions that may increase it) +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 300 seconds diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/rococo-to-westend.zndsl b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/rococo-to-westend.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..6e381f5377329430c0d7a8723f9ea9081556bfeb --- /dev/null +++ b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/rococo-to-westend.zndsl @@ -0,0 +1,8 @@ +Description: While relayer is idle, we only sync mandatory Rococo (and a single Rococo BH) headers to Westend BH. +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# ensure that relayer is only syncing mandatory headers while idle. This includes both headers that were +# generated while relay was offline and those in the next 100 seconds while script is active. +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/only-mandatory-headers-synced-when-idle.js with "300,rococo-at-westend" within 600 seconds + diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..7d5b8d9273664b0861e8ffe1c528e9e1718c4df4 --- /dev/null +++ b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set -e + +source "${BASH_SOURCE%/*}/../../framework/utils/common.sh" +source "${BASH_SOURCE%/*}/../../framework/utils/zombienet.sh" + +export ENV_PATH=`realpath ${BASH_SOURCE%/*}/../../environments/rococo-westend` + +$ENV_PATH/spawn.sh & +env_pid=$! + +ensure_process_file $env_pid $TEST_DIR/rococo.env 600 +rococo_dir=`cat $TEST_DIR/rococo.env` +echo + +ensure_process_file $env_pid $TEST_DIR/westend.env 300 +westend_dir=`cat $TEST_DIR/westend.env` +echo + +# Sleep for some time before starting the relayer. We want to sleep for at least 1 session, +# which is expected to be 60 seconds for the test environment. +echo -e "Sleeping 90s before starting relayer ...\n" +sleep 90 +${BASH_SOURCE%/*}/../../environments/rococo-westend/start_relayer.sh $rococo_dir $westend_dir relayer_pid + +# Sometimes the relayer syncs multiple parachain heads in the begining leading to test failures. +# See issue: https://github.com/paritytech/parity-bridges-common/issues/2838. +# TODO: Remove this sleep after the issue is fixed. +echo -e "Sleeping 180s before runing the tests ...\n" +sleep 180 + +run_zndsl ${BASH_SOURCE%/*}/rococo-to-westend.zndsl $westend_dir +run_zndsl ${BASH_SOURCE%/*}/westend-to-rococo.zndsl $rococo_dir + diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..b4b3e43679162feb8c3c5253f3f963d950f31d55 --- /dev/null +++ b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl @@ -0,0 +1,7 @@ +Description: While relayer is idle, we only sync mandatory Westend (and a single Westend BH) headers to Rococo BH. +Network: {{ENV_PATH}}/bridge_hub_rococo_local_network.toml +Creds: config + +# ensure that relayer is only syncing mandatory headers while idle. This includes both headers that were +# generated while relay was offline and those in the next 100 seconds while script is active. +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/only-mandatory-headers-synced-when-idle.js with "300,westend-at-rococo" within 600 seconds diff --git a/bridges/zombienet/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl b/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl similarity index 77% rename from bridges/zombienet/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl rename to bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl index a4960344f0a03265d2accfa52cd9a4ab1d7117d6..07b91481dc7cf995b913a9bf84edd3728982eaae 100644 --- a/bridges/zombienet/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl +++ b/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl @@ -1,5 +1,5 @@ Description: While relayer is active, we only sync mandatory and required Rococo (and Rococo BH) headers to Westend BH. -Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml +Network: ../environments/rococo-westend/bridge_hub_westend_local_network.toml Creds: config # step 1: initialize Westend AH @@ -9,7 +9,7 @@ asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-asset-hu bridge-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-westend-local" within 60 seconds # step 3: ensure that initialization has completed -asset-hub-westend-collator1: js-script ../helpers/wait-hrmp-channel-opened.js with "1002" within 600 seconds +asset-hub-westend-collator1: js-script ../js-helpers/wait-hrmp-channel-opened.js with "1002" within 600 seconds # step 4: send message from Westend to Rococo asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-westend-local" within 60 seconds @@ -20,7 +20,7 @@ asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "reserve-trans # (it is started by sibling 0003-required-headers-synced-while-active-westend-to-rococo.zndsl) # step 6: ensure that relayer won't sync any extra headers while delivering messages and confirmations -bridge-hub-westend-collator1: js-script ../helpers/only-required-headers-synced-when-active.js with "500,rococo-at-westend" within 600 seconds +bridge-hub-westend-collator1: js-script ../js-helpers/only-required-headers-synced-when-active.js with "500,rococo-at-westend" within 600 seconds # wait until other network test has completed OR exit with an error too asset-hub-westend-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl b/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl similarity index 77% rename from bridges/zombienet/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl rename to bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl index 33c3ceebcf844cc6029d41deb289b1a1d8103132..a6b11fc24052aadf562bc34704aeda9ee115eccf 100644 --- a/bridges/zombienet/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl +++ b/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl @@ -1,5 +1,5 @@ Description: While relayer is active, we only sync mandatory and required Westend (and Westend BH) headers to Rococo BH. -Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +Network: ../environments/rococo-westend/bridge_hub_rococo_local_network.toml Creds: config # step 1: initialize Rococo AH @@ -9,7 +9,7 @@ asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 60 seconds # step 3: ensure that initialization has completed -asset-hub-rococo-collator1: js-script ../helpers/wait-hrmp-channel-opened.js with "1013" within 600 seconds +asset-hub-rococo-collator1: js-script ../js-helpers/wait-hrmp-channel-opened.js with "1013" within 600 seconds # step 4: send message from Rococo to Westend asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-rococo-local" within 60 seconds @@ -20,7 +20,7 @@ asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transf bridge-hub-rococo-collator1: run ../scripts/start-relayer.sh within 60 seconds # step 6: ensure that relayer won't sync any extra headers while delivering messages and confirmations -bridge-hub-rococo-collator1: js-script ../helpers/only-required-headers-synced-when-active.js with "500,westend-at-rococo" within 600 seconds +bridge-hub-rococo-collator1: js-script ../js-helpers/only-required-headers-synced-when-active.js with "500,westend-at-rococo" within 600 seconds # wait until other network test has completed OR exit with an error too asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-westend.zndsl b/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-westend.zndsl deleted file mode 100644 index 82d1eee2f45cc12b60a85b829d4a4c17588fa9e7..0000000000000000000000000000000000000000 --- a/bridges/zombienet/tests/0001-asset-transfer-works-rococo-to-westend.zndsl +++ /dev/null @@ -1,39 +0,0 @@ -Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub and back -Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml -Creds: config - -# step 0: start relayer -# (started by sibling 0001-asset-transfer-works-westend-to-rococo.zndsl test) - -# step 1: initialize Westend AH -asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-westend-local" within 60 seconds - -# step 2: initialize Westend bridge hub -bridge-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-westend-local" within 60 seconds - -# step 3: ensure that initialization has completed -asset-hub-westend-collator1: js-script ../helpers/wait-hrmp-channel-opened.js with "1002" within 600 seconds - -# step 4: relay is already started - let's wait until with-Rococo GRANPDA pallet is initialized at Westend -bridge-hub-westend-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds - -# step 5: send WND to //Alice on Rococo AH -# (that's a required part of a sibling 0001-asset-transfer-works-westend-to-rococo.zndsl test) -asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-westend-local" within 60 seconds - -# step 6: elsewhere Rococo has sent ROC to //Alice - let's wait for it -asset-hub-westend-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Rococo" within 600 seconds - -# step 7: check that the relayer //Charlie is rewarded by both our AH and target AH -bridge-hub-westend-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x6268726f,BridgedChain,0" within 300 seconds -bridge-hub-westend-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x6268726F,ThisChain,0" within 300 seconds - -# step 8: send wROC back to Alice at Rococo AH -asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "withdraw-reserve-assets-from-asset-hub-westend-local" within 60 seconds - -# step 9: elsewhere Rococo has sent wWND to //Alice - let's wait for it -# (we wait until //Alice account increases here - there are no other transactionc that may increase it) -asset-hub-westend-collator1: js-script ../helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-westend-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0001-asset-transfer-works-westend-to-rococo.zndsl b/bridges/zombienet/tests/0001-asset-transfer-works-westend-to-rococo.zndsl deleted file mode 100644 index acfe0df03d26779abf0dd3c2aa3dfc8f37c0e3aa..0000000000000000000000000000000000000000 --- a/bridges/zombienet/tests/0001-asset-transfer-works-westend-to-rococo.zndsl +++ /dev/null @@ -1,39 +0,0 @@ -Description: User is able to transfer WND from Westend Asset Hub to Rococo Asset Hub and back -Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml -Creds: config - -# step 0: start relayer -bridge-hub-rococo-collator1: run ../scripts/start-relayer.sh within 60 seconds - -# step 1: initialize Rococo AH -asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-rococo-local" within 60 seconds - -# step 2: initialize Rococo bridge hub -bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 60 seconds - -# step 3: ensure that initialization has completed -asset-hub-rococo-collator1: js-script ../helpers/wait-hrmp-channel-opened.js with "1013" within 600 seconds - -# step 4: relay is already started - let's wait until with-Westend GRANPDA pallet is initialized at Rococo -bridge-hub-rococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Westend,0" within 400 seconds - -# step 5: send ROC to //Alice on Westend AH -# (that's a required part of a sibling 0001-asset-transfer-works-rococo-to-westend.zndsl test) -asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-rococo-local" within 60 seconds - -# step 6: elsewhere Westend has sent WND to //Alice - let's wait for it -asset-hub-rococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Westend" within 600 seconds - -# step 7: check that the relayer //Charlie is rewarded by both our AH and target AH -bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x62687764,BridgedChain,0" within 300 seconds -bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x62687764,ThisChain,0" within 300 seconds - -# step 8: send wWND back to Alice at Westend AH -asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "withdraw-reserve-assets-from-asset-hub-rococo-local" within 60 seconds - -# step 9: elsewhere Westend has sent wROC to //Alice - let's wait for it -# (we wait until //Alice account increases here - there are no other transactionc that may increase it) -asset-hub-rococo-collator1: js-script ../helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0002-mandatory-headers-synced-while-idle-rococo-to-westend.zndsl b/bridges/zombienet/tests/0002-mandatory-headers-synced-while-idle-rococo-to-westend.zndsl deleted file mode 100644 index eb6a75c373c7add04f895c01e332d40195150370..0000000000000000000000000000000000000000 --- a/bridges/zombienet/tests/0002-mandatory-headers-synced-while-idle-rococo-to-westend.zndsl +++ /dev/null @@ -1,26 +0,0 @@ -Description: While relayer is idle, we only sync mandatory Rococo (and a single Rococo BH) headers to Westend BH. -Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml -Creds: config - -# step 1: initialize Westend bridge hub -bridge-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-westend-local" within 60 seconds - -# step 2: sleep some time before starting relayer. We want to sleep for at least 1 session, which is expected to -# be 60 seconds for test environment. -sleep 120 seconds - -# step 3: start relayer -# (it is started by the sibling 0002-mandatory-headers-synced-while-idle-westend-to-rococo.zndsl test file) - -# it also takes some time for relayer to initialize bridge, so let's sleep for 5 minutes to be sure that parachain -# header has been synced - -# step 4: ensure that relayer is only syncing mandatory headers while idle. This includes both headers that were -# born while relay was offline and those in the next 100 seconds while script is active. -bridge-hub-westend-collator1: js-script ../helpers/only-mandatory-headers-synced-when-idle.js with "300,rococo-at-westend" within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-westend-collator1: run ../scripts/sync-exit.sh within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-westend-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/zombienet/tests/0002-mandatory-headers-synced-while-idle-westend-to-rococo.zndsl b/bridges/zombienet/tests/0002-mandatory-headers-synced-while-idle-westend-to-rococo.zndsl deleted file mode 100644 index 728d54d586a9b46625e3db70251b68c6501db922..0000000000000000000000000000000000000000 --- a/bridges/zombienet/tests/0002-mandatory-headers-synced-while-idle-westend-to-rococo.zndsl +++ /dev/null @@ -1,26 +0,0 @@ -Description: While relayer is idle, we only sync mandatory Westend (and a single Westend BH) headers to Rococo BH. -Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml -Creds: config - -# step 1: initialize Rococo bridge hub -bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 60 seconds - -# step 2: sleep some time before starting relayer. We want to sleep for at least 1 session, which is expected to -# be 60 seconds for test environment. -sleep 120 seconds - -# step 3: start relayer -bridge-hub-rococo-collator1: run ../scripts/start-relayer.sh within 60 seconds - -# it also takes some time for relayer to initialize bridge, so let's sleep for 5 minutes to be sure that parachain -# header has been synced - -# step 4: ensure that relayer is only syncing mandatory headers while idle. This includes both headers that were -# born while relay was offline and those in the next 100 seconds while script is active. -bridge-hub-rococo-collator1: js-script ../helpers/only-mandatory-headers-synced-when-idle.js with "300,westend-at-rococo" within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 0495eab9bd5bc2711e256a7cbb0c06ae13b1f2bc..eaf0d5d5d7f78e578644bf35f83d9543ad9af4bd 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/client/cli/src/lib.rs b/cumulus/client/cli/src/lib.rs index 1807b8a1718e8b5c800b3bf27b58e0f39cd2948a..a7b2eb19de88a5c585ec3f6dfe5ad46ef0399b88 100644 --- a/cumulus/client/cli/src/lib.rs +++ b/cumulus/client/cli/src/lib.rs @@ -30,7 +30,7 @@ use codec::Encode; use sc_chain_spec::ChainSpec; use sc_client_api::HeaderBackend; use sc_service::{ - config::{PrometheusConfig, TelemetryEndpoints}, + config::{PrometheusConfig, RpcBatchRequestConfig, TelemetryEndpoints}, BasePath, TransactionPoolOptions, }; use sp_core::hexdisplay::HexDisplay; @@ -443,6 +443,14 @@ impl sc_cli::CliConfiguration for NormalizedRunCmd { Ok(self.base.rpc_max_subscriptions_per_connection) } + fn rpc_buffer_capacity_per_connection(&self) -> sc_cli::Result { + Ok(self.base.rpc_message_buffer_capacity_per_connection) + } + + fn rpc_batch_config(&self) -> sc_cli::Result { + self.base.rpc_batch_config() + } + fn transaction_pool(&self, is_dev: bool) -> sc_cli::Result { self.base.transaction_pool(is_dev) } diff --git a/cumulus/client/consensus/aura/src/collator.rs b/cumulus/client/consensus/aura/src/collator.rs index db0799235bca27aaa4456da6c8649b0b76fef030..5b7669c88f473b8765b6b343d1797aa707ed5916 100644 --- a/cumulus/client/consensus/aura/src/collator.rs +++ b/cumulus/client/consensus/aura/src/collator.rs @@ -258,6 +258,7 @@ where pub struct SlotClaim { author_pub: Pub, pre_digest: DigestItem, + slot: Slot, timestamp: Timestamp, } @@ -272,7 +273,7 @@ impl SlotClaim { P::Public: Codec, P::Signature: Codec, { - SlotClaim { author_pub, timestamp, pre_digest: aura_internal::pre_digest::

(slot) } + SlotClaim { author_pub, timestamp, pre_digest: aura_internal::pre_digest::

(slot), slot } } /// Get the author's public key. @@ -285,6 +286,11 @@ impl SlotClaim { &self.pre_digest } + /// Get the slot assigned to this claim. + pub fn slot(&self) -> Slot { + self.slot + } + /// Get the timestamp corresponding to the relay-chain slot this claim was /// generated against. pub fn timestamp(&self) -> Timestamp { diff --git a/cumulus/client/consensus/aura/src/collators/basic.rs b/cumulus/client/consensus/aura/src/collators/basic.rs index 78f6b726aff0cb63cd08259c327bfbda71c05b8b..52b83254951f0e0ba0fd9ad5420d7faca2402066 100644 --- a/cumulus/client/consensus/aura/src/collators/basic.rs +++ b/cumulus/client/consensus/aura/src/collators/basic.rs @@ -33,12 +33,12 @@ use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_node_primitives::CollationResult; use polkadot_overseer::Handle as OverseerHandle; -use polkadot_primitives::{CollatorPair, Id as ParaId}; +use polkadot_primitives::{CollatorPair, Id as ParaId, ValidationCode}; use futures::{channel::mpsc::Receiver, prelude::*}; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf}; use sc_consensus::BlockImport; -use sp_api::ProvideRuntimeApi; +use sp_api::{CallApiAt, ProvideRuntimeApi}; use sp_application_crypto::AppPublic; use sp_blockchain::HeaderBackend; use sp_consensus::SyncOracle; @@ -47,6 +47,7 @@ use sp_core::crypto::Pair; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member}; +use sp_state_machine::Backend as _; use std::{convert::TryFrom, sync::Arc, time::Duration}; use crate::collator as collator_util; @@ -100,6 +101,7 @@ where + AuxStore + HeaderBackend + BlockBackend + + CallApiAt + Send + Sync + 'static, @@ -141,6 +143,8 @@ where collator_util::Collator::::new(params) }; + let mut last_processed_slot = 0; + while let Some(request) = collation_requests.next().await { macro_rules! reject_with_error { ($err:expr) => {{ @@ -170,6 +174,22 @@ where continue } + let Ok(Some(code)) = + params.para_client.state_at(parent_hash).map_err(drop).and_then(|s| { + s.storage(&sp_core::storage::well_known_keys::CODE).map_err(drop) + }) + else { + continue; + }; + + super::check_validation_code_or_log( + &ValidationCode::from(code).hash(), + params.para_id, + ¶ms.relay_client, + *request.relay_parent(), + ) + .await; + let relay_parent_header = match params.relay_client.header(RBlockId::hash(*request.relay_parent())).await { Err(e) => reject_with_error!(e), @@ -192,6 +212,18 @@ where Err(e) => reject_with_error!(e), }; + // With async backing this function will be called every relay chain block. + // + // Most parachains currently run with 12 seconds slots and thus, they would try to + // produce multiple blocks per slot which very likely would fail on chain. Thus, we have + // this "hack" to only produce on block per slot. + // + // With https://github.com/paritytech/polkadot-sdk/issues/3168 this implementation will be + // obsolete and also the underlying issue will be fixed. + if last_processed_slot >= *claim.slot() { + continue + } + let (parachain_inherent_data, other_inherent_data) = try_request!( collator .create_inherent_data( @@ -228,6 +260,8 @@ where request.complete(None); tracing::debug!(target: crate::LOG_TARGET, "No block proposal"); } + + last_processed_slot = *claim.slot(); } } } diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index e24b7f6f1c93b9bbe92cdf9ce5958194065862ae..161f10d55a193de35a2585e1a1f5725f30e19bf7 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -59,7 +59,7 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppPublic; use sp_blockchain::HeaderBackend; use sp_consensus::SyncOracle; -use sp_consensus_aura::{AuraApi, Slot, SlotDuration}; +use sp_consensus_aura::{AuraApi, Slot}; use sp_core::crypto::Pair; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; @@ -95,8 +95,6 @@ pub struct Params { pub para_id: ParaId, /// A handle to the relay-chain client's "Overseer" or task orchestrator. pub overseer_handle: OverseerHandle, - /// The length of slots in this chain. - pub slot_duration: SlotDuration, /// The length of slots in the relay chain. pub relay_chain_slot_duration: Duration, /// The underlying block proposer this should call into. @@ -214,26 +212,6 @@ where }, }; - let (slot_now, timestamp) = match consensus_common::relay_slot_and_timestamp( - &relay_parent_header, - params.relay_chain_slot_duration, - ) { - None => continue, - Some((r_s, t)) => { - let our_slot = Slot::from_timestamp(t, params.slot_duration); - tracing::debug!( - target: crate::LOG_TARGET, - relay_slot = ?r_s, - para_slot = ?our_slot, - timestamp = ?t, - slot_duration = ?params.slot_duration, - relay_chain_slot_duration = ?params.relay_chain_slot_duration, - "Adjusted relay-chain slot to parachain slot" - ); - (our_slot, t) - }, - }; - let parent_search_params = ParentSearchParams { relay_parent, para_id: params.para_id, @@ -272,14 +250,39 @@ where let para_client = &*params.para_client; let keystore = ¶ms.keystore; let can_build_upon = |block_hash| { - can_build_upon::<_, _, P>( + let slot_duration = match sc_consensus_aura::standalone::slot_duration_at( + &*params.para_client, + block_hash, + ) { + Ok(sd) => sd, + Err(err) => { + tracing::error!(target: crate::LOG_TARGET, ?err, "Failed to acquire parachain slot duration"); + return None + }, + }; + tracing::debug!(target: crate::LOG_TARGET, ?slot_duration, ?block_hash, "Parachain slot duration acquired"); + let (relay_slot, timestamp) = consensus_common::relay_slot_and_timestamp( + &relay_parent_header, + params.relay_chain_slot_duration, + )?; + let slot_now = Slot::from_timestamp(timestamp, slot_duration); + tracing::debug!( + target: crate::LOG_TARGET, + ?relay_slot, + para_slot = ?slot_now, + ?timestamp, + ?slot_duration, + relay_chain_slot_duration = ?params.relay_chain_slot_duration, + "Adjusted relay-chain slot to parachain slot" + ); + Some(can_build_upon::<_, _, P>( slot_now, timestamp, block_hash, included_block, para_client, &keystore, - ) + )) }; // Sort by depth, ascending, to choose the longest chain. @@ -287,10 +290,7 @@ where // If the longest chain has space, build upon that. Otherwise, don't // build at all. potential_parents.sort_by_key(|a| a.depth); - let initial_parent = match potential_parents.pop() { - None => continue, - Some(p) => p, - }; + let Some(initial_parent) = potential_parents.pop() else { continue }; // Build in a loop until not allowed. Note that the authorities can change // at any block, so we need to re-claim our slot every time. @@ -298,12 +298,19 @@ where let mut parent_header = initial_parent.header; let overseer_handle = &mut params.overseer_handle; + // We mainly call this to inform users at genesis if there is a mismatch with the + // on-chain data. + collator.collator_service().check_block_status(parent_hash, &parent_header); + // This needs to change to support elastic scaling, but for continuously // scheduled chains this ensures that the backlog will grow steadily. for n_built in 0..2 { - let slot_claim = match can_build_upon(parent_hash).await { + let slot_claim = match can_build_upon(parent_hash) { + Some(fut) => match fut.await { + None => break, + Some(c) => c, + }, None => break, - Some(c) => c, }; tracing::debug!( @@ -347,6 +354,14 @@ where Some(v) => v, }; + super::check_validation_code_or_log( + &validation_code_hash, + params.para_id, + ¶ms.relay_client, + relay_parent, + ) + .await; + match collator .collate( &parent_header, diff --git a/cumulus/client/consensus/aura/src/collators/mod.rs b/cumulus/client/consensus/aura/src/collators/mod.rs index 4c7b759daf736f69de48b586b082a7d01534d7e3..6e0067d0cedb602face8943737f99f3cb1a201a3 100644 --- a/cumulus/client/consensus/aura/src/collators/mod.rs +++ b/cumulus/client/consensus/aura/src/collators/mod.rs @@ -20,5 +20,60 @@ //! included parachain block, as well as the [`lookahead`] collator, which prospectively //! builds on parachain blocks which have not yet been included in the relay chain. +use cumulus_relay_chain_interface::RelayChainInterface; +use polkadot_primitives::{ + Hash as RHash, Id as ParaId, OccupiedCoreAssumption, ValidationCodeHash, +}; + pub mod basic; pub mod lookahead; + +/// Check the `local_validation_code_hash` against the validation code hash in the relay chain +/// state. +/// +/// If the code hashes do not match, it prints a warning. +async fn check_validation_code_or_log( + local_validation_code_hash: &ValidationCodeHash, + para_id: ParaId, + relay_client: &impl RelayChainInterface, + relay_parent: RHash, +) { + let state_validation_code_hash = match relay_client + .validation_code_hash(relay_parent, para_id, OccupiedCoreAssumption::Included) + .await + { + Ok(hash) => hash, + Err(error) => { + tracing::debug!( + target: super::LOG_TARGET, + %error, + ?relay_parent, + %para_id, + "Failed to fetch validation code hash", + ); + return + }, + }; + + match state_validation_code_hash { + Some(state) => + if state != *local_validation_code_hash { + tracing::warn!( + target: super::LOG_TARGET, + %para_id, + ?relay_parent, + ?local_validation_code_hash, + relay_validation_code_hash = ?state, + "Parachain code doesn't match validation code stored in the relay chain state", + ); + }, + None => { + tracing::warn!( + target: super::LOG_TARGET, + %para_id, + ?relay_parent, + "Could not find validation code for parachain in the relay chain state.", + ); + }, + } +} diff --git a/cumulus/client/consensus/aura/src/lib.rs b/cumulus/client/consensus/aura/src/lib.rs index 6ededa7a92c11cb8c313f7da01017eeef256fb06..ed6f5bdd4d6984350c5f59a3753618c3a038f323 100644 --- a/cumulus/client/consensus/aura/src/lib.rs +++ b/cumulus/client/consensus/aura/src/lib.rs @@ -42,12 +42,22 @@ use sp_core::crypto::Pair; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member, NumberFor}; -use std::{convert::TryFrom, marker::PhantomData, sync::Arc}; +use std::{ + convert::TryFrom, + marker::PhantomData, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, +}; mod import_queue; pub use import_queue::{build_verifier, import_queue, BuildVerifierParams, ImportQueueParams}; -pub use sc_consensus_aura::{slot_duration, AuraVerifier, BuildAuraWorkerParams, SlotProportion}; +pub use sc_consensus_aura::{ + slot_duration, standalone::slot_duration_at, AuraVerifier, BuildAuraWorkerParams, + SlotProportion, +}; pub use sc_consensus_slots::InherentDataProviderExt; pub mod collator; @@ -61,6 +71,7 @@ pub struct AuraConsensus { create_inherent_data_providers: Arc, aura_worker: Arc>, slot_duration: SlotDuration, + last_slot_processed: Arc, _phantom: PhantomData, } @@ -70,6 +81,7 @@ impl Clone for AuraConsensus { create_inherent_data_providers: self.create_inherent_data_providers.clone(), aura_worker: self.aura_worker.clone(), slot_duration: self.slot_duration, + last_slot_processed: self.last_slot_processed.clone(), _phantom: PhantomData, } } @@ -156,6 +168,7 @@ where Box::new(AuraConsensus { create_inherent_data_providers: Arc::new(create_inherent_data_providers), aura_worker: Arc::new(Mutex::new(worker)), + last_slot_processed: Default::default(), slot_duration, _phantom: PhantomData, }) @@ -221,6 +234,18 @@ where Some((validation_data.max_pov_size / 2) as usize), ); + // With async backing this function will be called every relay chain block. + // + // Most parachains currently run with 12 seconds slots and thus, they would try to produce + // multiple blocks per slot which very likely would fail on chain. Thus, we have this "hack" + // to only produce on block per slot. + // + // With https://github.com/paritytech/polkadot-sdk/issues/3168 this implementation will be + // obsolete and also the underlying issue will be fixed. + if self.last_slot_processed.fetch_max(*info.slot, Ordering::Relaxed) >= *info.slot { + return None + } + let res = self.aura_worker.lock().await.on_slot(info).await?; Some(ParachainCandidate { block: res.block, proof: res.storage_proof }) diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 7fee51310d01e2e6696c4cbb20ba10dade106dbc..5a014b10e35f39b0a5e00ca01da7cfd3ecc50a5f 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -14,7 +14,7 @@ async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } dyn-clone = "1.0.16" futures = "0.3.28" -log = "0.4.20" +log = { workspace = true, default-features = true } tracing = "0.1.37" # Substrate diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 597d1ab2acc2cff42d3230898c1129a7ba63b6f3..bfb95ae388ae3cd31f5035a9c6195631adbb8809 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -136,6 +136,15 @@ impl RelayChainInterface for Relaychain { Ok(Some(PersistedValidationData { parent_head, ..Default::default() })) } + async fn validation_code_hash( + &self, + _: PHash, + _: ParaId, + _: OccupiedCoreAssumption, + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } + async fn candidate_pending_availability( &self, _: PHash, diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index 8a559c603f33c138912cfc096e2d90cc879b597e..b37232bb4485d6f5ece63a3c940bd065c1d3f083 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] anyhow = "1.0" async-trait = "0.1.74" -thiserror = "1.0.48" +thiserror = { workspace = true } # Substrate sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index e03f470753bb6c32c4410a7c694dea8312c74c31..d986635f961c914c9ec6fa970b20170f9f8b9cbc 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -117,6 +117,15 @@ impl RelayChainInterface for DummyRelayChainInterface { })) } + async fn validation_code_hash( + &self, + _: PHash, + _: ParaId, + _: OccupiedCoreAssumption, + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } + async fn candidate_pending_availability( &self, _: PHash, diff --git a/cumulus/client/parachain-inherent/src/lib.rs b/cumulus/client/parachain-inherent/src/lib.rs index 57353638e197acf255b73080c6802e94647c2090..051eb6764c8ce97a8305a07bdddb8f06f61fe4bc 100644 --- a/cumulus/client/parachain-inherent/src/lib.rs +++ b/cumulus/client/parachain-inherent/src/lib.rs @@ -159,7 +159,7 @@ impl ParachainInherentDataProvider { target: LOG_TARGET, relay_parent = ?relay_parent, error = ?e, - "An error occured during requesting the downward messages.", + "An error occurred during requesting the downward messages.", ); }) .ok()?; @@ -171,7 +171,7 @@ impl ParachainInherentDataProvider { target: LOG_TARGET, relay_parent = ?relay_parent, error = ?e, - "An error occured during requesting the inbound HRMP messages.", + "An error occurred during requesting the inbound HRMP messages.", ); }) .ok()?; diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 866214fe2c526d77153afbea74b130aa1fda8636..6ea02b2e7c1f6d9b5313459890dd2147015359e5 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -21,7 +21,7 @@ use cumulus_primitives_core::{ relay_chain::{ runtime_api::ParachainHost, Block as PBlock, BlockId, CommittedCandidateReceipt, Hash as PHash, Header as PHeader, InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex, - ValidatorId, + ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -115,6 +115,19 @@ impl RelayChainInterface for RelayChainInProcessInterface { )?) } + async fn validation_code_hash( + &self, + hash: PHash, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> RelayChainResult> { + Ok(self.full_client.runtime_api().validation_code_hash( + hash, + para_id, + occupied_core_assumption, + )?) + } + async fn candidate_pending_availability( &self, hash: PHash, diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 004d30f7f94f70b7ed2e25fb9e1eebd9acc7c586..6e652b892104e929e5e0a5bb7ce8cf33d364e8e6 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -21,6 +21,6 @@ sc-client-api = { path = "../../../substrate/client/api" } futures = "0.3.28" async-trait = "0.1.74" -thiserror = "1.0.48" -jsonrpsee-core = "0.20.3" +thiserror = { workspace = true } +jsonrpsee-core = "0.22" parity-scale-codec = "3.6.4" diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index 3dda61635804d47440689872271751e0bba27d87..bb93e6a168c849fa9d41586ad8b9ec0013e6c01f 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -22,7 +22,7 @@ use sc_client_api::StorageProof; use futures::Stream; use async_trait::async_trait; -use jsonrpsee_core::Error as JsonRpcError; +use jsonrpsee_core::ClientError as JsonRpcError; use parity_scale_codec::Error as CodecError; use sp_api::ApiError; @@ -30,7 +30,7 @@ use cumulus_primitives_core::relay_chain::BlockId; pub use cumulus_primitives_core::{ relay_chain::{ CommittedCandidateReceipt, Hash as PHash, Header as PHeader, InboundHrmpMessage, - OccupiedCoreAssumption, SessionIndex, ValidatorId, + OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -194,6 +194,15 @@ pub trait RelayChainInterface: Send + Sync { relay_parent: PHash, relevant_keys: &Vec>, ) -> RelayChainResult; + + /// Returns the validation code hash for the given `para_id` using the given + /// `occupied_core_assumption`. + async fn validation_code_hash( + &self, + relay_parent: PHash, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> RelayChainResult>; } #[async_trait] @@ -301,4 +310,15 @@ where async fn header(&self, block_id: BlockId) -> RelayChainResult> { (**self).header(block_id).await } + + async fn validation_code_hash( + &self, + relay_parent: PHash, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> RelayChainResult> { + (**self) + .validation_code_hash(relay_parent, para_id, occupied_core_assumption) + .await + } } diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 0b1e001e007a493f521f10c2659653699da04d0c..98240c92adab38ea103f14699e1e49f7449b3d24 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -24,6 +24,7 @@ polkadot-node-collation-generation = { path = "../../../polkadot/node/collation- polkadot-node-core-runtime-api = { path = "../../../polkadot/node/core/runtime-api" } polkadot-node-core-chain-api = { path = "../../../polkadot/node/core/chain-api" } polkadot-node-core-prospective-parachains = { path = "../../../polkadot/node/core/prospective-parachains" } +polkadot-service = { path = "../../../polkadot/node/service" } # substrate deps sc-authority-discovery = { path = "../../../substrate/client/authority-discovery" } diff --git a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs index 5f5bf338ef9907756adb1eab3f0541e870677fe5..f01ef8b05ecba77cf6458fdfe80e966b3a67e6a3 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -15,159 +15,29 @@ // along with Polkadot. If not, see . use futures::{select, StreamExt}; -use parking_lot::Mutex; -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; -use polkadot_availability_recovery::AvailabilityRecoverySubsystem; -use polkadot_collator_protocol::{CollatorProtocolSubsystem, ProtocolSide}; -use polkadot_network_bridge::{ - Metrics as NetworkBridgeMetrics, NetworkBridgeRx as NetworkBridgeRxSubsystem, - NetworkBridgeTx as NetworkBridgeTxSubsystem, -}; -use polkadot_node_collation_generation::CollationGenerationSubsystem; -use polkadot_node_core_chain_api::ChainApiSubsystem; -use polkadot_node_core_prospective_parachains::ProspectiveParachainsSubsystem; -use polkadot_node_core_runtime_api::RuntimeApiSubsystem; -use polkadot_node_network_protocol::{ - peer_set::{PeerSet, PeerSetProtocolNames}, - request_response::{ - v1::{self, AvailableDataFetchingRequest}, - v2, IncomingRequestReceiver, ReqProtocolNames, - }, -}; -use polkadot_node_subsystem_util::metrics::{prometheus::Registry, Metrics}; use polkadot_overseer::{ - BlockInfo, DummySubsystem, Handle, Overseer, OverseerConnector, OverseerHandle, SpawnGlue, - UnpinHandle, + BlockInfo, Handle, Overseer, OverseerConnector, OverseerHandle, SpawnGlue, UnpinHandle, }; -use polkadot_primitives::CollatorPair; +use polkadot_service::overseer::{collator_overseer_builder, OverseerGenArgs}; -use sc_authority_discovery::Service as AuthorityDiscoveryService; -use sc_network::{NetworkStateInfo, NotificationService}; use sc_service::TaskManager; use sc_utils::mpsc::tracing_unbounded; -use cumulus_primitives_core::relay_chain::{Block, Hash as PHash}; use cumulus_relay_chain_interface::RelayChainError; use crate::BlockChainRpcClient; -/// Arguments passed for overseer construction. -pub(crate) struct CollatorOverseerGenArgs<'a> { - /// Runtime client generic, providing the `ProvieRuntimeApi` trait besides others. - pub runtime_client: Arc, - /// Underlying network service implementation. - pub network_service: Arc>, - /// Syncing oracle. - pub sync_oracle: Box, - /// Underlying authority discovery service. - pub authority_discovery_service: AuthorityDiscoveryService, - /// Receiver for collation request protocol v1. - pub collation_req_receiver_v1: IncomingRequestReceiver, - /// Receiver for collation request protocol v2. - pub collation_req_receiver_v2: IncomingRequestReceiver, - /// Receiver for availability request protocol - pub available_data_req_receiver: IncomingRequestReceiver, - /// Prometheus registry, commonly used for production systems, less so for test. - pub registry: Option<&'a Registry>, - /// Task spawner to be used throughout the overseer and the APIs it provides. - pub spawner: sc_service::SpawnTaskHandle, - /// Determines the behavior of the collator. - pub collator_pair: CollatorPair, - /// Request response protocols - pub req_protocol_names: ReqProtocolNames, - /// Peerset protocols name mapping - pub peer_set_protocol_names: PeerSetProtocolNames, - /// Notification services for validation/collation protocols. - pub notification_services: HashMap>, -} - fn build_overseer( connector: OverseerConnector, - CollatorOverseerGenArgs { - runtime_client, - network_service, - sync_oracle, - authority_discovery_service, - collation_req_receiver_v1, - collation_req_receiver_v2, - available_data_req_receiver, - registry, - spawner, - collator_pair, - req_protocol_names, - peer_set_protocol_names, - notification_services, - }: CollatorOverseerGenArgs<'_>, + args: OverseerGenArgs, ) -> Result< (Overseer, Arc>, OverseerHandle), RelayChainError, > { - let spawner = SpawnGlue(spawner); - let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; - let notification_sinks = Arc::new(Mutex::new(HashMap::new())); - - let builder = Overseer::builder() - .availability_distribution(DummySubsystem) - .availability_recovery(AvailabilityRecoverySubsystem::for_collator( - available_data_req_receiver, - Metrics::register(registry)?, - )) - .availability_store(DummySubsystem) - .bitfield_distribution(DummySubsystem) - .bitfield_signing(DummySubsystem) - .candidate_backing(DummySubsystem) - .candidate_validation(DummySubsystem) - .pvf_checker(DummySubsystem) - .chain_api(ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?)) - .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) - .collator_protocol({ - let side = ProtocolSide::Collator { - peer_id: network_service.local_peer_id(), - collator_pair, - request_receiver_v1: collation_req_receiver_v1, - request_receiver_v2: collation_req_receiver_v2, - metrics: Metrics::register(registry)?, - }; - CollatorProtocolSubsystem::new(side) - }) - .network_bridge_rx(NetworkBridgeRxSubsystem::new( - network_service.clone(), - authority_discovery_service.clone(), - sync_oracle, - network_bridge_metrics.clone(), - peer_set_protocol_names.clone(), - notification_services, - notification_sinks.clone(), - )) - .network_bridge_tx(NetworkBridgeTxSubsystem::new( - network_service, - authority_discovery_service, - network_bridge_metrics, - req_protocol_names, - peer_set_protocol_names, - notification_sinks, - )) - .provisioner(DummySubsystem) - .runtime_api(RuntimeApiSubsystem::new( - runtime_client.clone(), - Metrics::register(registry)?, - spawner.clone(), - )) - .statement_distribution(DummySubsystem) - .prospective_parachains(ProspectiveParachainsSubsystem::new(Metrics::register(registry)?)) - .approval_distribution(DummySubsystem) - .approval_voting(DummySubsystem) - .gossip_support(DummySubsystem) - .dispute_coordinator(DummySubsystem) - .dispute_distribution(DummySubsystem) - .chain_selection(DummySubsystem) - .activation_external_listeners(Default::default()) - .span_per_active_leaf(Default::default()) - .active_leaves(Default::default()) - .supports_parachains(runtime_client) - .metrics(Metrics::register(registry)?) - .spawner(spawner); + let builder = + collator_overseer_builder(args).map_err(|e| RelayChainError::Application(e.into()))?; builder .build_with_connector(connector) @@ -175,7 +45,7 @@ fn build_overseer( } pub(crate) fn spawn_overseer( - overseer_args: CollatorOverseerGenArgs, + overseer_args: OverseerGenArgs, task_manager: &TaskManager, relay_chain_rpc_client: Arc, ) -> Result { diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index d121d2d3356765d9327fdaa0a8c0563c3917266f..4bccca59fe3ea2eec816513778885f43c9504d51 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use collator_overseer::{CollatorOverseerGenArgs, NewMinimalNode}; +use collator_overseer::NewMinimalNode; use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; use cumulus_relay_chain_rpc_interface::{RelayChainRpcClient, RelayChainRpcInterface, Url}; @@ -29,6 +29,7 @@ use polkadot_node_network_protocol::{ use polkadot_node_subsystem_util::metrics::prometheus::Registry; use polkadot_primitives::CollatorPair; +use polkadot_service::{overseer::OverseerGenArgs, IsParachainNode}; use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_network::{config::FullNetworkConfiguration, Event, NetworkEventStream, NetworkService}; @@ -172,10 +173,10 @@ async fn new_minimal_relay_chain( } let genesis_hash = relay_chain_rpc_client.block_get_hash(Some(0)).await?.unwrap_or_default(); - let peer_set_protocol_names = + let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; - let notification_services = peer_sets_info(is_authority, &peer_set_protocol_names) + let notification_services = peer_sets_info(is_authority, &peerset_protocol_names) .into_iter() .map(|(config, (peerset, service))| { net_config.add_notification_protocol(config); @@ -184,14 +185,14 @@ async fn new_minimal_relay_chain( .collect::>>(); let request_protocol_names = ReqProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); - let (collation_req_receiver_v1, collation_req_receiver_v2, available_data_req_receiver) = + let (collation_req_v1_receiver, collation_req_v2_receiver, available_data_req_receiver) = build_request_response_protocol_receivers(&request_protocol_names, &mut net_config); let best_header = relay_chain_rpc_client .chain_get_header(None) .await? .ok_or_else(|| RelayChainError::RpcCallError("Unable to fetch best header".to_string()))?; - let (network, network_starter, sync_oracle) = build_collator_network( + let (network, network_starter, sync_service) = build_collator_network( &config, net_config, task_manager.spawn_handle(), @@ -208,19 +209,20 @@ async fn new_minimal_relay_chain( prometheus_registry.cloned(), ); - let overseer_args = CollatorOverseerGenArgs { + let overseer_args = OverseerGenArgs { runtime_client: relay_chain_rpc_client.clone(), network_service: network, - sync_oracle, + sync_service, authority_discovery_service, - collation_req_receiver_v1, - collation_req_receiver_v2, + collation_req_v1_receiver, + collation_req_v2_receiver, available_data_req_receiver, registry: prometheus_registry, spawner: task_manager.spawn_handle(), - collator_pair, + is_parachain_node: IsParachainNode::Collator(collator_pair), + overseer_message_channel_capacity_override: None, req_protocol_names: request_protocol_names, - peer_set_protocol_names, + peerset_protocol_names, notification_services, }; @@ -240,10 +242,10 @@ fn build_request_response_protocol_receivers( IncomingRequestReceiver, IncomingRequestReceiver, ) { - let (collation_req_receiver_v1, cfg) = + let (collation_req_v1_receiver, cfg) = IncomingRequest::get_config_receiver(request_protocol_names); config.add_request_response_protocol(cfg); - let (collation_req_receiver_v2, cfg) = + let (collation_req_v2_receiver, cfg) = IncomingRequest::get_config_receiver(request_protocol_names); config.add_request_response_protocol(cfg); let (available_data_req_receiver, cfg) = @@ -251,5 +253,5 @@ fn build_request_response_protocol_receivers( config.add_request_response_protocol(cfg); let cfg = Protocol::ChunkFetchingV1.get_outbound_only_config(request_protocol_names); config.add_request_response_protocol(cfg); - (collation_req_receiver_v1, collation_req_receiver_v2, available_data_req_receiver) + (collation_req_v1_receiver, collation_req_v2_receiver, available_data_req_receiver) } diff --git a/cumulus/client/relay-chain-minimal-node/src/network.rs b/cumulus/client/relay-chain-minimal-node/src/network.rs index 95785063c1aeb6649d7154fa39e4e111e226def3..7286fab7907cb6d475b81a4dfd97c5d001180873 100644 --- a/cumulus/client/relay-chain-minimal-node/src/network.rs +++ b/cumulus/client/relay-chain-minimal-node/src/network.rs @@ -40,7 +40,11 @@ pub(crate) fn build_collator_network( genesis_hash: Hash, best_header: Header, ) -> Result< - (Arc>, NetworkStarter, Box), + ( + Arc>, + NetworkStarter, + Arc, + ), Error, > { let protocol_id = config.protocol_id(); @@ -112,7 +116,7 @@ pub(crate) fn build_collator_network( let network_starter = NetworkStarter::new(network_start_tx); - Ok((network_service, network_starter, Box::new(SyncOracle {}))) + Ok((network_service, network_starter, Arc::new(SyncOracle {}))) } fn adjust_network_config_light_in_peers(config: &mut NetworkConfiguration) { diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index fef6f82537d7e5760dc71bc0b492276926f3bc2e..801712b1ad150a8a63e85c40ec0854a62b5969bc 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -33,16 +33,16 @@ tokio-util = { version = "0.7.8", features = ["compat"] } futures = "0.3.28" futures-timer = "3.0.2" parity-scale-codec = "3.6.4" -jsonrpsee = { version = "0.20.3", features = ["ws-client"] } +jsonrpsee = { version = "0.22", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.74" url = "2.4.0" -serde_json = "1.0.111" -serde = "1.0.195" +serde_json = { workspace = true, default-features = true } +serde = { workspace = true, default-features = true } schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"] } smoldot-light = { version = "0.9.0", default_features = false, features = ["std"] } either = "1.8.1" -thiserror = "1.0.48" +thiserror = { workspace = true } rand = "0.8.5" pin-project = "1.1.3" diff --git a/cumulus/client/relay-chain-rpc-interface/src/lib.rs b/cumulus/client/relay-chain-rpc-interface/src/lib.rs index 96f8fc8b5563335eb7796bc8fd105fced15bc5e1..3a4c186e301eab295aa3befbd3c5549636fdb2c0 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/lib.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/lib.rs @@ -19,7 +19,7 @@ use core::time::Duration; use cumulus_primitives_core::{ relay_chain::{ CommittedCandidateReceipt, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, - OccupiedCoreAssumption, SessionIndex, ValidatorId, + OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -110,6 +110,17 @@ impl RelayChainInterface for RelayChainRpcInterface { .await } + async fn validation_code_hash( + &self, + hash: RelayHash, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> RelayChainResult> { + self.rpc_client + .validation_code_hash(hash, para_id, occupied_core_assumption) + .await + } + async fn candidate_pending_availability( &self, hash: RelayHash, diff --git a/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs b/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs index 6fd057e170b715a1586dbd2dbf3f608268c539bd..9a49b60281b3c51fa1426903a0e73157a6f04e0e 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs @@ -19,12 +19,9 @@ //! we treat the light-client as a normal JsonRPC target. use futures::{channel::mpsc::Sender, prelude::*, stream::FuturesUnordered}; -use jsonrpsee::core::{ - client::{ - Client as JsonRpseeClient, ClientBuilder, ClientT, ReceivedMessage, TransportReceiverT, - TransportSenderT, - }, - Error, +use jsonrpsee::core::client::{ + Client as JsonRpseeClient, ClientBuilder, ClientT, Error, ReceivedMessage, TransportReceiverT, + TransportSenderT, }; use smoldot_light::{ChainId, Client as SmoldotClient, JsonRpcResponses}; use std::{num::NonZeroU32, sync::Arc}; diff --git a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs index 322bcc93dae6d8158a0e6cfb99ded9a29bee79c5..b716feef1c998d66eba3c5ea28ee1dd98c4959e3 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs @@ -27,7 +27,7 @@ use jsonrpsee::{ core::{ client::{Client as JsonRpcClient, ClientT, Subscription}, params::ArrayParams, - Error as JsonRpseeError, JsonValue, + ClientError as JsonRpseeError, JsonValue, }, ws_client::WsClientBuilder, }; 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 c64fff77a29fd016d7e1723ab461dc8082770682..6578210a259c956b1c817f579f66e84258a8ab3e 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -19,7 +19,7 @@ use futures::channel::{ oneshot::Sender as OneshotSender, }; use jsonrpsee::{ - core::{params::ArrayParams, Error as JsonRpseeError}, + core::{params::ArrayParams, ClientError as JsonRpseeError}, rpc_params, }; use serde::de::DeserializeOwned; @@ -647,6 +647,20 @@ impl RelayChainRpcClient { .await } + pub async fn validation_code_hash( + &self, + at: RelayHash, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> Result, RelayChainError> { + self.call_remote_runtime_function( + "ParachainHost_validation_code_hash", + at, + Some((para_id, occupied_core_assumption)), + ) + .await + } + fn send_register_message_to_worker( &self, message: RpcDispatcherMessage, diff --git a/cumulus/pallets/aura-ext/src/lib.rs b/cumulus/pallets/aura-ext/src/lib.rs index 34a41557152d8df38e0abc2d612151b2f74dc779..31b571816a0c15837c6175ab233204565cc7eb36 100644 --- a/cumulus/pallets/aura-ext/src/lib.rs +++ b/cumulus/pallets/aura-ext/src/lib.rs @@ -117,12 +117,6 @@ pub mod pallet { impl BuildGenesisConfig for GenesisConfig { fn build(&self) { let authorities = Aura::::authorities(); - - assert!( - !authorities.is_empty(), - "AuRa authorities empty, maybe wrong order in `construct_runtime!`?", - ); - Authorities::::put(authorities); } } diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 4216776fe8ac017958462aec1da5af58edc67f39..20f048b97d558962ea270ef51399f6d2905ab1a0 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.20", default-features = false } +log = { workspace = true } codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.0.0" } rand = { version = "0.8.5", features = ["std_rng"], default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/collator-selection/src/benchmarking.rs b/cumulus/pallets/collator-selection/src/benchmarking.rs index 2c40f4dd0eac4a8a2ad3aed7f162a4379ccdbc93..e2af74a6e60ef00ca9d1111518d86df3fdfb0656 100644 --- a/cumulus/pallets/collator-selection/src/benchmarking.rs +++ b/cumulus/pallets/collator-selection/src/benchmarking.rs @@ -22,9 +22,7 @@ use super::*; #[allow(unused)] use crate::Pallet as CollatorSelection; use codec::Decode; -use frame_benchmarking::{ - account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, -}; +use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::traits::{Currency, EnsureOrigin, Get, ReservableCurrency}; use frame_system::{pallet_prelude::BlockNumberFor, EventRecord, RawOrigin}; use pallet_authorship::EventHandler; diff --git a/cumulus/pallets/collator-selection/src/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index 7449f4d68c7eacc8b07fa45f2f991c13f3d5713b..62c00737f91a4aac25f2e1972a0c5aade5e0eed2 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -118,7 +118,7 @@ pub mod pallet { use sp_staking::SessionIndex; use sp_std::vec::Vec; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); type BalanceOf = @@ -495,7 +495,11 @@ pub mod pallet { }) .unwrap_or_default(); Self::deposit_event(Event::NewCandidacyBond { bond_amount: bond }); - Ok(Some(T::WeightInfo::set_candidacy_bond(initial_len as u32, kicked as u32)).into()) + Ok(Some(T::WeightInfo::set_candidacy_bond( + bond_increased.then(|| initial_len as u32).unwrap_or_default(), + kicked as u32, + )) + .into()) } /// Register this account as a collator candidate. The account must (a) already have diff --git a/cumulus/pallets/collator-selection/src/migration.rs b/cumulus/pallets/collator-selection/src/migration.rs index 58b4cc5b06a1ab7da17b31ad3c457fd992c59136..f384981dbae8e034a4465ac0f226fb4422be8089 100644 --- a/cumulus/pallets/collator-selection/src/migration.rs +++ b/cumulus/pallets/collator-selection/src/migration.rs @@ -31,8 +31,8 @@ pub mod v1 { pub struct MigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { - let onchain_version = Pallet::::on_chain_storage_version(); - if onchain_version == 0 { + let on_chain_version = Pallet::::on_chain_storage_version(); + if on_chain_version == 0 { let invulnerables_len = Invulnerables::::get().to_vec().len(); >::mutate(|invulnerables| { invulnerables.sort(); @@ -45,7 +45,7 @@ pub mod v1 { invulnerables_len, ); // Similar complexity to `set_invulnerables` (put storage value) - // Plus 1 read for length, 1 read for `onchain_version`, 1 write to put version + // Plus 1 read for length, 1 read for `on_chain_version`, 1 write to put version T::WeightInfo::set_invulnerables(invulnerables_len as u32) .saturating_add(T::DbWeight::get().reads_writes(2, 1)) } else { @@ -83,8 +83,8 @@ pub mod v1 { "after migration, there should be the same number of invulnerables" ); - let onchain_version = Pallet::::on_chain_storage_version(); - frame_support::ensure!(onchain_version >= 1, "must_upgrade"); + let on_chain_version = Pallet::::on_chain_storage_version(); + frame_support::ensure!(on_chain_version >= 1, "must_upgrade"); Ok(()) } diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 301a77003cb6a08c2cac2c1feec48fe333959bb1..83ed994d04167607e3df54587c49e6b88576d4ec 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 848efd3eab67c1b02473e6d0a62e75efcac16f35..7e0442f0b5856fa5153e29ff497cfee876c067ec 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -14,7 +14,7 @@ bytes = { version = "1.4.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } environmental = { version = "1.1.4", default-features = false } impl-trait-for-tuples = "0.2.1" -log = { version = "0.4.20", default-features = false } +log = { workspace = true } trie-db = { version = "0.28.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } @@ -36,6 +36,7 @@ sp-version = { path = "../../../substrate/primitives/version", default-features # Polkadot polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = ["wasm-api"] } polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } +polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false, optional = true } xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } # Cumulus @@ -79,6 +80,7 @@ std = [ "log/std", "pallet-message-queue/std", "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", "polkadot-runtime-parachains/std", "scale-info/std", "sp-core/std", @@ -102,6 +104,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] @@ -110,6 +113,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-message-queue/try-runtime", + "polkadot-runtime-common?/try-runtime", "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index 5f41e6423ac33cef4db6689554e92d04ececdf92..0a90c30e0331261026125f429efe70eff07ac069 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -13,9 +13,9 @@ workspace = true proc-macro = true [dependencies] -syn = "2.0.48" +syn = { workspace = true } proc-macro2 = "1.0.64" -quote = "1.0.33" +quote = { workspace = true } proc-macro-crate = "3.0.0" [features] diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 5a0fa57fb171c60f13b87d70305a6d58dad475a1..81965a2a313875fd8783cf9e22ca3dd652f688c3 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -205,6 +205,7 @@ pub mod pallet { type OnSystemEvent: OnSystemEvent; /// Returns the parachain ID we are running with. + #[pallet::constant] type SelfParaId: Get; /// The place where outbound XCMP messages come from. This is queried in `finalize_block`. @@ -840,6 +841,7 @@ pub mod pallet { /// /// This data is also absent from the genesis. #[pallet::storage] + #[pallet::disable_try_decode_storage] #[pallet::getter(fn host_configuration)] pub(super) type HostConfiguration = StorageValue<_, AbridgedHostConfiguration>; @@ -1610,6 +1612,15 @@ impl UpwardMessageSender for Pallet { } } +#[cfg(feature = "runtime-benchmarks")] +impl polkadot_runtime_common::xcm_sender::EnsureForParachain for Pallet { + fn ensure(para_id: ParaId) { + if let ChannelStatus::Closed = Self::get_channel_status(para_id) { + Self::open_outbound_hrmp_channel_for_benchmarks_or_tests(para_id) + } + } +} + /// Something that can check the inherents of a block. #[cfg_attr( feature = "parameterized-consensus-hook", diff --git a/cumulus/pallets/parachain-system/src/migration.rs b/cumulus/pallets/parachain-system/src/migration.rs index a92f85b9cd420e9e1027d1f82c643d90fea8b97c..30106aceab5a442c34360563fdfb096fdc6ac9b1 100644 --- a/cumulus/pallets/parachain-system/src/migration.rs +++ b/cumulus/pallets/parachain-system/src/migration.rs @@ -21,7 +21,7 @@ use frame_support::{ weights::Weight, }; -/// The current storage version. +/// The in-code storage version. pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); /// Migrates the pallet storage to the most recent version. diff --git a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs index ce3b724420f1c9e50b65a81074e023c6b735227b..ecab7a9a09311ae0f952a7842e9f1826b00adc69 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs @@ -16,7 +16,7 @@ //! The actual implementation of the validate block functionality. -use super::{trie_cache, MemoryOptimizedValidationParams}; +use super::{trie_cache, trie_recorder, MemoryOptimizedValidationParams}; use cumulus_primitives_core::{ relay_chain::Hash as RHash, ParachainBlockData, PersistedValidationData, }; @@ -34,12 +34,14 @@ 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_std::prelude::*; -use sp_trie::MemoryDB; +use sp_trie::{MemoryDB, ProofSizeProvider}; +use trie_recorder::SizeOnlyRecorderProvider; type TrieBackend = sp_state_machine::TrieBackend< MemoryDB>, HashingFor, trie_cache::CacheProvider>, + SizeOnlyRecorderProvider>, >; type Ext<'a, B> = sp_state_machine::Ext<'a, HashingFor, TrieBackend>; @@ -48,6 +50,9 @@ fn with_externalities R, R>(f: F) -> R { sp_externalities::with_externalities(f).expect("Environmental externalities not set.") } +// Recorder instance to be used during this validate_block call. +environmental::environmental!(recorder: trait ProofSizeProvider); + /// Validate the given parachain block. /// /// This function is doing roughly the following: @@ -120,6 +125,7 @@ where sp_std::mem::drop(storage_proof); + let mut recorder = SizeOnlyRecorderProvider::new(); let cache_provider = trie_cache::CacheProvider::new(); // We use the storage root of the `parent_head` to ensure that it is the correct root. // This is already being done above while creating the in-memory db, but let's be paranoid!! @@ -128,6 +134,7 @@ where *parent_header.state_root(), cache_provider, ) + .with_recorder(recorder.clone()) .build(); let _guard = ( @@ -167,9 +174,11 @@ where .replace_implementation(host_default_child_storage_next_key), sp_io::offchain_index::host_set.replace_implementation(host_offchain_index_set), sp_io::offchain_index::host_clear.replace_implementation(host_offchain_index_clear), + cumulus_primitives_proof_size_hostfunction::storage_proof_size::host_storage_proof_size + .replace_implementation(host_storage_proof_size), ); - run_with_externalities::(&backend, || { + run_with_externalities_and_recorder::(&backend, &mut recorder, || { let relay_chain_proof = crate::RelayChainStateProof::new( PSC::SelfParaId::get(), inherent_data.validation_data.relay_parent_storage_root, @@ -190,7 +199,7 @@ where } }); - run_with_externalities::(&backend, || { + run_with_externalities_and_recorder::(&backend, &mut recorder, || { let head_data = HeadData(block.header().encode()); E::execute_block(block); @@ -265,15 +274,17 @@ fn validate_validation_data( ); } -/// Run the given closure with the externalities set. -fn run_with_externalities R>( +/// Run the given closure with the externalities and recorder set. +fn run_with_externalities_and_recorder R>( backend: &TrieBackend, + recorder: &mut SizeOnlyRecorderProvider>, execute: F, ) -> R { let mut overlay = sp_state_machine::OverlayedChanges::default(); let mut ext = Ext::::new(&mut overlay, backend); + recorder.reset(); - set_and_run_with_externalities(&mut ext, || execute()) + recorder::using(recorder, || set_and_run_with_externalities(&mut ext, || execute())) } fn host_storage_read(key: &[u8], value_out: &mut [u8], value_offset: u32) -> Option { @@ -305,6 +316,10 @@ fn host_storage_clear(key: &[u8]) { with_externalities(|ext| ext.place_storage(key.to_vec(), None)) } +fn host_storage_proof_size() -> u64 { + recorder::with(|rec| rec.estimate_encoded_size()).expect("Recorder is always set; qed") as _ +} + fn host_storage_root(version: StateVersion) -> Vec { with_externalities(|ext| ext.storage_root(version)) } diff --git a/cumulus/pallets/parachain-system/src/validate_block/tests.rs b/cumulus/pallets/parachain-system/src/validate_block/tests.rs index f17ac6007a09bf02011473f95a537855eb43f3b0..a9fb65e11089fab87c543fbb6d7b54f6231a1dd7 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/tests.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/tests.rs @@ -59,7 +59,7 @@ fn call_validate_block( } fn create_test_client() -> (Client, Header) { - let client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().enable_import_proof_recording().build(); let genesis_header = client .header(client.chain_info().genesis_hash) 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 e73aef70aa491fc68aad4f9479222d9a076e7edc..48310670c074d1be2ec86f582c0c84622abc086c 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs @@ -97,6 +97,7 @@ pub(crate) struct SizeOnlyRecorderProvider { } impl SizeOnlyRecorderProvider { + /// Create a new instance of [`SizeOnlyRecorderProvider`] pub fn new() -> Self { Self { seen_nodes: Default::default(), @@ -104,6 +105,13 @@ impl SizeOnlyRecorderProvider { recorded_keys: Default::default(), } } + + /// Reset the internal state. + pub fn reset(&self) { + self.seen_nodes.borrow_mut().clear(); + *self.encoded_size.borrow_mut() = 0; + self.recorded_keys.borrow_mut().clear(); + } } impl sp_trie::TrieRecorderProvider for SizeOnlyRecorderProvider { @@ -281,6 +289,9 @@ mod tests { reference_recorder.estimate_encoded_size(), recorder_for_test.estimate_encoded_size() ); + + recorder_for_test.reset(); + assert_eq!(recorder_for_test.estimate_encoded_size(), 0) } } } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 8dde44ca0ff43bb3764ed53be7db0110671b0107..9078d5eda997526b8f3ed7d9f118cc9c927dedc1 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 5b900769622afa3cba2c47f493ebff1a279b182b..e92169be16b0b8466582f3dd143d9e3e1807a42d 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -600,7 +600,7 @@ impl Pallet { let QueueConfigData { drop_threshold, .. } = >::get(); let fp = T::XcmpQueue::footprint(sender); // Assume that it will not fit into the current page: - let new_pages = fp.pages.saturating_add(1); + let new_pages = fp.ready_pages.saturating_add(1); if new_pages > drop_threshold { // This should not happen since the channel should have been suspended in // [`on_queue_changed`]. @@ -663,12 +663,12 @@ impl OnQueueChanged for Pallet { let mut suspended_channels = >::get(); let suspended = suspended_channels.contains(¶); - if suspended && fp.pages <= resume_threshold { + if suspended && fp.ready_pages <= resume_threshold { Self::send_signal(para, ChannelSignal::Resume); suspended_channels.remove(¶); >::put(suspended_channels); - } else if !suspended && fp.pages >= suspend_threshold { + } else if !suspended && fp.ready_pages >= suspend_threshold { log::warn!("XCMP queue for sibling {:?} is full; suspending channel.", para); Self::send_signal(para, ChannelSignal::Suspend); diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index 6c86c3011d23807adfbde801ec6865b6731822df..c7fa61a3e3f0513e53d67fcee4efd6c3cecf29f6 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -24,7 +24,7 @@ use frame_support::{ weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, }; -/// The current storage version. +/// The in-code storage version. pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); pub const LOG: &str = "runtime::xcmp-queue-migration"; diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 2bf1e3c6425a629909e950c72826f5c9385bf4f1..1fb88cafd93c425833d38c0904f59490cc479294 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -30,10 +30,9 @@ use sp_runtime::{ BuildStorage, }; use xcm::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ - FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, + FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, + ParentIsPreset, }; use xcm_executor::traits::ConvertOrigin; @@ -133,8 +132,7 @@ parameter_types! { } /// Means for transacting assets on this chain. -#[allow(deprecated)] -pub type LocalAssetTransactor = CurrencyAdapter< +pub type LocalAssetTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -249,6 +247,7 @@ impl> EnqueueMessage for EnqueueToLocalStorage } } footprint.pages = footprint.storage.size as u32 / 16; // Number does not matter + footprint.ready_pages = footprint.pages; footprint } } diff --git a/cumulus/parachain-template/pallets/template/README.md b/cumulus/parachain-template/pallets/template/README.md deleted file mode 100644 index 5a6461233465c327d233fc5d97bdb3a6a85f8fd9..0000000000000000000000000000000000000000 --- a/cumulus/parachain-template/pallets/template/README.md +++ /dev/null @@ -1 +0,0 @@ -License: Unlicense diff --git a/cumulus/parachain-template/pallets/template/src/benchmarking.rs b/cumulus/parachain-template/pallets/template/src/benchmarking.rs deleted file mode 100644 index 8bba2a09867dea1d55e487661c01fd72acdf4dc9..0000000000000000000000000000000000000000 --- a/cumulus/parachain-template/pallets/template/src/benchmarking.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Benchmarking setup for pallet-parachain-template - -use super::*; - -#[allow(unused)] -use crate::Pallet as Template; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; -use frame_system::RawOrigin; - -benchmarks! { - do_something { - let s in 0 .. 100; - let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), s) - verify { - assert_eq!(Something::::get(), Some(s)); - } -} - -impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test,); diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index fba74b17f9607f58bdb17d7a0b05c8b764a9c4e5..654275eade81e5379004e649e11eb7e4acb2ec1f 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -25,7 +25,9 @@ "/dns/statemine-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWCKUrE5uaXQ288ko3Ex3zCyozyJLG47KEYTopinnXNtYL", "/dns/mine14.rotko.net/tcp/33524/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", "/dns/mine14.rotko.net/tcp/34524/ws/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", - "/dns/mine14.rotko.net/tcp/35524/wss/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu" + "/dns/mine14.rotko.net/tcp/35524/wss/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", + "/dns/asset-hub-kusama.bootnodes.polkadotters.com/tcp/30511/p2p/12D3KooWDpk7wVH7RgjErEvbvAZ2kY5VeaAwRJP5ojmn1e8b8UbU", + "/dns/asset-hub-kusama.bootnodes.polkadotters.com/tcp/30513/wss/p2p/12D3KooWDpk7wVH7RgjErEvbvAZ2kY5VeaAwRJP5ojmn1e8b8UbU" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index 685a00ddc7145ed650f7cb5496fe81cfb23f0ffb..454060d2a87afb84407323263eea97d2f12d5a68 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -25,7 +25,9 @@ "/dns/statemint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWLKxHom7f3XawRJqrF8RwiKK5Sj3qZqz5c7hF6eJeXhTx", "/dns/mint14.rotko.net/tcp/33514/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", "/dns/mint14.rotko.net/tcp/34514/ws/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", - "/dns/mint14.rotko.net/tcp/35514/wss/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW" + "/dns/mint14.rotko.net/tcp/35514/wss/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", + "/dns/asset-hub-polkadot.bootnodes.polkadotters.com/tcp/30508/p2p/12D3KooWKbfY9a9oywxMJKiALmt7yhrdQkjXMtvxhhDDN23vG93R", + "/dns/asset-hub-polkadot.bootnodes.polkadotters.com/tcp/30510/wss/p2p/12D3KooWKbfY9a9oywxMJKiALmt7yhrdQkjXMtvxhhDDN23vG93R" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-westend.json b/cumulus/parachains/chain-specs/asset-hub-westend.json index 6f42b5f7d8bb4a76c7390b538a68b1bb0acc1613..670935c9d2474242307d691d8707030c70f49982 100644 --- a/cumulus/parachains/chain-specs/asset-hub-westend.json +++ b/cumulus/parachains/chain-specs/asset-hub-westend.json @@ -23,7 +23,9 @@ "/dns/westmint-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWDoq4PVdWm5nzRSvEz3DSSKjVgRhWVUaKyi5JMKwJKYbk", "/dns/wmint14.rotko.net/tcp/33534/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN", "/dns/wmint14.rotko.net/tcp/34534/ws/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN", - "/dns/wmint14.rotko.net/tcp/35534/wss/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN" + "/dns/wmint14.rotko.net/tcp/35534/wss/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN", + "/dns/asset-hub-westend.bootnodes.polkadotters.com/tcp/30514/p2p/12D3KooWNFYysCqmojxqjjaTfD2VkWBNngfyUKWjcR4WFixfHNTk", + "/dns/asset-hub-westend.bootnodes.polkadotters.com/tcp/30516/wss/p2p/12D3KooWNFYysCqmojxqjjaTfD2VkWBNngfyUKWjcR4WFixfHNTk" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index 0ef81806cc5c08621f3c0a308425c72f836c3ef4..90b70b05016d52aeecaea4870f438bf980f7263b 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -25,7 +25,9 @@ "/dns/bridgehub-kusama-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWQMWofXj8v3RroDNnrhv1iURqm8vnaG98AdGnCn2YoDcW", "/dns/kbr13.rotko.net/tcp/33553/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", "/dns/kbr13.rotko.net/tcp/34553/ws/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", - "/dns/kbr13.rotko.net/tcp/35553/wss/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66" + "/dns/kbr13.rotko.net/tcp/35553/wss/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", + "/dns/bridge-hub-kusama.bootnodes.polkadotters.com/tcp/30520/p2p/12D3KooWH3pucezRRS5esoYyzZsUkKWcPSByQxEvmM819QL1HPLV", + "/dns/bridge-hub-kusama.bootnodes.polkadotters.com/tcp/30522/wss/p2p/12D3KooWH3pucezRRS5esoYyzZsUkKWcPSByQxEvmM819QL1HPLV" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index 130bdf31ef211ba6d353fa97944b2bf80320997d..a9444b89e1e2cce9c79a367c4c561e910f1f28f7 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -21,7 +21,9 @@ "/dns/bridgehub-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWPNZm78tWUmKbta3SXdkqTPsquRc8ekEbJjZsGGi7YiRi", "/dns/pbr13.rotko.net/tcp/33543/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw", "/dns/pbr13.rotko.net/tcp/34543/ws/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw", - "/dns/pbr13.rotko.net/tcp/35543/wss/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw" + "/dns/pbr13.rotko.net/tcp/35543/wss/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw", + "/dns/bridge-hub-polkadot.bootnodes.polkadotters.com/tcp/30517/p2p/12D3KooWLUNE3LHPDa1WrrZaYT7ArK66CLM1bPv7kKz74UcLnQRB", + "/dns/bridge-hub-polkadot.bootnodes.polkadotters.com/tcp/30519/wss/p2p/12D3KooWLUNE3LHPDa1WrrZaYT7ArK66CLM1bPv7kKz74UcLnQRB" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-westend.json b/cumulus/parachains/chain-specs/bridge-hub-westend.json index 018ab0ee6fd9810595c841237dd253b9463aed79..447207a58107a95bcd5fca173d9d5476a0ce9cab 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-westend.json +++ b/cumulus/parachains/chain-specs/bridge-hub-westend.json @@ -19,7 +19,9 @@ "/dns/bridgehub-westend-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWBsBArCMxmQyo3feCEqMWuwyhb2LTRK8hmCCJxgrNeMke", "/dns/wbr13.rotko.net/tcp/33563/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD", "/dns/wbr13.rotko.net/tcp/34563/ws/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD", - "/dns/wbr13.rotko.net/tcp/35563/wss/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD" + "/dns/wbr13.rotko.net/tcp/35563/wss/p2p/12D3KooWJyeRHpxZZbfBCNEgeUFzmRC5AMSAs2tJhjJS1k5hULkD", + "/dns/bridge-hub-westend.bootnodes.polkadotters.com/tcp/30523/p2p/12D3KooWPkwgJofp4GeeRwNgXqkp2aFwdLkCWv3qodpBJLwK43Jj", + "/dns/bridge-hub-westend.bootnodes.polkadotters.com/tcp/30525/wss/p2p/12D3KooWPkwgJofp4GeeRwNgXqkp2aFwdLkCWv3qodpBJLwK43Jj" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index e9f690234e4381f54377c7fe7174f25834a973a5..259669cf37a0643534eaa5d1776daf79ec402d75 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -25,7 +25,9 @@ "/dns/collectives-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWDumvnNwPbBg5inBEapgjKU7ECdMHHgwfYeGWUkzYUE1c", "/dns/pch13.rotko.net/tcp/33573/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH", "/dns/pch13.rotko.net/tcp/34573/ws/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH", - "/dns/pch13.rotko.net/tcp/35573/wss/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH" + "/dns/pch13.rotko.net/tcp/35573/wss/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH", + "/dns/collectives-polkadot.bootnodes.polkadotters.com/tcp/30526/p2p/12D3KooWNohUjvJtGKUa8Vhy8C1ZBB5N8JATB6e7rdLVCioeb3ff", + "/dns/collectives-polkadot.bootnodes.polkadotters.com/tcp/30528/wss/p2p/12D3KooWNohUjvJtGKUa8Vhy8C1ZBB5N8JATB6e7rdLVCioeb3ff" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-westend.json b/cumulus/parachains/chain-specs/collectives-westend.json index ffe73b5a05a391cc1c5396c235460830c023297a..e459c631f8be9df7c5c52993c116f11ef619fefe 100644 --- a/cumulus/parachains/chain-specs/collectives-westend.json +++ b/cumulus/parachains/chain-specs/collectives-westend.json @@ -25,7 +25,9 @@ "/dns/westend-collectives-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWPFM93jgm4pgxx8PM8WJKAJF49qia8jRB95uciUQwYh7m", "/dns/wch13.rotko.net/tcp/33593/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr", "/dns/wch13.rotko.net/tcp/34593/ws/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr", - "/dns/wch13.rotko.net/tcp/35593/wss/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr" + "/dns/wch13.rotko.net/tcp/35593/wss/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr", + "/dns/collectives-westend.bootnodes.polkadotters.com/tcp/30529/p2p/12D3KooWAFkXNSBfyPduZVgfS7pj5NuVpbU8Ee5gHeF8wvos7Yqn", + "/dns/collectives-westend.bootnodes.polkadotters.com/tcp/30531/wss/p2p/12D3KooWAFkXNSBfyPduZVgfS7pj5NuVpbU8Ee5gHeF8wvos7Yqn" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/coretime-westend.json b/cumulus/parachains/chain-specs/coretime-westend.json new file mode 100644 index 0000000000000000000000000000000000000000..c79fd582348b0223cd4c1de71b94075751cfdeb2 --- /dev/null +++ b/cumulus/parachains/chain-specs/coretime-westend.json @@ -0,0 +1,71 @@ +{ + "name": "Westend Coretime", + "id": "coretime-westend", + "chainType": "Live", + "bootNodes": [ + "/dns/westend-coretime-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP93Dzk8T7GWxyWw9jhLcz8Pksokk3R9vL2eEH337bNkT", + "/dns/westend-coretime-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "ss58Format": 42, + "tokenDecimals": 12, + "tokenSymbol": "WND" + }, + "relay_chain": "westend", + "para_id": 1005, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f": "0xed030000", + "0x0d715f2646c8f85767b5d2764bb278264e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c84476f594316a7dfe49c1f352d95abdaf1": "0x00000000", + "0x15464cac3378d46f113cd5b7a4d71c844e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x15464cac3378d46f113cd5b7a4d71c845579297f4dfb9609e7e4c2ebab9ce40a": "0x084acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28bc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c", + "0x15464cac3378d46f113cd5b7a4d71c84579f5a43435b04a98d64da0cefe18505": "0x00a0acb9030000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x000000008277f47279c4", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da998af9d0b9c163cc7caff71526e1e20bf4acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d834c58cefa69bb125bbc8bef14e90eabc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x66763d0040636f726574696d652d77657374656e64", + "0x3a63": "0x", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd0058544104aeba85d4125110284d291ddb4a3c50cb1bd0b174da063483a55a47260ab964ae54d7660813796247c0bec7d0f1b338b9c2280c6160568412ae63c3a7815a544782b1d1ea96f47ff926f8d0da2664efbdf7de5b4a99640afb1340115a114f7dbbfcdd2d91be3a3843eef26f979f4522f5a9bd54f4a9d7cb0d9bcee28fe9e3738e1937a9166f6707e9b5f46edf77febca5077e3ac8b3bb558280dee92c0ab13febf7e59ff5341265ce93916b5180787e58439561514395b06f6fd71165cdb70f35547f3b778f192b9116a00609dec11fd56143b1b7f3986840761ad9a7b3d7ed94523adba39a76fbec6eeaddce22ed7e7af7937c0d995e7d7a25abe653b2368cc9727e93533ee5800cc2c835da9e1f1baa6b28aed1f03c7bd850b307c7caa167672626a7fc39c76c4e0d40be609ccece1ec80d35793e3be8e286e267e7866a2fbb67af0d359d1d9c470b50238777f083339c773e8bed6087d48f26a03256a73e9d8a3f26c933680169fc348cbf9d5e6e18759086f3ce6fb19dc54a72c3caeea947358b3f6ac3a84775544775544f9101b36f67f1c7f4a88eead99c330c90994a7fea20076004d982911b568e4f7d3a8b3fa64f110809341a2dca4f073be4869ace5e1baa9d9dc5ae61d4a37adeb061d4798ce5d0536faf5e764f1d1c6a286e183bf5a2869a4f1da9a1a653076758d450fcd4599c1ed5515def93a57732fb265f43ba6fefbec9d790f6eaed95ac9a3fc9da307616854c6fb26c9f1ed551cd4c949cf2e71cb39e330910640e5a401a3e0de3e786b1b3f8a3368c3daa19090499831690864fc3f8b961ec2cfea80d638f6a4602b9416eb01ca7738d86f5ec2c823cd38c5c3be3e727eda9833cd38c5c3be3e727eda9832e76662a27eddb41be53cb38c5ce5f4eda97ecedfd5c3b13e8e74f6f71c8a43d25cb497b76904522e357a7f749fd4a52cdaca7ceb79c3d3bb38fb2fa4bc8f795a4723df51ecfe34bcefa92bd3d8af2e5a79779073b3843be53cb38c5ce5f4eda97ecedfd5c3b13e8e74f6f71c8a43d25cb497b76904522e357a7f749fd4a52cdaca7ceb79c3d3bb38fb2fa4bc8f795a4723d75bef33cbee4ac2fd9dba3285f7e7a9977b0831df29d6fc6e9f3992d609f22953f7516a9c6a72452c3a647755447755447355f6e183b3335393569cf396674f61d70ce19a773c3d839041983713a3b7b4f564c2cd4c8f33d9df1f4e7c9cf139ca73bb0219ea27872f3d4c4539d273a4f443ce1f0b4c3530e4f433c31f1f4e66989271d9ea078eaf234e609cb0909272d6055386501b3024685531930269cc880d581110183038be33405ac0898113029606d6039c06e80e1009b02e6c6490998164e79602cc0528089719a03530186020c4d530db025605f602bc0c2c080683ac1a9052726602748e00706c6c90c9816a7349c02358dd1a48593144e6a38ade1c486531b4e4fc0cc38dd716ac26909a73a4e4738e971f2e324c7c909273a4e28387d71c2d3c4a7890b98104e6838d9718ac2e90427289ca23851717ac1698c130e4e679cc838617162c12907273330139cca38c9e034c5e906a738b019607a9ac86832a3098ca62c9ad468c2d31482a63e4d5d3479d1f4a7e98ba6329ab068b2a1e94b93094d5d9cb434a1d02443530a4d58b01a9cae9ac0346535a191a00b09c468b22241194d5b48f0c7298b0461345d493006cc8b045f34016a4aa3098d26319afc4840869394a62a4d3134e5699aa2e98e930d4d503449d1a4a7694b1315303c4e4338c17112a2c90aa73730289aae34618145e1c4a7898a939ba6354d55c0bc70a23915e164048c0b5809b02d4d7b605d38d560779c8870fac1a98fd316b03c303f4d6a9ace38e9c00488290d263098ca601a83890ca62f98b660f282a90b262e98ee30e5619282c908a6384c3a30e5c0e4860907261b98da303dc174039317262c26354c6498ba3095616a81a904261898d630b9c0f4021316262e4c26305d3189b95f7c0f530a4c3130c970694c3530cdc0748509858bc245e2cab94c5c3a77893be7d6ee1057881bc405e2fe707db83d5c1eee0e57879bc33de21a718bb871ae9d0bc5dd73adb84ddc3a97880be7beb94adc2a2e1557cf9de24a71f35c3cf7ce8de2267167b8692e0bf7858be6ba70cfdc3297cc6de18eb95a2e1707744fb85b6e949be576b9265c2cf7ca03f9184e866739155e854fe17a5c0aaf791e27c2e3f81b5fc2e1b811fe83fbe03d4c1d669c69c66370357ec665f02b7ee5519cb614c6929ea526969c587a620988a51f96725862b394c29218df614985a51296b82c6d59d2a294a5b486d2194a642899a154c65214253f4a5f2881a1d485d21e253d4a6094c228b1a02446898c920b4a65945a505a41898bd2094a584a5e944c58f242c98a5215a5ab243594aebcac78a9f14ae3c5c64b8cd711af35906078055a1ae365c66b8cd717af3290c8bceebca27849f182e285e745c64bce0b89579c5713af33c0aca23cad34dc9ea324849e38a223d4c411124b593c09f184c7688a9215444d10915164c5119a2335de134a583c3d71b405c626e47274550446384611202317261146568caa14f131ca62a4c5088bd116a32ba3128cb81c19717404d195a23ddc15474514e1196243488c100c457d8ab2f02a447f96b03a1a96bc049109a2419c23d221aa82e807222188862082822808223b444010d588b8200a811702a52e2d322d168c6430c2c1ebc304c6d3e2ca706330aac1dab168381a426588b08868445e8e6a445b88ae86b284c21071212ac18333d4c6119c232288a61061116241e805a230b388a01c826a1042230485d00f426b5a68847c10c20aba21888720218286084a130443109a201b82ce04ed10e4264886221d8a70081293b446919b2124b818382a5c6f966018925314c6e6d9a6e8d67c736e6cb991c5c5e8d204e9b004a66313c4c2b7449118b72248ca4867cc1a9918db18e78c4a8c498c7ec6268eb25eb451cf9865d47264e568ca1195a32a631ea32b4654462ce3d558c518c518659432d2c629aeacb1ca48659ce29a19a93052234425c887a21b9ebc28c2228c4224056c83cb82284b51152d354266845c408078159211aa110212af846d885dc412442e2216518bb845cc12061269e119e294300d314a58862845b412b2215209d708a1089f08ed844e84688459a1192296582544214c21fce242c29584501dd71ca41590c020a9809402120a485f904e403201c90b12165217a41290b8206d41d2829405090bd215d215242b485590a8204d11b212d406d1164c663a1b9a0271575a7f5a675a6b5a34b46a50a2c20886a440621df72332114407c795d315477598d2f819e2124251969208ca0aa708d9790aa26b012683530f620c4e622c4dc1c404531da624c23c4c48846088b48454c22a445688aa10f92024035197d04a2885a88790361448088c500b476f846268cd20b442911e2132477184c6bc9e08af6041845796c068d9b0e4e70617ee4c510f37b418d960a31877187910aac2c9f049b1f40248c35219904d50202129a30edd0ca21ba1294d6138ed6064c6bf30ca6189cca7c607e83b23a807a23e45360495099a41c8093050eb05212e2e2236295a654638de0c482d787196f87844e0c0b224c6cb09a336dc9dcd088fcc9398a22994c6006b00db80362cb910c4068705d319a53698c460f2b334e5d3a3848612a0a0183822884c98703a3845528851885088764427c427b819bc2fba1b96c61051e1b4604283e373a914515174055194a52f96bae0d0883d0889c16486d0198e0db7a669ceb5b259e132420805a21d8878f0deb46410fa227442d4b6c5b667fbb389b1f1692db15de1416c58089920a482cbd9b4104a61cb626271218cd62cb9712c82d6b4ae08d1827e0852639406a94c100e4c5a2899095ac18f083242298ca0165c6d2c140e84eb082616967600cf00e5b4c00455b164825318dd1c5896560b5bcd2886a6283a3a5e98ed8d111aa333e0114b347862c612bc3162134a3034d9615a2108081007223a4c6896cec0b06c15d78b1804131bbf41fc42498cae8d77c5e362890c3b05ac07ae886d08d00ca72eac1437be386161a443b744501bd70f412ec0e6785bb87c087aa1b5c56be382e35d8d3d34b5e134466b05cf8a088493174d337834387d0173628985221496ca80fd3004674909d18f52154d59b63b4e3e38f1e03934d1b958ad314c2a0c1161e4c66d68fa21c88c111babc76806a52bdc4aa7c67130ba012ca3c8078fcf520bcec3a7048c872636416cbe2444219ab8040561f120a971fa033be304042c86262d5e1738b27435048df1fc783534a5697202b6a6e88b110d4c67c0d4785e582aec9d5bc57570374a250451318f984a4c246612730b14d9942381a9094c1b924c34217cc003554a38108139c3dce1010ee02001441ab0010316a08020407e680000d8a4338dd031810f02ec78a260039d18e07c9e4170bca6524e9068c0880848a4423062049cf4832552468c7c3b76bcc6bc5e621884241b58c244aa0a8954130f9c247122b5442a08d32b8c0746986c608910254a9820a0ca0329254a98208082d70a3c5e60942841e28112254810a0420855202c915292024b496dc008932a235521809044aa034f2f14d889922448aaa43e302225b501a7d71766b28125498c78a089d408541e40c281bf4e60290f963059620489912422bc94074b9834a06ac9084c3cf0e0935e267cc0c403a90f965e5ed88907a4a68c3871e201a9214b982471e2440a02f785c51d4822c237919a6ac2640244eeab0b1b911a416a040714f9400a04109014a1e055023b99f2402a040fb8b093aa25524da4425892c45f5b9624d9c0eba5853d48e26449922655244819f1801211444062a489d4074a928c109bf280899218d22b0b3b397a61612446905e57cc012348aa907c80a44a6a83a0d7950f245182244955922549885e5646f0408a0429a157156ec20401e18b0a2f6122c208463e509264040d185982c403234944f8aa25521c00410a021f487d3082120f9624591201244d4678a7d714762295a42a49132621548d80e4c64b0a2f6192a40a4993113e3052c544891323494478244d4678a2560f3ce50113251a30225585e483244a903c69f19452a20124554b46d880912a0fa49a24f960491223468c6e9787db93841a3bcf33906b34dacf1935daba31ba31a60893ab2f8ee338ce5faf66aeb6d9b6d74d6cd9b6e759ef76b3b5b5d26a69b7672ba594d6ba44b9569e9e67adc7dc2d669e3cd9329dddade6f6badbf6b4cc936d579eec596bbb5a4aab6d6bd9f6646bd9b265ca5c2957a9b55dab999976dcb6d932b36506bbeea363d7792dcab69d687bb57ad54eae75a3bd7db5daadebdaccd672edd8b2b595bbbba910b6ddad00b66c39cbb6369d6d2dc8cd69ad05396b9939e656c7d6522b766deb51d7b5abd8cc4df986ad5cd74aada5dc9452fa715ba6b4d66eca93a765b66c6dad96d9d619a42e55ae4d992d65e6ae636bed9cb36933536edacd6c9932dba6b59b76b4e575f41bbb6ddb6aedba6da51fed5a2bb3e568a5cc5c7976f735c9dd3d5ae6aee35a29e5aab5b67274d25927b5b5da5a69edbeb0295769d7516e6bbbaf56dbd5d64a9bda6eb6d572b4a394d63a9b562bd6a6b569d30a93a0bdee6e8ea3d4923870e0c0318e5ddbd66a2dedacadd6327365ae73f6e4b6d572d759bb76edb6d6325b6666ae67dbb6b6d666daddd556e6e6e65abbcad56abbc56e55cbcd952bb7654be9f731775dd775b5a3b4d5a2ad16a5fd7ddd5dadb5d2ae56da75dd59f2e356ab7e638bdd5cedf6686d6eea6adaf1b4d64eaf6366facd8e765cd71cc7d1da51ae9572edbaeb2aad1d534adb7237c4d3560f88e7791c672db7c8956b57b641ccd66b668ea3b59963a6cc1cd390b6ba9b2b8b2df2edda97d9dace72edee4a9927a5fcb99832739dddd336cf8e67d755dab5ba47db2d57fd51bd24e6cacdec2580f6a4cc744eee9abbcea3ad27da35ad5cd7ee2a1ddb7250100e4aabb547a2c8f3c68d1b372c775dc7dce2d608a81d830d35edae5dbbae2cd4ccfcddedd47577d35a9b6a9db36bcfd99f2b8afbbaaeeb68eddad559c5da1f336dd767958e9879daca2c8aac8104b567655aab57bd56aab5bdbb52ca89dd4dc55a99593c129794447a80393434bb6eb679ab957bd6aeb3fb6b6b2973b7ede6b176f7e4dab5b97eb3526b5d963f97ebfbe6ecb6dd5fb7adb5dad9b9babfb69c672767bb9bc5b6cc3c6480dadd3dbbbb999916a0766f6cbbd2e68d85b8999bc10c6a57aefd357794bbb9bb6b37a78f6a6464645439cbd9e69edd5d6ba55dbb9b52da5df775b4eba825802deaba5a6bb596eb38dbae0130f52872d12228a6223ae7b41cc7b96cb5185c600590c3e6985c9ddc7459aeb3b655abb575ceca6c6d73d6b6a5ad00749576d552ae56cb6c375b29fd68a594ed275adbb5abe57a6b5a9999adb5fd64c5d315f406b7079a30e180140736902d907a22a5c408094838b034c41680c0448911109624010104264a8c04a0444992291e1638f18055008b4047044e009860078fa00f942409c10323554a4640b201a90f9e9c04a90f962431b2240992103cd8c006989001c8a1a30a4913a9255220349120e40048397122d544040e30f1c04813a9274c3c906a620489930f3c903262c11414060110c10329273d923690a489d4132304b000030c02f081941126552278a089073928f840aa89d4074d981881c2200052499a544d3039c06c8154930d1869c2a40a89074c9428418274015412094c3a50a5048541009c280016180980d41412251a3002c2922421384112824b712049d592119a904203d840d508494224488560a46a4992262218f1c049120e344152e5c429c889d10d0e0013264d8ea63c40a201254a983499600224524d8e3c203565a48a04a9254a48555220181139a97292840429a48d2d58c224499507489c2c41d2a4ca4855120e7080092c020e0009493620d5440452a8091229251ebc9e2c91a2416c8191254c92386922f5c4c8074ba44410018911291090346152e5c448150952484f96485158a8453367653d6a359b714766f3b3b29acdba236c6565357956a97864365d4766d3caaa522bab7a6436adacda8a1e994dab59f711ab39b3b2a247d8b39af511b69acda86c568f3038b3d5caca6a668ff06c6665359b6d4778666535adacfa08cf66df91d9b49af48895d53cc256563deb8ecce68c3bc25656b3593d6235f908cfb623b339b34766938fcce66cd6f408cf66b3593dc2b3591f99cdd93cc2b3796401b5cf64e6c901274838e5ec67e79b48e4f372fed4f4affbda67f9797b15876ce20faa2912a13ec94dfc41f5633ae820174e11c8dc1c9ca27b2e7ad7b1d3b36dadb54e3daf80b885e09d0fb218e4732317bdb879ea9fbf442f669e7a17861e76de1110516c857326b95c2f251732be9492c4d946149344f126b5ac98e45e52cb75e3f54a6a3baf97507d390e7fb9c670cea1250a68e9f5ba62107d891e818b0e8af7b5a6a15e6e1d1c6f4c1df9e73cfe8608e4c83fb7e210ea9f834261779884248a4d84844a1e8e2ec4e59d874aa187235952b9c49b445259fdcbe72dc3f0ce477abd3caa93e6b7f8e3e55424d2bf39d2e50fdf822fb72fd18b5c74b0fe9c2290e99d47d16974cbf947a21f5d23a3cb5f14c1b5601a661dc7a56534ccba77c57b4bd907dd52f642b794b56e29a38028a0b76ec13454d7693b6f9d96d1509e5b07b7f0bbfca0f8912f21d4a7bc3ae72c2a605bd350a25b074551f416ddefd5a5c0ebb93604192f71bcd8c1e28365072bce78e5310fdd3f27651ebe15458f6a500cc521f33bcf5bee79cb37201aaae5d6c1d6b7becfe563183611f27da077fe7d9f77640986d755da31dfe51f5badeff2bb5a2d4f1c02137dba48ce350db3ee7e3f12a058b9934e9234f77befe5d8ecbeeb97cde6ddadea9f2e12b1e20fae69d9f255fddfd34f7203a261d65bdcc0fb8f2c3bd00798932c65778a3f42b722e1a7fb9d6ec56332772b190c5ffcd062d769548f175f683127a958f1987b479615f48d6abe775eda3193ceebf977a983b724e13d677103d87b42bea71ed5dfa5a51df3d63720ba4ec3acdb327c3bdbbcc580f5ae33dbd8e9e6edd05b1fddf9adcf356e3dec03b8db2a16b9ee4ec522ee32d29dbc6ec9a9adf69cc38ace5eedd4455954849465cd53af6190d97355d52959560929654d9e74be5555dfbc4522b02fadde9624502d7de72c12b15d8121a43cad800d9dde7a5457f107259f742477ad53d0c5b67a54db5bb657f5bf86cc6f17e2f5522dfd74d0fa764bd96fd6b7926e96fd5271088cfd89fde92c12f9683fb949fb64e0e8b926449f07990266be325ffdc8d9bb9901f7e5a91fddb2ffe5cc3e78bccb8f9eb2c697f3f872fe78795433fbb0e0fb296bdc9cc797fd9d4f71c8cbcb7e717e3bc82210023cf38e6ed6bedd12c8ece776673fefcb5db73cf2e60a206de02e47424242a2484a480ed21009c9a37a1c9594941c9ce1789594bcc51f4a2e57abd5727086aedbea4285022d079902498e2324ea3cc84676e4ece7ed6e397dbae82eea87dbec96f9b59ba0f8a3e5aecb3f5e7e3082708ad38bc02936c0fae62c4e5201d6c12e904df2a4a4a4249bb4e44b499e94b4949484e42d476ab5c069e6e896f35f4e95bce54a258f47f2f2e5ed9b0884fa6b3e92b78c8e40b045fdb45a60ab7593ba45be8644e0491e8127959d74f4ba01b6c0248bd54a4a0293922e18267912f91a52e4a01739e820d26d521fc95f48439b1b97b3b8c1fced6391c89391bbdcc85d0eba2ee848b7fb5926246a799293d9b7383cf3935a975ffc010e41bafcd3bdd73df2287a74f98d2e67a761d58beed6a661d523b876cb2d65ffdd52f6e5e646c638dce538c80e50c3aabbc859a66195e86260a45f7278383c5fbd0334743130f6979b9bcdcd57e7ec3494dd72e362609c5f5aacafbeb56928975707699f860a0afa3e178738fdd7a7a13eaf6077cbf9bcc51f9f779c869a5e1d1cc7717416a37af4280dcb69e647a7e28fd1e7e50fbafc23d9711a561df4bce979f5ae83b3dfe68d6a70c24a28e3773cd74a88d3c5cff778ae757183e5e6a19e6b5d0295e0a60430255c7dd2738d4b9fe782e7919e6b5c7e785028e41c64100c59ecc852f69dcf5b8e3ffdde2b8fdd705e5276ddea8b7163d0750e82e1bd1c9bb7fad64dcfc130f43c055870bbafe9fcb37f0de97cf3201d59523f5f7d96932c653f7df653fc313d8adeaafee99c48e409749783ee22ed9686815e1de4c4214e0f8a0e76384521d33b9fa290cda7e87323b96193acea0fbdec02893f5a0eb2e8224bab77f976cbee379fb7ec7eba789b0811bd7321422e926513219d07b990d13b17c9727321921b26bac80d15449654f345efc8921bb6f9e8ba214965b55df1f2b72ed57c1074f1f28720e8e210d883e46bc8e79e7f24edd3b0ea5ed905faeadf9886f2c859e6a88371f30e3ae8609c3fc5397f75ee0803e354e7fc25f5d3728e30304eaf1d39b93bc2f855e36fe4992b8fc9da4d99255ca0c5ac6a9f3761e0c4a07840368b31f9151e312b3c626ca6db2d0d45fd34d4fc31cf5fd23fdf72be7acfc941fbe468397d801ce534f3d5271ab2e390d34c1f80f4ea474f59e304f3fc65f7d56b43bd363f73e5b1ebfcdac822e3f5fef9d5b90f70bdfabc45b382e9f61eb18ee956dc402c42fa752a16f1eb2d3a806339c8913e4d9fa2033846921d7d9acea203387649a64fd3bf3a4bea0aaecc320de5392527a032ce325f2b4029603f07c1197ed786adcfb6875f6f9b779d7f5f4704f65f77a77f37f4ed72dbe6dfb5e4f639187a674520a27f4e6fe7e1053d8a76203b78f945ebecad5bceaafeae4037ddf3497acee28fcfe7ed3e2e8a527e90410ee715ddbbaf21d43da79e83f472b33a1589c09e92a575f0cce8514daf7590c5902c651f7ee3bdf2d8e8dc0718499995cbb931f85cc68d01f5d1a9579108eca7fbbca087b77dbc1c735d36a183f38a64597f7a78bbef7a2290cda7d3fb39783b8fa25fe7d5a3a8c7dfb7aa7fbedd6e59d55324f2f4d62d39cb3c658db3ccf3539f659e7358f52ceced0ad650317413aa86cfd37e4a5decafe7da9632ada5cf338d7bae6999f3ccb50a841f5960ece79a1637cf3e82cd79dfb272f7ca635cc871a48c73ab0aeec0a1c5388e9faaab00ac4c59d54f87383df5339d47755f2b049e873d957df5beddbdf2581776571edb7c23cb7a808e94756ec53937065d037d75b0c3beecdde5188b44e8b757928a666565653d77b93128b94666ce57f5976928a6449e9e92b30c8b3f9aa4e2ac7a667b0303e406b94190c3193d02390323d7b28c79fb5cc302c47310489d994aaef3ed20bd577c2a59cebe3abd200de99719368f71000d558ecf8e34b1b8a1e28f79c2384b1e3c06d03d9c46a3d162ed51ddc363ed0a68a8eedb19c03ea80b09cb7c1d0df5622bca23cf2210d6f3ec200d6b991a5a2c5736dcc41f81b8702b40f7e0d89fcd5aee1c2d7617fb60927907f5e63a4f184b1e513d003bdfce03cfb75fd050737e01be9deb583e3ccc4a764c32ed0038646c980b9c4546161730fb5ac93913d003530418a16898db3bf4161930fb2926a9ac9ebd6c9f4c0a71c5c373ed0a4cbde2e76905c1c9220366cf0d2bebcf7e8254fc613bdcacdf1a64760df502327ff38dec7ebabdf399a99253639b0187cca9792798322703610bc6f0eb83aef626a957bbb537d40b483b75bab9f529ba79d750fd5bf8511dd5b35964045d579501b349760dab5e1d7409a1b2facaf32ba901909b524abdbd564a2b7529901b8a6b57e43c75f6f082dce034616c3dd7ace8f9e9dc02e2ab6f3d380e8d1663a73de8eca08b7dcab383cc3e5a0e82b3d05b9779474896e00faafe202059f6833e3dbca5d587f35ba513ab07bdfae7cc3e3c6ff18e1659824e5d74ef32ef10c93274ca3f2f15979595d5c6570f6f390332bf7a548397ffbb53957c327f7321fd9b537148f526cbd9b7f3833e6f397f3a15816cde72f0be84fc148384cebc637a148deaf052cdacefbc755f6210ce3db29ceff977cbf99f83db2de76f2e7a1589540f3daa41a6c0c8352b73befae620831db2184474902ceb83b49f74dff216394521f5370741165b6439fb9687f749f7a183b79c0f3ab38f902c4357e2e39977800e7a14052f757086e0a5ce628ba4a23fc51f9b8bb7dc8654dfe2d0a43cf839fb1483ccac0f49e61d254852cdac07dd3a8b0ae00749661d9ed3eff27b773a8d7758e76ed93ea37ae6cd4d0ae8b4471597bb33e75570f8e63bdaab1879cb0140bd0a96e9455e8133ed51c5889409393df22a4b0e3a7b477b54e15125023772f622daa30a0e5286c35d2e370a72d7751c2ec341ca8298dcc865383c749757a1a4aceb7c2465a373d4659494752496e9b2ce953cc845671f698f2a1f29fbbcdb412352463a97c39dbc39377259bb1129b3d64752f6f9e8322307bd4af523523634e442a48cba47ca3cbfa0cbae83a48c529781fef21be3e82129b3d63f52464959927f3e521f5d16fa48caec0d97597f72095c36ba04a46c68c889481991739c2b91b2212527e2885c0297712e012953f2a892cb3c26120bec0629bbe14444feba4144447a8eef73a5a4ef033fef1219e108a223d7de8783762091755d1b766714e4eaee72231d3f8e08b4210e231cdd7505d9cff32838724441e188c30b8d82b8eefa735d4b442d9111ed9c2618c1765dd0290892e07372ba610452efe9c965ed4f4f1e0e1ca4c3c6ce61e10413b8ecf30926b81ce772d29fc2cf9f2c0ce6b2eb302758e7221a9df4098c827c02a7c065389c82a7279781fe24c19353e032cf3a3981d74987592287b59393d3042ee37c0252e6e414449d020924487259e8499e93fea4e449397050e04f2e33f22718acc925206530cf21813fb9ecf31c2e1b4926bf71a38d9c74a7a424cfa1a4e42f4fcae1492e0bf2a4ce9d5c87cb5cae63f240720a5ce6720a2693e7a0c075b80c87e77059e74f302424d2919e1cc965d791a6cb404772095e2fcfa144ca92485992e7f09792bf5c16fa6bbaccba040e73d9e8b0d9e4e432ce9d4859939393a4acc995941ce632eaa4cb3cd741ca2698c09948d98b94bdfcc60d4722654747fe2265487ee386bf5c46e42f5276f4f223978564143f4d67720a7284429e44ca8e48d9912779183ae9b2cf49522694c3499781a408fc345dc82970d94792c04fd3292065139058e613e81290b2eff3215236e4a0040ebacc233b0049d9073a1229fb3cf43c74d92539e0a7e9482e232215c04fd361a4cc89c89b481949ca4897e03a1329cbe14e9232ee824a1a73b25820c384abd86de2ca1726d408234c95266255ae4719911d3f4dbfa4cc49c741323f4d5f22993eb12b25193912297b15f911299bfd80831775f0c89086ce0f31a399182952788193270d3c6462462e0b228bf869ba11292b22993e554096b06797b9c8919fa6474076f4891d87cb2819023f4dc741ca88482c335625c8874899cb6f905878c4aa50172265412d7791b2590c67d8381303a032be102346798a3f38c0e0450c203869c4aa5077b96c2407c04fd35da4ac45327d0200590ee0d9651cc9839fa68b64117d62973579849fa687a40c24b1c0625536ff4859017600028c1aca78e28f9a984762f15895a53767e430841456d4f02256a59d735947c2f8693a47ca3692e9d30eb2e4f1ec324b3a3f4dafe4489fd8d967d4eaa977648153871f6ad82c6ad8f47eae9dd9e187a8ea23f18e4972c3a847358bf3ce20fc5433ebd959147947df9077b4d3dbe6cbfa3dc35b8d5cab52e7d9ed73ad8a992f3beaed22159f6b556a6080d52b9fa9f3430d63b236ac9d45aa99f5f676bca37df6d4f996f3d9a794b17e7b1845a3ba631fd6db3df6c1df6e2f734161c3b86165d14f9fcf353354fc50c3a6d73b9f2f378cbdce59abf22510086353a7d429a5739e524a29136d42058d37547b1d1baa74262a58df1e3614fdf632fcd23b5686cf234c29f35c9352c697aea74ec1734d8a9c075dd46b43cdbe6c9f3e874c4df235a4fef4fad349a0d168b4ea4d96edd559145292f0d52b4935359dbfe47e3a9d54407e660267197ecf09cedb35d147399fba00c62094ecc00ee7ad1fb28f26f3cf5371ff44c805d2705efae2932ddcf34fc216fb6832694fa5c14f6f679148a5d1a62864a4fdf450c8a4fdf49e8d07e4ef1aaa3c9a80cad83ebda4ce0dab606ca7cece2291f6294a760d638fead99c0998aeaeef0454c6e9ed94cee9e00ce924bb9ef5a40299a91cb96165d74f6cc1b8f97c900330820c82916b527878ae49c1fad2f5ed0278ae45d1f32dfe28c7e95ca3614175de5e1b6af3f60e6cf147b74d9101b3df1c9ce17c708a9b83dbad9a543f6ac3aa0b197ff3292a807f73167f70c3caf0a725cbd9dbaef328daddb27e59bd8a3ee72cfeb01ed520c822254bd953ef6ee9dff9764b6e1809df79c90d2b45f8cecbcdb9616508df7914a59723a96401734eef6a7b37e7f4aea968374be0eaeafbf2beafeaf52a208af3097638390e08d5cc6a52158a20e4c8771d731c1aad73b03af5c82654fc8746fb2aa1ef9cd2aaf03b22227cb7099506dfbca37ad5f69f974d3eafda861879cf97a834f8c93b6af548661dd54520d637b2de8ebd49253bae0c6a1db477c68981d44170f6dd2cdb3b7a69734e9ba492b1d3ae54f4e7e49c0a8973b06b58e739774bae738fe3486e58479655fd54d3737a4bea4fc657526951beec9c8a0b1425eb9f74df4d556f079d23bb1b725e761dc979d9395547454a946ff264fbe94fb877327bcea3287737ef2e3fdf928afbf3d6378feaaeaabfbaf712326bdfbeddc9f9e67d9f74e7fdd63b671108554927779d639f776a92dca5dd91e57476ce85d02f9dcc1e087f25a72839c5deecd3e7f605c8dd903fbb3314588ed3856cbef9e6b1b3e7ecf9e7ccdf1dbd27f3b76d92ce3b189c21177ef3c1cf79bce7736e0e7e1e72dc90cd41d2e5f9146797ce99f4c8a186f1e69e7f6439fb6fbae7517482e0e775dd4ff72eb7b18e765b594703a93f492ad953f72e6dd6d15e2e6036c44fd6d1be80d910cfaca3bd8fbd3b4b18a90b19c3a6aaa5f5e9dd7d4d926a3e4752f0e00cbbbbe3d9b7e99b10585ac629eb4e5f5a7e7e29f6d184c79f619ff1163e9d99dc482a5676c436bfba11dbd250435f5dc95be7f1e5d053d97c5e8de5dca2c55797b18ff4c98c313b90d9a1cd1e1a2db6f904375a5553020c525e082246c5ca8ed8f4ab1b31762a563ac6f9d50162d3b77b7580988c4d91e9320ee853f55947c6a608e71b298ba24fd53952c6a6c8e693946d240fa64fb5daf492ebf019579038f3851469ae7022c6319ea1302788165a7883e70632621c632f7914711a2d36b73494d357aceeea0238b3d0271c33f099c188f7510af9aad76af5d4279fafa42db7ea1cb96423cbcd95501bfebc25977849c952b639bd74b07eb35e5a7d399d5a57321bf3dc12a683f5d6cb0ffcc6914b98cfdb6d8901a8d4de9275d00851c11d386449c2539f5e2b7046c66ee5cacaca1a13f3ced092b8c4f0a54c1309cad42087562502f3f933b40aeec0a13d3100951a0934a68315632f3ff0560af38979248df9c4d84bd95bb29c4eb982926b67daf8aaf9676838aab0610a17345a8c4919bbd592165cc81325108d16eb485a597d96223c2d1274451532b44185468b6d70e39b8649e33a1c1469a8768ef57c757032c174f0f8ea30ee96ee4cdce5ea1dcc0aaa176958750e38a03d9ceb5c80ebf89131a8f4a74d5be5ace33e702404114898344b0668edd8509db33bfbe08454d03a8b41ac57b7b37f4cf77cf3167f0c5d5bef93f9e57c32bf56079b27776dd9cfa7a653a75ef515dcee4b08f379d0e937f8025914c2f57990e45941d96fb7d94c5b3c2bb04eeb55127ebdaf21746a73eafcfc6343f17876eff278ff36b7777a19a717358c7d68f3aff32952758fc43bd8bb3b368c9dbbce3b9864b256b20c6b20d03a3395dd1f2b63d9d56a0dc579f52e4e43b557efe43454e7d5cb6ece57075f30f3123cd75c08f4205dc3dafbc158a977dec5a935ac7ad931c07a4776722600ba1aedd161f553f5dad58c8cd6bb5a87d5b0ea1a182df912d234da53b7a2d17e8a2c89fe49ad834584d9a8bd2595587f2980df766ebfeac5183333e0af9df8837a3f48434035e46ed9617dedb06606fdd5bb2f667cf50e4c43d1af0e4eda93b6fabedacf5c6910f37cbebdf3b9fb6a7f59e75a96352f4b4280639e73cd85329e6b2e90f142e85ba76f49ab2ed887f5ea5d1dda03f4ea1d1eda63c6aa777b688f9657effacc0c3aaf0e6efeb2de8139df0125be755fd667ac63e07d59d2019d5b9931d07dc6ece520f4ee961d58e237af0fd29e4c6bab9cfd8b83cf5f9cd7a7ff7280e82f8ee44024a7701620cfebf7cf8f6afae19d326320f9da482a57d69fb9ba20e6f91457561b312b33e63995ee23a770595959fd2c22993e8398dd9fe71c56dbcc366705381d9cf367736200b24f29b4d66b7d4ecedacda973d65a70bb483388da3558af3fa866d657df48a45aeffcdafd0438bd631f938441cd0f358c7ac73ea83310b3f28e26b9611d9dd306ca0e5a3a69e77473ba39f501741b75ba39a5d42d52c3b6f6a1dacb76f3b9f9abfafcfe57ed6173cb91480ddbc8daf10e9e5f6f3b01b657f6d1aee9957d4c926a66b5e51d5c79c79c02b2f5ca3e3667b7ec635ed030ebe67934cc3a8bb40c656188d43d3eb75e00f6e1bca373eb3a1a6a6c58e7d607f0d43953f7e8faa92b5f61f718eaa7cead33d69717bcf517fb986f41ef2235ac736a43547be7d46508f4dd143b7f712f8e73ae9d59f35c3b53c30f35acf3edcef748a48675dcb5bc8377f07c9e33db940dc836683a90efa73f8b3f9a32ed9e44c0cdc16d8a3f3eee8a6e1d042f90d997a17f9c33e7ece12db9e7da19345f798708e4b68b9773efce07c1ce411af2ed5ce49f1d5976dedd66b274b0c3f07eef1f4841d1992c3b2a12a8488942fb266148523999bde76507d66023eb9d701d345fb2bc478664c9208336ec6e835ec12dec6e3b8b4186886449c283ce21c96e45205fe81fffd4e7cc2495ec4bfa9fb328a47b909ceabccb6e487be779148dea1938eb0f208330562f8bde7a4359bfa0a1fcad179da1bd75247b79bc2d7aebe390b5ce352a603932df00d90eb90238d053493bd5ad73d69fb30ec2b8f90038a8b21b8f3414e70568287fce3b6828aec980e639bf4043d1e718cf737700cf3937d4fd92e770c3ac473512d897fb33c178aebfc84f4fa6adb1a1a8733ed450d539ce3967268e9ce23f144d9a38df43d8a194723b7524f6c14f3d897d00a9d5867140a50a942aaad4c1aa7244157c624c9faa7c13379c30a74f1a68bc89317d6ae70e0a1b5649186c7af74c7b703f95e37b3fd762a0f2b52b47ebb59dc71ccdecf9f621580168ac0cff86cc056d64d8304b86cf353380be92430d9b5c7bce31b3b30181136be4860595e3d3ae84e918ed3cf521ea5d680170b619bb86e7da0f5ebec93cd77818e361cf351e5e105235e5cf973320b62f47f062c4b3bb669b91c279aeb9d9f333ce730d8731afe3b976439c2906f996d8f354479e3dc8f7a785a7b26a7d598545154564beac424306c4e2cb2a2d58d82f9de4c981021fea7ce984873acfded16895467bce7a76f973a300e8ed1daaf9d5c17a6d25cb39c521d49b2cdf8cf95a7dbebdf3be86d83b5fdddef9d2c9ecabdb4bc5595959a01df341f4f9fbf7c10eedb577beefd24f31887f7bbd4f882659d5feed43c0bee50c32b3a8a5e44bc874ea41a653b20afc1a98afeab764d9fe643ef5d9d3fbf4deef2af0d96776361aa08f497bb0c38f7df8f89e9d39039e155477b10f66a3c7369fa657b2ecbedca28430c33baa8bf5398328215ee00af82b5936595afd937e109acc9fee0d7d2318865c83c1cf53b9fe49b7cd0cf869d95f6e4f7d8a4dc6e9e014a9c6094e3a1ce70755a5d1784fe5c1ead9f8f0cc60f6d1f3ec3d7b708cfd9b1954da3310d6c3755dd76ddd7574765d6761ade99b9da539208cec4c0d555630d45025d34f57fae9a119343f7d6ca8f99399e606ade79a992be0730d86403f840432ed71a4478a33ce1083258d9a184761478d12f62891060630b1e9946bc366756f58ddc8d27ff38e6d506d185956d19feef95043811cc87d1f5972dce7d441eece07bfcb0d9b6290a4af0df39caba2ff39389b276df183b086d25122fd9c64b9b975ea209d73bbfcdeed34a8b24fc26fceb7ec9e3bb64155646a1875cebd611cd95e6f399f6a6eb78a4ef10793961cc3a186e2a7ee8fd450fed475b00ffad499fe9bd60c730f4a9956e7fba43e7bbd42c667a7949def3c8f2f39ebcb49a3e349c6e9652dc7b18381cfb7874349a29a3613902f0e6318c3d5b70f1521cd0ce67c334e9fcf8d013bb740662a79cf5767f6c13e6677b48747adb51664b0651fa5937df4b3835de710989d7b0e5a07ed15f27177bc1d7daa6eefd7fd68ef728cbb42c0a73e7e5367431dfcd16439ab218bd6f6d6dd6d6de85d286cac5b75ee6d937dd0670741ea9e832f21e58ccc5bdf66784b36f1df7cf61be95da74fd5bf5b449feae604029f7b2414cf3f8f00c73c928df52a3ee08a06b18f84d1a7ea3ce853f54e2442dd92250713d0468e757e458398e79e97b01f1deb5bce860809fa910d9ddc93b6ca087cc3f0e54bae7df50e1aaa2c80021aaa643c17682828aebdf0e7ab2780e77c651ffcec53ccf1a555011a8a7a75de53bb6bb3e7c9e79a0b40bc0b6b5cb8fa3280acdffadc50d54bd85b6742f27e16eb543bf572f472f3f6269b92536315e32ddfa9f6ea54dca0e9bbf0e7cbf1ed5089f4969ca2de5efa5beb61d19cd46706fd74031ecfbc63523620adce6ebe3768a765cc7c3b2d13e7dba9ab86f496ece373cfabc800ebd5ab48a49d7abd95c77fd4bfe9168036b42211fa390d3da4fe7d4ec13bfd2ba94fdf4409740ea523a174be39e7e0165271483b75b00ba72881ae025666ac732856666cdb1ccae69c4775079d43e93ae89cab93ae007e79eab24d2c43e5a953eb9f6f413ec920dfee94ce37b7d7ea8b5967f6c1f9465a7db1cd4b91888b39b8f2dcda3b63de6543a581cb83f1732b9cb3019df6c5ac5777393f9932ee92ef410faf90afe55504325d28f4f24e29013d74d1697897802e7a149d975fe896b30f9aee72f97843679101937491238c5f561a6d7acbc1fb02453240fc7daeb5b086cc9a677aae91b96a01900dc1fb6a89a2287221785f60ebbe4051f4a8b622270e119d8c9cafea21df0338b691533a52368b7da415ce67cc9eb9e24212f4a8b7a46cb3ce791b6965ad6f2eb3ea7c23af3cb6f995c73cd2aa23af3c66492b571ac4aacc62d6ad731b05c9a908ccacbfc06a3576b291044bbe40b7d6e7245fa0256765bec51fd4a7b524d3a7ce6aebce0a904918b99625d0772d063dcfdf851980cc54f268a8da50ed72ab0e62a30444b71aea22d18b8a6eb8b8398b1d885e7443073bacd373f60e64506264918e8d35e486e22f02e5c8438732fa91b358e4c84352d6f2d13a8b1d8c2c047aea2cf8b162911b1ee4e115bd75a1dcf0965bb102462efa768bdcf02052d6722267f6e1a00d7dc9652d231749d90d0f5b976342174ae846be74a118f90d27ba5064a1df70ee96b3e7e18d9e6b2cd47990c51f9cdbbbe47bebdc15f2bd752207c12956a0e544eeba505aeef2a02b6b79908f57d6f2d159acc00d37f2a826ba32972f7978670ffae720175a162b200b72d1652e1772168bdc70235236bab874a1c864a28ffef28e095d283259c831d795c9dc953ce842b90ec51d8a92cbaca020b99013b9acc865385c36e4a3158bb43cc8add8c1e83748d92ce6f2a32b9b3117696f9196f52012cae8410e7221152510ba110945f49673e24616b9e150427779d19589de22ada044e04b1d84e414230fdd455a7db12017afd5171b997d58b2e4f167ae5a1e92565f2cf4cd83aecbc72bce5890e99db328819194852e92565ace6623a79458e77cf3208f6a902c793ce71fd92290e9d4b9bbc4fae651744e31f2205236632409e545ca8e5c16e44beeddcec33bc5c8973c822b2bf2081cdcb89479a683b57129f39bdbaf3f06cd73133f918c6551cde227cb1a16d08c0134a64f0b5b5a183306cf1839637808437b5f1d39c4fbcde77fcff579e6c3f5f9cde9f7b32884f9fc66002ab58a051bda6fcefdf6602bb4f765bdbb2f4b0af9cdbdef9e452115dc81430b452106a052fb8d0e56cb9748d98cc92eb934bacc979446d20ac9454f22ad90d8703e3a9147f5bc63fcf4a07be5b1207fdd2b8f85eeba562e27f223d22a74a220d2cae52e17dde8ca66b11ba49516c9864a839f2a79565072cdcb9f9f6e9d7fc68aee95c7649dcc65571eb30a5df41b1ec195e120adc2d0895c6625e444e495c75a3e445e79ec066925445e792c24ad04915334880579e82239c595959595152bb9e6a5cf4fb24a24c24dfc243930d2f9d29e69f34ab8cefbaccc7b61e82dafceb48757ef4409b4dce523ed31c5e52df22a8864b3f92c569d232d39c5911198c5c68eb5bc5a8d9d6cd26823095c235fd65b6ec5632ddfbc14e137f265c922e3f4f2c84f9fceb4878b84227ae8d5bb99c1247d132bd0128b84de22652d0f5b62c8e339875504b3aec71ebc7c79eadf567bfb5179a6c0a4e1e6a1539108f50fab8ca73e1db4e1141b30c2f873deaaf13907bf16814c1e6fc1b3f8f91643afc3951065ba3f74cab498585aba13c8082a2bf0a006ab01539899d3268a33a09001ce1a7fdad89400238276682c50384fd82e896d03c36b17d3ca5519ef4650123d5c49d3a78a324acc62a002062d59e09961882c98c00a9918c3c60b0a2b9248a1052d65e4b0700496181ea880c184156a9851bf4079a603faf0d0054b0e3ac490c59675c21156c8c040e58b10b10d882e7e2b630d5f120616795280620d27aecc7a90f2849a2fc4f041e20a0d2d35ba2ee401ab33418b28070c47ad1726466fa8088e1e387636f1c7365a137af8b8ab5d1266ba24462f7d42ef82226ab50a3c21065680a1f44d126b420c92b0dd1a31e88225e49810e59bd3e7823bd616b50281522e6c81e50a22d270a266f4c21938a410c68f963d21204a63c80a3956d4792ac17e7f62376011b1c5eca1cf0f5788e0fc308688e3380ecc05377431451b50b06046192b00ea689f0a30e8f0051e38410c01688fbde39605037001a286374e4ca14495a42f64b4f451a28e0e637868586b6d2ccb9fb0b3d67aa8a586b7564800dbb66ddb9f0068dbb2e0388ee338306a360a0c3923c7e9e1c0e82e09b734c41989729033bbda308ee3ba3b35ac5d68e70f65d31b18672678c41cf9600124860f7368501344cf1a785c90c306960f6748e0b5b9e10934c260830f123eb4e499028a3f61d4c892a13363dbb66dc3439fb8a378a0881c9006167a5e2053c2137c92b0b2020e538a4083821577bc32267863bfc811a4c4d2eccb9d3743f8b132069e35e42c11484c135eeab061c61a3266d8b66dbb02a89ff8bd2b5a376e9b1795853214e6058e0a6db031e20c375dc4caa22b8e38c14f175df42c5184123cc6d869f8bba0e130ac3831049eab2e725ee8e285082804a1062a6a609c19e3470531b62f018b0a15eba1b5d65a2e4e6d7462806033840b28a8f083151ca49006971fb6b879a18dcdfafe30953e436357c60327b0060c52c874e902893eb1b2080b0c5957a408d1064f6c83b3049509c2289282a986258ac8418940808888e2824415668099d3264dcc6e6aecd9c0a8c551c2b3839487ead9b6087edbb66dfb03a8ab5c948f0fcc5afb0015b6c840840f6bf4194301265889e1cd1653c6c8e3820564bff8c268c18f116c60e9b2e5ea846ddb74e80963420b6ab2e02286d8e6a7e560f5114e5c90854d1a36c8d0020b59a021254f9b2ec290f2a6081e62b6931326c80b1b4bd3c6f3c20faa68b2a1d5ca3f048dd21faec6a271a8284f9c3c73f200513462d90931782bea787a7a90636d51f7c34473840a615e80020713cc50b2620b186fb2f85153a68b2e46c35514319b1a4360a094c20e2778c1c41a55b0a8d1c3842f6eb408e28a3163e07001830b220c7c79214d1a5c64e9c10427a81cf1021524beb8e973860e73cee820461c3b1d7803c55518294af4e027049c9c91092fd80a1e2b7ba8952cec983f514bd466342966aa6041c5851b84e821884e1242b33045d056b861072ceaf4d922041d861c8ee3b82fdd6aac50c5586b6dd8d903704438c503da50e6891a117f8e2801b6edfb6ddbb6edca5557b72965fc36858d2a26111454b9a0a58d142e74a1020687406ae810854d1c1fda90e2849c20aa1637d02b3552a0d65a8b4219cf13734268adb5dd1d1004601031054d1648bcf9130131d8102184195a00c1c6c847866edb3c3836749bfd9e06301d00f260a140a50440324ca982068a1e4a1883c60c2ec2b0e9c2e4d065c1449b34ec0579007180c0d8580f57b3ab26aa54d1a5872a687001ce181e42383e0072f50a60a86922501436c260c1dd098918b7f96b805913468e0c6c8c61e7852e88b0e28b2c68fa88b1478b2e2a9f2296aea042b864e1e2093a67b00122043e50c9428f1d30ba24f1c795c5b487e39c03d9f09c57ce09381e1f38540f17c5588318175a46f040c59fad0a3096e6c9f19ad8289c2c33140e177dc29f0ae78b1c110d77010a344ab53cf1d56cd7c5e9c46c2bc809a2badd98469ff8c7d6cd24b238a2091fbab85025c8183f9499a10b397142d08585b302ed86155ca3d16854c6a271a8e8aac31ac114fd1686d63eeae0ae7658a3edc1075a973c6ab858230b156848d3c74f192cbcc4de688144e3a95590450dabb12f65ac2ddad8d8b66ddbe205236a3384e1c4963739ccdcb04697345d8081868a16845228f3c38a094de0f963070519c2c0f0bdf1628527064dce1531d858d3c31d3d4a415ea800c6891cccb439e1823953e0f1628b174250268a15a229b62d841378c8e20207159e80b3e445072e5edaa0b973441c29c49082c6aa8041e359c1eae250305d08c57a643801d00a73e09c2943c90b6118c1a70e9f10600552c27b13c80ed2e7698eb332c3735c0e6d050c115c14127236af5b0f2d84cec0dab66debea96c1986eb3b54d1f6b6763b88013a60c2a9a089347853469fc00e884187688e244adf5c6093a43789eb8b21d07049ae7c4e7eed4a6b8fe0b9a98192d5af890040c6780618217464c37f3810c0d4ba4b96244183d77bacd06b529632dc78518bc1ddbd1f190b8caa26a6a4576131f07dab6891963df6079e15db0f1a0d16853ac77f68ed6cb2eb4e468a65b33f6f828c6f413ff56f461ae6a982ddb057f041e243b667cc33181021f2c4e18e326893159572c21658925c228a289285e18a57867faf413f7889df9d34ffc6537f2b09161adb563b409bbcdbef9a10eed82072a091af6a440a676831e3a333437c470041559646419014506ba2853840b7cdcacb9f345873066108186952b63443b1c57bf9855f45183884f8d25383a7ab834e4805d121b0fb40c976d23c2f5d65a6bc3ce663dc1d5ac6460f305203d377861c64c0c0eb52c940033840c7b6841d4f1893c2d1ddbb66ddbb6c5d0ece9ea0d2a26c4200399335854819306ce6f1b1728fc4684f5849b22de0871f5841338d88926dee0c0a7ca992a72c8c3c294ac1e86f0e28a36028d4d2c71006b8a1d2d7cb4c0e28a930a56a451a38a0f3aa04007853a550d96d0123443d001038829e860d92a52ac49830e17658cd1c69db74c042961abfc8980892a69be706941cf10575e7edbde5ca1f01b4d0514b8a401031617c888d1d962dbb66ddb7e05345d1553c36fdb057cea126a709689335d8d891ac425b41c599bc5e6ed8db75b06d65a02b8912b269c91a58420a840e3bba863e68b3f56e44401478e10bf1dfd36c7dafbd65a6bc34e0c2d4260c4943c6c5c1db16789366b30c1c213213013a58db75e8394b09623428a6db3bf6ddbb6bd0a603c8fb9f8cdebb66dad4510d7861dba0616ce004db4a0c5092df4f1220f57faf1c282942a45b051458cab4f7449fca007071fb8f8c0420e6fb0e0236689326ac033854c8ce3b83753b83cc72131563fa0b5d65a6badbd801846a000841028a4a181c403c61425f4c1010d326216dc22be1c232c2d75a8c883460e6b2435a186cb19698461a68798058f18a27738047bca1eb288d3460a25d0b04620cb45940f96a508148e58c10e1a2362d688b7d6766317b212333891860a38cc59e30a6b54c2132918a1821337ec10b3d6eb9b3e7ddeda22b6502db2c0c842678d305dee0cc101ce165a80e903464c203dbf6d71c8a1b16152c6b8c62840806a40244c78c106cc161dbcf0504495315f90e1a54c9b1048d1a1b2118523a245e0428d24a40c91458c1bac4cc0e28d1a448831538585c3b9306f1823ce0972be3c91658bd915304ce893250b062b6cc041224e056f66f0df7ef3a2eec131a93c5966a8c1fa220b3d48d42143041453d8d046132b3cf85b4dcddc346021079ff1650b3654c819838b2b0ac872c20830a4642903cc1b295a820e502f50210826989022059c2b2b6248e30a303a4cb1e70436d61832c019a32dabf61b01388ee3b8ca0dab1b9cc0c2115b8cb0d2c61004d8e3041e16b2ec6051e54d1434383570180b40ff4a063354ece0c294134050060c35bc69618d26b8e8f2adb06540419d31b2dce142cc1458cca8b0010405202e69b858418e095d1ab5ce470f80fcd04962cc165dd4c04cf819034c9f2b96a87395c6145d1a597004f08dc6f5731cc7715149b4b1d6bbb5bbbc849c5614f4025a79ce1a2eb26eb8420525b050c08b1a5e80a344145f44a14366a313c3d000c6a2f187985a90bbcab4c7f882162b27b071c613719a48c0092b40c1031d3464044147cbd7e7bce3f31c8ee77a3cc771e3386e6eacb5d65a4f7c14e4785ed8352c015e7ef8c1cd1a686c5144ac2cfa25f28062683718808605336154f8c2892f31a88de435d6a803031442e0b9c28505c1183a26a4a1d3650b2c6216092a6fed9b30657cf81683b7d67990433cf4d5b3ccdaa38b591fad75b7d6da1678a04f3c81600bc6eeeb3bc7715ce7cef9c8f95011c7711c7742adbd1b40d09045adce15953e53a8c0c49b2e4a2071e70d2d0d9be58c77413776e108a6cd1cda9ecb1413ba206382164c10c11d00862e42bc30850a3429c4b8da11543cf79c96209ef3b0a1849e736f28013ce7b086b2ceb98eee31d268b428316ef3a186216d5e0e7d51c3aa6f2452c36a8f58181ee813bfb5dd0f213153dd66cd02a178f3caf9e6614375becda14672f68183e93923c6cd677799f698e1a0c61914ac4cb9d26242ac2cfacd47daa3481b25fef010c5175da410db9ce1bc71e1373fbfb93754007e7318ed51639bf3204b2503784b860dabcec519f9cbdaa38bd5b1d11cf1e5082a4694f5d98834b6e79a1164d4aed81822ceb383cfb521c6f09e6b437051c1684a29a574de491bb976a626c40f716d081fd80c33a594569252a674cacc8ab1614a2ff38e24234869656e582bd1ade3db8bf8ea68a810b8e9db79cdf74b50c4038521f8b422308bb543a15e8592573488b53769d5d3c12900766eb105b53a7d39bd4b1e33db593d67713bb7570215dc79931563afd7521bfec43a92c674b0aa97de532776162be0f4f3891e3d4a7055aff5be36672a575dacbbea629cf32dad8a342dd6b977ad0c20c6bd84cc326fed4672c0397f9131d66d1b49e57a4b9ee9664f3d8a7ec75da64f65f7b61bab470bf55ed558757a8b8cb1eacc949254ae3f5399bb271931946e308605be332b68610c487b4a9693365900e79591ab8cb361932905ec7da9e6cbe66cb6063c98f6e0bc1c378ee953e57c73eafdaa80e79b17e99cebdc92453cdf48191beb1ee94d8a6cde91b2913ed1ea0fe058117da24eede6a53fe538b65d8ed55bc2fef2a04d5f00ad8c4d75ab2f66c15a81cd2d2963539d72aca34f318e59a75648d0371bb0964abea75e9d9265754b9ed982f09fb9f2181bea541ce27df5bee76ce6a6dd5f40a9f1730a402a27f33d726abae73798f9b29b4cde61bdaa7b2ace0a3fd0faec7273ebdebde106371f825edf72d62c76e90da91efa148784ee89413807bd1b7a1587743e7d92cc3b66d9a4e7e02ddb7bd23d156d835656cdd936bb8b3a3330d61696781bfcfce6b40b3b3802a6be9dce410736f0405d0f85f178eb1c58b7b02321345459c47218d006d0dbb74c2c27c797ac878f7fc97e7ad85869e79c739b3c37e7e955dbf37ca686b24dd8abb62146be7d6be7d924b38ef9638a3a039ca9cf0982df5c06058a5567e5b1477664499dbddc806c4e876c24146fa8ee8d1c32bddd3ad23854abe1cf6fd7fed850bcf964a38d369ec52cd6c1bedd99f52cd258077b546fb769cfa2908ef2d39bfef1d2802e179d7da8a8a140676a28ced9610db5f9ecbf2b3a776720f839f5f0be38f75cdcf3d5bf3a5fdd73902930d58c5caba1cd3305ca7c75b10607bf70bbd5417036a97bdeb5e00c2d157d17e853af219d5bef3a8f1437f83aafd5710e7a9ff37b1f098473cfbdd0b93b7f9b403eebdef711a9fe9153d6cbea4e66bf39271299dabc7a47969b87a4e7dbfccd75695b61b660c6a8b8dc0ab3059bcf58140def4752c9a8bb2ec74030745d8e7d97bf9c3d778778e494e8f5c7045246d1a92804f48d2c4507c917e89d5b6f518848be407208e7dbe71dd74d711b50aef3c812bc65e82fcff9e59140ac830e921f82ee6d539f836439bfdc888024f30e926a66794ec16dfee7ddf9179405788eb177e1cca0a33c7b8bc7001a8a5acdd9d7211610a44128d944660f2a9f53614341d0bb5ceb063ba4a177798fc8802a12a11c6beea70b9875f98e080ffed380a8ef9c8a43dad52aadb01410f59db71864c9535909097fe9b916173023f31d905999a73af29d83ad566955e637661d65e77301b321369fce75e1d7915ef85d8e8942da37f22bad7ebc4e494a96542452a9e84f518e1ca1e8ab8a7ea33ee9d4f4e9f5be86941e107ff4d616d09a3e6bc0c4b141ec5823fb74906f7df189904bfc907d3073ab452275b2f38f261d1aa7afcdbc63e37c63ffd807d71de7d33972faf7d33ab7cf5b1bd65b3ffb4704243fded11c7727eddb9977744779b7e4e8d46fc089354e07419e358c754cf3e7a73313582ff97682b3450684de777a78a7c420edd3a7f39461e49a1ada7f42a0f9ef4307411a4e3148e79e4f35d8f725b2e87dfb452eaccc3b5c6ebd6fcb5db76c2f81b4b7c872b608a47df4283aded790f696b7b7c8fb1af27dfbf74d1ef10eca3688f3a63d3846bdafcb5be548e4fbd08fd807752b1279f10eea2179d4f2a89eb46731c8a49d09f2a81e698f20b2f61375ea22cbee379f6affbc6c6706cc86f8bea8066bb728a4fd739e6af10eea2ede41695f79071561acb4282f3ae88122e972e61d9ee8f25658d207bd057ad5f62df13669b9428f6a57e82d3174ef96f3411d20e9f9e77df9996d10478e0ddb48f22d39e4ade6c480132b0d178f35dae75a1a3ecc3b24e8a694f29c96c99284e7be9346bdac7c27d94514453174d0455114456726b1a980200882200882ce4c201b9ee7799d73ee799ee739337967701cc7711cc78d338cdbede014fbce6f679177d8ae61d6a775be9336d6b7d645f6f1a3d9471f8f7dfca0ece302903b30729c832eea94524a29e52d08cfade36b35722d8d9db70eabdb76836c5e3daa39ef185c2e57cb450f1d7497cbe572e90141f073cf3be71c0441107402646666e6c9cd85bc83f379adc6cd6dd93dc779c83eda3917d9073fe77d9938ca3cc027f6a9bc3ed5f8a49faa3ed20d3602ad831b5986bf3948b93f2b2065f7d7822ec2f720b9e42badbe7a97ed4ae6196fc9255f7b25cbcfbbefd3b879fb9f8335eced3f921b56d6df2cfdeeb496b4ed79df9e156c0ed6591bb6753bc8b56fb28cfa76d00bedb5ceb5e7da0c653cbff9266bc3b6cdebb8a7cedd5249f8d637f247f5a6cd020ae19cabce79ee798b3fb6eec97cae5ecec16ee71d3cd56dd0f9e61e59bb5a2fd8cd39ab77339c0ea8c4e955ea4381182471d0213353339a049000c31540303024140c87e3812ceb3a14800d8ab24c4e3e1507234994a32086611886611086010000000c200431c52cd20240f98d80fa372520bea03b32db02dfc3c5c0646f1b737b5671ab412a4bd3d0b46d8338fa132f40f8f97f0e6842a284a96cfdd1076c01395441522d3f82a6e5d29d49a69e6cfab01634d157934db4c0396e954670f0205056eb49d63bfc6974c9b3a92ab1d84b2bb7ec8f3336c46497d4e722abcfb4874887f6508536fc821b4fa23df3138578013124db10b427a358fcf9a2cac1172f72e458467633bd79682c41ed91b536a90b4b31d5ddb59f787cabb1f864e8fa938014d16c4299fcfb881cd59999483f8900b9ca283b8bbbb9b90451068fa0516172a669c0b9ff57636a0fe534bed582442000c630a942173385851b3a1f23115bd1187bd05031642f476c7ba424795252bab50139b366b1a405306c6f4ccc9719f1b67f155d434e3b09921dcfa2e435087f9f8b7118c2b44f239196a50a51e8c719c31a10b57a80a4a83dc42045824254da68bf187a0a7ddc0006a67c81f8d7b79a5171320507f60b9825d30ea3ad38a751c169c4e5be36f60cb1d66c30c0eb092870fa0951e872814f3abc3225b81f51ea6c868c0cfe5c27dc12181a59f5f1b78dca9fc2bf341c594c3c0e3b01aba9e9ab10319139370dc491baedb28c27ca48d09791302eed9c8014a33b9d86b6ee4ac165a5058ae2fded93bec92352d0696b16a8a5bf502c842c3d6f7241e152d5142029d8dc388879a6c5dca08eab615a483e87147525290c16f38434eba1662fd488b6243da065b71fa4f00c76499a503193fc16a7d8005de30c26316d0a833392e38913ebfd7084331252c47ce24864338b0960094bd64caa963c24b9c1beeabd95ecbb6121697eaf734b3391c6ac9af1f4d1731ec476f3131b16f25c8198a9af8489b787cc6cfe572ab340d2382d2e508241d27518ed748f06eef1af2d909abafae0c5b92601d650e0ea8204838611a26f1c6169273853980c39177cc37c8bc09e1dcc129303f7c9817ba7fb910736e3ac80937278ff91180543eab0068180e8dd7a3d5ca04fced799bc12b078702614291a96f1da2323c3660de1f3bbd6263617a1980d2fa29d96a4250f52632363131e6a0ea090a415967ad27738a334ccde5a94338abfbd2382a7c33d9c3d6c10f0c38b43037fbd3c18d1374ffa8645cef65febb6c2fb11069ee80c7b970a7e8ff569295292749093c1263a56f1b16e0a72eaf490e80584701f5eca3ac1ac0b356c3ae44249a42314bb8c0d91cb4cb20c86bd8e0eebd90b1da7ddf774a632f289451149c6b2dae220b2c8a4ece63fca9bfc56ae532a9ab4f1e2d5eed41abbbb3a8ddf0c0f33830ac31982157e4fb8d9d7361b2584b6c1e8a8b1c1d677cd7869aca31f2e2a72f8c39ffac0d638db85105cf4e368f14b511a7508900b6ce666c46f84846a5229e83b3205c87b759de873182ba204ebebef8e0b4a298737ba3d1af644a9b36cfd1edef8500891e781fdc9bafca08592d73de6d2e2c5573fe5764b929d817b5394b756da5276aae8a0f62e647d259123f98c6418c900d0175afccd67c6d64bd222a487440fc5a6c6ed63f3fffa346859bdbb17079ca724ee535f0a1d1af0200df269c898621df1815527a4274ec8dc3230e863158f6b9eb96525348b2e3444a74644eaa9cabcad96b0e12b7b138115bdc82ece7d4c62224a569448681384e8738495c60946fe9caed286a639a21aaed28e5ab463c9453f47b1b304e359abb66e324edfaba71ec50900ff2d4f9df249147b65bc8b12942720b846abbcfdede10186b14c2f46951a6fd37ee65d0bbd0820ddba418813d07d62cf156bf30610e0a7d6d842f3f76a35064c44b32a06227df918c00c7d08d7097baeeab8c624d80670ae83d966f7bb11a88491b95f3e87e3ef13a51e8fc352da9ef9ed75ba4446cffff645d5bbee462381938c6c8ce9dc25257b7c33860a3f79a160867317139858ea3472b5a8960fa635d10e6c0284907c2204a9d3b974e105a12dbc6d741ed924e107eb2908a1655f1e998451eb12a8b0eaf12716d96ccfb70fcdfab0f3253cf5f9e5ba446facc66777b63514acb870425899806ea596101d5340c813baf06eb94a7f42985cf290a2036c12bb4b744292fcc8d896c93420a8dbb990b04101904d8c52f909439a3f6b1bf1a397c75ce4ff4a10bd321e32f50c896e4cb5f9fe148fcd9700c7e3f38a0871935d2d3c9e048ecfffafaf2587ae45bff8a2d289dd8d47f7b06fdd5268d4a3ff289ffd04fecd8f6e8c5c9faf11d6f6fd4330fc59920fdefc30d27b85f5d73a876193a657247b1116a4d88dd0f0bcd59392629480356ab2cf17a63a8ca37ed22a32751000335a3d2dcf69cea7e0384e53e0e8c6b4c79366e36504d2ff29d7a91744bbb37aa5c9d12f9c640496a7b6cb1cfd0451cda9917d0e0b97fabcb8683f607c9d1b604eb4fecb4aa48d52b0360a22c97aada4c7096c19099171f4c07a186d381f51b4cbcba01bb996b9554e059b9e0478645793aa30a3336925a3eb1c7705e637f72ed2c613f5f8072b87e48eea9cb45e2453a168bbf559b39059b0b18098494b0515cb35c830a7cccf3c6c0e832c6b61788e0722392361a643dcaf9bc185e774cd28dacd887daa4c327592c72822724bf16ca34680c22a181f9b470231055ba0661036fea389b93a9664a76953000e59ac28b1333357f4735b530d2d7412f224b67834c5832090394841e306f96038493e147d6a24c6611e268bb8b838088c51c0c7c42f282de337ffcbca009c4be2a3af655b4db8d0898c0396a8846aa9aea682b107034fd50b32ba44fb083a12bf0cf76bae99f4d95c07ef9a60a147d43421ee19081971ae9fcbafa604b49bbe7e14e997149cb875bd5f637052c804cd1b43a4e83efa7a40ed5eb2d26436fb374a685b5c2a6e87b44a7678d66e410ca8224db1df70ce8890106a802807a6c01a86744db1ce270f35865543cc13e0f6a2ec7f2b829377b660ad860382f4711f0042802541809ef5ef222bc0ce444b424b658279930de78ca84e7b9106fdf4e6210f6f294485d570c7a1d70ad9ef721eab3410e4c801ebdb406ff20e262a4647624f95c4c651e5dc463c434d93181cbd8f0d212ff7a179344b0e62015964adb30a67cfe6cd92186507ba3057a7a71c4bb711b15c3ba44426462bb43d3b9e893af6b2a8bcfc4489d0b0054aeddb146486575b6c1b4b2a970fe4363934c0f15ecb6d9fd80211f87c575fa023b685c0a32e2cae30f679ab7ac5a2a4d938b117282a896feac5c7898bf11c3e9c2b0f6dd224d4c9df4b84395c4f16a6ab5d8900f834499202c9f8c7ef4665882f801be5c7c24f138f0233a75f8702b105a15d9a4e94bdf56973c654393939f0bcc99a588841a9f98175bf69992932d57828c18daf7ecab2ce2131f858a69fa85e9a08b7f29b2376d6b159df51798bf7c5f139214d59a03f304cc360dfd6305b810b12a5e98da0432cf78fb7170a3765400dbff9c7400560453eff4c900e827baeb3f5af08ac51024bae4a812fa35dc8e4a79541a323dff7c4be8030a69a668bafa66e961fa1f15e6c825cb13105224e745582f280bc154a7be6d0b98205848678e9a11906fe4ae9e5086021a75314836b1930ff10eec9d89aa9be8cc143d083b2292279758786ac9dfd5d3988283d82aae45fb6dd02c613ea0697c35ec5f5846db8eecb84600a20a86d947e3b57d992f00d6de082449e12fca1e6848d8c74668c266bd9ffd673baab27c7749ddd23034904642bef4590edca2d370920a194335b7767a6522b0b16f27aa1a5d8889d0a18cdfc359fd39d7153bce269b9b37c90af5f08525114706fae6e692740a344090492472cec7eae86768cd8e2406efcecdf4280e3a03349056c2ca247cb74fd07730f5f02988f4bf4a9a3562a409b7e15690c46a07e717bbc90c7631f9f0a7da046d7c4442d2e9ffcf4c6becb6977f81700bc277717ad9944768494f2e30183f4cbfad1d317f9088051facbcc162fb2bbf9b6f90f6e7b055b7801018070376b1fd09701098d03052f37dbb647badafa142e5eab0e19ea516e033274c089e05b7b1503a10e53275bd4727b8f947d7b9f6c85a18babf01375f81bf474afe58fe2fd7e15ac01e641b32b85b246bf593dbfc18436f6dc97c11ea030ed77f13d17536840a9d077a29216079042caef39c25dc35dbc5f28daaa8d31586111d9c2d642463aa2f17eb562d44600eb18632e76e35e55d40900c18bad152879a2222d28141289879a94d216e60330d39d51c6fa955699e949335d4249566ab436265e40b7863b439e1a13f6d99e4e0ad8dc77d2f29d0ad3c884ca8332ccc2873ad907064054b704227c8f424b8d237c6e049861ec6fd514d973b879a83ac4e21475d3bccb1cc567e32a0c92a50b14012a487a4504f79d1995b9a1e90ba534b34fe4586711a81fef40a4277d201ac6655b20f9c4c588bc89133f11dc2f0aa0ce71e2739b302f2ad54778134453ad8e001841306f36455dfe1a0d165fcb08502e6719f0352a9e6f9c34f10a2a84404b7b56704507cce052864c9b7dab7023c4f3d25ea03c4dc434563653857e147de5417dda63ebfc3f349eebc2e76410285b475c4e389ce740a4c69748e66a3b098158e91734ee7b2b355ad363857250ea1ce18733feeb2f35cc4a7eb091d9163d22e84b622df62bc56ae3b228d1de11c20871a16d4cd7b92d4f749cf46b9bd1ee0e15c50e370a75d40e86b86c7dce10bcb5ca261a917e68c4361b9be4c7c0b57bf9a8b88d7c9b15816ad1e99339c6ffce45489152020deda8343eac8da6d311679d90630a0e19e5a552e708050afb20cb55c18fb3c3c52fc1e5cf776dec2aa5d3677c828b07213c9aabc43774aed044abc02c3e00dd97d01177484bbc0a1c97b80b02d6cb5aaffa69a15cd5128c3f6bc958b20e2626b42a3004790085beff8a2da2439082460f41982f6dc9b3303e3e017c8e00bcaa3002d80d6f41c5b99ac32d3013e25295ac25d02e3b37b40cc95f3b9c28717020d1b8635dfe40823927e64455aff9d51e501cb995ee1132dbfd7da1a96dc17d4e19cc66a57e42ccd4de2ae266a10b9d9987b5dc281128c1e053ed6623314c81aeaf6ae72059007e68229102fbe986526d62a058faef918a58a98b37ea616dd2869151fcac13f9dce68974d25a9d1086298397b839c5e08b30ceb36a4866a278ff817b60644c4a11c77f92572e3886e553a387447fa019c066c061494f33a104882db20c5f2b141c1a73229675b2dfcfec9adc9b98e5dfb4884b72f5b0a4c1059c47e6951518b9b85c51b06c62f30899c9cf1d8f80e7009188651d6440866bbc4c1bc7ee8c2143200eb712e8344b06740459b9fa26a8a033dbcc618a1d906a6a31749efc012ebcf63ab44e2e6789b25ce39a98701c1f3b935127ffac6f3b284a92f3c045e86191415ba0eeec784f5d4791cdf00592b775c387b0bf40136d88bd503c525e524f204a62f80d947ec2e1680363952d676c4916064cfcc2511b83270242c465447176770007b5cd7aa11a5c3e60a86e9eb1b0bd852832e84d45b5dacdb4db25b26f24b0ff059f486947c3173495aac70212d857fe5b6185d432be8902b51ad684749a43a51eee3ef8b51e94c27b8270928e3e0b19441e07644e0745139450f5337c8456b285d6493a0c12449554b83bc2407741f3e4719ad1b90104fbc59a24ed7259602e2cb1ca2848007ff295f48b803cbc68cfa36f86993c0a612360f2d7400c9ba93a62c8510e7bd0d28e8271c28a397c8f9f19206430e01b4ae4d088809a4991f560517e29c1a6c511f9e6e66f5e0a2bd566bfccb218f3a10a6d506afa99e5b1d077f427f8e6eb6c13e1af4e69836b66c4db9707227386f3a20076562385eda75969a717893b62b83a17f4067bdd7b9b14cca728f0d4683a3ce85cc03c48613c97e2ecb7486f35d179567fc65778b7030b4083d906c3aad875f7e91b5ecb475373e4362a5399248dcfd4002e41ccdc881210b7adc8e149475f0266ba799902298f32739301b76368ad94398783a0d444019799e7d214300e0833b0bdacc0b4acae510f36ee89c06a5c000b3a1b495daa3ecfd8ad1bc3b4dfe8355f54b942b5b935076ca49e405511142812e54f0162522ff2c8e86a8ad6a28326442fe2651a457075d77bfae2c1d9eb382cab346499bc929bb27da6767d19a4f93ec279b339298f87cbc31a4ee256d9f99a97a35ad9be6e2da34e5ae26493f68a12cd96351c995cb20ab06ea6e8acf14f76234f86bcc5eb5d244775f31686533986d7a34280735c72646cf2139831505c392a1155d7ad63861226978241714cf875d98c1b71af188cc5a5679f164522d2d4b0dfdc7cbb573709b0deccd0cea01ea4e6d63a2e0cbb5143037f089b28306334ca18e9995e9ee94574a477ff245a918f6c1846a676dfb80f3b800f334b9edbe5cd63be1482c15894bd109c7195602b7ccd45de9c58efc97ff7be17726f049afec455b888ee2189fd641a801a90925f14484ccc4d28202515de24edf177c6c1de88b0e8aea25c749a95700ae098c0313427214a0816d2b661a68248555a41dbe69602b5a9dd43135bd018f74ff162590bf075c5ece05841fa7a5a84d709663833a7152403c88e9723e70692fe9a1f0175ab1f232148bbc88e766b82e22c6747e793ddd19d5f72dd1414480d3a7202f1106c7358fcc17efec17380c62964847c951987d64703e14f9f48271ed47f1457a30f0d53ed01be5ca322b33253672ac47dad415d028748cc3013e2699c928f4f664e17ddd40c2293929ffa786268b81e223cb07921c7ae9549bb1e53e8aedcab387b32c9a7f11889d4383ff4d9ce40989d960a1d20e749f41e178b133e483bd80ed4478aa0be033d55d61826a09bbeb1f10e045e8380c4c6400c04bcd870b8a8f39145376721c824b333dc3527e3610b7a8c481344b21d6b8f0ac8b735b69df22e3a7e9455689c304221570c6d133705f9368e7d01353033464420ba862323521942cc23f1a68cd322c6c9f544ea4cd189af0dc719285367e7ab8359d55959336b914df7ca26c7e676cef524586b5a01ae9baf34589e7c2b581ad42cc622588e996d0e809b299171c9452c91a69fc65d611c56baecfad5b239e18b5935b7fd9f575a2371c72bf1916533f01203148d22d8a08a5fe1a7fc186143e4a5424799858353231a9826a395079b28e75e7ccab9e9b8bdaf4263e7b2dfc89cdd827c7cf3efec50f86b5eb76094ff4268d9faf49e1db5075b10727148f024ac9af5326525b2d8f26de68c22c448ccee7db2faafba9653ecf7c65862650df08a6ed1ad2e231caec1562006463b72a60543b10942e6a8176f24ba6815748ef0812c8482b50a54410011c88e52f9c60eb05a1ea9444ee5747038fb13f2eff53d27ebbbe8077b1b18736b00d43e90c26efccc0e7e538350ca3851f210f3cb8086cc68cd9038f9695e1e4b3f1c4d3d1e884e47d41b77034125352f118470e1e7d53a9748a934d03e8b4477198195c53328ac33f0c210621991222115b9696a2c81b10f55f313856a0386b86a003acdd17b41ec8523fa3614536124b5acf819bd75eb5213704dda829bc85d74a65b172bca009da1b5ec54f514a9d30d0c0ece781a483fe752f8fd2ade5a42c84e4c0a1300e69441a3c0850b5223dad0211e14132f9d2da5e16b46e55c8ecf46054060fd40725d16b145d37c0f2cd5a1765217c5ff1023241cb30ca03302c9ca45082f098815dc044bf1f516cecd0a07379554562ad950cf26f799840377d603e6f3482eb83d13d21061a4bb419a0b22a2ad52124aeb7b1f7e42ab326163eb697a93509a820e83eb144c9be8c735138020195047101221bc7bac483b5c99a6f196f34aeb91c809d0f1360cac89f850fd73bcb23d3e9c2634bb4b8f7aa836b29215f08f601f4a834822726a47498e6459a431b2b31ba8e204da5137be156c666c94fab8720329256292c7d93ef4365a7f258aeecd2116ad226b962a9e8edccbeafebfd07f9782e80e85d0141c5e8b2d3fbd20d2516519fd53126ef042003ecbf7b8394bc9f43117c911154abd5faacd33b3ed31d47c5d8bb8dfd3d323e8b8be55901c9dabcb29a2d2b3e7787136ca22b8c3253b9d885543adacc0a9181c9d421d90756fb5e8afde4bc27741a71425a51a79bf5207664690feafac9dc066f990a8055760e0aaa0559120b0a053e050a016f69dc4c28ed0a3d55f5078d96b136d4f823c1c0f74093c742800cbfac1c614f82cb9f9e04eadeb3feaccca46000cd5291e24918411a0c9d8231d4f61c5e7beeca0674b722c934d53236f480fae3f3415ada4677e5b6e97df42f412d25fd2c1748c8c487c9509a6243ca1ce2a5b2622891a930f06ff221462e7209e6c7069504d4107695fdccb1801627219ed3ee23c3dbb42770543e6df2bccb2ee25c56ea4e65c632642f6ed0a729f4eb618e6160a7968c760b77f41050505cf29739ae30941e25667dd1bc7f28ac5201414cbd55948f1a38b6193cb491e6c2cef62c226026803d417e7bc5b20311d653ab18d0e98260c88f7df7aa10ea3f9a1e4a0761acfb6c96f24ac1c04f935c0f28b2457232c958dc766eb16e0b2b09d9e230fa769d49997071e4de0362f9bf9caeb58497cfbce2d8ff694e6f6f665aee96a30c13f882016f0e4e07dcb78d3d00423230972b3d21f1c2c55c682bba906ffea62f6657eda4dc3a28e542b091333b24dad6c0ff63a9b994d663bb7d4d28b29b3053e47a182e12e9a443d73839966d924ef3e8966d7d3ea4621f361e517b26aa8f110d6465724fa1b89955525950c2e668f1a4b30ea053578381ca8a19c5ce62c2da349f0aa900a335380a96c215e43a636c2600f58b89538887fa6f57f4647dc4dcbff5caa8fd6471ff492cfd41376b1821a9d468a5a2d40143b428e0f2821448c8e18d601e3abf3c3f3a722a8eac8cbc3ab9d88000b8efc250de3c7d3e785637230269cd67aaa95d9a0cf3ba7e8743cc89cd630b59e6d8b5bc88714e6c6f656d016dc1beaf8ce5434028002398148bb403faba14017507c71361cdd39517a16693e9c8cde19216c4ec87e46477328d4f52365e8abd882715dc7f960dbb9d241c61298b0782521c9de6c8d66d6c8fe6adb79dc04729e8b14cc6178e05ad90bc9f879952664fd1ca2a1adabbe51e856c7d1be40cb6a1cde605237a188ac6699ffb09686dc82a8991148e1688e99f8dbd38d85b40dc86b333039b80792c0a6001edb188c156e7f7b0d2c13d8447fe5bd97786100ebd1b24f87992014dbfdcc78875d745560b043cb096da79f33d3bd40ce29a6eda0c39464c2b823118aaca132f9d9100ef9c991119c2e4d1636948f005f25d878478f0f317387f37bdfa3b1c7b74e51951cfcc1896c112786ee4f965d2b2491bd611c49a36044cafa5666bab4d7c4ac4b0cdc3f835877437ca65f552fea781c567d4c9d2c0a1afb827f50d3a9bd6620e1dc285a9d5a2417ce7adb52669cec27a421d6f4361c4709427208a4cb0a634f7a08cd61ae4de26f5457966fb48ed84d3d938eb025c5e3bb8d1d445f0c75a9aee019a4189576ca408873edf34a301f053162764e17151d10b0e54659094a3bea2a93502da86f0a17d8181e35b4b9fec02942e47eb17b74a5428b3fd8eca8645524a8a48c497048d3dfd679d9a99e2267f10a2868ef000e7f85bd3869a72280040c237bbdacd3c488c6c038a93ad9f0583c60b68e6b4446670b2284231c11842d0aadb929d1431a0febb051ec33a4cafe22840c826295c0f542eac265a8689daca47329a983d0de1f669ff9787fdc099937937233a8412be838f77807b26bfa2b949ef29343c0c7b5afa9be4149221764fcc1a52b201293934c8e69b787385a3a98c364e7afd06c72c594889763a0f84d3e83a9ea1cb9fb06220ef1b2ab4c16ae5c7909663f39ff0c470a404db927152c05889543cc7005bb6f8ff70d4bed81b5147f1fbb4f2700bc6fbadc80148f4aee289ee8df240203b25c7cccbe317c238ce6e8f77a4e44b4d7f2b625ac823ceeb2d553d9c2323a28531fa7b70cd526c0b1504c0145ea0efee2a70bf8ce46aa1584f7003824a7adbeb746f544a1298b2302e1bba4e07a483de1714a32ad81fbf05500a70c6aefcd662b6791b18d0734ddbdb64f283a4ff409fdfa47374aaafafb3465289332e20f74c948e707290159d40588722ce4fe61a988062734e47a4f1e086920c2c4bdf157cc206a670f1cbae26a578801da111322a64468708973e3780d668dd90588add099c4840ac5d54afb40e047f3bb9bd52e795327a7a0a7e98583df8d80f50240d15a76aba88e7ee830c30014aaabd2b0981a8c50de13c4583d0e39451d516be6310ba87741789434c189e32b724924e669a69b2cac9a228a385470bdf25abcf379cf5a94fa84fa0bba2efa3a384c0bc304800e8636cb8b6d24abd890af55b8fb4d4499b89544b22336bcb04c4820fdc5dbc8a428770bee3936b1478e36cf55607d44f59688fba01b995e54a24d8bd7f875f0fd8a98df01795e115c991005dc8e2261113687d610b445a596da35745c68b7dc150548ec81a9921950590538602dd85a5dddb4001d1c2e37ea4baf625868f8e6d8ac9119e5484a313cdb8eeb6530557775e00c09272135b993930f412ed0635ee4e65924f293d8e7f99017ec37cb41e5438d2122d2d4e43c7b4e289aba261e82d73e6a807dc5ea6e01b14ed9f7a3cf83c4abbb9e53dd12b1a9ee11642da7747cb71caccea03c4820235cf99498540e25e5f12610799d31e9b0f17d01d65eb10b24aea2d8e71d9809a54140d98041b4b8f1bcbcd082141f53541902e7ea5a1d32e967a8e711caaf61c1cd2cb5d4604532e2c69c7d40047afd6c5c69df593595a3236eaec2b481f86e0dcbd99e857a9dc24c99262597e76363947493d941403b2cefeb117c6d79fe6c663fa93bcf154335c28f6e65cb7c802c502fb69640f9a580aa01d31c446d9581d09d2cec45f596596c333bb24999e266833338bbbd621bb28bd5378ac4742e2e8634d2f99269c5012e3420deeab6c98fd6a725c3d44320bd46b3d84b11e234a41f1f6f4bd5d38b2cafc89c1e4710080a89a6e14d93b1809d9d216dfc4a83b29512fcf20a8c11b1197c49b42c4e3040baa8d5faca87dec1ecea146542fa79b08d976c6359d2e530253ce3442367f18e12e2d7b00ce1581528b29f87ca85b006c675192ed1d5d7785f723a939ef911a1c4c2fb2c2aa09abaaa8fb52fd3880616566e85842153da86ed48f0a36259a7d2cd4315a05dbc2217438ddd8c069f42c3e6356a2b8b0718bbfce63067b534baf27250e4f7cef252430d02adaf35c1962edb8116aab0c918e36cefe05374982753ffb80d0f867fe2ddae359062d234836b5332156049fe0e2ce210d65c7d0679d3455febf877908058d75a33bc34d1155e5614b002b16035be28fd492e284ff9b2543a95252fbfbf3405263dcca5495f3f310d92bab89023f95705c100587c35b222992ae7002d8d68e1e33e9fd1ad7ad0fa7fad9b0004c76e7d0f08311138b1b319b385c9693c9697042e82764946185b668cb5122acc0d826e9f6f8b4685becc55c531a38222114199f4f77946855b98181976685a4cd82627ceb4110366edc9343d1094972f09582a6766a05010abcb193d2deb2d37af155d28eb8032e8b086193136b0804621581e681371ca80db7165710bc4a032a1841b52ac852454a9d9b1609066daa851f34c766cf1c5a0c15fd844d9b8e2944fa64e4b1b0ce07785c4eddc14880e5bbecaa66a0fe1da81cf8894dc0166fb6ddc14125a34d9306d808829391871ac4919142ee48c40e8f3bccd5a06d746c0140ae26291d9ee330557f7c5c5421cdbcb497bf27a5006fd147f63eff544707d1e599a6d3cdccb52b13e7b3d654153b0a69c04831ba602224785f67f61153dc60b9220712f59f97a386e378010ac69d032baa2894957c9916c63c9aaeaa24175fb76a67a830c442b864e1991730f114241641eb297f133cf9e290421556db3e97fd04757f88904e27f4c3215523fbdc04a2c49be1545d3ee52eee72c6d2f4a3110938c5b4d0d277cb8bb564159100ea1f1c9a7ee5463cfcf3f3ce963ace93f6fa662b9017f00e4a868f8352a99681e38b04115bd01def38c7f6e07e1fdffbd6a8d22a065371b395f00ba98f954f74443441d049dbd9dea1083100ec143e63ab637a5339c23ad43f820653f567d981afb92f4fb0c3c3ebc3181fcf16eedaa7ff8bcbbc1480acda5520dac104d03dd4b1af0c97210e31168286a591aa889f09966329718f0d36963c71f9f95173281d69f94df3462cc6b75b42b9fcf85aee96164016e5d14dd4c2f300700b7ac4bdcde6a65f989faaf80087d6d355bf466b2db139001aecfd1e333006cbb47066fb1b65d2ed54026f71d0aadeeff602d89a0ec7200dc0658be932de10f78b719366b3d4ea514dfad1b145fc28fae03df2e919b4c311c04b1aa5fa8df46979bdc13f8ef5944b5f0841410a603e00c04a570e0787b9534037232078765c2aaff246d8e00d879e90f44bd790675ca399f0be2d076c27e607dfde8b5c1036f9b5eb4d475566ec6a06772988f9c7cdb294ccafab8b68d1029ef4b4f943e632b9ca6cacb1d78de13ec3f016fba9a400d507ad084ebe518a9ccf70768417e9f08a295f419bc3326c75f86fd34b357caa3a23423e01bf5cf55093051e58aa3f17d7f48606e0c77d0da972b0245467065ed236edd11d70c20d84e357db1cc50fe37484826580929a869738a6e612e4318230741450c96c2182ea25c14fdd01ba03f14335dbe9688001ad334bc9d97fb2d56971d7a9e14f8ff2fe453933d0f67f34ee0da2e39e39df3cb35bbe24ed372c9d9faf2b7f6f8b7cee4be22e3a2c8d91a144b0bd60cee21712bc92792a02f315bae3202def9804f6c406701d7605c004a3bc1eca316367e4983f8d5149f93357985dbea27ead810ea4e95e95a63b65e22001fbdd713ef207dbcafceb5603c6ac59026f414a5db7150036b52067c4a865a372d325e2883e4187886d793e68345bb250360eb3944b38e17caa60871f72b4e8e88803f7f4dfa8c0267bf15ad50c47e1810b57488ed5a5fb12cc28870f4ef9267efbd4157be6b14be162632c6987933554ed791c86426b0cd8eb5b9b6d368ed715f13ad858d40ea35cd5262d3901a4d83f2584bd5601f1e77b2f8996d17eb36061f7bcdb810dc7245d5673d1b56078ca7c2238f6bc5f7ce097b7c481a87be064e5ac57144dbf9c21c580340ddff2894de13aaefe32d9cf396cf0634bf382d20fa6695d154c7197c9b8ec7506e247d98d3df1e99fe02ab492b34d32a26bac2ce32c90c234ad18221e587a05ae23e5359ac0284039a1bc0cb1d8f645a75b464cb545c2d748940a6885b9c672b35a4641e340d4488201dfd4e127993de473e4dcc83c159fe57fee01b80f18c36bb4db41c4797f5abc90273d967800de7cb769e535edb4e7946fe5a41a483a51baea65d3c3b70e24d5c3940a809f239c88097dac2997a6e87dfab5f27d7f24901876aa2472ba3d69e480489f91f9f34bad28985cd01fe617d6c7827a13dc488adc3e89bac0df29abb54389fd666868b784e5cc25079c0e20f6548aaede97e0125f512a6ea302a581571664aa91fd86ff9de97f27bd78730deee2af36d4666c07268490cc49c62b6e3ce5eaa256f08b39aa10060f86e8204d9287480e4b621732055d762bfd7f6b227a658a76b1374564be16a35a70ee2b2a7a087b241e4cc1b2de8fe301a902befe769b6b85ad03fa1437a7127f2eb15668648315f18d6edf703d65d94b5de4709ee70c54c30f5d64fb692324427fa37e2884b40457c3d9a9ea070dd32d642ef98a95bd2d7103c361ddaac2366768c2a4588885ca84ef49ed30a620bd5b0fec9e50a8d9e98223425604a6173a597a0e0c3520c6695981c0b3830224d92fea529e93106ff9f5fc3852cfc2ed6a41a1a8fb5da023e05ade2af9b9bc498ec31638be2b226e3aa893785508dd3304f9974b92c31da26a78604ab35472c9056f437ed387748c23196e9ff1193b0979efe9130d33344160ed5621f20509c359ad0517ad96883f8faebbfc795d2d062783819a3496411bc5ef86b059accc2eb5e034da126a17aebd366d28938cedf084795b3372e3c9bae5ae0a1164f8494a409b81741026647f8c37a54ff96c342183a89a31dcb4fb9951154735d3d0a3b3611192160bf5ce69ad7b09f4eac59573baded954a3d5582dcc52346d30036c5d930a8f0a09b68cca937e181e44df5bda0e10d9908948b365b970ade749336c0c0f4f1c269c5f93b61b27e5cf22de3310095f1c190a2084e1471b60a22ae41e80c5c2ba892a076deab3bd75a45d04593865604cb6a64ac15635e35de8bd048edb6f0d38554996ca2146f663d42afe548c2393070b04c5e8e0009fda196379f0ddce8e392026f5d116dd889cb9058313a532d82d117a85a86fed278de34ad703c5d633010c2a8e18f2474c7d4eee97994096c1e0108520110d0e06a208bb224f83e88d46185096b3e0bbfd44b74526acddb4fd824b4a4d49cfe5b73817b1ef9e33200eb09cc3dcc61028528b63451c01e078167ab04f50dbf70e8f68e1629460e4edab7b7e037f0691cbadc5b9c36655bf0328f992cc0cddced284c1faa3e1dfef43a9d91dbae9dc3a64486aff7434c39ca5e6b8051d454a9806c6c23790748a0f1eea5e7f37ac3044ae3c21ece803ae3ebdcb964fbd27437f463469659b2e8c2aeb8b1c70e3a7faff68c7956abaace1f3bb6e81184afd2fe354327d20d818ddf78f4c7c81747ce2343afe07535e65ba9747b6b223bdc7d362c06aa75f962595041d408f5e5a65474db4cb7a755d349a1917989dd1949fb80630b14236bbd60a313ac405f09ad227936d8be98be57be68d73fdef061faa7848795151594f0d040571ff44776bc9d79dda81a939185e67195f67f984c50258b8a70add15d6e8ae310b1ce0407db687fd739c9e5fc90115044195f23f8cab77ef195fe3a49b6862b4c590de31d034526481795c73f02c3568002ea85d445fb6b1e4dcb7321087113348c84f384b34df16a7f237e17cf8c543f463e9239f3bab68d04590bf17f0f58ee9434c1c29ae782ee3e5dc6f0798773ce79b82ff15124356fedc7f96edb9801eb4e4041a2021e312073b5318744c1a1c6b14e86e2cf99ae5de89a291e5b5293b484068ef72cae436abb4c0b6d03615690d43b08581bffc74019fa8e3444fde35f91045daea9fc478468583b6d571ad30ddfc2304cb15bc04c13a46803bd805e660316d5300e3498e7c1f4196761aa731011d24d9895dc2927e34adc7237ee42463585274bbd5dd711e3a968798d2ca294f7b48c81ef16878c0854ad9bc449d81fcbe961110a57e99eef1858a5e8d9f62d5fe5d2284d9da4aaa637daf150215b06736ab2c5f0723d0f68e79ec41521a588d670c2ad0dd0349c9b64c5496c466517e077f52a8c8afa0a59e551efb253fcd3e554fa1284166098b06529aa97ec918ec4e479388e5e18dc864850e5bc05842252bad4ad93edca857ae6ac6ec5e1c658a488c1b06d692062ec9a63ce8f87e2ed2d1d493ecb3fe8993c42284f5311674219235972ecdaeb1efc74feed50d3086f38719aab3991c3c6cf5211741519ab863f6b4d5f4299e7e832a52b30962c677baeccd79cc823cd155146d08eb699d7e6bf7a089cd5a1eae84708144c64578d20102b1010d7f4a42ac0a21404b02243a01965efe8371569cf7f59c1bc894a2b59f7a30240dfa8157f02e3af0effee7b2b03097f7e0a3689abc8b5a3414c921155d29ebeb873693092e0de1f15ea5f123ea24dedd0d159041f65db5867bee85d56f9248ff4b0f57a5caab5461fbe5ecc1b9b524413685db363589780e7daf644d28ee37f906f38fc4336b4ec0a1b7ac4030f6ab9ae35ba7cda6c672dc764e3edbb60e9d1be58bc870f02bc4c159dd16cb5eb713bd132de1f23095553e66f028e23b0ab0d6fd0193fd3490b0e402287e32419e7cb668d689d25d1bc3c6d0dd9bdcd841c087d8338a7f4b12aaf06c61e799808b5a80f79777b65e7b93b0ef3b66d2a6aef856777ab3c020cc8dae28b6aa6020ed4de4cefad58646e4ac0039b6f0343469ddcd1681462cdc593000ed0867d67a46cc718c773a4f652bc4cfe09d6759737ea995235285b5e7723ba9dc52ca15faa63cd342999dc060f6323001778535acab5afa40562dfa4894a71bd5ffd982136e9844c7955ce9792926896b4344941556a26edc827ec14519845e723ab0a3717efd5c7df22915a050f4959bd4923116b6f13c9ce68f87028926d5fe03a4376b690e63d00634b9b380ee79b2c7ac66a063a4f7fc086be5e874c61e0ba692cf0b1e16302ba1ae2bee104630a9c43c4207b7e99484cb4dec0915783306f9a08049d41cb2eb2ba61ece541598f02df88062c75bfc9064c4da8f3c87cbe707324349625404a352275daecfc314927fa5cede5d018b18e75dd5cabe6041c6874a8c48cffd838d4302ae0fd29be986bffc7b9f450bfbcc1e64134a13dd75001d42062870067017fb05469696e7071e45d1628fbd024e867f53c1a5910fd0bd8c95ea23ae11c2f81626bfce1fcb3070024762417b450aab1f82764f8ac01ca74e552882862a3f897b0b1d3c7a44a00a7b48e73c4e9aa35a9f5b39ed7600b76b5a7f8c57c742ef7712d3bfae7c0377ae182ecd6e8d4e5de5672fde51d42413d1bfbd573f1344a213bdc896f70c8c84709b70e291a7c38b4bb23c49751d7b429d33b0e164982313aa64d236344af68476629c4d127b071a44844e1ec6dd6a0a1bf91ae437db1ed61deeba9922ea642827d0e32321d3163ca075d782bc311028620cdb5de10b8e4d45e1b62abdbe853ad875c157f34c8b67bf48e2e651ef3284a7e6bb356b72849a744d7869033106c2e735d3d3508403bd52c010c16a41b579d0b822e808e0c583f4f4ae0452a78686eccafd5664b524ca77548f28ea33cde7006ff27ef0db2840ecb521fd2198668e6885f4c5719846a7acd9803ae99246e15e4e79cd8db39a1b11b5322c92ea6cc49dfa2f2b1674a0f35ac9f5e63b8a0452cbf80041406cc969dbdd3985daa9cf92ecb216ce5a81d9ef0cba09e673134d1e33e8c5267b35e1358ce2e49696f40af33f4b5346096bdd3c50c9123431dd1339df1771465ce71ab145e6cd0d4486549e53330d74a4651c0869382df9951359a6be34672d310d29c88a6508f11e073980935199953a71160af7e2a5c751848ebf8124e3f623f59dade4f1b947b06965c7f4d6b79b61813fcde5e8a27569f8397c3fbdf70ed4b576486b44e9e4a1a385f4e0593888c4b1afe3a03d778e2a7b4bdf70857dc55c6f03504aa56569ac66f9a9f8049eef5db0354c167423ec69359ebcc80f2df28420a17a6690be3cb9fc58a99501b4d043746a29a8eecfd1c9276d2a53eea1a8468715697b081f2c8eb51c66193aa7f81739e89be6be28c45f092000c912bc22918440a6ef3e798b74075d18ccf2b9dbc055a4498012801edfbc09ffbe69baf4d0416f247685d0a3f94766dd48cf45653559e7c7e5a261af00146e4bfc7143735e534fcb52d0ad1bec84206643fa5f3fe6028cade8f5c8cfabcc46faf22fa574ee86737144a5cbe668cf585375438e6c32d0b1ea19643c12da7423e895fe7bae83c5d10ef0b21c06493eb8931850a4343a9e504b709e2472b39ae4f9e371d20b44b38b073fe8dad5c9d310da7424d7e8be2eab5db1d6ab85cc8dfdf1741200e54c67179fea4075d9a9c7a4f8455069f059bb39d020c22432da124a9b823852165e79cacb30f6473e8afcf8be954e5c1a2894a2c68cb9ba8f5458cae4d17bc89502296aade703cb8493029f15c27ca849215155e7e5921ecd46ac42052507e99af3e0e2f8e4747b98f3339cbbff1f0c457b151c3103456357ecf43c97a0ad8883387ad6d550fe7be8588096dbc7482d49df3c71a68d4feb604ba1038e7be6d37efa4cb9736f2c7b2e84acf9c90bae2f6b490ccd7f682ad6cbd19586205235d03f7545d2b36a04e84c9d61c835ac5a58aea009809b46481f1c79c79a4583be8c0df45da1900dc60d5686bc0f1e55d053ab1ed27b5f036933eb20e24bbb6e9d580eb3f1920e62d26bfba1b8141788b6606e5232ed1f1d356b10965e5714a1840894ecd0748eea628c33608b7a611769dd776143aaa8641f6a5196a7c031eb1fa88fd71f81fe2c79393cef967c5d391d6bb4e0bbaa4574b1b0803ab045256bd37a1d55a82401560b221eca45fc1b32d073cc941c13af82170bb64210d45c1d824a9b10b42304a1bf411e113d9631537283fa843acdec8d9fe1b4947e9681ef5e8af04551824a544eb097c5727b11e0a88e3466aac3df86ce73d65b65dba8689b9f9082b343dc7290b96806a059477fc88c7ac81ba5fa155b91a14a81b7c177812810d1bc075e79b38cd0de2b3ed5508811effd043ac73479e1c7bb43d47270de84d0fefe0b6ee706a219b588404901cde4aa35280180834a662292ea4e635147568b88260c98ee610c5d54797b9375d4c8b5677e0d0b5e4bc4517a1d43b242b8c87352b78cef161aaba0c8622b08323398db9eb18c5357d969321ea04cb6e90636b94b1bab3e76f5b77370708b8748cb291f30408c91ef13424894e1f2e76c3fe4c3a152ef732f082e17d1c1f7ff118299d491038e8ea66f87e00f87eb443050eb8dd41b05adba3ce23757a8a9216fe03598b3d14320b7ee49a978334ccaaa0b46501b5d53c7a30a305243ab6d4c5da81e41ff554dc8620ca0e1de522c4b8895e272effde43973649b097b1cdb206eb57a7bb976344d13a9c5413cb83fc99299770265c988d5787b93603652d303723477363853bee3ebf3cb69a5b9b2ccbd466b5c8207d0b072d75ec6291a8b4fe59e3c138bd1f18614d46f1d73a0055c5b914c643ba73bcbde0a89e324b989050e3c20102cfae9b0172f9cfc3d159847ee34ae7e19f69200ce3ce0fb376c172e49a5cd4000a06ee4ce868c84a76d538946a0812671f518e6b32c49a05b1a38518c63b1ec69a82cad14298e39d0c11ad41ee6c428871cf86b1c66072b011e471c786496b90b99a08631cc6a15c3b98397046961a0bc344ba893c2ab63adad5e0a180d401a1139d6b3dcd81ea8b7a0e977360ab17879d735560476806e28f05d776fd9a53c8050ba91a64d865f5fa41c90a41f903d9b4027cef16d21e414674b0f08510c8697a2f69d20cc18c5c438c5587e1dcacbdbc952242d0021cdfb35b29a0e9ce97a18d1cd927d3f8ffbc406141e802c5196f06d1b10c07be45448a90e79d2ec7d0b2960687133bc97be6938ea56217946b898ab16964a99bdf69f06faf636551ba557f654bfa1192222124cc7b66922b609bd44b3380c72c983a55508ae853a82c5da6a6aa389f771e1752abef4a7e83e9292d19af471e99bd6fb1dadceeeb1e374acf57737821423c60e9f9bf881f7063178d353848c7a8ba2f6ae096ddc17e50cbccf9c8308f8e0f967627b2c013a4d687d4ae7dc192f4f2b0245121067c67b43f41d2f21dbaeeb4c74fb11f52534c5295493ee17e58f64595b66b4e1ad3ed464b540333ec33559f721682d1080dca7729ccecbf3c6c089c161ad5b793057f1863b28f407308f433b210c57740f3e430c63442a1a4fad210b29f9bfc83d9174c84649041227cd644f2652e1c1236e88573567fba269700edac9a452c4babd3b494099f23f18413de25ab1f468d06e75ca2eed4bf0236be6c6e4d6f04b1e714b34adda427dad5d642d1ae5c48edfbf4888fa8bc0f87210892d8adca010b5e0aa1e1750dd34806303ac394f1430a9f4d143ddcf346a7b13bfa5f52361c82fe1a7ed52dc77849b5ad860bc547c1fa07424dba848608fe9f147f1ecaefd759cc1abebd424cee6b98330ed10ccb87166384cd03ff060e654ef4ea7fcf6df6a6566e13642e5939b8aa1a8c4e8c53fec2231feffa0c2e7c6a6ba9084acfdffbe862b982ef25365d1517b03e9a468409128e4aedddc6a51790137b793df1b6fbcbd27208f82dd4690be57e6062b1772a61f502ccd572e0eaa7bca992c31f758de65acd63e78b79619dcd8f5a840723a019958b7828fdad9c84b33a12ba7fd7ad2ba861fab98cdf07f20d8104acb9bc75191d895b34c9b4c1f5cf9c56bfb0d7816fde5e33135aa89e445e5ff9c2b30eaf015fa0e1419886580db51e490a0f9b50423f826b1e032d3d83d2fd0f8ffeedd50650f8bb71ebee0521b6a8259c60681e2f6c32e1c92be19dfe8e8779d538e7dc11560fd8fccc2056400ea343c412b61c592cd9641c521d1016d208b7bf421af809066905c057f5de0762720e601acb3f8373376f17a329c78f029c682cf14dd75d580824d06bd765082509a02456b2cf47a289bb4add18aa608171e69fa1da29eee2c42d046bceb592fb9ea002f4bd4ca6d5c618ab1c502939d42eb9f3ef618be2f69858adf17b080e9907e129f461904a3c9eb2494d47d9e90938194420710b2ddb1b48be0181ed5b2d099a5bba744609ceed9939ff39eff6a14c486c4ccc951a7154071d80792d24b9ae4a9da9cfb9759a4daaa064b6919308ce224937e375f9eef544e9796a621604ec487042c7197088cdd3e7f5b7f971140709c3b7e3f60114a16cbf3688d617992b688b9fd5d87e795d843f875d2f567b454f27b212473d8ef218808b57dca7c6a01d9286cd7ad54f52888b411bb5809505e4c3443dc573d35ad2c23c9f783ad6fa2ceea787a9d5c187bff7b6b590ac56ede50dcdc93ed982fdc516cf7c03d84d7d199fc366810a9bce0ae67ca8c9c81a4f8d4d3a65a5a946adda1a1aab0e10fe5f5b03612d3018a2a25c406cbf8c2465de332d816dcff18003c93a668fcb714c02591986f7b33d8838a7181469702d456cf5891403cefe0df4876c0dfe86bbd866f8028e9a2a094cdbaee704fc7547f0823299ccc5258c1771c02fe9a0e6d7ff4ba58f0d9b8d851b2441d0e3c089115e3c0b65c7a367a3e9afa9611d17714481ab5a56260318447672e5ce06ba58afc44c628c99d747cc21a590794de69b69268448ab9d38d5125d95db75af62286c922e014c22280daf6ae7f34b9976539a74e0fca294501703f21dd5d3cd18382d8a30cff5953d99b80ad050a5d2f1daf61b9c178e374d1940fd2e9f3ac0714156b970dae85d295a5eaff81aa80f5fa35f14f875d79f43bd9ef3f1ab389688800070997f830ebe04240a055c17207bad9564f587a814909fbd7d80c5f31ba5ca154f55b2913ae05d74a5e3d6a2444004d183d5af56f6b7b25d41a713ffb4971d21284481f492410a60c9f39969b8f93e6090c189700c4a1a50dc84fd1a08e81027214ade42750e7ed32771667ba3ac9ff1ae8458dd1a9296eb21f78cbe6ce3cac8c10e32173f0c0251b9484c8e89668e24976d6364c182b54aa6c16809ad6b4c9e33b6873802453a39c617e4da1a71e698a1906b26c3d1016b20f3655c6bab5f1c80414a327ffd5712facb0f3c75fc5085f66225536038307f8c2c4252fb01870fc78d2200ed2e3a3dfe9e9b041625c0b71adc9b20126951099399e1a18969138f064fe2564a483c5ef2b4a1208b71ee0e46f01d4789438a4fcce813fc04ec596341ef64cb9d2e4071c0e66ff2a2bde1132ed62021b51d94fb6f241bd35b065f133c5f83b7f2cbaaa612cbffcb60511e685ef3783292f3ce5a1c11518929532631132b0d1a29e7e49a8fe1eb30c493f25ef05c096959d54d4a73a63827f8ad7ff1ba5e0764d28ca4ab003645fa5b07a53e76227bb517a8002cbf8e50dc353ee25ed126617336115cb723baba81e9242006e598ddc957504a35f6f0a948ad9c3b64e9c0b8380dae0f82d51f73c8af822f4e4031590addf40a6cd8017a82d95359508a2cd51cd4c6c9278e218716747258403bdf9f9f64a31ed52b00b33eaa07f6c2fa89d453050f63e21c8d2eea320395064100f0180d0000000008861c74686bd4bd3f6fa5042a51ac5bc98d33de31763711112152e4962277b405af05aa04371ec6536739cbb29605aec753b50cc920a5594b085317b141d4f50105db1423375e105d89112d71a2612e8b16109d0bb1caafe4945a6badb7b24f2473f6debb8630fb44921caf6e00d13ce7546698932a4bb24a6badf91a06380c908a52024b95ae29503008c285cb891b5bbeaa22c0c853843a8b37042b914b31a32893b160752c5d6a071354e4988c15099a25e15c62b40885c05a52050b0b39250df7451eb7109a31012cba34e90032212d9100929525258ab48cb6709923af0ba5cd44ef0a23aac6a6c690c6a608d140595c8c1447aa2c21eb02e1e89a0535c8429c736e42987d22e73bfa4899a37b927912923c75ab3d95d7eb11c49ccbe82871cb5ebfbb9286acb278a51d718b92b1820bd92f68068249e80cbd1898170c778e5a8b536baca277d86e71561de044baa57463489d19e1e2a16b868727aca7235b9eb850445d2318e29113dfc18d95e5dea605175a6bfd43c937331f4c6f603d9e8469fe63e6cb8d450961d817b2db426badb54631502d25b1c83103ce838c9029ab1e53183c359122b3773cac69adb54649924b6b7d1271d39199db3ad1ac9810b931cc608acbd775e505090d9e4220cddc206613f11445ac4491ab0e2794846d46968c70e11882702fb8d1522a7594645ac203905c4b9c738e06d468418d26d41ac8d332a7925c9c73ced73827b9c436309f70403be7a12fae93814dfa8ee93bfb9cbe5adcf89203041855082556535e4765545959516c97c5b622be05ade6dc508ecdd066320c97b4952d39482eadb5e6224449adb5d65a6b0d93e46ef1aba7aff4ec4155a8ccc842897b8b9af224a40d4dc611dc111d62716857458e02b0829c22976684ccca392380c906505c5a59b478405a97c4bcb8906dadad5d15640feaac43ad611525bb96386a814ceac84f4887436afcfada393de444decde8456bada5b24fd45aeb1db02b5619f418220a82d35a29909c4abc695145d1a0bdccba3640d72966da96585870912d4038b5947a58ca18f689c3328314b41e4a6aadb5d6bb6986294d5bca90e6a46a6d9246ba51e462e30eb1db46d0180a3242085c1107a240c93115250a598bd14a4d1157eafc4704f098c4b851e5cdcb4990589b87163da24e6451fa9d4029cc4ba4b270f32addd2536badd5230f780c7391311d6aa14b88afce500b429c46275b128cbce042c4891230af200fd0c83281e2060bac1a1fa6fabe40ce391f6acd39d781c98c9a4d872a8c84931811312f1500ba2176e40356dbd552df4337cb57d9b38ca943677c6ca18a318951b64eb91e47b8c895a1f87116ecfbcc8584b3ac3934a196a8267157489f5558c4168abbe5426badbfb24f24679818f448bd9aceb44860998bf2c2818f2745866d504d5c377c17c5de7b9323d788364c3361f28674406af25643cc040a2d1d13a844f16224c90c0f1bdc1303e0ea994a44081664022e0a921e105a303410b14528d4e21ebcca6b02cd0049483576dce842925663e4c2c3706e0712b0847066c812066fc02a2c613f62b4bea0d831b643480cae221f891a293721d2d19b198f195d8658741971c5c59817b22ad38a8c0b009dff9e04bd900c6744722493485d3c967d895f19484ad4984b8c4d4034ac58bce032923225891557901188a6205d57ee88db25c5af0c284a4490d12811266ac9b25584c30aea448e2e1e57c4d2de7bb305b34f24c9710b90beb7606d09f68c025a54116d80d564c690046001124246902126b8aa9a3608b186e58dc9cdea8b88ab1bb01b545340265f55479820dc20b3c7a1696de69d632cef1c5e0fc9182e737a902dab2f23dac6f0475388ae214a529819fd18a95203aec95c9a8c0b42a34965adb5d6239c4648a9284964430a09b02fc0ababab9f94142a5d6d349a049d48d2f0416b4d6291d05aeb095d6badf590a74950935b171d5f8ab07030da8005d88e2b4d6cd74384240dc6809482441a640d21914989f10ba115b5e6bb404c3bfea16c94e2356e2be3cc5600c7115c22554149d6932d59597a4009d281b62c28403956600dd142aaf205c6abd425590f3ca80ce1b042b2c6c5c477c513338968404042b8e38497a823271b8a20e150e1042b0c88cb8795124fd25a6b2a4e65a9d3b6bad65a670d09eaa25a02c407908e28b01f28a8b01c7999d29054a6e1a8e23c9b3e9a84f838d20445da4f0d6a48b464ea45972c0d9c73f25291731c01202ef03bb3a2b286e5618371abc599d0cad987221f5f825c262773009c0a9fc34d4c455a8aa8485ba1826cc7579c980c10e50552e5ea80b164092e05d7972c1b398678fd483204cafd01838c0a0201929952957d22c953492edf9614711f9c6819425192011652721eb24e68192952e663096f146e0cfbc4211c9ada1bc5bc252ae724b9c2b65b95db96f85b7252c92af88bc4f2030b16962e9eaa4506ccfe11d3e49679ea1c952371426048433d2860e42b4890998c2767409c462b20505341821b4cee4bedfdf6e29c733527ec13d5a448150237e0588890e1e2aa484db735006a05d04510105da634f01e7c8d2cbbd0c8ac90384b2104c611d16d0a2ccee8298ad25097d18dd4de7b93239212f3e4a4d020b7b17443854c708c6c37b9994122317e4d5ede664c41c2e636222908902d54416e1453d90b0724ef1af26e78bd9baa9b2f77849cd49aa8010717ec14a4f22ef4cae984c939e75cd54dbe0d586d890a538a9a3285f4854990880fa7b42525245c1e5a6badb5862aa5ec9992f32267ce0524a22918406ca400ebc0e34993d80a28b032332d38740b48ddc18742b1382d7241293090226c069b93164b34b460c8683d3d80e24d0b5077d07602caf9b9d8bf19397f69ad032467b9f2871073cec925546e46a5dbf0c72b4d4e84a04823e2a1a109181298d1d987282155daae0e0a7a5fe1de572b7ea39421101090882df24b1deb0d1f0d47c305559bc21994d3a4da23d368449036058332234ca6ca62acd8b06409657975195932f364138506649cda1aab9ccc1e175d4f408890646d6100945cd205422530b610c17273286528c21c4090d2d0a86c65192271f242475a1290b2ebc45b227b812aed256613226a5290825f9cd03acc28b205b8620957d50f29122e0e9c6dba691b4099a60d480cd35a82db62535203469a74c5c55397361249ee0d02909a6d6c5ccad1b58f1e5d975d05a5f60e1ee231c1cc99d9a7b5661be3dcb04f8c9323559473cef9da6b1c5843d298a973fb50a821c7988828566647538a0c31811a9ff48d01545993b9a0141b2a57c138e75cce29fb44724fe9fcd6e09c935ce35826d45d50c55e59c1d5508abae00ac293242baa0cba8a5435ddadb4997ee618622b8adc50178da1383518bf24fd6b4a834c2b84aa30a1c5dd0c4a33333333b3b33371c417e79caf01d7826bc29e1964d4c03476041535d818d31b8c9d9c73ceb994d61c65915de41927b7c6d70d1839a7b7c5e0af2c9b7c2849b192624b6898648fc1741091b436d6a405c70e104ca3909c8e0865b8a4b590058439356585a5a022b230e48406dbdc5395131af438b4c197b4d61a051a4a6aadf51b08664075d9a1f5c16ce8c6891145ba700cd980413a60517a954a157221e88262ca1a0f284d563acb0059544a634428b27cdc24ad35b964efbdbdccc019a071ce493327c04d3e41d35bfbd81ac7225ff98814f9f553ad96747cb8896991003e90c5cbd3970624c2989aa00d15e1028503c88bc6d2cdb682ddb24f24bd4c952f9158994ce562dc6dc416a2b5d6426328a9254c6bbd4de87e06fcb1256840b60032b2d2398a9b988f2daa2b222a5d566c3d9921a7e3458caaa6b3b3920d691c8aa0f264d12c2e460f293b9e0851f1d4c012c4a5048750b835f6358373ceb7b24fe49c73cec7b42bde100d63caad840c9dcf469ef834369639da0a286bc839aa83b65b1bcbb036e4a4d9022474c8800b4494539915165059aa3c510ad1b61435e343cd95c1246a25e9a0b2838d089136116c8bc9b02d48d9063562947b97d194596288ecbdf7c6b0f7dedb0d080868c4de7bbf8d619f3824d154b7de9bdc03e1747de5877da2c6d033e035ce39e79b0bed774d4e18259108490d875af00114d8bcf9529065be7d986f717a2b0ed3b5e67b34332ff330796dd50e1564f3335ace727df716f42bdedc8bf14d8a6f32ff5d8e90b22deebb8fc0b6b8f3b58eef5f76d75e7c4dd687ffee2fc6acd93b54803fdf9cb39ccf7d0b3ace7c7f9a3fcd6ed8bcc96a7727fdcddf34d936af61f34d33ebacb3e6ac0ffe9b654c996ff1d92649f345f182699a6b7a7bdf9234dfaa33d9a777f833e78f591b08bfdf7c0af9020512fec1bf83f57536cfc389b98fd9f601f7f130a3dd1dfc1967c0588220b5cd6d5eebe6d7acbbb467f798f5c15ff3ba9df91444f896ec362fe20b36bfb2ff6cabbe04b625717e09664ef3ee510a19a312d8169fe91c64fcfb1f9ce906743caa593184d50218473f5f3180bf158797cd6a38a3f5fb3ceda9c17fb3a27fd77d7ecd2a769bb5fdde8ac31acce221c6d91728649ffe076c4bf6d89674c0b62a0ddbaa3ab6edcdb06d8fc7b62fc3b6df63d81607866d71544ea6eabdf77235aba59fbfc5672d5eeb986d39a0e7eef1a38f75dfb13ee9f337d16b9aa689a62c49aa6a4fbc208a59ed4777f229e40beceba7401c13c0b7cf7edb03c0b76a005e00ec05669ffef603409200505556ccbeb697d55a7cd6392b4190faa3fbfdf647f7f4f7a3bb0be49fd5b2da9db01f7dce9ef57d81bd5eab762dfa7ef410fdac86a2798d020b88437198d5ee8d15a7fe5dbcfa3a4b22ec14ba7885c4ad7f85f50274f1ea48968a8e76dd6314d8c730b26ea18b576148fd0a0caee374f10aacab9fe20454f12a2ca89ffd9ec3ecd4b5fa62f9e78b5de4fc1caab91d7b665b0e6c7b75e904f7d3b407bd62375fbcf7cf21d631ff3e9a6eb8791dd30d2c19cc2bfa679a73fe49571f1dfe1dc629fed4cc3b5e7b6726e0b12deeba9f615bdcd373d8cd3ff3b7d7bc37b33ee9ebfeeadeee0e1558d0ef9b2c36db11f48edb73adb7fb571ffc16f4bbb6b99b3fa60fc83de57c15cdf3acb73f7803b9b777821677acb3cb3fb8a7cf39db9ec3be9f7396739eb23ef7f1f3f4cf8bc67c7b7ffbf94db5ce7cccde359bac8dcc65db07e0bf7faff927d9ddb96f660982d41fdc6ffb83db73d8f9a3eb2eedd1fd657deea3afe33059c8bb9806ff4c9af6e0f73159dda398260b4d7ccdfb332c2f0b4f1488ae77c54199151f6121c6d1afa3e255bc13da93ace3e7690ffaf9f77a7fb7f2c7ebfe0c398b3d66457b8b8328a9aa3af2af7aaf8ef521df7cdd9f183dcbee8e389a2fe66fef6fff5923010854f7b84602102a07b4a3ac8ff9fc53dda37fde5402fc75e92a0153fdf492af63dbb1abac4df9fbf9af4571305f20b34fbfc638e66f914bbf9ffeeedbfbeb9c0307b4a78feeb4e7be4fcab6b79b13a0fd8a5c7acb41e4d2cddfb1edfdf5fded0576fd64fafab26d073a74f375cf53b6e58076f351b61dcbee8ed8f98fe9067e0efb6aae38788471f493ab8edae2e003ceced9b3ec4ed86c768ab9345b6395fae666925c403a189b060fc3c939a7b98043a34a15545b0db9a11e2b19312e78cba2c523aeef3b046f69bd7574ceb9ca4b5487ad40eec30826434044d828a9861a0c9991015d79210900d6b375cd01811e5e7051d2b1446e2dca1a932a38d82b84298dcb2ddc4aad758ede9c735e632b0b915373b4d61a6b8dec58675b6d02044384a436411bcb1cb25faf4984b2b71d4131610c2842e690043da6fdd1e8eb2e6b7e8a2fbffb634af1798cee0e3651076cdbbb976d7fb48e6d498ea61b509e2e1e23fe33fcf3aa7e611cfe3aeae6b8fccd13ec89f9f3cb157f86cc5b772fb3a61f13c3bfd5529dbff9952fa8bfece3df92ad6a9a5f30ff37ed21fbeef96abaa9bf7c415dca3efd3d936d7baa8ad91fccaae33c46473def937cfcedbd240cc963c4d3d674ebfad5a57c414b659ffe5e4f5597ba7e1e237dd4eff3d7a59ce43ad8dbb1f31d077dd44d2dc56394b23c465a4a4b712dd5358fd14e37a03c47ea96da8571b4baa56ef118dd097b66487321b8f130aec2c05167a67b6ffde9ea83f7b9b7dee98955cd5f6360bf67fa699a9efbcfc798436f974e705f97f6ec3efd11eb887dbf1006629dfdf7d374c34d37deebee49990e15a427527cd47d78584dd3c7f8874fdc1dfc1cabe83b459fc7b1908a310de73d0d8a817dcfb02d49c2b0ad4ab2b7f3d0e76d1c01de666d605e7ffa986d2f867ce1636430fe619df4f7e3139b73fd2d06f694f7974579e9d38c3329e6cf59de9b180bf1d29832dd70e2aadd8a8530c0ac3ce89a0163217ca2e327d39edd7d753d1fafdafc11c5429aa729dbeaf4ee58fccb17d2e724dbeb3ee46ff275e8eb5e4c23a0636dcad77f1ffd7c0143f68dcfd9564d592c7477d65eaf3f893ec730e216431f5fecf1c742e89f8f7f5868a71b4ea089818763c08085ee04cd8aa3cc95593b6fc6ca2acc47d3b4cd2a4852679d71ce69dae3e0f3599455a0e986cc4fbc3a78714606e6cf736dd5dea1023ccc407eb659d8db1f8c571fdd5bd0af48de9b6b3e7312e7a2bbc33f3f38cf1eee65153dcfc8c0b0fcdb9cefb33ee4eb32cbf39ff94f613ecf35677c3e0e667ebe88751e6c6cf3ad2eabe8fbc9ac79d63c6b9e9e36ec0fee29eb93ff3eff56c7fe8822e73cb3692fff59c3336b5393c1e6e62164b6cdfccfcfc0bb93ffcc39b7115474fe0ef0f999f5c9af3b39848fb9791e4dfefdfc8cc0729e9eeca3e7ebfcfc7c08ec0d7bb2366c9a662cdd9a8bf29aa1666500b93a207f2b561565a083fc0fd6f47bebeeefbad177b03ac89f7dfa695852ed31ac4a96afaa97647dca3f3f1791e425337beabefdd1e9eb589f53774f129fea7396b5313f5fc8907dfadbcf4577e7fcfd774d2f99fe6e15310ec9595d06febd1eff56edfcfcfde4e7a2f3756c2eba13f6a78f87e9e7a2f4c774439a558c6b068ca3df5c19505555d4a1e63a30c35b3ccbd13b9d599665a9ff07fbec922c4b8c35c9fa5c71ebd7e69fdfa29fa66c9bd3f59f24fb83bbcf6d5196fc936575f9e5df11e38cdd7c0a77a734734ab6bd6a3ac10ee3dfe5532877851cac536eb8eb986e284554ed1d2ac01b3f05bc5bb1aa974fae3ee756f72e9f7c0a77673f89a1b7325f6295f521ff547fe32f778ccac6b02dcee9e5b732ecf9e49fe43ecbdf64c9dac4bc7e73effde553b83bf74b36a7b732afbfcde9e6a3bab4079f9f9a5f41b7322cc668dab3d309d0bebfc2ddd9d84c3798e2598c8e9aff52e841bf7cbd9a7bd5b7c2ddd1ed569bbeffbe4ec7da90afdfac7077f6ebaf49d78d9e15de34bf8299338e9bad702768f5ee54ecee7894d7ae10351f7d11eba0f7d73550f669b59ba63d356ffe8875b2d8876b68ba21920fa8b40c590b62ce18c51100000001b31700002800088683b234d10335f614000a45ba90a498501a8b47426138180682c100502000410000401080611086623196ee706b24bb86af8cb951f749e57dbd23f830dc0547252728c144e4aff9753cbeb4de4f851d4f0661944eba0797013593b8d0641e5cfef5f89cbda4b1d905624a450bb6e927a63fad4b85ad3dcc4544420e2864eea051610dc2d551afb24cb17e03b471e0f2662ad6c2c26d41e922297d75f1456e6963d95e63572a676ad6f8f60c8d9dbb205ba78fd6cf2e8a6c2737141d1c80b00c9d77eb1a94988cb8926dc1555ce6304ebe95069bb3431c29e66b6f7591b9948ecc42599464e86bc15de05b9109530399d9d9e1dad18c24b3261ed66133f9e78accec9d025c3788cb18b357c8f5b9f8792a1e2196bbfa8afa4eb2667ee4b050b01530194590eb029296fd6f553d09aa49e1e54f525e2d05c7f79ad572edc19a7c89701756138ce2e021da0c2f2ee11432e0356edb228dd6ae3fe2b322977529723b786be1fd4542129eb4cef15cc3d5b175a643a5c80a2611fb2cb3dfd6cde077c4b8317836e520b330c84e606fc1d354e21e90abbe792bd43ea6a3eebbfe50221cd287ebb8461ea524a5755a0920e9a2a0c5997a4b3f301af1410aba3a6987972599fe894ad74872bd5cff0c7997027a184b3ecd0f5ced8ae403823d001975000b7c84e4224c38bf5839095941d5ab20c146fe1067fcac790035bd52c8738d6bfe3ac7cacac2a624fde8ce203756c66b0badeca1f04a04f40ed619cb8b4920fd16447d203e7982bc0ce05c881063e6eb78bd88e05793e5f74835726607bf24264617fc0e46f3770c2f8215370e9eea7a0038fe09a21c7d2f362f24142b0ebea63a8ecf686e9ccadb95e7a7e4ec6f54a3b40e2851dd1af908e0664d5e69bc1e3dd0c3e83f29cba773a13c4c24a3804d2af3364af28bfaf17b30c8daade85fd6644b20587500abf369d7cd4c6b87d4592225c411f5f9ca14a72304b53a5758e9c07449319db1af7c0b5a9065df98b42acb2a0f7a3a3db607fddd1bf4d6f343c6d46be22112a9feb21588858a6f492c46a98c315b6a4b75bef4329955a22c9ce4da732e6cc4e8df314b9f8c919a96228c988ce5f4eb8d7832c4dbefffc0e9e7e7a4a0528b825da28a7cfc6427bbf5b9136e0c49520da85996387fdc6c0e1969ac24ff12e0af8863206a47b665cf7f88ac15e8827ad3104ed7d58fd660d864770e72c281c7aac92ce4881cc0276989a66bcbe9a499c081ffa81e7aa809a4940622e132dc346a86ffbbff6b1c08908527dec3ecd8a03256c277e2c4e14e4c586d484419d45788d48470acbd97a346d1877912bf1ca06e2d3c7f11548212a5232b45f46eee012219e04c2256b98f54db11aae2783d40246f86a8866a7105c5787d7e789f3a32c79463a21c7e96138a2b456d4736bd84d09c1675ce6b5e46b8633efe26a73c2d7a2d8a6ecd7fcb11869af7e948da6a3c7eae4247d3430dd5c961a2abfda960f43792da51f71c720ceade781ef5cd3281eb4cacbb14530989f3b5efa227e636a6175b59da01c7a8f399caee74b87fa8e485fbd3c6dc2ed3417745a588b7c3c8c86e0d1d9a21a83816d8608b0a2bb82c0a583d462185f32a40ca9659ac42a860a2b70cb44fba35c09a38b3ad8e6cf4ecfc041876a1429bbcc5e510c3060476150aafbafd01e4c32956896bf2b30a21228c7bc8bc74124739dc59860e06e96aeb3b2b89993cbf213f123a33eb486b073087683758b01b17f209610703fd70b8330939ee00c9157929c63d60944d14596ee0d7d9acf28a5699c7d8605fded0898c236213c19cc656fbc9d46ca2074f55dfeaf83f74e5162a69d5f54e639574a89100b3782850dbc47ad8e98d6f28d2814900a74680358b763b8a7f6bf8400eca16769ee5da0d0cbc6d2edbcd6cf13edc07df0c6e90606f21c609f034cbdf022ad220fa1518a87b48c16659edb8c68b19470c00cfae6c075275059944211fbbbd7bed3ea5ad8795d178263748ecf521723780dccfe47a3f3532b6eeb8c2fdd4a8413ff868a41418fc8f998a4a886172be22896040875832ccf48b2a0ce46a95cdbb921f9d20c1caab5eca025510e60d5afc3619c445db4eca630c8a1d737bdafaed6c0544a13ee2b1ef6f9082b7ab30be0d0e6edc0e5c66c7ce27ed7cdc894ca1a4a0f73e79005ee09545ab976673d369bc4a7b817da3901929c01a2f3676d33d3558a59da5467121ffc89dfa53e20c7458be408ff96923baffa33641b84f0555e484f0420db5a20b7be5e6a928a0d3e68998e9230f96a9abdd800bc19f6ad7765bfe9558196ce5e103c3081a0f856539561e7b51a4254e3030686c5d3c5492c04cd0e0c007fd5191a8b12dd8bee11bf838aaccd54637821741eaf090cc39b14acc52ca6c46d1451d17c1139d1ea665c254572e4e33ce513bd9e389d072a7f9bb0ee4966a7292c4813fe67b57fa8b99fc49681a36b0001703003c3f3405de0e2c776da18b033484ae5d10ac8d9125082e40a1073bbf0c28bf7e4a146979a913f54e53e6e2de007e57a516bf264ccdc5106dd488bb20be7e54a6ba47c898858f26d347fa98a1d581955c5d8cb518adeb093d24167915624649d41c6b25e3bcced7e62ec93ca7340366731beba6e9a3bcf59dddf09cbb2cfeaa29850253b8a7a57953ba7e536664a67c63726f78fff27c7a69c10b0584799b96eb1f91fa5c811090be48c1ef4ab231e60805b882affaa2532824075ccecec9d1602ff4c8a5cf819a47440f6b575b2aa7244bc1d4fcc74d7e14ebc26332ef9ca035feda29d5903f1ebd2dbc233d29a97c86beceea16cb26c5253bd9486c79926d570291e73ab7e64f22ad594239751f4f18f32818612681399ed0a147b4c393db0de22d912cbd9ba4600fadd5c4f3761b46115358f5289549b76611cd40b9227bf236cd7b2b5f909dd5df7fbed39830ea4087ecfb6570f9d76aba35f6479cc3cc060924d857d67090c5a1d1d60ecae6b2643766dd6cc2bcb96a8e5985c8149edff7114f0c4dd02027ccb6f2eec561124abede3ce73b9c44c7d74a00dd59e1606ade37b7d1ebd976da49eb022a9cd8028712a2d20ae14fef6744f47f457dd2de16b4d249960a8a6ca914646de9d41f1e9e651e0a766727c6dbad1c7dfd8f8865a3b539f14c857de4f12309606f73e05c333eebc75debf17b23fa3fdbb4e8f733bf3ac2ac17925c95ac7d7a4c18024e8f8dbbe23cb78a9e3d30dee3eac87ef915ff1ce40040e2bf218cd009c204a2ebc9963066b40034c43fb457a81cbd467472e502a71777890b619f6ccf189952ae552f859083e6214e6a69c891fa9ffce49d6fd9b8771d186e70a2536433ee9758fc6fd5194b8eda1f7d650e36cfb823bcfa7a0653c5799e55da2224ae1fd97050bfeceba57748e9e04c496b9f09854cd1e8c8fdf2ea306c2446648a2a8f9922ce97a3b570eac6b0078f1ea9163c01bedd094b041a2de827a54d8271ba6827597983bd9be5f2d7bbe8604ccc5f716fb12910ca2ff4bea038c6b2be5637543c3e91e7c854620d4d970bbc4e473fcd91bc547535fe54526a4783c00243add16b1e990a2732d1e63aaa7a08b9609868f9c6aa5fa2a32c46b3e67fa27601e226a2fb9e915321423ea267773c74b2e9ae9b35bae0d75db2f9d5f2e9644b88aef0b4808dcb2a7e5edf1d6d3bbdbbca613126dbf6ea46fd44c63b0fc093ce1897049d3c379161a7a14fa63d91c0be9b5ed818844c8ed9dc81c4b49a6aef670601ec19e2411278e98270d19cb9de188132cd4cd7e9ee6c4e44ed693417ad89c56785e6eeef745497c638bbf91b470b4aefa750263d1141d87aa9f135e1aecc542a712a1f3ce9bff76f0ccb684b78889dc3fa7c46e77369ab97363f03c713b12b95cc3955c50640a47d4e67c07f429f66573fc03ec58cee88eeab2d0451121e37a656905761f40c9d4886fc1348d438667a6532ec2584c9953f3028e406444174c45c1003e1ad82345e2b560b09826cdd19fe7ba56bb8b6c2e2901eb7646cd051ad7c7ea3fcddec2db90128194e204ea2423613c9699c949eccddaf77bb2d4d0660c2c37d1d79e8927c46fb2f2b0a7399a83dd224d9b369a09d866c27d17ddad392cee25aab8389a4f1667477fdc382e95195dcd77268f5461e7839a0cd052018aed1d5d394b524a88d252767129ec6b553232d96fd88cd123b5bfabceb7b930abd63a6d14bda2ebafbda6f6814e7a6cc182c7e37396b5eb374f97c208905ec936bb89195814f9346e1b9bb56b1dd69093b68639db412ad17520b259dcd8c1a5323e97842cd68d271bfb18e46c9ebd88459d7c83a951dbcd962b46c7060da7d894e87ca215a37a57551c082c005b7e0e01b670b3eb9c2f5785a625def435a8c25cff04ae4e86a17dd4a77979abfa80f19314065a545c405db15cfe0c90fd5a840f11c2266a0b4c7cc6ebb67475fa55eb6110fb5222539a05b5f79c60cc5a94d7f2e686ab53d73fbc8314bda99afef07cb2ac97c53290d4562bb45cb6e4736f1198d5a8e8f94a0d325a3c589cd54a4c715c2a6276c730a135005faa99f130e6aff54c022d01b2db940e0ef6e21df2c48e0793c5e74a6b63f2e83b1732766aae9db2f0a7b8aedd9d9a8916113673d71ae92a5713dfad49a97c34510191af44361c8d528185f67893ac8d55f9c436efdf2453c47485941d7b5666ded89fa1cc0f9225cab8659d4df833c087e807f17fa1219c1ccaeb8716e9612446a0fa356df19c88843d5d5acc1e7f6abe4568e4cdbaa73c8055e1dbad21f9168b5f35b3577adb3307fbbda4de561c9365252d883baefd6c668271ac024a5a9de2f5bb90a791cd0069582998c8717ceb40a6c391f5a9b7a71aec4dfde39f103ff5d686404a2bf7905f9d4ae820893df0ceb554dab736e3d3d773bcb3bd427d328c38d37d0e770b72afae10209a27367ea7aef37400161e90ccca759b67f573c8b284049391ee4d4d8d1a0640d6a7e966464d4d33a51996c61c3e74d2acda62a9f5dfda4d13982ee48294030fcf2de9563753ffa7dcd80faf464779a99ceb4d0d1d777eb29f0dac749aee6d7b19c2fcbdeabc84e91184505746d18d03cad9b6160e867cc99abcc2c57f93f1b9b1e95692a45a3fc75a7cf580addac1882cf131ab10ee379b7c0e22234ba745a9406bfaae0d1a1e4ee4ce28c072ff25c5a6ed3d87e21157307c82f2ff48361c54a8fe9f9909d50aae91dbacf152baac26314fa0f64e180b880e2b6285b717552cf22b1f56533c1048a6b046fe230d80786e68a70022d0b6427399d9c6c7a3259022aea4a4f6fdc7de3b34afc19d85b98f00407ee57618c6db2a7ba9a00ad52a7d60c171018f7168c47cbfa5e511afc895456f806792aa69fb5d7f857a2ef80283d37e88288184b96b2ae00d3ed4704835c2d0e992b6a24c0c279284f9d480c3f8085e1eddae8f066e414c8df3ddec5ae795972ee11a473a45a1679d5273dd93d20553d06786e2325c25cfd6fd4ab373d448123cdb1521e9c26f3aab260192d9ee1c93c8e021fce4abef1ed762ccee92e71c5e92d77960fb856c479c32c1b0571d9c0560ad0e2324a444bef6eafe3713c0b852ad0ff5bb60dda7de28a6b5f48a5e80bcb3b2a45e9f596084971aaa86ccead4151eb4b7d8cd7005942dd2a4555ad0f17e77b49d0c27403515223918de91a4a268d0707ddea0432eed2e2a9c78d6d6c378dfa9442d904f14d6fb811db28b57da5c09a169a9f7a2316cdded16c2bf674165f021bef0766e5110d6f38315a4254e7ca3026d6865a270f91575107aa606d20805478d2e5dc741f96890d181ed8459210b262eccebf6bb0f2b9b4cc6224637d89ac84157ef0ad74affda6c47ee731655328f3618955a18f1940afac49dcb94d9b746a0c5ad4f86d142dfa9b5906cb21daad96113f3873dd06825443d1624d098e305d687c48bfb6e4e8eda47555a00921dc0218d77b3ac8533afba1123358535697965b6d20eb55665ae29f47b6fbb93893d1e74d3686ee3f0a2de05d11ff27497e7c8c54c8236961d774328ba8ebd09a7c3862ce5495ac1cbb5dbc529481845609eca2cc9784e3da52117d9b6946c925d068fbc92f68ae9de5c3e810d7be50e14d3bfa902b2d771524f44b108c2884602a925983a8791fb28a1077e2cd2626c6d805b53560a26d4d8d28e9f03326fe204c45129ea7bee6bdcaa15717acc744f530f2a0ed3a2248e72d38e4575cb4f8ec33f3467ee6c15104febe44472f940bbf7a3038217c0f35abc0c6fe4d0e64ddc577e4e35887ab8cd97d3a1410c88791da5b8afe0a3bd8570e2b5264401d0e484480ebf15af1d30c5af309bac83f3634a42665f219f543f95225e825d70d7b1fb37a545630a083feeab24b2fcd416516d33888e401c18eb2e058c8e8586ec7450a6fdfcfda03df3046f50ee8874065d32bee7ab04ef527494d46c6da403183f9db292df2e97d95075027eadfd52ea5ce8dfc8e82876097d83434d8de267c5dda69aab532d545a2122bd145eba3e5bb9b331b6c67a1c1975b1bf8682e5dacc282510116a32dd9e226ff23600f34910c7c174c90f591acc9d169c96c4da3f3b7591f2b40c584c7dc429d33455eb34e1d38139335ad408ff8c505767762488b27af431daaf44a08cbfad30820c3c767e402bc4a60be177b0529683a5cc8db34640f6694e8ab01be1d17289544eaf6b7492b2f71454bc38693109b80e8c25fff3fe17a2c76edb557401cc00fcb6c12ddb17504f94d519020b9234c9e02678766c9ef0a25c8151583950a076a957957f66e374349409b49516352a0eaa47fba79c44a2d515922db3dcfcaff86cfa6736f8f0ec2326eb5a0a8bb6dd1796b03ac074a8ed1eb6e1719344e85e8b6c1688532752eb4e5340cb6e1d62002573e4146c3517438ac79155ed6024642f66d47913df842e2765b24b81b5fbf77fd017427d8178408686c34836b93371fbf18a2ac6fad7821b8b1f9dcee8afd090c67274400fd8b482dac61ca6b65e5e76904c9812f3059f9f790bf278e359f2f41338cba4e829617c79d09c862e4c3d720b69b85e50416fd16b377044b8be08bc69766e4b15a60096cca5c88cf046055c84003db853eed7e153c59f5dbcc26e7aaa9b02b6e40475e0c5c05dbe84d025d2c92ed2f0b2b2606565dec9493adea72fbd3eb0d753921e9df8274532cef9307b37b3d51f97128e8440095986a378f3057c7594241fa44183962dbb648bef6d3810470aa897ac3bad3ebed8fb63914550be05b11e9611a8fb3950c8211d3937e96c1432817d802172cf0ca268df4beeaf1b8ecf8d1e906dc41654d8a3e616136079bfa7721d74b81e8fcaba8917716a1956b8239aed39966b668ed378a88014d95e02a268a503b25cb1ea845f159dbddb1e7266ee2158ed48ae019932c83ad258194d8ec953ea4c50d834ad10329cced6789b53fbcc5bd65f29f892c745558e08dcd47a98cb3050aa28c02ff04039904940bf1b032aa76282a571a5d104172d0de2c69b87bd2ee7ce5635dfa892c5c15090f177c8c7138a839d4b5c22c6a3045e06630f6695507904a2f4f58261c0633218b50d409bfa92d85ac726c99311f83e83f7164f238f1e547ac401bd03d39fc214430ba89ae8aff05326e8e4efae50e05dffa8f8229ca26048b83a2d5621c6d80c86722dd4cfea591e2ac1be8f921b4dd0ae8a2d28024cec64a7c38a9a2de045c54226381717eb905b1a42d38ac4c9fd23e2aaa56731f331937c74113a67d367bb37a5dfb95a15f6152b6f81d3e59a19d8de4a1323d4ea21624c1b76c63b5cb3da7b9d1b612135fba3a63cf980d12315639e98508800319b852f805322237a352a00f2ee9cc830bbe01566de5b1bc9fa257bfe4ea993a0066db65c138d3d2d809fe8f68d861be9d5a94751db4799f832be1e58d6c9d64c985fe5776923810adeabb3ec1c005fccc9e64db891a58505cc72924033b92281a41b1b856496e83f7d0fa2d671d36412fb4c8d1d5ac84d27d09b7a477da7f86f6d1085f2604d5a2686adf949697d04f0a3312cbd041438d2b4c58721a3f800bb9261143bdd7807bad5b5387e69da934a4ea8174f98b27305060200b7a669fec51b91639cf2ea55fd216c4666e5c42f6da13dcf01625064b152b2b769eeb48c238fcfa939d2fb9741abd0d88b3db52051ae345e0f814c4b9c8ef3bf9b7429ab6078895d4f2634fdddd4cf7450501cb5689fcd1e266fe5130314b2b652397bbc10d6d9aefd8aeac87ccdb7ebc7eaa1da49356ecf2f4633bc27090bbd76a0838c5bbaf1b4ccec73ae64500000215c2046337250981cc3a3eb91df95a49ef4680cbffc2bb5cab591e6221882a9cca21456bccf97ac3090917c9d7a7902ad12a9ea4e37cf17297c66803e770e5ce82472413226481d0408e8cdf79682cb9a03f2da36f5ae80d17548ea01ca922ae461546c6131689b4f6595ea0493baac51104a9e2b4a52aafd0203e18381d2aa804b99bb45484637f507fb475348c23cca44ad5e5404986aeb4e6dbcdace85bc36112d5c80a2a6180db4ab809b60e47a0a2d47baac2422e156d67293d276eccba21e09fa3f94cac1ae41c5502a18db51e8c5f8ba76b62b799e6d0a2aa406d92b2147acb1cdb366d9425ca3b08384d56147c09d3793677cb0454776ae3e74d85a65eceb4ee4597351e7a694829826daa8fd4cc11cdb3e23d3850f07314637c8c3cec0a66e6ca88e48723d0703e93de7cb3584e97918e23ae2adcaf03dcd26a60ddaa930cba20c96d8dfde951686774ab9145218fcc7376f4d11790468eb0f51b318dd2b5a21219bbb9d6d18cf031886c54fb0bfb63f2274314fb067fa4447a11920c6b9412833071ebe6376e96a7d5fd769df53421702f19e178abe2f9af5b3542c5cfe3d140116010d26844a668b0b9526b124421bc5a4e0ba88d2a5f84aeebcfdd199f7611d253d56e5e5a26c6ceddfac5d0c5d8119999f23307028248c2058389c8c7f36582d5ff4fd07c6e6acc39cd10053dd0c05b250147b648c64f5adb8de375268effd72e756bb744bb2ac6bca5ea496e0dd804289f895776d135cb862ea6b116b8e846e890869bf81793428627d80d36214c324afda99317d43f2b75c9a11cfd85e408d8cabae6a94b74cdf8194aab94a35e79e1f029400a231dfe9c6e267a7ee61ac7c5e14c3a213d2251c42412f1d1261743454a64ce510c8ff45f5d1e5d2e2459631bfbfa60224ba9ce3c2e260be16e7b0f6e802e7a5314f1f1e6b11da08525b05fdd5326cbf2f2d7660d39deef7e5e1638cd72ff548522c56c20d3328259d7599f95de98d0e99ae0ef10693a5884bbfd9d8ddeb1c09755b5864412fbc83344ac4402aeaddc8674bbfa6113a41232805fe92ee1ee5559758d6e0f49dcc04c0679006a5cf709238fd203cea8651756a122e07e005cfe26a2f1431ec0405480080928028f546f48322054a851ce42a4eaf718c80c53dfcc5025745b9ecdd14783b44b5e1697c94b18e79527ec856023e0ab6c858b4ce8127c3e88c6839af407ea4ab51d808a558b8bfb16c02c4e051f3f255e200c177c33514cff357d9146f289eca57de0b977fd115210e05a13ad48f28cb2721704b505167035e672426fa0c003b64e879a2d52685cbd95f38ecf81c53ce560155415d8caf918df78c0e1b8f9488a3ed6344edd1380ca27a278232116d213d10c75bb56df460b6461800acc14a800a3c78d64f4245b7ad9dd03c8666b0ce77d6fe3cce961d5949fb962a2dfbfcf3f8232c8f14700c53e82f6cd2272570f0f6728180cc53fcb21b3baa3f993a8628e26ab20580762f96a38c31b1cb9ae863c9d0fb0df5d876e3a3a719babb37cf731f63bfcb01653e418c7120e9e917cbe6e7f899987af5b568459299e44b312f948c2262f3c66b06be2e8f936ac63bc179d794658c7c24a2e05f71b71c049423947244008ffba41dec5960901f2430bc4554baa6225dcc5de100beda54ddc09848d50bd3b1904bda579e5a301dbee8107c98c655945dd7d126aa09576ea6dc38922988838faa9911197018726195142128201ca0d21af23cc7b11dbe5904b00dba4b5ebf32ce250bb5b10aded79501d497cd6112d57e5b98ba8941c839c74b5309414450c9062b5053f283a78348a7b9701ea1dce0971ed0a56ac9d0c95eb1e85a0344681fa4a54a33c49849d4b5c48720387d27526f11449da415c90d15c6041bfda48fa5c998667077ef05c353a8d108ed6c3505fcc99d36046246d594d60162fafb8230e72e7ebf3cf2545df23b348a42a738af67cca3bfa3059ba960eb1619b688136af979fc3df7c8804d46ea8287618287ae5b3c4564e0ba6140ea8d1090f7848e3cd801ec9d42131a1a884277b66909b0862300b9db1f2f7c593522a401b5908290d66baaf9bbcb305e245dbc33bf1eac0fa4735181f919630742c68787d9986322a5e026d93d21309055b17ad2214a5004991d62cdaa4eb5209d0f41b5cc99af318633ecc92d54cfd577499f6c4c1aa557e3662964def6969d2224014046d4343d33723d6b2fc4e262b99fbaa5beb0e62132f842c9cd8783a871173a842ba23959f9d5906c64a56ea0a05945a38ede7bcb492118ceda2e574a7b5c8aca9e5f04df010c5caeef6e0a37462d716025adb71f7194e107d0948681cdd972af1b6668de39959a39bc80967804e314bb8f6792c62d3d272d0cad9037753329a6356068f8ec64cc19bd14aa9991f6d914fe0ee53eea9521d373f2a2195139af6b283073329d235301e8641349b5c789e1477a0c72690d3c48e9c80d0516fdaa9a3b792146fb78ab48be2326684c9d98ec890b8e50776711a9de88a13d57bf3bad540cd2bf86220d7645ab9118dc1ab44c39838bf86647418746d9ccce36b622204e50eaa76a82edf346951503cd5d5e8b3c66614bc6f62ff3df8862215e9e2c264d1ed7bd160c55190b9b3332053241ea8a3dc0d38cee41ffbd39c6517a9a2391767eee87b34dfa6223a6662451ab28ee7c32d6926328adf37e3697f41ce28e9b315fcd10847f6571405be820133698da0436572c40dbba0c25060f50da124d38209d9e00a8b3fa0a7cab9a58ef546936e0861fe49bc411ff0fcbc9885c15ba7448ac23f2980eb808ed78b1bff52a289c1ab93d9fb799430da8f94020888fed6f334f715ac8f0ce47427126fc20aea4db35e392c319707d19a5164cdbded34ab91a4a522dd0d8ae1baed6deee3d130605b6ba2bb73bf3bc0adc72daf63b7444ca5af52ab84372b5578581d116fd021efbb2bfe54c37bf1be2c764b1d2ae9820655ba84b405d93496b8cec558120b8c6170013ca81fe1021f777cad2ee99743e579ce8773d54738a57dc40e5ae1fd4a4e9077c013df0c4578c551505255798725cd66e32d16aee8c543ce750d6cc8f947927b177b1ff955e910e512a14a81611c83e8e0969fd74726914f632ea655f962c6294ad4259a50519fb1c558adb4bb5b9295864924ce76b9b13a24442d514d0e7622e88b18c94150b354167fa30095a562df5aa9a63baaf3c90972738c11b58d14c7c30dc1b3e9d86bfb7e8dc71ced9d17ddddfdd5dec4c41576c93e7eb43780c50acd5fca9758da7bd648c6eb3a899112939584ee8d0e600dbf0b5e4bc659f6c0ba42d14c9d5341582d112e3e825d929abfcb9050bbe7e2415d4ecd43b24e8a478a76d09062414d29898f2411e7d79812e4498acc76691ea62055d57ececbbb8a1078615b0c111b8d161ca558ce93c9a60bcccb8b8a0608168958f0a204653623e6d81baf923e5e0cf72770d9442e3f9552b3036a103f157003e69faeacd747f260bd24e2174a5b432be054803d3e0c7d0c07034a6c549d9362b6e4ff5dc00c5e810d40af7c01de7c1c47ed9da20405da64312002caa3799a1feabf18933879e0c394f5cf3c3af956b077b6c8b52fdf526478df2d35e802c0ea5068c1b3115657628c6b04cb1a3e46fe036ce0a7ff55c4b962fbd007a9a87578b7ea6ff9eca39149bb19c93a064e38bc7832c93e198282d2ecfcd649e434feee4cf18d15f4407ff1a1694984c1d16964168a5b548a5c9d789b93d61e5074d013420908e20ca0453a219834806aac6f650caae38f59249567f9343c2a5589dd8886decf49d7e0202887b27ba77481aeb06bc5389f8f603f7fb36690309845303d719666e12ef56d99b3343871d46a1e3bfbf735cb3896b09ffbaea233df64067df709d355dc665027a8bc7e70d820543a1b2996c61d24c0be2cc72031351fc80e6f36691c0cd93571feb4afae752ca80d28a90cb30c6430fe0b67123a91545e48f11e52969c774794bda8981f1e70a5674643e9784561891023dbf66e0cdd4234a343c7bd7052ee8c345568a483697b9e24a94f4af85d8007dba5238c704461ef9212906d2da2d3a8fb782a7a5b6cc5f95a8e789493d0a7802db34a8f64d67ebad1b9a8091bcb9440b8ea7e7dc8726e2c59104dcae96cd7431af28c90219b510c4b6a5319aba2252cc3e535c300a782575231cbdc30a1dfde6644e2fc02a4d1721ca8af22f5e5fad04d3247a1dc69ad702a57d8a1dfb04f16eb1045d610177baae8f041eb6e72ee24a3dcd4c35b1a7bd11a36beee76a27f8bafabeb0bd8c0fe45278b596fb06fe7ba6b2d929ea40812522d5a1245820dc247adde667f60bc37c91abfeae88dc5e5e1f8cc6786a2c57fec4570326d8c3be78d57162db8471076bea45b2882fc653d6df72aa658497535ab5f94df0794b2ee5c5a4db87acb2b4457e768ad80e316f4994b313e421c5682a110826e9c9a22ebdf46977dba86c1b85aec2a150fc99423e8f79caf30bd68b02c18d61d3eb5870ca47b0be348f4fd1964e503b7037031f179aa5fb9a9b8fc6803fcaf20afa9fab8522ace75e2b5952a74fe9c7d6ca5e9d54b293291441fcf4879e86951906d6a18ba68ccd4538bb4aa2c11d5fea27e32bc6006330e5c408a6ff6ee53dee40c76c88b500df529012c326763088af42f4f5ac57398b3915082cf34c4d0284993cea49495c7ad07728108d9c70aaf52d62a11a699a2ec38652213e2c2b3fd4d8dc4a2cf536adffa9cfd10e69ec6ffd369d1da17460b45d0a61c43f9bdacc8b161beb4c09b5b032d2bf68394946850edb19444b3d6b8ef132983810e8053cb967adc0b285b8a95adb610c8fde24e47d67c909e80085bac1000611bae24e7fe67b3e8f524a8e53a2117ac5642a066c1250b6af190d2a0e12889dd6f364afc49247b02fb18da54050ee450cb40207dd8c6cb11980fe82583820877a2800cf70b36928267f8b1124055ac3c00c994f3af9e163922780c60a584ee948dcd25c0a46948a38b780c31f03aa56333ed2465bc498ffe3ff534af74f8057ebe59c3b85cfce68b94ca21af9d51616144655f247d181a94720003145ab6cebd891a0592d4e7895884d18959c3c1f833024bbcd6189e29b1857b0b59b1072efa08548ba671923f6f6b235656f6f739abcd7795a77eb258943dd2c2379991285f1818c46517a816a9eb10717eb5484afada0711bfc02c7229f6eec6d8387dcbbc2f6d29b32d56255c71a38c4d54d1b409a3903991228fdd7815d917c9726060eb066f46e25e3af89ea9215cb1778bdfb0ec716ee0c9818fa884cbba2d8c4c7f5dc7171212b3ee8da1161c91080c014e67bf417fbb379fe4fb9ad2458c2e6533054c48d8eac89484187100289f402f93513a18c3167b310963aacedb83efc0dde0700b4a36f6815e23c05a32c42d047a8f33ab54305e19a503f808a2d062e0f54f717eb72298b102d7294de80620ba28c3fe4e40834b918e06329687682eefeea600c3f0a3ba04b4864b6712db3b9a525a9c9e357231f83294b5cf66c9267b4bb9b794522699920c6a0a750ab40a34b08dc91447ec1449537fb3f1e54529a53897fa4751caec7f5d1c9fb33ba3eda354bc6e477f6558f95786ed183118067d2abaaeeba22fca70ac6fd72512d1abfa7096e56d1acb2e111687dffa17fd5d79ac5e19968eaa5bf9171b6157fdd196a55e10e4dc150cab5744dfdfca62300c5a1bd74bd5180c4356128cc130487de25763300caf14636885d9edd039e75c0e900863ec980324c648a974532006a2e9508c910a758cb15482d547d1e59a7a17f34acbe99c3fb169cda773524ae7e8e7b77a31966ed28b26cb8b9e246ad1f7b3ac88eabd6a8f92a51e76adb2b6aca286d020121535f5d3ed0ebea6280a3a98b5acd98ed175ebd6addb2184cecdb0b75d5314d6cbf22f9df547bb84240a95304511e7a673530cd982d016a0d818b631d9420f4541ca51f0ddf970967ad68d1c2b7ffac7ec62360748142a3e45b9f70ce7391bf963f4f83ea9eac35deadb378aa228f9d4d329b29eb6850327562227faeb125dd785bd88e53b5ed48ebef5cab3ac8c30516d995567ad530a898e5a66d163db275076b11c206d46f169c5049a13287eb5e364fafa2ba9ef1d57c33a4ea65ffe55772ea5b48a7a6c3febb89a956f1ddbf2316ab1d1e8a299ac559c3ad47c5aa959e9502a654a9952a6941eaca34ef44b85ec750c7f3253dfa46ceee553207ed99ca5e437dbb24ba958d72c948f0afd68eb54c83a29a50baba6799c4c7c497fbefbe671f1256d1e1bbfdba7fbf6dff6b151f471f454bd18f6d48f9aab597959472f7fa55e49fd28938f65b24219aa56591bfdfe2b13401198557bb42c6cec21b3de1e258753557feaf610ebfebd7b1ac440c8f83042af34886138e7637584620b3b520cd929aacd65484185f5c1362652f848d1630d601b132856d8d9a6b70a7380789b69efcec20cc70710ce6efb81f5f2fbd6fe72ad5786ed87d60dbc81df2c38eb75011481c1faa32dbc3938ae5255fef5ef8fc140c4fa9ed6cbef6a0c86d193bd499326cee33b4e6408e8876358a924a51fd1bee347384f13df7122ed45fc081edbfc5c1b087a12bee344bc88f3f811cef3c3815880fc08df7122cee33ced1aa8891fe1473811df8912c88fe81fb27e38901fe14730901fe147fc7020dff1239cc78fb042e4da8a6ea251f1a10d8a7d41b40c7313b6aab79d0bb34f2fe926aca87e4a33662e6f399703a4629f56527593e85a0be7985bc416a26872d9ed262c3b572f73c5b95ef45595030476131ce7b4aad84749ec9f8ab6e825b4bb09cb4fff555dfa2b4b5fd116c7dfd56555bd8cc47235b9786bc5399fa6a9bebf957413b79bb0d5bb4491cb5fd5dbb89a215ebef58be961967ce5fefe700ad355d48e7fb80543695be192f512be3206f49256e2f2b14546df6570be0bb5ef5fb24b5dd8c7ea255c2ff958bc7a49576e457f7f5c0f2b4ef55144e95531ad90f41246420d1144d5a0d8c8993b6524963e6cad7b492ff9e1487a897713360be825544a5c8ac215d1fd0a913fc13f16b6582377f77ae3cacb7a7fd418e57bd3441ecee489a6e19b98b975c373f69bb2d1c7ac9f662ff25bb8d00126fe0edfd60d51bd98855c6fc9eb7d1bebf5c142f71c20a2e82ff227913e11d6493f73acc8bdff3817912a8e7b6a8ad7ffba8907cfae3f61e30e15a6de9f830ef596da30e3df9abbd7dbe307917b7417551ce79e5dcc7ae700218204d6dbfaf527f6f6ff681c7f226c641efca2eb4da43f7fd7eb4fd8fe53d66264e5b37cf7d2559c6f5370114fe6d0a40dedc7c2bfed0c56ceb062a8997132f06fabc2ca6f8d86e9f6f841ca17790b170ea03f9c09e6fbe5f3cedce1a90bcbbe94c33f7e8ccfa369e4f3fb0f03115ff4364e747ff4f527acfc17918523befc254b9fd5eb03f65f7980d4efa043751da4f74ae63ffc71441edfeb05418e33895f8a8fc5bfe253b1ea507fce2b5e3286c99808f3f4093e0d16bda3ffd848bf337f1b67ca46ef2263f916d9ca9332d2bf60d9955199571e7d9a812f457f4bfdd7077b676cfbf632662dcf160e37fae66a8668b93efc9744f596a04b669a4fbfd9dbe387cb2dcc14ff6d61c2404491429815a52bee67612f1761b9c61fac553dbfa8562f5fc42211bb882a7fcb8b6a4b35cd8f4ffa211cf4c187ff5209ca8f3f58d1df1e3f58ea3192e859b2951a7f84435da2e71d57c34da6d1b476ba2725643e2d8c8c7a2ca47eb0f23167c24088e45f6f3d0f6702fd09dec998489fe053f5328f85505667c23022ac380cc33bcca1998a421d793221f3f5cc511eb1b12b1471375e823ad2fde47a287a9ac5f780ab69f146cb0102ab469d933d9411ca07d28a5a02d2caa57a17c8cc95f51072f5fcbaa9a694d84b35744bbaa78c503ed0fa764fc1e76f4d1db1d4b756338226f31e02adc6034e884683f4b1b2b87e8a3f46e866530e52c5fee9289accfbc7dc431969e7ee8fbed4111b5f9459385af4575c713e2e917a69eaa2e8874093e9aef0299f8e75d617ea5daaf39954146a897ed2509a8a3ebd7e423d650487e8aba732be9e66160b071165adc703aea67f46d06a9a14c4beee1f57e37e3a8a56e3a28882510c63961f9f5aa20159f7b74703a2a88a232996235925632f9251eced273fae8683b8285a0dbba0c9bccb40b49fb81a0f4420cb2f7af893fe954908d15e58a27ab10b5aa38283b81a083c6940363e907def016a89f857a596983189f7b2a7699698933a52c5ac9f34947ed24fa82518066cd18408bb2612855e268d4f238b23b916277ad75d1b0d97bf6e65f49873e19a0707b150d3b475d3eeca5c7c2bfd9cd27d741f79340d5094cee41ccb218e26f90c00e74c3ba449c8b22bb97ad9b173ce39e75c741c7380346ca682e3dc026220fa250fb9fecb42b259c8c2f8d1aa381d638ccfb22a8c3146f7c3c98c86e96f84f90bad0e7fdf0e3c7c371affeeb9d1c868d477fcc39962fe03e05c3f03b5942c2459c8c68b6300be85eb213a179f3a177b084013e120860163de5bcf550e6220eb2e0064f46bb6f25936facfb0e72173f91d32d1eb90b53c4c467a53c6f2eecae6bb70c1e3b5a82fccf54552cf2fdf5a8d0fae5f38a86513b272be94ced28ad31f5f5a2cad96596d353e74e52086f1e22cf52fdf0fd9392b5d5a9ee52741cbcf92b5f662256bed05ff28e3f6821fcbbabde01765de5ef4c7c791d5baea6d513888818856e5201e1c44290bcdce3e463e0ef2216b31af768972133c6446347380bc79cdf9e6c54358c83567bd3cc4e7cf36b38b7578c8756a290bc13e46c84278486cecdb1523eb44e6b9321c3aeabe9e752edeb9e2a8e25c4f57580803111f76935648432cacb2c5ebe9d5b4b290cbb4f2ae0663794b8787f0103b1fa3d853cac2cdf2d72dfdeabd99c5e226b08c857ccc959d9e85b00e36c258c89c95e78565cdf295224959f497a89a28ccd5bc8b2c24bebbde2fc84258080be1211ff3cf4246bcb2b3d2359cd428d20264df4ffa357830513f2c9524d71a38b0764cdb168e15d87050a348d35837b0b26eb8a92765a28719f5335b7996ac7a081f8f93810f27848de190f11fcfac3c5d6fc9de39dd9c3578660d232ec3b11acb9ccf5c83a767b2d4c081eb6ea951c4c2efaed0ea86ddddeead6f5851394028f85cc388bdd4c3ac6776dd728d9e0a36cb7cca718d2296f2aaaaaaca551cf87d7bc892aaaaaa1eb294dd5a4df5c4c944075453cb535f61462e1717ff02e1c3e7ef1a3c0c047cae356e8d22b6fa95ccc2b162bd68a58a317e74516fa9458cf0a9fef0dffb67e9b07484c056d67f46ea5949076571bc62925482793d483a0c80849329cdf26acaf15e39406a2298e86ffdafbfddf8b773cc3cf0ddfb74f35eedeaffde7bef357ccf7c1061df63fb685ac67da394dae7fe322a07ecfd751cce49ec0bd84d3baf3f5c8702aa54a9f2effb5f15815b1cb742e802cf9549d8db83f678cc2ca9237df2964e1d89ef5d6d0c03be6794112b7b9c5a8261f84ffffcfc2c51c23e4b7aa7775aa765e0549c8a53712b7cc8d1e0c46c0f23358d1b1279888cdd2cb7738e2dafcd3316e23c7233e99d9681483a9955effaa7cc6e641575d9bc321ccd5e3f1d950f70ffab5eef7fd53b6dba59573531a0d9eb71347b5553f538d7c3afaa00548099725c0fffaab24f39d6a6d9caaab771fc3996ca7a94acac2d677247f9d119b2a333812610f5f353bd833e4e2673eb52ca8cd2a6941e234958477f7ca4cf18a69429650c3fb1a1109888b7371250a13e452ae40efdf97bddd3dd975c0d7d5841a9c4c9b877199f9dc17f19c3e87f19ac97f93b63dee1dec7bad213eb9e95b89a52cbb82f29b1ee7d0ad6180da24153b0fee6d23da11a7261b69340469f38da27a34fec23bef7b1ee68311806d7981f9c0f61fda5ae01e28120418204b1d182b711830dc0ef9e04a43afe1b48c4cde1acf5e90d61186c72e609ad51be05a65ec0ee6701c3a1fed9fb967ed3c469d1c79915bf5974523506a904432ac1b42df89b410506ff92603c0b18db8f39fd3023a369bcfa180c63d6f9353ee687180c8363dc57a3743b591ed1a3c3cc3a5c9b4bc133f28b825de6612891a2f3bdf8919f8d7b3d4918e949c248f391c2df9b428f0b187cee9e248c1cf131028587a74812468ef84c2913e83d9e9e223c459298526694d898e7d228a58b18f348ca3d534a0f18668bb9eec7ba672297796c2c626365f97336652bd6e653c4f93e56f62a306735ab050c47fe9b8fa2936346dfbf6fd68c14bff86e65a5418e63ed9fac9fe826fdd34f34691ad83c4ed1ac473a64f97db82a55bc0b187cee9fe96837699acbae058cf9df47244d23957013fcc3f6d2208691c3440b3ad735c1469aa631d14210eb9e8f3012da2c4981d8773cebc355a942c45e36e2e227bad37141c5fab77f4ab7c446a28c551aa1410cc3dd0fe586268634011fc2772d0a0b81cf63088ff71e8fa611c2431c7c3cdc674a8cfe1afda4f1a708bef7de73cf83752a0fa99eff5dfaaf5e1ee257befbf651f4d67cbed7bf77ce5ab112d5dba2b8776b551c59ad874e424b561cf7cf5a95855c55baf7fcc69458367a08a91b652b2f33d8ac1bd6db34cdd8ae64de32147b2b9bd44a19f993e9d30ccb64cb60a4120c112ec76a0b0ed3bd26fe84b3b0d6b06e867555469f1c6d973eac578675f323fc86fdf0636beffe6e67c56933fea535d6ebcfba8f417fd28ae3ffecac31bafe687b5d460c8601e1ab6c1acec8808eba97c16f32a0bff7fc41e71c7ce7e0730e66b25e6f3d2b7d9b86f1a5cca88c2fe7d36cc29b59513202a9ee3277732cf4e7ee722a9e5a509264a424c968341a2161252b2bf5f6a0499228e1a1992bc3c224489228191a25513242c24958090f7192c6496243e2c4c66f489ad8f80d09921f1bbf2169c2c66f4894f4295e5662efcaf3a5c449af7a517bebcdb0f03da9de190be1fbd1a85eb7573e7c160114815575c6ba2befbd57d1e856cfc6e7240c045671aa17e57856543909c3e0ea554ea2c4424ee25e5d24aafcd945e016879f7aeaa3122c31c2c73a6631c6883d24c2c2c882e3bde8a757ef132b41fa973552952d83510b7b9b9ea20ccbbc4fd5b364b265aaeafbb164a4e7ac12bd27b1485209e6297ca8248992249d83f5480c3dfe8c7812aea78b381eeb884cebdf43ea8894fee5afc44ad4e85a81a5fa52d52be535c4b764adc98cbe610f474f1a3dcbe8faf72bf1c7b3f2bd77b544efa938923fa2f547df91d05571462f471527feb3f2d53a1a413a1a8d462347e4492c2b4f1079c206468ece08b7e38c70449e18392346ce0847e40967c468d4ac11352deffe5d4d4b1dc2c9b86ff951bd259787f5a592ea952eb53919f82cb5a5aefc7c916359796af4d5bf7a63ec1011e2b8d8b6eaaf21dcb3d42b4b31f679cbbca792641f8c7d6ffe133d965dcf41dc951773a21765d7e98797cdc87035b265f831e9883823569ab464ba8f2f0bc7c25dd154acb715d6bdf690a4e450ab59f92b5dfe962cac97c22749d2cb6fc15a5ebe4bd69a8cac0d7e4b46caa85fc95a938155004560b4fe78d6fffe78d123f64f561cecfd29cca9e94f451f9ae2de433de478da9555c9ce7032ee63bd3f5e4f1162205a4fe9a19ed2432dd4403da5871c4f4f69a0290cc39f044ec6bdaceac5ee0ceb7e62a51286f1308f93918d06dfb7d1d5fb96c25e7b8d8a4f0277094005d85beae3a8de5249545fbdd855af949622817c39b1b00e3a086f54cf56a4242525f5b162ed05cc46d65de62995fe4fd6cd58fe3b635d0ff514fe7939a25e19120a120a120a120a120ae20124d4a2dc06c4127900f10812e21124c40388479050108fa039ca58de9aa20c56d925c187855fe1a8b4156ce1908dcf83812a0bf529be876fd57a59e806db0ad62bbf7d6b35a3bfd747f85413b290053e7cf7c3599959ef0f8765ad65669df3af14401198ac3da895f3392bf9ddca8ad3f19b3f0751cfc6277aecf5c18a926cfc8a7b580f34185b91ecedc124eb15a7aa28f557a6c4cacacf7a49363e96ad3cccac87580446cff2ceba8931be8d9b908a32f8518995b7e919a995c1af20307a96c7b2951765d6cf2a8bcf16aca3487db370505f55d925d9ea59322b937daa7e25a32d533d5b37a8af7e3265c946bf9215c1041332be12d8c7ec669479cbf05b192dc17c8c123a6f03ab58cbb0509050905090509050d08f964ca6333276788c99183262ccc49011c3fdf42c60cf624d23c3d2f8c7f7695d4f65f2e78cd55938e87543c66fd60d5ad95a19955d195b37e4533fb971bbcb7ada24c5487d621931285347729c0b466c0bdb987061889d8ebe1e2fe2789a8875b7b1ee58af3ce4cdfbea8f7ed60db6d6c7f6323e15a997a9eaf548d197adc977db2aceac4dca7afd59a72acefb96e3551cf8cfb6ae9e851de337ac4fced56c62feccb0235b583940ad571cbec1300d6b625ac6b1901d35d45f6a634ccbb81bae598c9187340dfc266c9c5b37cc42e090e94dc33a4278c88e69ad1bb769696f4ccc080b9873ce954ad601a936ee0d11c2303ce745587d38fb5efba9faa20195ef512078e50091d56575f5d75320eb9292ba4bbe6549f8de494b5279c96faead2ed1201a4483681014cde57bef399c1bdf9f08cbefdbe5f7324247555f5129a59452caea7f34cefc7649497f46a964f5e1ae39bf256d5a45f8bead7692fef55646ab83e0ad6fb569f5b4befb9951b25edb62dae2b804f5a6bb7b3b7cf74440f7e93f6dfa7a2d299a0324ce9f693f3855b462a43f4361443cfd2b7aaade1fd76aac5e10e4fc95b53e59f5d2faa3a9efafb2180c8392b15e2be23707510e9047a93c3a4485a8100da241a31c20ad43812895918f9e028de8d0685e2ad443443d64f4d7e988326c527f1f66e768cec74a348806d1201a4483240f4625f573ce1c20f1452b706ef5b055ee2fca8f0f7a453d29f1e714bdcfd9667c5186737db3ec237791bf288e2ed1579463ac73bb082b1a89aa63a3d19b8f61d57bd0e8f3df5f994567bd1525618cd99402eb94927371cc220b2b00db9850f1c452f16339d64fa65635e5a02feda5f4af7a85b056651c79e1533915c338f83be79c7bce39e79e0ffeb1fcce55f2537eef4c8fdb8148f76d92fca6c86f82dc6d5fe69cbf7b771eb4bffbbbfc6692cd4efd8d7fe1dfcc44f59ba209f69bbc5972cbd8b28fac71bff75e95efda0e586545b517eedd3f21acbffd95ef2f330e6febeccd5d7702f6bd6f4dc37fa56cf95d258d4603beac57f64f297380b5953ad8e2c80fd85811c00fe40471e884c8c56f2f0c18bf6c62b01f78ab79bb75e33893ff046b7fe563e76eed78ef2fdf2b25849572c7634b007b5580c5674980283431d858618d695732ab9fb469e6578f150023596f0294c5748ace39216d4df36cf5cebaa948d6fa69b22c0562adbff7fa363593d71b95e5f6c2bde9aa37dc5fb7f05db336ceca7c0081f227cbf9cfd2117fd62b7a6fed85f5adbdb87e66a27af9ce7f0f65d3bc7f7b2bbbf3ef7cea29ebc6fc7e5ae1c86ad211df3f567f7f985dceb1f809c13560577e13db4eb4008aed8ec28bd846c18d4fdbdd12001f086b8fb91af8fd5202187c2a600d8a2243f6f27080e7dc00f86773cdcdaf06c239ce3594d9d2861ea0b44c01024b102a2f9c94e8210bb7fddcd64486bd27cbff6e5d7b2166b81ab7d11e6b1a0358fec62ff94bfcd2368b9f980d0458fbc9c2891dd9f623072a6cfbb19207cbdc9e5b4da9c9f0b737b51a9b96e1a7fed6684d6c7362db0be16aa46bed17d034ee5b9f2e006ee08fb280dd92e512ccc7344ded31c33e2380891e211d3c618a2bdc50829d335039b204305049821620172043a14414059512cb504541a594be0463e3621f8147804cfa6dfac4801f1c0be8133f3f5feefef605dbd37614b6bbfb674a7de226a365f86136f33025378282ddf663f96d16d0346df9191044d3dcf6e3f6c6d89e61fbdb605b86ed2ae460fb65ff589bb6e952d7481bfcdf35ed87bff50b016bb631a9e28835d9c6a48a2e58681b932aa8606fc9b627b22b28cc2705d6bec53927c3dcb46f4eba75e3ef4118a3941445393b725319a9e6a4d46a587bd138f34b7a17b1ed5b8f6ddf78da8b8b7246e486c7b6175938dcbe9df6a2fd1451ce30eba68d1af3af28c15cb5e9365ab16e562ce798857246b26e943461dbb7583748ac8b0bbbbccb94035afeb65c2f059e8f6d2c24524b8b8b75d3faf4d2f2f2f2426259797919612f2f2fa297cb7a79a1b3a2647c7981cf5d73f3e1e2bf3163b95671983525cb9524038cf6a925148c9deee036a254c2c03f764b509cc01dc37048247bb12323905204edaeb4adde0e58f72f076671aeb46c833fc7998d6036b56fd674836d5bb658e36776156b9be35804aee635991158f7aed97819db68d60ee99a5f703a817b05dc1b03c140308cebbe5b070a6c5bcb3bdae2b87681f3e6da7b6bad55ef16b8b77bbfe3f8f3e71ee5bd0b76ce9d3be79c73ce3d18deb3bb51039640d2a7662fff7b5833ec3ded9393fae4589ffc52eba5126d8c04afc7a1fb73ec1435763737bc6236c7390464c02cbc1042c8af0bb6f5a0897f1f95b5f75e7edb1b33afccf1a38ddf0db3fce6abecfb7eef7d6a99f520d9c75da01ebe6c35f263cc1a26b2389cc96c4e86cf0f6b4b12b0ebd6bde62a7e1ffffb7e9c57659f9afa426d34ef2f7feb130f52301c7e6f3fdc3219a4c4b0190590c95a946a587f890d9114239148561c48926235463a4ff8a08613b06143c9844718e1eb9682be9b61082c60a0f40814232d29839bc3132023744b119e40d96850ff9e6a34aa7fdf604c38614422da5630424b45f8e27b104688cda0074e2282ef50ecbd962ad2d217d603605d07eb584bab1182d468c02741114290c0d5f0c083946d61fda1bd700f4b2f2846725f83bf57399c7105d5c3b651e4c3c2776ace3bed7b0f818537d47f55dbbb082c7ccf51397ccd9b9004a6ea81922aaaf0c2a4e4ccc5acbf272c1365cdf598895760f2af5b27ad8cb658611eb0f119b3f1298a87999625a45842ce58af557b0f60aa2490f620b214a10c10c658a593f207dd469630f3e20425a4222871862a1ae1794565474a2b96fe347367c029a10c824949fa1356ef694684cdb8ea9d315a9955bd2f84ab2155965269a5d621a4a4a1e2108fca9ebc955004ad57dfb9fac1c18350ec3dc6a209596f43d66d0382407313ca54acf310033115d69f9fb826aea67aafad84b110d23b8ec25cec1dd83bdcc4de522b8180b35155067232ee454828f110c5488c85ef30d1612c3cc863c113c2638333bb940723739352ba8184549c8f7577db5ddd076bb1ee884bc2157144dc10ebae08ebdf59748dfb692caac3c2c536b89fe97efe74b2d7fdccd8eb7e6c63612f86858b85d5e9b02ce186389f2e0212e703a94023107209831042f8de7a940efb6115c1b3dea7b7862ebc1dea8a35b83869542ce145a8c4b3035f59027b4163e11e62d7dffd61bdef3d1caf181446701b3cd9683c1d6d636ded05e7c808dbb16086b27583f5bf9365e607212451acd1785f5a41c9d5c43424f529c60698f729c6f6c9d957bdbd70eb27b0afb5537c0d32bf210c416708987fb324b9c14f692486d20a5e637f6666e6667e8f04f3de37f93ecaf7cdbabfe7ef555abda578afab934a30dced48bcf79e6c01f6228c5404e260842fbe577f380b2174d69d0c5cc6b52d815435219cd55343587ff6870fbe079f6322adc8c7ba9f9492484fa7d1c0f7eb46b0feee737b50920b28468a7f5b58e73e8d8a75efa875b363f9e78a0fb642048cebd580fb587ece2889c508c90bd87d3ddc970fae624d399cd580a59eb4176e87ebd8fb7a32fbea45054b0fc67f2b23d619c1deca08c548bd13c51856b0635de4a306521440a712122d8b49229560bff760c348654cb8fc17dfbbe8ee50a475d3ef482598eef604140e85f8902da9c42fdd87fb60120c9348303014098654c29a06def7fe54c684bfb4ac1c2f5a37f2a115448e7599c32bceab9894d414a4120c77c37e3c78026484dbd400f4822fa8c1b630015449b1841440fc24073f2b4bb88d0c8d0ac982364523c30b4fa3626261c90d1a153f8f87b0b095302af358058bb159d87bf5beaf7e62d1d2e12f2bb47460c07e4549eac7e3a14a952a56be6d96aca6fe5845f02cac38af6255ceb82a151577f7fb1e0cde8b2c3e3a9e0f3b010a4e783e15959e35c4c09a36c9f695cddcfc6aed857f0f927db04acca5c430ac51dc24c55a1389ec3d3d0b2ba9bd70dfe203d207d84a8a7177185a76aa1febbfa204f3ef5b61a1fa896ea89e506161868484eaa781c18916543f2d3b2e0bd1c54a55d3fa781dc4441fbf1b8deb639f68fc6f278865a2eccababd786f65de5ebca7f37df59e8a39dc3a29a3f5870fc6f8a8eb740feb58ff91d065245827ce815dc048ccb8048175a21360a0c23ad6bbe706940af4b1fe2b4930bf100ad6a18f4c012c82857f211460ecab947c80edc524853edcf3c408f4a1549c0e804e2f06c67a35e3f48619947cfb6690a220e9a9859329483839c91e855c2102e66fe3faad97accbf95786f5ffa16b18c063c6130ce0e16adc6c22ab7a2556ba8d0aeb2cac3348516acc5849420a46c8199683b814fefefca13f7ff8fcfde5f05aa50a23f1e6246a1d9e1c0bccfde46475a7d110c93a07c8e75e1280144b4851b2de2725d15ffc9751ef37107bcf41da64decf2a6b3bb3d94eef453eace77856b29d8f5bbbabaa1555ef8cf586c0facbca8ac0c166e5a8ac3b8cf13de8ef30f8d7b8df73e68308eb2df3c1b2625262587c979e615960ee486fc0fcf92fc9b627d6abb7454981b1a4186d522c21c512de6e03d2c37f4d7cd0f348a42bbf6bdedf93605680f95f9275afc2bc93d4bae12cac520c18cf384bebf506d64debd395360d238d19ccb38ffbf1a1fead01b3a546e372b36e1e83c9da4e1b3d7cb33e70b3f220607ad1d6340e731455992a49cdf9524a2ac2222a2bfe2512322d242c8ab981629919afb86192660bfd7f9ba678e5dbba51a287af6e5858be5937d95fd90de96306d93047b4878cb17032f0f989cb439707009599123dfcece149cbc087f0e1bf29d930e513cb549402cbdb3465ddacfc9c2bb639118320d84b0900b060d8dbb485848bb769919016900d18b4cd891814611bdbf93466d6bf5838dac25859c064730a98b7e9f912c494b1fdcb9a2d68c5ac1b12c502b32800dc3627863821bd4d4f1734cbe2f3b062ddb0c038acc444294c171a33d157d64ae52bfa045f94fda00560649b133150123375a000c8d84600321e7232f063b2e6645ebe590cd4271960598b7583ad1200f8a903fd2cfe0ed98b75835506ea79993ed098413760d23626572861af8c2dd5038dd96807eb868132b6a38c857880c50780c9bac1d6c5cf1d7cd02263eb830e960fb62d7ef24063167b80c58f1f4b19db9315eb5303c631960fb6a59fadba9a05ed05fc6f79468e18b1f0e70e34c222da0bf82d6bc078a84ff0e1ef60dd68cb402cd427f88f05ace5f9e508f624d1c3d68d6ae7cf2aa3b266a5751379d8e1a9df81871daa29c77cea67a52aea7aeaf99d0ecfd6e930afbfae1a001a65b46ee2941917e913fc0cdaeb679c3f7ba055467d55796bcecd0a93b53565cdbac89a6dd1ec0b7c0064cd864bf60187df925d4849cdae64cd625fc92a635b6a342e11b5e65bd6ad5e9aaa69ca8155d5e84d2391754d1f40ac893ef5d4acb0aa9a72544fd9748561b4cae877114d439f9fc5ba29351aa5f6e2a5df7472521425fa6bfdbdfe563f45d65545a65a502b7b69c09a1342aeb0b76760e18d26075b7941324b279f7a4a66d4cf2679ce7a4760abf854f5da3b3af48d3578fbd8fed9f2f2e55fbebdbc54fe71d969c95cfee5a7b36e5e9c89d4604d73f9c752d134cd56b0fdfca4691a133010b1fd0ca56932b61cc5f633943edd583f62717979a497ccc5a5c5c55d5cfea5e55f5c5c5cded4e2e22ffe2dff92b1e5d1270bf4a93f0821624e367d5a409fbaa50c1809a3d2a66948dfbf80a661f97e0634cdcaf707d134a3ef17a269b0ef9740d388be9f47d35cdf6f81a6b1be7f085753fafe1fba6603f4fb4bae86833899fe2bc3f2f4a98b6cc0d5b011c73f5e2f3664bbe5bbe5fbe5d9b6a5e3c5bed43b0297b7712e190fe9534be59dca444859ebf4a99f25eb217dea5fc97e9435917e51ffd56f659d449ffa4b591b7132fd34632a195b9131948ca9e028465c0d5fd1fce36a18a88be02c6c1be987fc63fb557e5205ebefe7214db3c344ba06ebe7241a0d0ed2efede3d2d4889de6240806a29fffe46a82684e4eeed49c9c5c75b2621b145420d98161f0372741748d0f1218a2070980864e1cc47bbe8083e6043ef94213f636212a57d8dbb2e0224e4d737fa669ee0e969fa94062572c57e1e49c733b3010cd4a4088209a13176648831165584111234fb08115a1640a54e818018a1776e27b4d4ae73c4ef99e94523ef94fbef7de7befbdf72084104208638cf067b618987cf6c650046ef94d39b8c7f21476267abbbb4ddffe1cb85b6e2d7a89badffbbd35f58efad7b73ff0a8e783ab0421a5bcfd3fd846c6e0bf9f6da00244158ef063e365cd467f0d06822d7fc9d5d46832fc7c6bf45facd4625b142c3862bb5ecc470d1002147b6b8cb03e99746cffad619bb4a0c7baafd1355810fe050861810de8582e51692a5ec8420d5bc4eb61a231e98211f64213f6fe6d5658b671db150d188293ac014a60913540892c9a068a29ac60a5e587691aae82e52ff0587662b98a4987b3fd389cedda80213ce953b339d6a66fbc9f05a0020cb30be813dbd41a7d621f356009227d6ab686e52ad0008425082188064357d8e0390c91010a2c3ca148902136da08c307530065666666e641695edb10f6ed60be5601779052dffe87a6815f1ac280ac10ad460827d35f6a32a361edc6d8f633ad6686b61acc5119095aa67f2801e37e219eb88f0d2d1d4f0706acfb917246cec838e39ca4a6c0f8b1fee6baddb763e7ff70dcfde087858a5acd8c6c332fd4f2538c549a99218308314c814194294534a18402e89cc1064338021a7e88e854465c549899312363c6d5d0e61e1804c852a0f41443c2689b9131a3c68db13c05288210032054c1840c98b071319b5304291409c28113514882848d9c2254a444718624a8c041156cdc192ab014b0d042052a5c01064c104214a64049d48511ec3b42d9f096adf7770feb4872c02eb55d6a4ffc96a2a47d6af938b26254845edd7f0183e98a44df367ba96dd928577fb0fcb6db0a22c7bafb1e24fbaab42e33e5700ff263bdfef0510ab3b91d33574d39e9dd1fed6defcdbfabcf07e18b2e1dd515bbf7e6b8a2649c97eb6ed983f9d73976ef4eed4563777f9f1e639d8b8fd25de9fd2ec3fa24ffbabfd2653c48c1a475cf38ae4a8f42bb3c7eafb5d7321325236ccdbdb9736fddcdb52a6c7c475d0dec0ff86c9da5e3c5c27a4760a3bf7bcec555cec908dd5154455155d8f753626eddb4736ef2e7dc6584fdde73fe2e73f7eedc73d73025b4b48b9b83757730e6ba23b05e231c2053ddd745f85c4b49496965d38898d97d73decef96377e7dc39e7deb9b716e3ba23d8e19ae29785e7f720f40761f5a68a92d11d3abbd6ae88bf0cacb157117e840d61eccc545192bdd9f67bf8cd568eeaa753cf4eaf66fe3bb54c0c16b0bf31a42760fd336e67d08035dba0a721b615325af7d2f2fac08039db9878810c7652937af6a860ed9f0a338d4665ddcff822a4d7bd404b27a57c9c5d370708f04524b07b8bc4ad3d39193e0206d32777bf3fa64f0eb36ca74be7f88665d61ccef8574ac991b317845d927539dc6bd65e38ebdb0bf74f08bb24189817d61fb3e1fc5521487b37b57bdd6ca26484ee5c3be7bcfa8ec9fed839d1e87bad392923747ecdb17bded1fa9df26ece91ec86e0b798c9923e2bb0f6d3c51c5557cf62bd99b36ef8bbc64100dbfdaddd3784ef26d71a02b1ce1f6592ed4db1bde9b566eb321f406cb70f67217c6776af8372d0dd59392a6bedc03163bbfeabced089f9c43045ca3138e8e037f82efc97f39891ccf9ed67a42c68c292192bd06cd08a82f9cd864d4fb62527e39e720728b90138ec95019b8f63bee408344b02f3e118e27c8a728bc20d0258ea6d5a561f5c859ad915c2ca9f15f5183dc2e8103ab5c34a8ad1083376931a03c5c48035fb166d4d43b167ddc49c679347c8593f57f14d547c938c6feae8ceafc3a23333f5e7046936a67bd7d60d02d8f86ee5a822fce8168e99589fcbaed630df1830f71b906334c164c09d261030c01f7e031a0842c083851567bebfb769f9f1a7e89d017b2f048eeae5cfec52dfa3b2f3275b3aa2a5a62001092741b4294840820a765695a5ac1df21dacaa87d59d4f559969c28a81f8957fa3c94dcf24e19b22ac66e603888d55e4f830be4dcb8fcec6afded558d5cb94bc6c23c724668b3980a91f07f4e9b78799293ab7699a2a13e56f92ce11b633846fd36e6920870a12b4fac0c22eeb4fdf15309afdc06a404e7303b8adc91374ec0f67a18e4682e407396070c2061698a149cf02e8b7d5801ceb2fad0cb405d04e820501ac21e06189fb16f380744e6cb78244297dac69aea7367de1bf2b33417abdec5a4f992cfaa649df54d13751f46af6f90062e195f970163ecd207c43180e7dc7917ffd63b32e05b202ae628389f744543674bc082061c37db378b47032050948389982041e1bee8d01a3efde148c3e0e7d6f7f3dbddead9b8bca5e6662ea5dd7f514f534bbf36fc54fff65a649bda9a2de04a93731f5aecc07106bb17d56a859a8e4cb174c9bd829443310000000027315002030100c8784c30189a80a26f51400118caa5060461588e32887614a19638831060c011001019011daa4019cfec2b25db599508915818aebe07b478a4d07421aabe3004a299cadfecab867b531b92ec46e6e358cd3b07b68ca4f4f0fca2426b53a863107765629a9fac1e0e324b22e991696c8ae1977498a9b3e615ce2baf94cfffc9c4db5e12c98cf70f6a7a51d78fd492191e7dca543d02860a989e455c503209a40ce3623b415000c2c74a7b8ca2728392a301218a97bde0151a973a41509a0c262e624e5a32644fcb4f2b89e794357558dcc0fd346a2048325bd6102a916bf653c30bd1fbad41535e879e0bea4af6ead2d5950a52bac6894fcc87d7388535d39840fbe7584eebabcaabaebf78b051038e07ae204998cb3f73fb8c44d484eb494bca76233627113390bf27f9e82086d404422c957dbadcca081e2d66e2b2a2df4c55234584cc93e72ea922f4bd481f6ff165e5d7d10b90b5632eb71895e8ff7210b602958ee97d0523d5d542f2633f9c0ac240f7cf84582ca7f092209f83ac3a86d0914c3be4c485263edc8347348a3d81115eef44e6c7a354e3a2807214ccf1f9bf6d53c01f2f982952bb869c6d019a73739c98e5e36b9d6db87319ea4b5ede49804f2aaa391fa8dd9f53fe98fa4bb5bb5b5fd3bd90cfc10ced3a7d8a9e719876bc1f9dc1f6aa6dacdc36c596ed4f138500a6ec9967f8f54c35d490989c799471aa158acf157492119024d2287bb3474eb8c4cd47e7d6e421d0c58206b6281386c1a52b121bb6089b3781e483922de78f71d51e9a7c880e978a550fdbf71e3ea60eadd0f2d3b7408d9d27ef6680fb6748626552d054cfc784f50bb720ba69821d7e631e1aac50099fa404708dbd35047d695dd8b716e07c280f3392a0ccc6a0bfee0e7bb3cc216857898a31ac056ec370d2cfd3490f4870e42fa11bff079070f0b639d0852aa032395dbcab695d36c83345540560be43aa2a6a9965cfd01602ccbd4bd3838b152fa238207b078dbed55e7704865628592a5c40369f2c8fa359036ac0e03ebfdd311c627e9a9bb8ea265269aa1be32091b5b9428932a81ca4fcad6b0e43770b85042fdbb14a385849fe947ba12db5c689c21254efe86c1b0d0e1032ef8886d917512bf5328e08f3f6d0003ce784ab43f095753663fd77854aaa4f0a78d1c6a00922181e065cf004392799434bf0d97b3c9aa1b91c3945c20cb3d2ca116741470ac19a25cb5bdf21ac54cea988f92417efbd36bf41c559cf17e2c15f96eca61e9e504befadc4c7c71a333e0dd5da2ee40ff4529a569685e669c9051ac3d50811645f105c1749e7fc9e3abdaf82c93fdb8d80dd83975316f00464d521a7b4da487baf6b274c16b156dbc01d7276b2e2de521b3f05cc899845d5046a75e2d18cf60aa438f1e16013e19770bcf5a943c667216c8c13378afdda36cd58f23d775e4e3c0e5c307e63b625713785e3bdf53655cb8ada1f92d5411f78fd3d85964cae332a5ae88a765c625a2fd649d5d602f93fa7e71c3d3a81183a03e3a6add5049191bb0cc6a991aeef01e2ef8022249aeb9d4268477f7a001223473ea2651d2bbfb79371304f8c061974c7168b3634494741ede3fc9c9849234b52c11d8fe2e5f590bbbac0c343279fb3e0e15482ffccc6980dcd1906c00ea8bdf051ff84798cedb4ac8950499f51ff908901774204603dff911877ba1177f57fc73748ddf23df045a70a0c2e7252e92eea42b8963e52cba41e7db85a33c9ff33ae3c0fef0ab5d9e4102d3d9cd8bb8346bb51beda3c7eaeca540fe0dbc533bd0ffa7cd65d4aaa4a74a99a94a95eb1b24692afb945fa9b8ca25ade7d984e480d3291cad2405bbc28dca050d47a34a921c2956cc36bc0647e954f22352bb1d4799b25ee1e547242e560b4781a3f4d8e169043b8ab2ce5d0b38ef122f34e64997b7ac484fc922507a82ff42c156d44ab7bffc71183821192fd7a2ff79a5180ee65bf5d18ea33bd5141c5a7f8064ce2f6e8f5a14b560dbd711873d2010170945bf2bfe9fe1561ae4d9e6e53df1c472539e65317f72a84358328d846826644241dc4b46aa68b42f00910d905f7ae0ef195f34ec13636258b264e618b8d0e0b58f00f686af4ea8af0e1248159035592625dd1a3805f429788b32f412aa35b90c2caae9a2687a4652da9f3a4e4217b93db098a919c28f9f658b8595f210e32b7383fe7ed0b13e5e4e4e8c3ec2c14165c2be524695244bfef1fab58304115972093d2ef13191c60fe00a200172c5c50b3ec6585efdaa8552dff6094582ad1983e1c3f1dde885cf1dc8a87c5c86c4dfc60219e2372c7528832d48d728223645a97336a0429215754cea391603f04205d3e3074914864c1758ead8eedf2c76f4fb7e8b913ac7d1451e9523f5abda93246e3f6edea7460249313869536061ac32c6362e0fc0205ab5900f1fa58f91b7cc9a190d3f770e33d0d3dc212c33cbd6709d539d10578f39e9ae609a8043a9c041bbf82c7635502c03432d393c318beefc423639f53d977f275c519a0e55b714923202d2f047d048b0ab803fc22704eeffbe21ae396d6d5ca1de9cbcb135df728338ab2b35303e8aafb5e26a1a8ea99c00e3d3bd22c10c8600907c39bd9c4d443809c13a875dff54f859999aeceb0c753769e285062d876d124390a34af2b86e782e0d7d8175916c91a87d3948d68d6dbaf7544242aa29447b0d0aeb138cb78c8ff28ac4bc9b420d01e8104ac5775474b7da3b4a6fb3d064ec4569f6b09f8bd0cfd65b41f682420044551e5d13a8b1a35798f71a3c41455528852065ae06f882ee2b5024c759475ad31943e96902bc5374d16c0434e32b4a574b38ab0af9cf694065f5fb3508f127006c9edb84ab63e42a8884a0a5c21f853cd07d9fd32b0d1d9ab4851a00f2bde3a60bc2217c0cecde13c4a53c5cb5145b4a5cebd68a7dcd66e8c174dcfb35f60538b11adec6e3c81202480c211239ecbd1083a1c7e514a6efab10d3421afcf0aeb6650be907ef6a2486fc483d491e3e8f40dd07341b0f1e7f1724f1a366b22f4d9592ad45d7fab18376caa45d8b86278da15e1b2adc1a1fa64f6b9b3dcb3c3df966c7effb211f89a648c49874576e284795de1d98c93f5ee8d2510b5ee8f4a66b1cdf4d2dfd8d17b97c0525bc242fd2b004628ba2da234a74ee8712ce5be4aaf23e88b2bc502cdbee38e4212ac67e35ce930deb89f982b695f8fb7cbcef0a757a2cdfeef87cb41a1100d5872e28ae08626825ad8f642b8a6277f13db1551f3595e732f86fa23784a49de2be1eed30d995855b9a864f53cbf5c0753b81a1b09f0d2202a5d0212d1b83028dd42c91dc9c62232ee732ca674406087250d3015d97e96a9d1698b168cdb20a7189f55d0233dc7156baabca96917ec63a85bf42f7fe6fb3bd640e2944e9dfa04a99c66e24e0420ac680af9cf53576cf54346d75bbe8878bff972be5798486c9e4a5f7833b8e39eab41d690f33f8feb78bd632ee3332acd7e89bf0e2ebdbd06702529caff9b356623ab22671e49025e99a48836bd08d66e4399f7d87f4893ca938fe9251d547d2b3479898d19fb27bd0372dd89f0b5c028f5423af90b79cf4b62405795c3b9448b57ecacac0199b32573f90ec9ba9484c0716fa5901cbe99de1802db34971a8305ab54cd51632ef5c416c19a6616021c53692a43c9f5f6f52dfda726ab7ffdd244a8e6ded14fd786bf99b2ee06e80580afd46ae176a46dbd0428a2da46442c266a4643d24a66abb077f36432a3796df963605e05e7592ab6945b0f852f9fe19f3dad306e3a51d42f0baee11eaa33286687e069845e770c7b14fddefc9e782593eff6e6775e1c89e31df15e512fab3c741cd1c421df33f7c657d889425981bcbf98e93715c0495b6eae1f62c10374ddb1bd9467b42feb3f3bdcca2b7b42c6dbca6a7702ed7f27c237ee986f25c5e3b92dbd01f75895e6cb0facbde69f32dcb2695847c00a0115a268cb55b19b0b8d09c8f8d01e13ea3b377cdf6add5637d112e235dc84399bf84ba514b9fde676398eaf471b8c7dd4ea421104daf1024fce76b8ad3f243a6de82d3deef58c7be466d3a15f7a54c83ad257ae9ed2c7a6b5935170a278b5115da6d27dca7fb3e2811a5c908607784f2ac8c8b0180a4096b89d1bf497b02f60d60fe06271135e9418612b848891cb8753e31152993f816e83f8134573bc0cc2bbcea35643ca6b9bc4e05f4c433062c47043317401d8e1bcaf90d7919e60c4059dc5ec45f876e734ebf6ce7f6a4e28e7463952e31c44cf91d941c328dfe03cb47c2663e3c2095a5af784e66db8bb3fd1030ecffcc64613e37d8370d5266ff996d169d0b771f14a2f1fc51426be19b40baa14c7960d5af6b3a6542b5d1ff27678196f04f40cfb883621953b684b3ecce5941d25983f34c40b66723fe200186cc8cc6c2311a3bcb331947272fc477a0e52f7e0476c7081b99d17e4884149e29ab01c234c7607936e9d44d462af8d17241bf6b7c6eeed8b8f183b54273324d7bd8127df400ea5fd1cbf57f43887daa85859a43eb5517d58dc3564a5abefd2a7512ace33067d983a2ea816179320049703c02c807f265a5f26e6d93e879d992d2e82aa93990f8ffcb2fdd7501e98ccbe100b93c25ff5fd4d15d4174ec931550161c43db0e19e4b5ec3984c18a465e0078980cee75e96cb40027fa9df2f3da6f44febbc3b70f1ab889f332d0ccb37546678a3bc977abfcbc430bc1f4ab76d565feb1be416b19462e14f428bc946b514bc417fd8266cf1857654a593b3bbc9ed37f4ea8d6a430392ad63819a1b903d8f9fe75922b8d7d90bec25149f9907283a11db2b9b46523820ed28584308f3758f823f6c1b1b11e74d90463e176d762d4747bf2ea68291e1f5a59c389ef472277a00f29402bb30f1aa6450a4c12d09401e112bddcb715081c6fc1cd105ce61f40cda0359a1fec7ce3518d5a575dae0888e9433bb0c1380f6a6fffc47d8f268e899bf12847bc803c19e754173476048dc2c146ef9c6dd3f7b4346f118dcc42400183c55df5fdd0bd2d80a3bdd3334e0bdcec952080ce6bb6ba89332bf25f0bba7d97b23916e76b1b4fffa03f97f2540e8aeb7946345bb21469988257d196ca1b67cbdb5a90d235e83ed32407975be891ea3b464205d63d9f6d60828ae85a4add0619fdac9b56f54b2116027b4b44324094cd35cf9b12b4aa22bccae6e27c0b83aad84354644062df69b36125330fbe32585f9020d2ca6ad3ab05c7a9742b3428d86dd9db671e0ae87110585601736363d4294c94420535795be1b2c9aa8c2d4aa24ba6761fe8da75a4ec56a17c70da70d5898a318edad957cb4e1351de914220d627af329db40afd430a403cf68892de9835729930fff6cb7ca32f20f38948d9fa61f8546d175baca56b8286cf89f260d58d26a20dac04b786782d98df4bfa7034a6556979fed283062b23d5f25acd46aff33e9ef03f5c5a1febbad08b1ceffb70048605bd578bfb2b78ca47d7505035198550013fba3df5fe725447f18e598565ea76dcbbca802b9825c484edbd0f31ad23337c2aa62cb852e082d337f959e172ee6ea58d96d34bb49631b815af38de81910815861a0dbc9a184945290c7565863698b8a5d9bd5a0b3c85cacdcc20c22f287ea9aef6834679e548d7cf33a244b22fce7a8cd24b98149325fa9cc935f196984b098f0e9a9f891d404bf90bb8d5adaeb7e75cfa706d33a19b08ed93f7c48722919eff3329aadc9c05d08703f366b241d84545fdd631f3bdf74a70429944829bda222a9b5b621ae80ab650fdc3c6b6b386fed6d99cbe5d341fc910ab35d075b93b5fd17d0572ac454e9424a36ca9f6cfc6232ae9b7948cade26081212435139bec4b9fe918a4a2b7bd918d15865ff7c5db8e8a57c9b509533cc6f9dbc369c33594205964ef047ed3032480f57a51daf0f50898532cce9f632b026f03ada662cbf2cb674d429a4b01057da37ac63ad80cca8656d30c98b0b30862ce6fd5e6d9b6c8ea013a1d3a002e2361bf80f831f9afe2d19416130425c4653c9c0bd15601955d98e9a683e396f35861d06943780cf4acf14d0f60bfd74d7b38e6a2f9910d264ab490e397c4225a7778ecc558adbf1643892aeed80ad5ff58321ea645da1b7983cea071faa7aa0229c9301c97806cdb3a0f1816914797e2a40a0cdd60cf39724154e8d7b019be4f8ed3aabfb2cf2e57bb45fd91ba504954643d926b6cb445e72f6fca556ebbf829fdb261276ca380ba918784a3ecb57a538f6221992f8dbf1deb492d38d684394e1967e88c9edddf75fa0260c05ec90fb85d18edf66124efa0c7b9be74316ee259c59c29e4504ce9210493254f3bdf19935239e383373e78daba2ebae1b34be290ab10cad114f2d5feb5cc91a21a5554483a399f0a7e3c65aba272033735920c0505ac2368071a91ad0362813f1f9d85acb68e322525f9e2e283d6306caf04331f4a8c4cc269f48176cf84f20b009f1f04b44ea3ef16ff9bc5f6bb32c718c465f152d09058d23faee9623309fd4780ed1085b307933f544ed547c536cd75fb0be641817479708c43a2eb89762eb1b9badb2b1c1951f9d04238908f342fae6a64b15097d621b7676d41c390b8d7095bd9bed61ece6c61a94f1c8d397be96f1e4b3cb45066ba476aeb49c242b5acad77635f29b624107725a87f625a56c2b82b885591e4317f2e5c6609eda1dc12c53aba8484a20ff98e164aad449bf3c2c120a184a4da60a1ce36a33e42a1e205b3e9717a014982065ef7651f87e40a41006103cee135290fe95affe5ab92143362180a32895485cbea8fe01de534516c6f0089418d52522c8702ca9cccb131c652db6139159169eb4c648d2809e2238822de9bc7b24dca62515c14a48659ebc5391ac13e56b93452f6118be74710847bd141f37e015c17d2c02cc0251cc3ac37175939add8107d648d107fc5144455026b6b7029187841ae63613486b7d9ae5469d1496e6a8684b3adcd404c094ab9e4010124d3dca930c8d05d12daf9b4ef219500a66a48512aae667e27ac4845bfff9a67b22cea4b13d9a412139221c42d82e4c60a8b211a2b847f7bc436b544ad30a6af65ae6b90c9545d59911c0ef867021934f5da7443a33c33b0156eb1941640a1b378d37869c616426570922458a90e610e468fd35d66c067fcde095cdc243e26b417fb15c6ca3260b08c184efd1c3c8cc9653712ed35eef44d34179e892eab5b45a8d3bc53855ed42e4bffef31caa3f3a8d17c70df9cd20292712aaa4e73921954a36cfb468fce2c9c4e8beda9042bca173fce9be524f9f2fc094bad23d3de37ed096776d9138a23a20b6c0789916d970f42ec862512a959dac4690e93cefef7b952f0fe2058c44f150c570d28f8a5d0c07bb7981ca264a988a2cccca98c449ce7aa59d3e5b28f337f46502d7d78fea8102b68065f16871130e8731f171090cb40f2eec39408a89c75418543752e87bd5ab0a2081e803a0ca141b47064c620c15654c7d4be212fb582d1563a995c587ed54f3a5ef12922c65df2b853859451c9381220626a7e912a18549a4242ee95a26915ed88253e5bc1af85e617e15aa965de3287c9a968d833ce6502129b7224a643d9bb1a01794f86a5b802b5cdea433c8fbc68f600b613df2bd41f4615907e308871254b23ef85e4ef9abc4d9dfe99798dc0aeb97d107fd542123a11b9aa592c84e2037e5ec29186971a8c6dce4e78d95922da1431f7c0ff28683fb5442bc64c6a267c07b216647693c3cbcba1279fad01fdf32d695534e49eaa4e86cbb52aa993854fa6e44ca54d3ed305e2a084b0718f6a0178d00e6ad8ea17050af510daca3afd2d714b6d2c553962d01d2ce5f168697dae36f44b47ca46f4c64de0fa6b8dfae0b2091b979aef9b116bb0cfaadaca5773fca38e8dc290a82de2002fa7cc6c02b23181c58431a6a99dc541727ee077926de7707fdf1e0b62a2978b3cdc463aac40d311f840e42aeaac2cb040171c24bd2a30f886792cde82c55240a2d0b5155ea02f92a47b324920f7b472f62cfb46f332c12c7c2e672f4a41511d9d11eeb020d95bdd494eb1b10afb4e65cb8cd3a18b1ab40066c03321172c42f4140353866a788852caf0006c957af148522e768279d766bb4a119e0e07134b3b17b04483f7feb45239c19982e0573d9ccd422cb00f52f20ca38ce3f7b41448c6ba2ce114626f31588f9b65124cb1b5800a0af29b8cf335d091059ead14ac5838ca1af54a79fc66c069e4d580d02d09443f4271f097c2aa332716f93ec3f53445ece18c16dfd03292c5575fd19f010ef398d8883b0c48809e9710a2b381f11c05cce06463a866460624a0e2d1709197620df4f6c2f602f643f023ed728df5b3510ca1e5d8edf365572cad7d2027a699fe8fc2fe74e008339a39af39087303c463846f981121ad7f05b26d9d90f06213a43eec74d473fc05f1aff4e217626ac68c8164a426934e04af43332f456ae0dc4a68d91d46fe5d8566c6fef467bf6608ee472808f070960e69fde29c409f142f233eb405258db8a0ab222b3e4cf6972645f59fe54c38f58c3b623eae44382978d1d5f1fafb6713f1e2eb520642022215ac9db28113a070c6bab209826f78da6c7bc806a4584507aacb8c7810afbb6729d80c161b370f0d89db7d04393cafbbbd8bfeec07bf8ed649cca3798a6d3ff53c2c169965b237629b2c5f15250fa6b0b34dba153cf8d2092201ca65fc21c4d10cdaaa46fc260f229b803dcb84db241403e1246ae5c8683f2df23158841e0864c574066cdde8e87aa4faf1906c522be92aaab1d44ac78f339a4c70056c8b6b622d22c615661d118a4d8507e90cfc5fd9fba9db592fdb7f28cc277d46cde02ca40a26be1b4938d77769256d9354fdfb6792397ec2a8c5b1818e5576ee83cabf445ad4148590890a3f1e5c43a7e51abbca0fca7a35239a67e7fb0f5190848ca9f610251d238027aa9168bbb0c88592bd10d99c1cafcc5d1ac3c2c9761bca28624fe63d17e2df1618a4d70bf73828b09ffedd886ec562e8861333f5ed01564996705df23f8f1adbd53a50d6f2cc6b5b6cf4af521395c060a3988e9ff9c313b027656dd6204e8e13c21a4df0ada3a9510477637095104a833c351f2b5f557c0c5905030dd6628222ab1d365900375ede0f8a72dc4191a7abb3c391aa951cd7ba34b40c90ae5d172ba63de98dd269bd9eb469564e4bb3632aa460893c553e7ae0acda13e96958f617aeb8e12318c8ae6b23501a4490ec5f68de024113bb729b9ba0a2352036f22ed279c4d88c0e9b04b3484c5583943977d161f6171c5e13d7f849a9d534d72d013a42d5818d6abceac463d06691cdf8da77a09232b2c56657d985cc49981b173301f3ba4c077c486a2ac5c3c9f1f3b1c7855b5c5ec2d9e5764a374b3c37ce0ef5d8108f08ce4cd9683037fcee0cefabba7f240021c2567013ce973851b294d156555dadef26711f46ac1e128a5299786ad49fe6a2288fa6985423ec1914b1a918beefacac8eb0d0531e753856d51b20899d1508753670a2335b8698498666bd07aa27149af5eb610779286d62ee85d207fa239dcd1669e61833a443333b28a0d6db6f1df8071895b16852022dd4e3d78a33137749f6cc0436bf71e2d806488e206faf1a8af7315222aa40f6113895ca4511361f1d1f91b8336b2a1ab9a1adc40dae0889b154a6653ec221020cceca2cbdb752fe8f194e78e668aca00bf0ea3409045bc51ec442f8dab980eb7191b0169e492e2c56e65c929a7ccaa5ea94f7739c66c1c0fe4550a3f0746a3987b43461741ff7b42e484f40fe7e6b424c413ba644a715259262f1b71fa80277129bb760a62c5f98991b2c4d6cec3ace91d5be7831b1b47c22ac29d21600485be28d4327cbfae15dd433b2de582717fbd1b0f0538ee668f88080704ba635b3b8f76639e9981a72fe70f8d2fdb59201f9cd69a36d18b8c7a29cd1810470fd9ab19f74621101a0ad822c69c5cf79324b80eb65f120c1133cb23511c7dda91259881e6cc56bee5005d4670e60c11d8470006d2d1f530fb2d7dde4cdbb910414cbe9c842c0e7ca4deb0c78864daf616c4500583932643d85644d76d4adc7870d0db3a51f31e127a23feb3ba42a6c2e9269f5cc219fbd3b3bf63cd9f192a783259a4cad6a91929e925e04946f6185ba87b1a3282158529f7c8bc113a219d1b5c963c2e0a2171aec49f9fe5294e56e00b77844a3f64c22ad1267e90761a89e11b9358e6c8cc286337e4c962df46bb5b5a39996c9347460e82569ad42ac872e3aa620f4900b1faf4dcf256c1f8d05b81aa68a728370a02c365a705604661bcee782f75100625dc6c711c1fc99b3a567299d9c19a5d346ef637284b07ddbab10da19456b84c44c60118937078c0f484aa4d348e971a90652d5a69b576f7a55818899ca1112c1dc30ec3d84e2a537445be77781479f85d43b58a87f464bc761a2fe0a575001cc13324125eafa786e14c1257a45da4c11fcc1e449f9fd8ecd1297d7d7254135e174e06f2c371f6bb5ee1118180d9a5b8b0f74517d10e1c073ec66aaa143091f196be9b0af03f115d2b812f508765fdb62c4b6b5adc71d30ba4bbcced166790505e502559145ed681806d3586084d94fb2351b28f11b078f45279afb3c53d8e292733e283e23124549ae84ffe85cba7703b15d161585bda2affb634c699c1935ebfaf2f5244e008fd03e0c637545890440708d0a8143f46a707a0271236fda05562e6143e26524d251c45b44bdb907d001e4b3e652dd0eadab133e5a3b3efa6fc45a4d09a9a08f81092e0739ac48b4c1e5b7c2dbe9ed7493e845a176ebf5a216f051e61e9357ecdaf4351cca4d1ca773b1ee3d3e5dc49a35ff7584f2c6422bb6305088ff8c02ea4c57803429c00de49dbec6b333789149eef1fee484a34528e1181ecaec326311f070b93171fd7dd1b9cb9e56ced4024c7973818358ba22d3a26f71036784a12cb6e313d10736a932f386420e1a0af80f34ad8827083805acb6108c6f3b95f631edacb1e65680e3e7cf84a8083440a04824a85b82870a2791ce3aca38911100a769449c77c9ede91172c403cb4bdf6420bc199833b2378cdca0ff0341e8e868448e1b2a033732b1da6ca60d9c7e64dfa541e40c239d9444684e52e81426534efa9ed624d929e8b842904b37f399c1cb8a4a0d9ce766221637d4db48105855d15b20644012d32c85cd4be2a1ae14f41c4d14d6796b27c6e8c1c0ee72e0797cb6f76625fb5d1ee03a29c4805d981a7d13c226774541562d8ffe522734eeed1763abd24099fc532fe0a507fa98322a56f39a87aa6dc7ce9d7c01e005b1cfd27956a41e7aec392ed358e3b1c2bdfe98e6a990434bd17f8f12590f08cde1ed16d75ef3f8a16fdf230d1424b36c67e4c6b5aed49ce7f959be4b4ecbaf4a1a0492a7e343e4f1d988ec0b5f987ddf18a0bd491b6b4a53c02d83bcb43b4e2c29b0d2f11bc72c7619d7493206934f3367f6f3aceb3f93a9deaa8181adf7eb98983120563dfb8e190fabfb13e0600ebacc9df51b4c7db53124774de234276988bc3a7aecf2ee022d40c8ecac6994ff325176c58a169b44daf1bf1c817de23fade073608f2020ad500c48fb575f9bcfdf48e9cd2d349d3e0dceb0245b114934b2d8c04de5661d27769ca3f2ed1a118750108cff90079bb90976fab8cbe58e0f9f00fc234fd22844a42e215db8648dd55da30f4bb34a59413c384d7a8f6f31499d72a3acd7f1fbd99dcf44986e547c9b2022204c3a51ecf4fd937e4884b42dc3b83fb62f12e19f4be4319c881c150427b7e29beb552f48af83059262856623a714de22bb4ddf94bfdcb08fbd647bce37e7404cd00f92613ac329549bd15b6d66edde3d315aa933a61ab9614a7d8e450887dfc985217dc4940397f33cf0e018237807496bb64ad5018a42ea0055da5049f730175bd1b941c0a5bfc8fdb12d6ec6bcdfab46f50581e5c5d1d18abb400d2ecab95a0a3a8bd32a88cb496fe383a5042b47a68334930639b6e37a39cc2426172750828f3f742e0f16483a70772e987099877d10572fd344703a4cc9254b9b3d3c9a6748e388417333638ed93f5600044354d4ca964891bb6b0f49dde6a865745db0eb1f347bbefe6e4197d63b15794cb1f2f472714382f9d87180ec0876127fff3b637481c00120f1007998a3f6958eea2bf69ff41550a10c40ce1761c3a2f27f4862f1758280e6e10b1034b1d1db90ccc90ea558e00229282d3e4e9d90415e8198d8534fc62fd5b737a8e0d19d890640c7bea423924f06695cbf2f788e5dbe55e8eb53420107dc34fb7cd8dde4f3bfec3fd2e87614ebaddb1d41646369138acdd9685d64be14b829daa360533ee65157113d048a642cb4a9a03c4e6f18f08f17e1ff52233fcc965205362a8412f609d685120f3144d6ff88d4b72187837cc18038c55214e258099fb80a0b160c4ed2abcf9b6eea524df3f79e8fa4391f7440f3712834002d5e13918f900bfc39c16f97a6d559461e430f7cf92cbaeee7111cac18029f7799ceacd579b0d42a7c6635aaca1306713921c6916474c4f524bbbbfb686957646ec918a06e3ec08591b01c17f1d8e625c36fb929924ec4a88f95d2fea6960da11b844bbaad7c03ae5860791dee533c245d503a46b16866dc31b825b893748e14b4720224a60ff4c788a6a087e6c6cce317af9cdd1a9ce6fcd4021acc60b20c5f464573d17071ce9ad3ea542bc9534a58ebd3ea68d3dde93942adff0c97e9fb6ce7702ef360586b33d2649bf0c4ed774af614dbcd3aa09b3993ef52d81d4ccab155416159ca6110280c97eda38f7ebe57fc70b81990f4091673b70c6e22befc5da54da0f7e2225a0fba18ec7a9827d594c641018cb12342f5bea5cdd2bb2d95418f974203dccc9e8af94a7c447af6d57b935dbaa976ddfab64c962b526cc7a59f06cf84a90159ef6ce0eb3b92833d2c9491187ce4530ec99cfb4cd038ccbe0c1803b5c06c251e8a7a8656a91dded5828ec55d802a0033cfb9747edae1f3a0d72608b85921e40d9de34f7fc1907e2c1610104a7840ecdf2eab0ddc3dd64f5dc6e17eade384721e0a62ca5eb0003d54b018eeba49e23479cd76af894e3d29d6f00e3367676f0505a616a75d05f03f1a1322addbeec039dff1c1502dc133ce545177e018670890a35d64e4bcf103dca5a596397cc792f578c66cdf06062c32085ac3738b6bc9d6691dbee16eb164a85b8e7f2962aecbb9ae17a820626d07ed2cc93ce4dad485d31655a23de02740627725e3a2d5041ed484ad10cadd37a25c36d86db58cebb8a5d571651d17ec314d02a9230933531ab94289a6fbf2822c4cf062f624fbb6f1ff8a23e831e430a4b78f44a0a19c4dcfed2eddaf08fe8e00f24f4082d883a46b4a81da8934fcfa9b3d5551c75fafdcf68b5905350d033e55906591a09917c1396219bc4413e30675ec4fa6a49f8189572d40381f1d53fb9c443328687e403ba931bb9b7dc72ac89802383a68eaba70290ff2c1be6fc88ab32d62d8232db3d85290d4949699b3778ea04c41134403ba5ad8936f33413826a9b38954cf8af73305635e1f7ffcf282d2371c2117b0be0a8ce4b1facaf8d76a8a967be7770c3de309c111a233af287dd8155f10985c033c703e41c04700f07deecd3f5ba6f5af2e20624ff2c73b04da8caabcddb10022c8842c21e9d06065cb20e7f3df9c0a7e78be50ed35b56afb2c582837538970467853189e05377f77cd139b0819b8605d93bb5689f510b42e25e36b17a0721bdd13d15b129da3b82e03c9ec9935d625c2e36e1095872f129b25b2f2097d9bef24c5b2b7b26808f8315e82d0157a9c951b7542addaddfee165adf59a87cf66d84c962a5302d8aa3e0c4b79b8eaf8fe2af92ef9bac3c7c89825b6d416895e2203f88a9e025c906eaa9e33f9874c11d0c0ed3f908bb3a4af9221c87709c3318a9d250e4210bc7b01d4c2e61de4b7ddd302d95794442345b7b01ec1d6e5a6a71422d30707948273b9787d2bc16c7cf32ad2494bfc2b1ced293157830ba77c965f5f54141171553e5fa0fa10482766a523d061e1c5f46e1d20d70428461b7b3e5463c5d0f6d46d64f7ceb88186580c6c56884b05b5f0744bb2165f6ac97b93ca650ebe70a341e6fd07032f1aea03581b25b2ab3c0a02f91edfe1e7d2f82087f079393a3efa0010709934df362eaa15e20be81354d776134da862f7d3a607dc93c2bc0a1a88d45737523b8d99c4b24ed27a8e0756cdfced42d24d11d9e50f153c9914e7376d61116630add58d10787dab5295170dd1781154f80580b2296c7016f0dff2fa0a7dbba351dc2b848ade144cce2504be810d4540b80380281c60dffd1cca6f886a47a9f1ef3801e90d151d1154180892d25a063d2a56b96ac783c12dfc62413179d9fdf33d1818124e927c4ae1d4f9bf8f25aa276a462671ef4a11cf0b4222e1721ec5f64d17d41de39fd885a68939453b159509d8cc334d8ab00ab360048824d28b79da9dba7da8559b3eb2cd090ab32f9689a2e0895909b40ea807f3d59bd98169e723ffbb6c63a3c93722138e23ae30f86900d918ac5179a7db8504920002a4605612fd8585700d4d62c836eee76831f0b888db59c58ffb77a1180fc505388b343ab353926dec99f7fea957b04a1c32f10c2674ef0d206440ee1e6fc6d2dcbf7a112043b43414d267c6631037324cc16e465b520dc24379f3aa35506ae67c8a92674f8aadc5f132b52c8b358b2aa2a6c4ca2ed6fbed9df484d339a067f278c972ddceb603affdebadcbe7ebc0f719a46e4dba8ef5f5495c89a8aecf94cbc7317f71f0742d3cf276089c11b8304c8c70981b13f11108f5c60046a268072edfb7d1ea94216570d854f5484961ddb377bc17f8ae0059f6173421ddfa9c5431869b0d1cb63ec5576db45c986d59cadd423a211b924568b97f99ed748bd4009f758ce23599bc7a81fa6694ec28941aa647675d28fdec6a33daa33fe158d6e1b7d5e1330d2df796470e1478b15be05eded45b03dce11d681e5d2865f3d3d070c9d711a22bbf702eca0359f6c399e36503a45437e2b3b2aba8b0145145e0a04587b01b88a742e7d64433054679bdaa28b1d31a65557b09052df66c4165cd424f03fbc9f89ef59bb010b97d974c2416367ca3cee55266ba0e9b11dd4c8ff7b4c338b8f6439bd99862a07dee9fa1319421247838cb70cb2f97474031e082aff9be88831fce1a8656fdfbe944b4935dcec3eed5ed0309769f67aacb29c7adfda679040d8589c4ebe56cb33ef7141e7db7ff3d4bb6941415662cd6616a7e7d0b9f066475a764e58a17f1310bb9dd653336cfc9d2f9cbf2b6aa03485516574c1e988d8b509695278aac86e37061b132b546b9826839b33305ccd196cc9a7a4e55a3e4dde815a3037217750eab75d69963b5a85f06f29e2e3aa135494137e47474d32a0174bcb8b909775e84490dced7b60b44f11c5dd2c8f2e9fddc03674782744a128584e9f921f0a5d35209f164bee8cbe4a1ea9934116d605e53d536aa730a96911a6ded5b9931c5d9446c0e17ab04ef6814a6f2781f159e5b24535993060b06964f19e4d89efdcd7f0dd3177cf0525dffc45435417a00edf01ac8051d211258e28f61a76c82e3eb751d524ae292be8746ddbaed3a0f62c2c2760ae4e2bc8ef97d6c089ac09709010c72cecf29a720bf718bf59fe2709729165115c0f9fa1d4daebaf439326d1e1e142e88088f48146e8d707c8ee4aae1da9cd0e47229feff049d0601861bac4b6ea3ce095a9ce823e7ee05da1b5c9d6f7005bb4b305dbcd10014f241f3e4e5cce03946f5ee11482844f992820fa64344464c8d20148fc7dcc0a4c75fc465e910d96d8a822440840e1a8365ec8e63319c534236eafd7387fa04edce1d053d51893b9eb95ba4a40454b4ae7f468bb16a2cde7df4ce72f1721ed57859770afef63f504784e95f7da17b67bed0752750f50a7641032d40badca62f008278ebd4ee2e7b86944fd62385a1c77f6617fca5014fcc95155a6b284da8f640a3c278bf7444f5430b8731fe42f628193cbf543c32fedaea7d6bffed24e65e947f67bb08ffe586fc25d78b45236bf5be19953b926764922f2113df087d642fd3e201d78ab3abb6e922a83794dd0a939744d00b359bc2d5515a80013c00f1d36bfc00c5e2e13f78ab060b6edfc8150b253bb18e8fdeeb33aaf06898d29ef6a7ae37ededc8e31b613752dcc8a2f9fb9a4227786e2aa631714610514e142f50c6ca161c42d201f005426f9fa7e83e7d8854943e337bd156aad34db8a6b6d2062580b14238e7a029c01b31aea228a0ed832cf65aa0ab9e8abfa81a3627a0abc5d9850c73b5c0ea8602b307a20aec08467b0f8207cf2ea52f96ae1b179f4d0ab387f57405ddad42b84307a1b47cc801adf4b9918300c3bf6c1584001503a624aeb07942f1fc42e47d5e003d1c1b0f658da4f501e9d9919c7d6941fc903beb062c18c7ba0899b8316e10907ca69936288fda1aebf399edc3ee9e315a75297b5c4e10cba3c2e468a60c079f66928d038b300612ea624818da5f301eefd79369c0c4373f196428ee8205d1a5766b7c84f418464c52157a62453c40f2403e2cc290da24effd180f31f8f571a63a0c5e70c3b9c5bc0a04f1cd67d1e5c620dd82b8bfc15e8b90fb0e4585457ebfaff61762092170a1cdc6462b3aade4de42744f99f8201b5f3d5b3ab571f55db7a3ff392c84793afc6a388406ba84aebce604a75972d2613bdffd77edb7ae89fbc717cdc7c4c70c84d4347f472fb34c96abe2bc9d0601270592d8377408d2c76d3440c04e1f5f416131538f896369c3a80dac3afaf127f6fff543ef27e81cd075554adf27a67d7ccea699a6d4cc627c1c7a101d08c455367d9eb8f6294bbd579b253834211dc040cc8e34ac72b7b2ff45516948962c93d74f89ca24e37f0c548fa8911aaddc2c40991129d7bef38a065d814b014cbbf9f41e232085355241faefd65e140fda53cd3befe86058760ec2b8dbee9729620e333239228965c7e2994a5cda298824119fff613a8757714c5347dc3d29f76e4558ee505ef4bc034c298f44ff8453398c0b29a797c3b1d8bfb34b8dcfb0a3af8041f77f35f0eb709f0d850aa9fa53cd16d9bbe45dd75ed7572bd505f36d62deef78171c2690a5a6aa2d882e86ff5135b9424bba1f511f73d931d9e8d224943d2e4f9c7dfc78ba1939dd522601bd80f254595d0a8ad27b6735cd8537ed3246abdce5ea074ff196e66058b2a1eb2b14ed06d75f3474df8ac7f4fa8786ed7dfb75e3c08854cb73f7933e30852db0a2060628579664687323bec6a4d795a6dd072dd7a281aceaaeef6b996e25563287e016e21f2eac476a0e89a37da5b24b1758619ca9d4fd9654a215cc8efd61dc49314650118028c90468dcb7dfc70f609bd6cb17e80ef929c8931ed5bae485d3f250b4c8043c8118a50a7366d0c150cf35b10f3206217cb9397f80406ae932e79031221436ba58290b89de280f7c0aa141da824bd7e1330bf7d5198575d0dd9857c09432ad97dc30db5ba7d8f719c8ba39c00614f10e9e445161f849748a51e908bdbba90a81f0434b2bdb8a20f5f8a22262ce20e4e888fabb229cd62b9770930ee4aa44dc07f650da0a538a85134be03ff4f9c5723a31c2984f53d6a2555f2b9880bc28a5707ac2a88022613fc1e454cc60c08726036dcd16a694e806ad4e7773bb0538fd816a997ad295dd4be28dc39d07768e1ebdc827844c51634af9b7fc8f05b82026849b2267b604cda4bfa840a843f66769aecf08f482951f3a21b882d4db971aaa5036eb5de65ca0e4ed3620b9cb0c6914913e2ae6cb59628106e9a4dbd8de4bccedbb12d9f540123a4bf9c349450e0e10272f2381f262819d12c406da1563c0db61448db497552f74d61c18461761a0976d6f7ab6fe20753dfb5c47cef784e0ad5bfa62020cfefdc6468458560e114484ef22a6464075ca0b2591545292ed3e30238543f3b08e30a848082cd4100858898b14dc246d236d97d1050c520fa7627c768d8d682fdc63db9ef4608b2b0d1008074a800298b5318724820c84d9c1e90eb9f0f8bc574e1691f0ac33457bbc9bcb7149195fb3dce492dfd6a61a31ce3e3a069d77d818a45312c94306b23dae1acfcee74a258b701d2476d09c564390c8b926c46d99999c0423fe0f669154e1a139756be4bc353e73b0d0a7703a47035c4a80f8bd8839739e22e2b830c7c1cf9cfc7442fc01383f479e20f4e8b4809f3f11fc7aa3932436ae92b004676c74a8a03fe395de86bc2a30179db5bb4c2c8e526edbfa83a7e63e428768dc2a1195380a8ea4b90e3e77576930fa008433da3b1d1d044fa7babdfd3020c2773bd2d93619a7b58878a5c1d8d54e9081a654c0e920bcce90a233d474121d3b5ed22901d5834128a392e3e30918cfbd8f756a223f5303f61685a0fe058cdd27c4efde1dd77f85ba1074c796df37b3ab3462c24c9012e08fd3ea1b37ec981426c87f965f11879f0cd9076f2c26afbad9b0bc96d8badf2561ba6b014a632453388ff3148d3170b60e0a7f620e030fce2df18598981510c4b05a122dfd01cccfa0d1eb3132a7ce5812869e7c1cd613fcb78d779c551cbecb4288ce059d4e4e8720da1da87c69d366b373014e05b69a028b249a183fdac9dc71afa336fc1aa0d855174e09b06318edf085ea832e9ba52380aef1b5021c2bf910fdbc7653401b45b1b1ffd256ba8522f2a80711dde4daa7c66963926865fa6f699026e83c37d55c17d734b3f06dbd3e53ddc4013d318bc76dc19b4077b10f1370a548bc3e3d6be3b458b9ce39a1277ce8c825c64b1d8797c117c2b777e9dd1a3e1652606bbb9f07dbbfdc0645d6dba36b204a40938e7a83e33ea3b5f98304796c29ecf0ac273d8a3fc61894ea38ea21da248d4172ea10ada39d9bb751fe1cee289b0804a5cb8506888b3f92202faf492b17697cf299528bc72e2a08088df1b3a800f83e5684ef2a3d90851a935a2c9eb0f0c970ad6f085db0485e6129396624d89f63704e17f56529219366ce7ffda18c4f8d17b14bfee5707911a72b307204fd9763c022f6898669d6b14a98e12f08c7ba28c3bc18c5a1d53d14904679f1e46d0ed2d8db733cad26d1d351e5244efa7068c687143ebe9561b8fbb12b7aa68af39d124b537b677ea76bc60d3cfb474811b453501ba26a9f4be5935cd9b3795f5fbf7575caad2feaec345a7d0e1831ef7207e93714aedcf17d125dd3f695376a9a7301e08984ed2ee38e76c2802b90381ac03591fc175d4f8572353bb60f217787c7dccc5576efffcf5f63248596ad3ee818d6faa7e53af7bce91f31d630f9217cd46a9597d4ea87a5ddabf17a0114d6cfde0df2b059987d36efaa4c5db8db0fdb8a3bdf6bb7ff40ba688e4dc08d7c45892a523281829ee882130ea5d4e39e602926fe8742beeaed2a0a1d2c90c5ed0f5716d526943e0e1d98ddc1b8f5b60b3d9a0c5542025646a6d123dc19f3440741dd292a092b6646469477ba2826307c0e01f2aefa2220c6eabb7452f65377401a89a1d7f4a55cb3ff7e20eb92d790250e5f468ad37ae0c6a33b79942455f7a39a8ce01b22cd31b0a15c4e49c4d70f78af92b3adbce15b7122c36fc50054c9121cb95fb703588da26a4a1621e1d5643f7d90f63b1266725f29e92452f7d627e02b6a9788265e83c2a9faa3e6bdbe69c38716c07ede97ccc2417682403373228af5f9723d5e0f6f45e8d2acbbb178a07927d0ab90f5ac5df6b5a67b410822e74256f8a44c27452a327d86cc86ac928ff8e44854892c35d515222787bbd2fa87c56738ea7f5f8ec95f63c109709fe309e9d21b344701f18825abe943b2b72a77fe2f33730baff222452109b50807822d642b8fcf64dca9df9aae7ae2914501b65fedb8ed13b9a166cd7788076d9b3229933ee7e064da6cb38e012d6908472da0611c6dacb1b734ff7feeea0cdf4d9bef31b7e4e03bc770d5eef722254a174aa5f9d53831eac5917900996e63eda06eae2a7cca6448cf7edecd0856658c608c0f3da4a1358d334d4f9d07d81266e6d0cb4865a44bfe7dc4392218ea4e07e1b62ee2de7595cba898c5de5ce1dba76c3a3f0a20db2698baf0687a08ceb3b9485dc60035c6160c2411d9ce7f0940d86c8a391b1d932546705b68bb418c30d422b8a68ffd8323a839a6683979f31d95f19929fe4a133ae262217dda6f11504c7f22011de72fafb2e5df5a0cc1785c3378c9ebcb563a61c56149607c7be1558cfdd968e1b340f6f5a3c0be4b3477ad9a09d09f025feda475dde6d22f382acb2afabd97b097bb860a46041bb892bbc3e1add8d662b011824f366dd5148f42e447bfa213478c41dd6f2b0d247fc104f4adaecab44ddc0ec035145d9ee3dc4404d75063923cc746a8d04c9f1a48d989df3e3c475e4ee2e68b72c22f0828e56c99c14f53939b96f178b17f8866f619c4d9053ddc10c6833ff0e6fcd1495c31bdedb438b1e81222e88481799d41b5c9b0eff3824a7502a94e692d9ee6139482aa7fa508e48e6aa20eed4c952fc0ece58efe032c12921bf59d1f6cf40d84d8c5ddcf52ec8644217df88431b212b015c450ee622c64cdac37c9ab1b548087848754cbb7c936796571307c48b1535e89fd2e58f8249f93c1c6d931e1b0e8c2e822498a49e0adc3722fa23a249fc0933fbbb881609390deacfec077753c8fab01e021763d945c6f62730dc043a58ea85ab8608bf9652096ca7d3a5c7d00421f0e71a61d61241c2657451436193d273797667cf17dcf255733f88d2e27a6ec8dca5c88a860a5eaf6d5801ecaaf9933a559459fbd8fe685e3b356b4b7599909d13ffcc442410cc4381610cd49150b02346d79b97d0a4f34f7dccd1d377b27f7b7c64a159be28129cd5a279b9226ee4854b079188ca737ba461395f6f243aa80b992c7c56024a1a017d99cb8e8772bf3bdcd07861274b1411705bb0dbc3ab369086f11bdaa1118929603200010a5f76d2bbeccc526321777d251b9f9b7a513f2362596b93b25a4ea2723419e8256f706bc047241087f030a3cd8299a95bbfb7ec5adb4037687aca5c14e88e3a047a8ec3742b367399830bb1c8951bce310139b831d52de51bf215672f53e47cbe208243d49ac13455993b9a420872e8a0a8a1680a44f825b61f759608852b9024abd0345c9d03289ca4b9907b09573422067fc2917b4413443f40b5e90aae5488ccc0febe58836a015e59511bc0e23bb6d44375f83471ba8f146872ef3adc27096f8be34c37939099326dcca450c6eed6cef048f33e064310a946e02cc1a8685fbc9a01292bd9626c2e59846a48859e4e05683daabc65627e2e3c2bd5de471c12e04e945ce3b9e7623a49af816a8d3e622d98b91a3aff59b9a836b490d40c0f95d1a1f30cd16b0a203c9db5806b94437bbb02fc74de9828ee6aff134a6a647ffab5a965795c0846dd98325025bde53ddaf2038e65899da0439e293cfed5cd88b56e779ace5b403e85c5a07371f837606daa6adcf8e73e5698cbb694cd86a941d1a3df83aebfd0746498e7724011305deb256c081610d1ed5d071de90c1937931c673875036d4248b8aec2c1abb09b4a5a321c7256fd7d8570036debb9f1359887204abda9d853927ca300bce3262038d976a4a33f486e95bc1f82992e31fe5dd700605d626262d4ab013028b12a3954db650891184deea9eb0a28bd4f5be3ad88a0d211c37ab5d29aefca456e2758159fff9dc193d36a9fadd7519620c3bf3c7e0ab9d589daabd80741153ab415d323386a0aa4b481af08b302034731b545fef51607630367155a2e7cfb4fb7d096808c98b526c3e0cd7f27125cd38bc24ef48d0be532f4058acf2e9c2d2e4cb4439aa08300203aa2ef48b9c4ffc7e5475d03fe21a68684fdc650aa916de7d851babd9999310409e0f15cedbaec864bf8cc4f2afd25785dbf7aca062f02e8433311786d75be35346f19cb1c1c41627f6286252dd16cffcd44b3f05b0b6f7aca3fd7ef3b8371861383b7efd05821484c0cce6f4e7be6a8b497fbd65c9eb485b1a3bcad7092505292a9f9c38f4a6f0e7a88f6edfd38916c00d52a2fedaa931c01a4fd3f7f86d958cd8301c1fb093d65322778799eb28108c4903a6b4273942348630205ba474640a949749cecf3b24835c41fd0a93da229bddf7d0bab8873c35558dbe7e642743f63512489615c9f72ba825bbcb9d7ea586cdc5dbf1a6e072c90080a7a820509af1f72e0dedb949c37de849caa18238e9e2967f57d971b5fe2b4be2452c6fc89b2339fd10f6c8d21ce49002598e9cdfaabe475f9347292187c8460e41841f4cae873abfbc85c02d6b3085a34d9f7286fe7ee243773eb6cbbb6ded2d0cc84c12b473f8afdb50c2df47b53f0795ec282fbc0eb9c785a4863ed7f23cc1ae18742447cb2b71ef3cac9fff1ef6b48918fabcff4e434a6220cac3f2031846a05895a97ce3c4c63672e3f00453ad5a8b467dc8f7eff1b1757155e414b960e87979e300fe4780ab04b86ba42d07840c32e0a520409870507b4f4fa93da0f5236ee49c2952838520b6933fbe5501a59e07761d0717e6e00f0457f7bb0efac00e3c7980f61371ca5ceb0136d207ffc289bffde1994b3f673676a2a991fafffdfbbb2e864a7c4870ca70780bf7a6b3f755516aa0f0adc291f955bd38a6d88a49b6c6a42ed3dc390c31d5d9804708b02dc6e35f0c1cb57da48088dd8e91596e49344efd4969604ac59a4312245668d9ac503d4d521423b56972c710c7b88232e5525418f37c2719d943cd7bfc69cc81bf7c2dcba165dcf83388c33ef15f5d08a048780391627878c714211b71b53176404f2cff43b04ea6c3723240b5697dbfe0cc9a3fac6f67bc8dc97af0d35eefb68f6b93c0fd5e25e1843c609c1a9c7ca78b5c161ce4df6d49edba7797094b489e9bd80d37eb20a461bdc09da8594109cd5d5460aaf5bc8f61a08565f535f0bca958c002a57ded9534d71d10f2f49980fc2728a51312b0008927c581a687f6cb7d0e3cb3ccb033032ff33199d8bf0a20de616e851034ccfd51f8405bc603fb5c43bcd7d68834d3843577e55d07773d4583440b019f37cae21d2561224bd92f7a35cf481daf3527a0ce4379c45530a8208212fee940ab9c95d6032f5a8c0d2867f4320d48a2833fbbf3476730c96c989c0128100c01776d9dc7a4c47a37ab04c1c9c36042abdf9238de87089135fc7c3e609896cc036a556cad9f74454548b87461ae584772b7b57138f07a22d15c19758d9d2909dced1bd4bd58cfba01b2d7374d4c1104dca17d1ae16fa6f871d5dcfefe7707e05be8bfbb278567becf1b544f73b56c44d2f542342c408f32fd7c609455e3c998e8cef10efe13acfbab899d3b8b1b99ac88913eb50e3b60372bb26eb2c040e175abbc904971ede858f5aeba798365028ce74c3a7a22e552428055db2dbeb883ee37f4a04314c37c6d4c0741c82aa28694cc0849c0adf0eb8cdd9a322ec53a92a265f73db1dfab00f66f87bd5d82858a02e7b232ef6c33000eee45780985c958de9e4979ac253b60d7963927a8def81c92e5d47cdc459ea596c6141c821ba8a5e22996f12b3299ab799dc72083b4f78ef8e0cca79d8826c1a781028585f0b155a2a7ea8cb8329ea259c5737f7593b1fe4d9a96dfe07f59654f5d130c343ea53a38a9a9301f3cc596f853796915a0af109e4287b7080e8b37f085ac39a512d4f494507adf258bb9f1f7a3a5d4befecc96f8fdca736b0bcdfe406b4ae19c43de01c097be8f4cbfc5f04992452c06272ad1e500bc63d593ba02e32fa4cdfff4a830dd6e88fe326487c3704c51f42417961f6b411585177ae0f9e7be13c7121e3cffdb973c3f1d3c6dc559dfbe16b2dabbc9c34b5c3361d098c6daad4cd1154ef0225e2743df24f09aa8ac4f2f5a55c95955f64d40951d72163d96b200374a4c75fc8a41c4a71bc20a1751259d95313d1693858192cbc6f9c26de0e544376a45e2c64b5bdf88b16ba374b8025aff1bb2c7572ba030bc2f771ab3bfb226d8537b88365074663ffdfc5157b83cdc3f27978d02a2a16200d26e8c83151fff465845425fe8dd86b8c7773d600ef2ce50f6c75f0badb28f4912a21769b619df0d460f8bd3cb9e536a6569705d838e6da6921b0506c0aa65d5982613ccc04b104cd388d06af82932414a7081be45b070f18c2055d80ed69f5151494eb72a7e66db3f1660791bf5da4fd4938466a26d83aea3535a43d6ab30410d0cc8f0992441b10306f0bafcf4599ee9b7804bdb1e4f6ba2404810484226600775f4bc9d8370e46876ffd20078f1b242231367a04d3404d92ecdecc2eb643190237bab89fe533f293bc62c7c685f4dad40101cb784a8df534068b3da274458cb0bb1e38d678b4061e369a50d4e47629c404240064105d96882c000578d60a003c76fb2b6f63a86e9ee405650c0f4b833db812154914550015689d0988300edf7f75add8ff6b59bfcd087ff10f9a72d0046b6abcf300ed2795e7e9f727987aa65f343b9be49ff7c13d752fbacbb84a1386acd1ba032e4c2e620f6524a95235b0e84a40cf68f2e1a4acb04cb7c1124b67bcc470e344089099e377074af8bce7a6b7b3c68a5761df7c1a91003996013d1be219ae26bdcbf79836a44136e376e5313d7195f8d78f50eaec287b5e84dbc3065920d55c2387f9f7beeccef202b3eb8980c22feb61ab3ecd09360afaa1e26441f50617c5750b1226ffb140f4bd090bc1bde405d54886540993af696fe80583de1be557a64cd2838575a99a6ceeddb559bd7b932354717830c821d9484d510f3e2f9ae9ab8abda4a468c94f37072235ec12b118274928ba03358d97ca80bc238fc3530afc7e1af805362722dab86b23ed5ca022c27e44aed81d31ef1bcbb400c7a99b8300d395f442b3f77f16377e58c23a250eb22d2fe26af86f5e092857cff21438f3df3617c870e81742a20e031fb21eb438d8270b8e7852e87511d52b40a7d54c8e31ffebcff6a90ea261297f13f240e6fe885cae1ffa29810638f99b668ce9a685e13c814800dc7357e97399c546813c04cae2ffcc315e531e597013634426c7344d2dd748868d617e6153c3999408c46792e3f12781642c09c3cf2a59a0cde911fed8540c4e97d58de79c3d243925591e738ace66803e0bdb1fcaf6b00501af1449601587e37d12e5df09a33f7b8aaa79e948ef0f148bb8661fd7b1a6b5ebbe03600c5c63933ffb85fb11c11a99daff88dee9f151cbf1284c9197ef55068011c5cbfd2af3585da0410aac4f21d41ce2d0e3ffdc86f4881fee241757f067919faffa27d1c6e146a973c35368798c9fdd64ecc506cdfb96066fe80efc0307f30156845354474b89f41aaefa3e03a4631ffad5358ea5d7f1f8e52b76f4947b2f803a7742acd202ac7c140a9bda15e2a8d565cfa74cd57857ec090b9ffd415abe6943abf93e117a63f126b99bbf0b421dfde6bf316bce2beee03ff9e03d0492b19ce8de7f4f9608673eabc7e580b10de4df6c7198d4fa9d7d1730388cfc149527233347890e039d961f888959e7794eba56e106022a6f4095ff2f9cc8233cef8a51dd81637bebdc83945e70992f1ac1b2a46705f0fa22652a8e69b4a65276ec41416584602aa0ac41cc8423a5f19038ad67463c8c9bb1471aac683f062e92817b24c569b42187a8d06e34fddb527f1ca085f204ac7df615756f3af52b1019ffe330f44aaa80532198e4f91bc43bb3c3f530844ec5c42388c899c410c7e08823c74944da36320d9b56b924da3cc139c02d944e91189b7d71c0365becb9ede664cc0ce49d5062aa7576f0360d962444747317ef980db89f77b66d6742bc80083a0acc3601979d21f8b67406b099350147536908c7c797db8972a6c75f1a17399200a4a8d2d089301292f46fa983a2523b17fc71a23d90b38f9059ed90b8c1fa54a71cd59001e77ddbe27639434167b5a66166ce11308a9291583758ce1beb877a652848ba291563521ac72348ca29064644faf4212c7e6d0aa718efe2012717e62c8b54671c74dfb8add90320123bdb50901f0eaba445cc7c95df300ac6aa64cdcfb5bd21b2bd1e6dfef48161d9b039e0971aa61e2883a92e83323c18e2923a7128ffd4763caa2fc0beb1bf64272d1fef248eef8d6aca165e1150b1b3da23e4b83de2492b0141420b4a26f1cd1958dfcfc0f8d7315f569e9ee8651f6e6277592bee0adbb7cd1c3dad7f468ff745952b368e17832c22405f0b0d4473a505d0cfb62f6b5f376fe994de8d8eb64299787d0ca80be8c6ddded1f0d76df598065e1b8cbe371928ca3e551a60d5478d5caece54f834440e11b121ae07f6106bc32bf948bf1a2516b0ccb837b7f6405eb8e597ee31a0248b9230da68b6a57f92b303eb857ae41f6c06d6c176d931630b305f068b975017647ba6306706d6c1f4aa98d32679f09a661acdc1ec60609c8caadeeab00dd8c9197ce879e48ba6c05ca3e9c7c8717ce99af107312316e8e8fea6ce61e6c10e0de0dd38e5dabfdf10ffde7a9494dd03effac68d9e40fa9eeb0cd410c3186d126fcda4f77c95a26c55182a365494051a0c7a46461c93331905cf1c851c51ac541997092554fd93e4883ca29111c775a63323293488e1703b15e3a7721b758555769b108ee204f64a94d95672c930b4f22a8299113cb23501b8a27b72c0f9ef2053d88c3c6e418c1eb4378f200efae682dba25827eb2521a01e9b412de35524a1fb1b5393421a19cc26b72515521d2e7ac72e9a42fa477163385703a64a380284a5eae7ac0333c978df5cbf23c07b0aa21ac035db763224a5d5a1b6d8f392287f82b71667f49b6b948b4d80139088f1b96a8595f1dda5baf13612a7f4f58fdd31506781468e9a7256491d08e08f67e2480d19b99e92520c5081df67eb53d7cb4afd4e1011af3420eabc1efdf1e6ef6ffb1161fe2b523887729840149d27dec84711c5542cf530c9c792331353bf046145ee41591adb4cebfc197b55cad207ee123bf01f928e31d2f063ecac733dc84341b0a5d104edbee9b20de985067d098a74cd02202c7ef0b37f66a61f029ac182f94f3c69f0687028c43a9704c216d82822b4de17af5a19e9937417c98497635c840002b0471a0a32b56910183c1168ce5ca30f58ae335c9384ad07238e41ee70824cbc8dccf1dbb7389b86fa720bedb35c874de6b55b7486e798653d3dc394d3ab2a6546b1e0a03256cc9b80aaa79b63f13e7add14310f777232c442c57c442ce546d449f627855bfdf2b9998e15a5b28257c04c616fa8238caa610027c5d889d2ce3d55644d06f12d9f799c7d4246e4f5e10ff41d5c7235106e993ca0140da254b036ca422a3b2494364643b0b3141fa9caa30f77068b3e4899d3b90876fa5bbafdaab07968b36ddcadc961017e1a37031031c0e35ce1e26630c54a9dbeab97dfe0cea9b334cd834d5be1eb0e2606244cace2ffea67bbc3b86f8c8894553b52a86b234155deb24ed2d82ff296878f26e0e35103e1b9ad0b072f39a97ba425118aa5ba5a9fa0775cd96de29323a5baeca4dcd320fba952f84a5fd0417385ca28f8a01edfdaf250a07cfdb9508cea29bbedf26512cdf41a12392a8e461ee36fe05a3485c635cd0d40c4955242a23c7ee02b40b4d7fa14fcbcfe2f566f5981c29c458b94adcb7d513c66e2e4be5e124f04e263d6dd6aa7ddc7b61cecbb9eafadba8aff0e8be3efa82f5063ecf2b861de814941237db554f5545979900cdb2633cdeb08bc4358e04e8494d11bd4a7ef3fa6317529923e991c4bc80cace4fbb1d376e170da9f46930062986ed050adafc2ead92c96b281bd7a834e3f827e7f521c4ba88f12c5d26bf368c748bd00a31527416ff02929ba3b1468215813e5c56e67565ce8f5c792b5aa09d1446fa66f58238b740a30e26c701d91e056c08283cce61db4381a0b1e60469ed7d00b65ea22dcc027afebffe8746f9076ec959e38b1f2818a3b1e3c5ea9fb4bc370d15b5976f002c88232c20f3adbd272b604da91722e668d5636d57e5964f4792b12378b0d670b06fec4b72c83b99d3159f3062d38e6d834cd3fa09b8b688dddbfc24d926cd08aaace802859631c43118972e16b708b02f4397b8501333b8374d07b6175622f3798e32e3b70583f51930e3498e7529292026a419acc60a8d8e17bd6eb1e90a6089580e6f4d4371f796749193112e40a10b8df3027e233dd01a4b66b0c572e7be9b797f8d65e7f877d8a688d157de3f36d85a29e19cc64986ebdbcb55008eb379d176d757bf528270c0f6b41e9edaeca341b7e68a0f74ae0e05ce502af5c275a56d5cc5fb8b77cdc87aa4b61c586a985fddb29e0455453143e934363d9fab03a74a80bd31f09f04b37960fa05ee8bc00df1cdf2c40fffcd5812d438dabb2956b4b53851298f333d9ce99aed2ea2f262405b6473b0510d5e4fce875d01a074501daa94c57b91828ea22b4589734654ec46097f053f2bceddee82e278ef26b28a86391ffb9bd5750842a00d51b6d00408a8c850ace1357e42727ef345a66a65198db9fc25382192387caa0912c097ae923e4642c4e6af56459f017ba28708587585c7786cd2e504d7e1a8f925e28032992426c8d47514d0bc07334b64ac929d19fda5aa3617f1fa55422e772b47b234525767a0d26187033e38f96187b87b7446700f3ab69fb70197c2c36b65d86e87e491c951ad777968685c155194bac29cd67d01725d63bfda30f9c69ee2b05432d54aab1f0ed0c61b2676ccd117035ac19c99ad028aabc5920fb6f3d223a1dc1ee6edf1bfd99745c4291ceaf028ab56e183c04064c56a3edbd2dc607c6fc70bed93c4963c1374762847892dc3999434e4b7049dabcacf09beb670c36d09076e6b66496237b9caf248e72556007cbaadc408bac478814e799ed7cb285f849f9d2e7c7e75415df2e5f42465d2b294f7d32671872a2c21c1f4e502057e73d56319c41fa6eb7f6905b38853e3458282897e15e989461722c9ef35f7182be46d04f8f8a9b72513e71d684412bc591e673c08ebd5346228a140641453348d3182278e7cc65392f65405b96364c2b83cf998e25d1512e239e1a7e23abea869217ec0560f1869f1ae2a27b1786fdd511f1bbe633882542f2959b17a1e031bc00bbfc4500035324f62987b05ddccab55dce6ca37e2342a6c97a3d2bffb3f58d70011bc731480110f9ac379eefa500609f59ccbbc195d917a20a48c83ee2878fb8c2cf7a3c769d6495e030841538777972f57b90831b3c33bcfc2b6ab22038618d90e318d7c01b673188aa5320a8a7719635f5609f7b0b626426d88ee2d49f326850094a875a199ef345d78239ce12aadcc5079dd8a2a0d7a1f1bbdfbb0d84828e2904be96a396375de4a58170a03a5fa6bf4c11b4fc6bc99e8208ae96273b5b58bdf5c977e6d833f1aeb6866e3b1c923831339f76e673eb9a1dd8a36b2089201ad8c4cbcae92232474673165efd71f534250f3474c980d93ee909393b8513bb17eca849fe41a0f153cd62856f5de9a2d98c49423481809b464f6681d39925e9372ab55afb11acc981055f272f8c0eb96e3d89b1fb302c0616970e0abd58bfc974b98692f5ca65bf64be4c082b3ac19f8bf9f87e3f08983d38af6c7597cba8865b21d68ff30d97c34c9c8e957a7e9df6b8bbb24eb764b9b452033aa330ae20dce07882c5ab53f0e5e8a0807fa97162e9965b25460c734f2c9f89fea5df8a84e53fd80d1f8328add271227328f8c5a63f6882b2e1ed17113f3a6513dcceededc2e9a11df1c4170ff9fd4be0cf0e99e18f08cb86421d2927c7646d8fe5d2fd396a8c070556288d669b1e1b51e428c56f5820579f0e8826210422035239a080a1a7fe893e9165ac07fcadb8fe6f96bf6064243061f0a8a8822d33cbee804f313915f4903874032815a2d49d8d2a6e35a01d72687cda576c9b8ed5b190d8be83c66e2dc187bc523f64041e93313a5c76e16fb4d8f4291e33a15c626a2cc719c6cc8f407ec9dcb9de7f7603f84f9414a3af2d481cb130ca41d3810b530eec52dc5220e2631c231330903b987a58333cab9fd48186efe058fbac2e327a3b092308e9878d6778cfa8d315834729a3d4fc4f93579c7a80b80234c5b57d16ff568f2ce3eaa1f6bf8aa53a3912984f9339d77002a3af52ff2c8e16ca0b7609fb5f8d566b8aca477c51866630f0a66e4226e6730d1a5b530638abdf3398513a219edbc19ccb5d08cc3f9addb9a37927e9d6120c1ff34d97b8da4985923405b5706dabe87080dd421cace11508e9f85be451ac5a07663c18197ff25d46400cfaea22a3cfaa61dca7bd48e50071cebc8df346f94eeb2941e7c4a99eaf1413160ab49de76c8f41685ec34b2b85694e03d6893f4ab0bf8952306041d7414ba52288220855b1a17eea810fbcc9cf9e32fa51231661b798926c2746d4c6a6941d8164df386601b3a615fe30ab6384859412afef5c3b319f8f3731e6551c7f5a371396f6038b4b554881cfb3eb8cc3b4c32e72aaeb6f1f1cffda861df90417612933c1b6a1fb8072d83b8cf64d6ab61395805392ba4111cdbee60b591dab0a0fe637af4017fe005331c861343c9b03ea749e15bcab7a79d2fd800a73726fca4d0042020bd35e01b097199b0810f8ea5ef28fc7c15a6b6daf521e612bb8f52963dc240ac60f94cfcfa269d887e2dfae7b1697b2e594b18a6cc31c8ef75f3f3361fb2eaee8e2df6af8fb0e67fcf4c867e51a47d72d6043c38dbd28f9ab520986d93fa8a16af7cb548309c55e237195f1221cfbb70229c87534112d98f060651b09b5c70bab5dbc1621a1cf49904590081715412cac94363db6a0e19c0d67269ee5c3580fb7f0016548d2c5ef7309cf28e7b3fdcd7a54cf448d0070a4010f590815c846c50b02a07e006fa40fed32d680ef295b40898d899f4534a9afc1889a87cd94a59ec6c48defef385eda0cd850a6398c13d8a8a3cff1d4f414a5afaa31efdaafd27072f9f456f9f1102830932522f5f992c8925cf4763ad00a042905a377a21fe01503f30a87aad66c55a542eeac275eb23a355acadab3ee02b022ec0937a3d062854a26b57fd65b6b9a7935d4910865b7e09c9a81b729614555a1f97d8fe82981646563a39e6f9f479a898938411bd861bc5ccdd19a60ec8c6859235da5528e5361c20818446a3c4f2176c219669721641c22db50a0f6883b5d82d33f0ef4c73d96d7562e6e022af81a15aea512fb442c5140903b7e24864c8f6554bcca8df495b04accce70cdbe3dc6b025e2152071f03795876d1032040aa3a9da202f92f18af9ecd7986f0bac82027ada1f36483a9dc6fbb52dc2e4c4334af01d247e28b136bbf2b07e19ad315ca9d7eec4c07443335b8b10a60ff58b70f8de156e8464eef41244fabc00bd296a8f8f0745df93a7f3370bb407c1a9bae4d2e32b3c75e1afb5be2ab6d3e7c6c3a0dba0ec0dbe1f7706139d308563c641eac5b7db902692292def26fe1380c63e566322fbf65ae22906223a0c390b03518043e943c46e209b836dcb7edd50292a398251976b96414f731c584624043d116a7f8075c9e4791df164266e9b6492e58564803b215b207e7f3a374c103fd867ec654941ab4136f886672906a0c61fdf7f576858d20303dd7e014ad60d576565c41c7ac9b7335bb42c2e3d4fbcbcaf349c053ddae0367570625e4839fba2174095b0c968b6ffa1e84f32f0fdac4d788115fc2e1b228ffb4fc676521f09d2a810d8366e97aeb04c02779e94c0bb920849a3d9bb06d47615885084eade4677bf7e033e4f0be5f5c14e3d3c28d236071cc3ce8d343826c38305432455eb2129d98b3e6044678d3b5c3f40a5e0a03c52ff2b206b3365dc9b8196b18660c71936c606cb99efa3da9363027867ba5738f7afedea2ec4b0c9f060102bc965a0fbd31efe643954629ed127d9c2f56e014718b9599e718fead709a3f458723064797d16ae9442f4706d83b7ca4443690b2ab2b9fcf6b047812e32803db2b157b4fb6f6106483b8229689d48624d179df3890aa1d5c8d6483d3ffae285e4358e03c8d70160f2f0b4aa255ae68f2b82c1c61746c6fb83af6a1b5e440e2e8588c89e3fd54b5e245339256b5d4f35623319491cb386e9d16993c062cc221898c890fc8b6d454805fff18ecb26eb17c0d0bf0ead937da0867b125781a299ec8ccb258027b38f72bf8ceeb678c3e99040642c28e9658e77bf668a06de491c2a4319281d881bbd944faf1ecca7fd9591a18ee05c4a1b86d2e0dba8da107387bee066275a64bc15ebd20b4db1aa9710cd4cd108c318a71ff313527594f26638f9c6b631ab5eedfa9da00d267f34040c1e1d8b26599f26235d7d126c73316d0107beea2313041bf4b3f588ccbf91bf8fadb67cfd6e6f3017c8bed19aa0df40f24613d825d4a481e4e6dbd6f48ba9257bb6f3f215978506115c7213602a89be197a3608c680b8cd9114e0f1eb25433dcd4a1f4daec3cd39a83f62edaee450cbe1284b003172e9e2e1d7ad854be60b6865f4a8335d70381196739ad15105f2106467c1212237a77b49a9805d1b6ddb0f6d2fe9ce621a985085c71df3b4357dba226daa480402d23d4028c0b48581c7c1da45807d205067d3eb100bff2dd26e10fee1b04966411174f0f6e0d8d3be376d27b913228c2b6aec48e7cc210e4b0ae35f9a429de563de2a371fb93a4f36824a437045cafc52532728971ec5bb461c281e87cb8f56dc3e2079129624d69ae525ab9c3953ee7c56422d6645df32a4b562bf1c84da68d61ef3f772c7ac71860af2d15f13b160c39069c0164f403ca58bfaa59200ebb4a070d854c341707bf3a0476b5796faf4c957e46bd2c81b55a7348281486808004fb94e489a36ac8ea073317737060407001e4c75a64ce15b2643d8560ad8cc6d7c1d3ba7d7f8a0917ae6d92ecbdf7de72cb2d654a29f40a7f0ac00a2015f087cb9fb242e5f25beb71387a96cb6f73e566dedc48ef1b8f4aa3262a8d37712228252f5f94bc302d2135947ed251a0f493a6d246ee74e6f2cb27a7345045f87dec71f9facc91bdd049a9f4a6aee7efdaa59c33cba836354d7a6b33a354d36addb8c971d29bd3eab6715cd779dffc3ee9fd719de77d1f08a6ecb4567adb0f4ca5acb5b1b9c1993838d21bc77a6de3f5cd8dd738385ee7e8dc98376e48ef1b3a1e73385656a93cc681c3e30c5673b592deab71de9837bc0e31f880f4ad18781daa3e202aaf431c1f90be3683994106d23b830aae846c2daa2ab812526fbf07ae2f398bdf86e715eee1f73e40131db7cb99a5681256fb80b4284ed66a057d098ab3b8dbbddb5dca39b38ca5797487caba1cd7759e67c1f03eefb35eed3ceff3e814ebff7d3f3611f4c0efe7c60bebe29893ca49a97c80983b3936366de3efd7c591021e9d62476b7fde6cb1ac29964eb1f23b1b9b023fafb399d2c6c6c6c69b6f80e3d055a5ae8ba305eefc6ecf91f2fbc9e8a4d2296dce001c872e3707f2b9675e7fff9204c08cabe41bd25d173fedba3802b95344ba19a7859d53497675d2b0d2c515dfbe610cc1658730a0d8e88188024e62928a5480820a48806b74d658777216eb185df247fe4cc7ece12fe6cfc419faf838ab7538ab878fb35a8a0be01e8eb253c7ad97e7f5d15f87b37a38ab75dcf67156ff95610f7f4d1d3efef267e90be01ef6f1bb2e1ef1ae55715541c73cfccc8c81aeeb666662ffb6b06861e207326882f8828408081f52e045882dd488f55bd5e46f76efb68bec2c74df6ffb55fddc5f3980e38965e9d275d670771108265d762872820c199270c01145325c41c512359c11ebe7da51fe61769977f0ab9f99d9ddfd9bba39e79cd9f7cda6db40d92b52f07084093f7881e202505030e60a28b0b800c40a9888410a1a4660e840868816581441b4469a24317d458e6b8575588e58e7b83edc63a208ca042e4e986082bb9cf054a4a4e54c132c5c49b2e79cb22b7bfd9eb31c88dfeccfb0e3bc4164bdd79cdebce3bc9e4468beea9c72877b5aaef866e3bce211ef0edda1ebc35d82f1d96d7ecd9ffee26ac8cdae0f7f410c931ccad860440ace380ad3c40a5a90c1840f42c4867a70e10ba32d36ac31861633361821260b2753d2f0428cdbf7f6edaeafdfe61dfcce6de3efd91523a0cc602106349e865290429636722843ca1a137e8cb37347040f4bbab8029acf80dbba50782882892f653091c5286a0a1dc6b0c265053e1c81011563c498018a2e3448f1812515144da9c2044669486f2e64b3381ef158e4b9f1c4f6f77c57cd1c99f8b77fea44d9912747f338cba794f31ef1ee5013261d6848c114470c710293c1e54b1334184d41c529d6cf551e75ccd3fc95c753c2fe2500171b7a78e2046c6c299259a28e30a3ccd30aca88f51366cafc40f4a4030b530c4921a20541b46102349cd6b81acaf59c55a3d8e7e7b7ab7e8eb9aa6c15f112a60127317090018c333ea010630e54e1850d297a688309333166772539ce923b3b3b3b3b3b3a5c4546002222e4afd155640420222ebbe30f00867db0b4b37377549d976559662793e1eebc23abf117da31bae38ed1d5806a48c48b52c12c1da151810b2840c164e8072e556ce9a10a26c258112b0265863154ce6001130f212843430c4b616c31521303025e1781b8a705bbc9dbf137ba3f7d977559d52c32021091cd4866f5b6d0318f55a9542a22413749e49092994408f2978a7be45315ef002f1167c917410c52c18e2ea65aad6dd7e59efbcd05cb3df72e56eefa11d7a53dfe3bceca4256b97c0471f964485d96b97c7cf3dbb9c746b297afc9cf5ebecc6ec636d8be3f0427bb1d7f43b22eab95523a660f821ebaf23329ab6ca227662d3d16ace4ff0d57aeebf5f029b0fc81d274fdbb2ed500cb496b7cb9f3adacd2325b9674b9ac7cc25048fce57da595fa4a6ba962f3465625556f55b55ad6ed9c6f177cb99ce48222035c4e5a43cced2b1276e33de77daca3f56f2309bb21ead48a63add18f6fc8f7f5fb7bf99d5c795f7f3524f5fd3d849deeacd55a07571fd8fccd8760f33722cb10703e4764d9dafcedcf1f5d362f5bfd40d265b77d29012b66f6ed77e10afcbedd77a970e589ab0f6edee62b7023da88df5780656b7b96adf1db7bfadf77d2b32a30565e12a6f6d21bebddc223ae3b5f86556cc4bee22d7f9ff5b284d5987fed2bcef2f77f7f96bf557553cabf2d9dff0d971ccfdafefd257db80a8cd5eee8d5a7a111edeb775a3836905e732fc73d10be2f8eda8360e866af65997596ffe0f2e11fc4dfe5ef8345d7b6efc8606ebf07bca36f7f777b27e9eb1961fb880e4e3441a191018d18b13640165b9068a38931a06c89757b0d1df3743e495811fc256d22d04395ed3751255bf23b1ede01def75726e517912df9dcfb11d735a28dae1e96bef6fdfd707533d8be54ca1d67491e062f0ff7c8ef54602ce79f04d8e9665f447eadf2816e75ad2ab0bd2756807b962d1f81ae87e35f1edee12f7f03865d805bf2b71fe075b1480bb684a3a0eeb92fc1fbed4be89efbcd055bc251fd12b6f7be04eebbefb7b923cf95bf12a2bdbf8be3caf2cdf1a2d80c9861060ca71bc2e8c2892464f8d0822acc302d114505c6da957f08db7b1f02f7ddcac50fb6f73e687befab18c47df7fea240d788ffe8f242962d1f59ab943e2a3076de91c79fba1f716de10cab6caf92b04df4a957256135267d9c25a5b07f479f2b1f89fc25f28bc81f413e11756f86b6f62bbff8f592dfed815735856dde015ee76f889db307fb77fceb7f5d129643cc1047c860c50e658089f9fb48581024d4b060ca17596a7012f37f091bc2b266892a68b688716223e663a0c0e4841067ac60068a983ff3380d5b144a98c9628d14b4e00aae05556650a20b169e28c302cf0a1e96ce4c69e2a40b00a0008616393889a1864919287e60618736d04065e113830926a0619283172a8491c60b60b4f8e084082c47b1dec2883164c658628c1250b019629c008523c0c0e26486a1262e1091260a2598a26078ea98877ac837c9103944def92e92903d091cf42b515d1edcd343e49a350c6056cf24728d1a09f41a2992c000eee99720f02b9b279844de4cf4e19efeeccacfaee46c22e0431467f1e59bddd1e7f6b74f8f97301e1386090f6984185383090358c1531037a031c40a44c4faad84752b50b106982d699c9888e150912445114614356d8921258101e572d2175f2e079793be88728bf8cbbf896ef703054120c88eb3da593e3d46289201671571560674ceb047fc357253910c38ac89624448b016c15f3e1256631fd4111647acc0888828d6cc4caa7641c9263ae619dd480b3328db2aeefe406ed36aed544dd9a46a4adcf1d7cdf33f8fcf73009ef983f82b7cfe0efca5c1f303f92be7f983fce53d3f117f89cf2f824753cfcf92b00d9ec3adb590e3d0749d7b7cb9d0af0e1b3d314ad9017c5f85005f85f55d7d2ed4fec32a03f81a5611c07b6115d6876115027c0004f022eb3520806c5107c7125c6dbb1f1bf57ec13df4e31efa3e9cae61854f53bbfce57c614e8e1a04089bbc8fe2ac61cf2cfda080a652a91450d052e63e3d7cb22c48074a3e7d40006983b0493ff90236789eb049d1c73610fb8cb7e8a3f031f6058c3937a5a552a954910c34655e6ade8ecaef27c5cac1aaf4fb49111121ccb66da9d4a73efb7e522e1dae0184ede42d2b4ad169244aa0a8ec543baaec1be1c8d3b681cff3365f37759e4e1335a1e057bf9be695765db64488a3346ddbc4310417ac5ae77dd3e6584debbaf013b51dd0b09c94a6e87217276a6edfae6ab3edf7d9f7f37511edc05abbad829be7d5ba6d75dbb6ad82bf816037659639a87da236e57a11efe0e8a7756f5b1269d39dfa40ae6dba33ef0b37ea7d9e5f1fdef9f06d7b0eb53970b7ccac82fe6e7cb0fdfc364eb6eb9a43d2d24eaf1471b38596b12aba8375d1dbaa46bd4e7ab6724f96514dab35b56dfc1cc762eea647330d1c876ed3ef07070d7664a6cbdf2129996f7370dc603baebc794feed16a6a9333939f4d97618a73eabc0fb4a954aa39701cf27efc56aedab6d12d9b72dbbc3f1014c710dcd651d3fdf4395dfacde6dfd031cfb85db9f5b78cbf0d880fefb8fbf17dabcf3bbee7e781f9196f5577f25625c33df54701f0f02f9803eacf63ebf2955b3f64d89cc2ad9afa8e16a19424a6c915ad89a3d4fd82790d3ee3d669e66e516961a978c2eb32d622b3af3fad4818fd3a97a4d29dd4085b7f36f9ab6ffd398679f0ad3fbdb8b5d61647952afb7eb2ad05ab8942475414da8088231788629a58b52525a218c74e906bd6c48efcc7ba794b3ff569c774c255107d9dd711851680438c8a9ffd28c3dcfa43312d5c05694f9faee48f52e9d6cfc4512e09b509842062232654026f866d0b19b123ee87621eeb187317169eb022265482ae85d891cd97808aa12576c4fd68ef0270888daa5badd8ac89bfbcafa03771abbeaff9b9e5d67162e9e1d69f4ef6d6a9464e2f7532b9c490e19c1f7d8c9b1f1dcdadce0619de64a7f44c1c55ef503829374516e7475f923937a23789dedf0f10cbd60ae7478954add8ecebd730bc83bddcfa338cbfc0af3f99e61486c9a86da630b3f854e3302039c5b88fd9935bc7ccc9ad63d6e4d699e6d67966642f3e9170f6f9e5d6efb250ca2809935f30d4ad3fce14a4995b65148ef881c7a82891b210bc3a64ec28a374c4d85122dd5a5f22f10e2e0c7389a344b2e268a9b855d4e25697225bf5a1b4401c2b2de2bbfd11d17e5a91adfafc85407f4a912d1d30ac3779930a09eb1d2dc28e538a07ddcff79bc7097338abbe874980f06539abbe904ea444d8fe29d6f725d605c51ac559f5eb07c4131d4ad8dd6ef3ba90bb53e91639cb9ddc63c2d6e7cad8d1752bd04d4842d747c23bb6af0f24eb575bbfdbae43c97e936263e5d62b24f494c23dd59bbc55bf566b55f5bf88fee4acfa9de84dceaabfe90cf1e42feebebe3b75d9f7d36d73eb365147089b89cc3dd994c2adfa5ba731d92430acdcfaeee4afefebfb99e6e15f1ffc2f742767d5ff446fe29efa43d8714a19bde9d69f526a6f534ae67455bc438584edad8a46b62b9f6b7042d7bd03bc4c7f7ef77cfa73663658a942c2f6f38f16c7bfad4da06f159dfbfa4f5b497627fd2addb38475227babc76a650d1df3b49c1ef36bcea7f5ce9ffcd2c4d5f6dabbee14579b9824c98fec6affc3ffceecfb99dc4b5693e5629128f197fcea2c96b3b2f9fd645f07435d85cbe12c774e646f217196bf13abe23aa904090d05090d31b7ce1aebaa1ebb010058e7fae7f08eee905bfcad8a80cb0cb8cccc2fdf23c2720008219c86d0410a13acd0019834a288a2018da215c498e77c17bf0ffff3b37829882e8316e4bb7c9ee5ecae3d6114d5c4dd356666ae4aae11fe239ec71f106e0e467aeb53edc7a714c64e40b174f8e8a032bd8f17a525ea5af5ac1a4e6ebf4a8da5baa3699a3656165fb23767f5799666a6892861aef633c7daed7dfbeeb5ef38864292f9e682f51e7c9bf74c1c6b4a053ed28f2c5b6bcada4fa51adf63b1474e3ce232325feba40cb30fbc07bf02de836205beafe2c89f1d715d4dd34495670e44c447902ff4eae59c7631a7b8ea1f8a69efdf50242c13572d0235994f7f28963d0d8b844864cb7f8651d7ffcb78a1a3a0f9f4858e82b29f2f7414543f7b4ddc4421966cf9ab64cb9f8a2c5b33f3af4dcf31edc7fa1cd344a5f923eb7a26aea4b8aa40f6da07cdafa2d051502694fd508c63545cb518c459ee2161dd1f89ff12ff22236421cb9694e23eaf482121e1ac7e6666e690382d482a95bfbe2ada6b91304dacb2c85f7d47f79a02ddc1aef8872e8f59d1a53bd83193f223ece7ac90b95295195dfe01506147151fc98caef4b08af69c16c969a9b7725a9cd59994db3f725a6e7f7625d39249c9aca490948238cb87b3fa419519ac46c85f4df4c174be3f4807404a96f8abfbfe2087a964abe96b7235a4bb5cb81ac23df8a068a43a8b4150ac5e379dc5f6e63cfb6b2524f5e0a7721e14c7e92cfba038e6dc9c21e0a7fe26ec409cf71b9cbf1157436edee681dc88ecac1c1c71041f047d6fbebecd0f797f137a0ffa9096bf1f6b82ede12f10fc54d8371506e90b7e90bfc06ff0035aa2a48320a10f6f0579ab5febc167ae4b8aa38bde15fb77ecd1df50fa9ba88ba4e4b8a606d267affd50acd237c1506c0ec5561fd0d73e88ca17a241f33351688a2b176bcc7a39d85792f28235da4041164659c486887848811921b224c184536cc8042f94d9e2c415252992621c00f103104d5411c415505c4bc79e0a96bb9cf0e58e6da5caed1f9b876b45ca652e97bb9c204667cd3bab7f70565f11db8ab3fa690d76fc3b4295544a747e1f92430f3be0738d70473f20dc774fbf1f557807f7fd3bbcc36f7ff3c03b3a7147ec197672b0da2be11de0f71791b020b2d5db8f1a70bd1dd7171473b88739c8d673f9eb0697ff131f0097991395b670d4e08e7f55771c198d3ad6233eccc57e7b69628b0d39643105991362fd4b244cc88421cad042c309515ec4fa8b8c801446e70da5a388fd445bc212751192251df3f72161d55a95ea5721cc12e44fb1869095303f13637fddfbfd3b96301fb2e5efe33efcc4aa56f5d7592070cc47b6fc93ec7b0c4434f1c50b2cb0c812731aa6f80206335c30e386a898bbbfb4dcd352daa71a1d4be9cf4e04e846894662e425207f7155498c264a65ce5cf948fcc54a66a25cf94a263bc06e5d985cb91bd492ef7b207f7d747bf92ba0d4af40e058ea5721dca4fe266ca2b0e807a809544bfe976139063e41c3d10bb05021228addbccd1f05d94f7d4a143a5a7d90fa9b0f4afd8d2874e42fc4b2c5b2957a1b51a8ca96fc94c8922df95654712cf5634d892b7f8ead5cf4215bd243026a0053c4d0850f4cccc01245d10d5ec4a861c6099517beafa1f7fd5eff11ef722010bd711c5b84ebfefe2c85eef61e8e39eed75bfd8dfb8e535d77e77e86494ad071ffd1efe7cb66c646fa73ef0e866e67f5b9a7b5bb5962842ca8a0200a12555061fa20ea09852f6b9ce1c428261fc9922020ffee95ccf75013a269e2c83f24648aabf9435da7e4b6904fc8f6b79558099b281472966424ce923fafffb6f2f7ae406dc08a35a420838b0b3eb080d872020e2d7469810531f940446818e42c2253ecf338edd005140a498459212687ae88b182c60b0c51b82813938f44fe12f959c88ee4b9cd109d13e4f63395828ff8642209f31ef1b93dbfe8d2e4ccdd71b94b932bb74b31ad3a6b2ca53cd8197a5f6fd4d8f188cfbfcb5f46b497af7d36eafc30f78c39b78a23fdf997fad41c777f2b84fdebf2f7f17f7f5697410b96fa7c2cd68eb32c9bef72183771858888c8849808683c39492335c47021a1a1e58eaca446989bdbfc74fbb34939298d283051502e274531f198e3f69aa14bc51590bef43535567adfe228443dfe79c4aba27d95304d54cd5b256cc6faad4c42c240a043992bac68c38631bc88f50791300f629042862d9ec0d2248d58bfcba789a853376baddcc3c373831d5d5787bfa6e7d3aea3f6c840af4e88a185cc9a32606ce8e1c109263544d5e082342ee8ba145387b9fccee4622ebf0ce34c4e4d33a35a9db54aef4ab5bad58debbce979d2dbab1e33d779df123841507a83489cc7ecf107a6bc30cccce28459fe71de76b08b1f1cb83219f344ca1427f0e1288a98db4d517e58ea98a7bb87b3fc5b87b35c477f8ebff8b67875601c34d8295556ecbc2efb25ef88a12bc2aa7edadd5d4a972e59d765ed6e76253a6686751df30e7b97266a722e27a14165877bb8dfd61d156ce39e137776444a67e634ebec6624c8329a4d1e874180bdb097072c89d0052888c803267353189df4727887f6fc0be01df279a9c76e70017059876139f2bbd58fbefd7e9b7bb297dc0e5ef6913022b2e55fabb5619e8854a9ace5f04e0b5cf91d5e39998a3b0ef3e1c9f1196ac366c05f23af21224291a13a99355b8a53868a050e5d544183491042483124c39a2554f0840937b4b0020d2095adc5d47ab90b13a43baab4321db775b1f6f22bc3e66736f5b2c54fc35a67c65ea6933f76bff7339fa71453612c3f773929cd1177acb77938111b779c38f41593067b73b98b0962f0889793bcb861cdbc3eb38adb2dc597fa6b7fc7d4803bf28c3996a4944ccf239f41c01d394d13a63bb6932ceed84fae7c1e3bca954dc50562d810828d24aefc5703c395cf5233c595ef7ac1942bdfc7c70bceb8f283105df9406d185df9448a0c71e58fd086d2958fc4c995bf24094e5ac3c56806ee4274e6caef6282972b5b7646c5de5c864d2f52b444714516221ad2888db60bd4931bd82033861660625c6401f6acd7f3972482260a13d0f090851461c4180d355d9e9e0ca1431719625b8cd14410f91dcc98f434303ced161df38cb2e9caf9d9d3e729ae3ef0ef0f2113d9c5ecfd331a7648bf9fbe4b5e915724928ee6d12f9f25e5952bdfc3ac5640da83c0314dd4be8a26ba644bca7731cda3af7c69c59596240d5d8b235df9b2c95d22d131cfa819ddfadf3fc7aa84ad28f507477b6f9effdae7d10586f67bf0bf1fb3a8261c1c0a459b6e7d5a84f320700c470ca10a8e289ba893e611c65f4d8940ffe8cb7074a25b6fc297ad6ac5e657f48762b2295c511148b638308e88621c3bea1fffda2f225bf5e5832f7414f4bd7ca1a3a0d47fefa2d05190bfad424741e0bb28e40314a528249412e5d2734cfee88a4971459f63489fb8f278c945f9df87003e159138abfe12d9aa552e3194841971610a1cd074a146cc12b1faf249c24430630c2b6552f0031932b1fa72a93e1876912c025fcaa5a286225bf5bfb0b5855d057defffbdd7fab2298bcaa26891746a1e57fcd5b00634418ad59761780aa318c7388bbaf55b8bbf562070ac49954bb2557fb5024a3d081c0b21f55552a26c92adfa52cc184f886efd46a279f4adef45feb2d257248c63f5003f24858114e3d8d00a64949a94c048f9c2ec49b6ea268e19d4adaf03c68e72897e4c33d28632ef54d0d4df8de0ac2e525f7b0f41f0582bc9563fad61fd3043b1ae863464a495fff6433121a5958bab0fe8d70fa25fdf5d0caabf89422f5bf285e4506c28d6b5f703a4922df956d829dac438266bada1e51e4941d001c37293bbd4b274fd253373376b9ae4dadddd4d3d244a96083591c3367b25473979ab53b0939dba2905dde474c73e13d54efdd44d59946d5f9a5f7e9cd399db61f09991e066ef61f60999d74826afe6cd9a04adbc43b4db0c77293f27f3cc85861db3ed3331c7b91f354df4e7b699b9f3dcd6b215cf9869afcd6ce8be125df59757667172add3fb6f10d99ece92fea31c9aed5a7c136378803082034a6d44e1841429baa8428b3394a0550431c41254c0a892451a7e33c6eeec6c5ed871c73fc7ceabccb8a2b47065cc142640a920893066727628d1e48b35463de420048e2776545de7f1a9b386e561bd2375432e6031c30950a470c59a206a165060bc2ac61817b8b8e00c1064d8b8c08e39b029868e2f551ca1050b261aca600105e566c8072f30a421c411485bb86881f252460a231b8ed81883af28638d4d182bbca026892eca90c1640b194b50d1040e53ba582385d8a83a018c262cd8b22685a32315130268262c278049586078160021c2e2a4cb18589a60c8524316224cd8020d259ec034beb6c2f53baacad3a3ea7a17266c28e07217264a17bcdc85899a2b664e3592c052830bc2a862c4155dc5192b727c8a0c4c3c5101c2c9c9f3b225ec9d97256cc6dcdd0b7771a609c76082a0128399145660030b331568a44030634a0e3d8839a18ca3293bb8f1c48e7f5dcaf937470f155f1d3f19a0c0f2f86c89a53a8b4160e274051565b068028d589120971f44c26a2f5d993486962baf648a820a1a92b8d822871762521c8ff0d395520363a594b04dd454db268e55cca1e2583371b4538c4999e3b08ef94b1f7a8db5b99c244697c9458c21be8881025781ed2e278901450ca3a79aaa1da735ceedb756d8b1be8be7fa38ab7538cbc98516be368c526b5ef09a6801cfc8d059f9ba70813b61c9b38285cd84a62e8aa21a86eb52a4dd17346d5764a0562a191c66c898446964548861de3544344ac6889ab2ea2a038357db366682d1fc7eaa4bd6302f344f133e6d28c916d70a8612acfd3d87714ce5ffbc83e7b2b336916fec8428d9e25b6bbdd561b349d3b890c75bd6abd5aacc68a918aca05e8d25c35cdeeaa7edb76dacb0af3ec27373883c2c2b367539890ba32bb9e082c855d822ea4a186ccee5a42d9caa992bbd853bdeeaf750d54f2cf0e15c31b89cc44515775e4e7a02e38eaa4b44d74d79e305dbcf9476925e33278bb9b3c79c734ee9934d4a754c4ae99c3367ba171e0fd9fde7289f4e7166c059d23bc5cc2ca59472642e32ec5a552a7f76e7e9578a6392ebb46dbe7463872b21248097ff0097c5ee39a7bbbf9340c701dc164958b992ecb2b37c74f755773334020279ab8820fbedf217348988827a0631522c1359b684f4cb1d7a495092adfe6e2b21fd3a42588f84799564b7de1ece926c74b265cb9e73ce29e98f926546bfe953d621a564b94a25db480665d87ecdc7a505f1ed8bed8b0cca701e9da339e06f297586b0fd45feca39e94f0dae115a65d8e3d09552ece19f0bdabf9bd997f22c4ead37268ea1db0160a581a45c9dbcc4630e2a2c97018e1d1c9f4a85c10d15007e6addf799dc68e53c1fdcf277a48c0adbd11b18508a73a3f3fda0322727e7b3d6a66c3490329433a39b56b917e44f77647f64df9afa545a2cb783dabf2af7fd5411fc7e480878decc9e0e913f5ffb869470b3ebd788177e3f529c99a4731ed99f19422048d6c44e91fe643fa668a14caa55ee9983506de3bcef2703e79c93665ea7cdae4baec63c853c6d529effcd4b7ddba45ae53acfc8b79915f9bb6d5cd576542a9af252b4083b81708cb2ce386fdb7e6edfddf6b3cbbe736edbc2203a644c5e823bdf6f673d39676773f3fdd0f74f0b62fad0c17a481b934d0fa57ae8b8dba54baa75b5f33e6ef2ac55e51879729867f5ac8eec328bc8cd26b3ea5637715cc255e8d28fe7fbfebd94f7ac202e7fcdccfb36cdc572ee3b1189e3fcd5fdedbedb6edd3ceffbb84ef43a6e87fb54aacda6080b3eff4e8ee6215f5e7e9ba3e261a5c22021cbd60f900fd9c27181fe54edfba161c6acba8d21b8cdacfadb27645e2e9b24d8bee3b81dac9506f97ea838214073e8676d3307b284fb09c1f170be1ffa3dfc452f7f97437bf8e01e2c76721304421fcef2cfa8582ff31efea2b31d5461de56dd795d6de5d6dba598cced05dc1cae7e1f27b75f0bb8445c04873911111191512c7b244c6017f593feb1a3d8da3c7254133dd97079fc68f5c54ed39bd9d7ec6d992e377b2ee32753cd69a5fc92e3ca9ff22b0df255465c19861a57b2a0cb954e4857ba18e65f19c6316f2b77486bcac4f4d78ae5ffb49793c0d052dd8b62bf9fd56ffb553da5eb523e3dea9ce04ac8bc4da75899bac1923dd9d1cb022ea401c3a94932dd5103eb2ca5b4f9c27a51a8e0e58eecc5f539b51d7fb158ff2a95b539ceda496335202a71c759ae627d2078cc7bfe3ee89827be6cb16047af5aca2a6d7e3f5db78629d5348d366d5fd8e9b02647f351f8187d7ffeb15d16ab11cc0818e7cb21b6c99cc1523ef1c4134f3cf1c419fce59061fbd9fe30439d0184a73a07caf673b7f79037081a4afa4301050e282c7f430d99fe72470af91b8a77709fc1527a0ad08f4c058e282c83b95324a17fdc681c5158fef6261d27c0ce577f544affbecdb429eda694d226774c5dff7ee0607946479f551a779f7d27c1d46ca7dadd9a1c55fba07d143e067ed75e461f0c3966438e75d3ab927a302cfa18f8366c82c2c740b1e86329b1997eda9cfd75afb64ab3399b9bdcc7715fbfede3ef27497d207c6596651909db6ba1f69fec4f9361d6029bae1e45a3bd9452ce4ca3b56d4ef5b23087b392d278b953279be1f37ce735f7292f0b691adff7c335fa1d8ecdb229bb7e43705cca79ed79ddd3fb3cc8424a43ed046b80cb4a667eb8a9d0003130e418e82c172bc70b59f6158089fd6698dd4c74e5e0eef6fdf0cba2c2d66fcdcee9c3c16f088e3ba5f77990515a6f789a9d2f2595947e3f5f0b571fb755a9d1ec33cda314030cbaaefbaac1f7d3519ae58eaca6f4334d6a9a465fa35a6b54f47c356674f13361f9fb01bfd8ea3efe1a59294817547a090b304bd55c5645332d6b4dd3fa332b612ed9f2afd5950939cbbf899ce5fd852e5756e50bc1639fb884be8088848da05bfe4caeafd031503444b084978082323198eed83ad4ad3bd71943c43bda033fcfab5de2a5ef477999f200790794e5660afcb8eee66aad75e3c24efd16fed4e742205da83d90842d898ae2a85a6b98b560732f057e32ab9cc769d9e7814d6bc1cd05f7d0bfb1af7afbf61bcc62fbab16de2c91b086c20c258aa144759c4d779ec79f90ae6d3cbb75f5e2789ca6d5dad5aedbbcfaab54fd15587ff5556eebbaaeebb6ee6fd8685da55dcd40fbd1bada69936f7c38f81b82430332c6497f3fbc86da65316a2eeb721217686e77c3637fd9fcd675dbd66de1ca03bf6ddb58ec529b4d286f7f40988dab697ebb54f7a9c709fb723a9ff339fed211c7a1aba393921f10e622f3329cefa6970abbeff8fbc16c5c4db2ac5d6bede6496daf13e6b09094e7ac1eaadf0ff79cbaf1fafbd11ae7d3c46c0cdbdfe9785c57bfa31e4ec8979de56915075b5f7bef93f44dbd114dcc7156d32bac36cdc0e1d5ef47c3c0ebba59b31982e3500a343a6937a5dd1b80f55321dfda81d65f5e576d1a9acdf707e40753976e0a23c60b63e3cd9cecc67b2f057e36bfbdcd8d4d2a95e36d9d8e8d77b7e79efb9efbbcd4d71008ff68df75e1f640927ea87d7fdd6bdd8971561266d1effa2269285209efd89eaab4f416cd01fd2f1473e96fa197db5a700f942f2e7dda6ba8ceb8b4cd5cfa9a18867ba8133b72d4a5f49708f18ebea90ffc6cbc8ee98ebd46121dc065753800dcf88f195ce696ffe84ee4718f142b7ff4dc55a5f3974f7f72dd48b7da9413574232ca3b9ac7f623275df6323297cb0cb88c80cbadf0320e1bd676f93b1b41b694ea92e5302c1f17278e2e16eb5f25c58c3579b497e6c07ff49e734e8d6f966559bf16fe643f8284b5926cf92bf5936c79691e4ea539f0f771b958ac7f95ca5a2aed85fe0c333456f693844923b7aa7f16cbe5734769247b60982fc996bf8a8bddc24b58aebf349230bf225b2a2a8e2aeb578c240ccc817f0da50cccf2772acdc3bfb4520df7cb1d9dca751984aa75b8ae54e53a9411f7aca0fd288d74a4cda959289f38cbbfdbb4ac7a35d39ee739eec77fe01eff4e7e3f788c67d9abdf4fa67296bbf61dcdda3da09a26ba1567f9c7d02dff1bc2ec70bd5ba3f4e1a967b8fe7ec506ffd23c640ccd813f16a51eaefb142d4faeffe8535034240cdce3d2887bfc3515ece856acf80f15fc7e54bc4313c721693d9a8406893b4a30d75fda78a669e21882db371ef38e6e1e7cbd73b18d4ee7049667ac73ceee7d782b49988c49b9f39d15c53bba5b83612ec591646bfe7418ee7415ee7413c23471d39beeec445a245b921ac9967ca8f19f9a3acccd6022b9144991aea4e22c69c5593293c23d92165df97fb39925ea8e540bd207325689c699e5ca1fa9166ff1e7cc32b52051af644d1df3705bddb6add65a2b277f634deca6336738aa9dfaa99bce5cf9479028f1a56c4b6b5bfd5e5e137f75d93b94b3e4f793b3e4df8862475ff225287f752faf338511e34edfcbf733fef25e6a1cc7711cd1173a53f53677f70f5cebb88ee3388ee37e96f86b1ca263d8b19ffac95f7dc65f2ce42cb9840ba7b3b89f889c497ed7dfb5d65aab8f477234d1975660a574314f4c1ec697b235ecc869ae7c254b849aba7e28acb52858b9dcc5045fae3fec7217133ca962c79d162c7769a2a6dd7d1ed045852c97bb14295d035cee5214e5ee3c8fbf3458fdece507c29fa0011411111151ac8afffdec781f594d5489e34e8e673761d8692f4f86d4b54a635e55cbac852bafdbaaa6f1a77d2b21b46a5f438ddf56ed059df46a7deb2feeeb6bdbb6852bfb791de536f0eb835fbf72a9edeb6f627d6da3692c5ff6c24474557eadb3b20782c387cf6f080ef0f9f3a03ef8d5c14d1c876e15333496ab6a76bf859c27aabc5cdeb6a7f539cadadc9e7b0e579fd76d9459ab5cfdae32b76962a59968e4c11e7af28e9ea2463465e73527c65dced93de777f79c995579e14b551361b56f7154b5ecf9c939e79c73ced933f3e4f7237b6a1e75df3409d4cf83ec7dcc714d9c9ec33a0666b3cbb6aa6593e33a8edb3c3ba7cca494cd6d5593946619cd6696655fe5dc001c439089ae1ebed236ac44c1ebf7f7d3a13901d7efce19d142ff24507f7bf69e6af5db5e0bb7ef5a506bd7811ee86d42b410fcae867efbfb799e1350ff7e34277280ba5dcbb8dcea87dfefbfe7db71a779ddd3fa7d69ddf8f3a0f3eacf075e4e42f3e5d6d0efd7d19417324f6e95e0652f644c70b5af6d63b55abfe3c2cdda54d7759e57bbaec3f16ae8b776b57e97533bbf36e1f83d354dd3b82ce3c4aaad90c5bd5e55e14db1aaa9524a9ed212e1305180c344810c4f7efc90c188597c9959b3890b2873eabb29bd54ea7db8166668bc90e5ac90e7b3e227a521ba5c41eff3b80d044170d37cf8c679a9507bff52afa542ed6dc83765a5067aa067434e85148df7d9efbaf6b68ff5fd58f179a258ed4b794969a05cefb3afd355d0fb3efb5a48d3d8bedc040b3fdceefb290013db5d6e82052957bb9dc8e2be1f7ec194077ef6bbea7d077a1c0ee881decd6f7f8373e379def7799e27de78369ffdedfbd1bafadd5c3b7a37e53de7dd78a94fa552a0077aa9df3ec5e1e0d430f5a954bfeafb49712a2fc502953b72d0ecac811ee8f1e6ce6dae0c5ab82f95b36894cdd171dec1b73fcb5cd3681279352dcbb8ad769644e8ae863c7d3bdf9361953f5639c324f2ae84684f65c6f5f7e5be2118dc16c710745dd7691fe7f9f733b9a7df7329a5a6494dd33419d2efa4d675f742911377d5957674e950a5f074e5ef48cf1675d2c747c9ed9d63e69c33851f5ece3c738ccde16fd35cff1c58c7aa06f8c387c28e5306a31ea8744cb7b4454d2ac5684400000000c314002028140e080543a1603cd8d5b50714000e8d9e4466489b8903254a611832c6104280218018202000303244c206941b9faa46376312ff1a63a5c71b4fbacf63e9a9071df7b380c69b34fdd16da3b7909ede06979d6c0d6281ae85a7314e100c70c7edd1c427ae349df306b1cf8aca32ce9dba0849656973dcb9cc03e8ce604e1ba7dc5df41049232033b25b32d714dd718af9d4c2ac61a45fd4b2d23f2244047c96285ad220c6ccff90adb41309107061c5f317243a37115906b460931e54e710c50e60880b357865f246da1a901344a80ad7d0b0dab501432a9978ddc6d9162e52e09365f1810dbfd4e7704d333401fc7b7a94c2099353226ec48024d3881ceb4eeb8ad073be49281aafa0ce44f9929dc5f316fc73eb775edba78c19dbb2db8f2fc49611e316426fb0001700f684422949cf306f190c84bbc8566142827af98ea999c8c1f479a23d4f45b0147929290d4b4df0aa65fe94a531b941d0dce236274c6628e3e6d4151b9b1c1a2b1b86b020eb338df9a0be7289ce5de752fb840416b836549e33de0a036c8e58725ff7bed54d7ee02a37d7bc807f5fe36637cafab576efb40d46e6d7f9e9a7844b58edf948b0d173838bfef5d7b4b2b556fa034e70afe251bf16c5d444913aaf59f81b9ad064fccc99f70ac213294fdbd8847bde78c19a0c9d0142d53d041022a0374ad9160534cc753b33e029c14ab0499041317b0dc0c8d8990649a588ffebe3cf3011b4099ba42f04a5264958f2f082fb1ffaab260586d0d88c9e359b3d43bd2ba4cd1d142f85c757354e23e128282ccbed6cb1f47451f30b02aadef5b35a24798615558b99cdccd61534db2d00f714237ba294eb80f90677006c8741ff8a3e96f80056e61432c11877f15b0819482d145a98003fedc2acf134ad9962a5fbb77d899f845c48f8710a2b6035152370abfc199ff3c43e6bc581f5f14d8499b7de720b84056b7e6a6fca9e7ab01532ebfb033895353f3c692a263ca2e6f24baf10e6a68090654c5a044b9e4149ceeb7b436e79bb04630fc408767efea4225facd7624e0850ea779b279b52efbc0722c5fa347ad3f8dba07fb862af8612a39b7f94b34f96cd42f8beef4d6edde5a9ae163865fc81edf7bf7151530f96470f1960b6d58b02c13df9fa81cc1233050161b8896c51e2aae7c8e2bae7a8e72f1ca6ef89e8cfa8169a9b7414d5f40ea8784ef2606e4c16cbca59ab6929741e5b96b27e70f06701ab66ba40abf38fd8e47045a5fafebc80dbb461b805627274869d20c2c378428c8acacb9fb57ae4dda63c985aeeda0cd8a7da4a5b7c3e0670bbbf11c73e16d6a2631650d407edcc3547a9d6da4185631d26c937735a7532a0d9415286cf904e2c3963d25dccdc12a13a461b451a7931ab8c2ece1e4f5a5bd3258607854b969eefa3d4cd638a9aa380d3773890ca1861c419c103840d3e057cd9cb9ddf0c644ce90e170c7c3516dc73609c21290d30704ec75caf3d238a9b4f200b757274e111914d6ffbdd9e5045050baec1de7f06f5d8877e0c561ba7cd5ea379e1a04db2368b6e123977cefcc9bbcaafce1783b3c230f8131899c535ea63644cc37ffe734874d6849ff8fccacb30e5dab7c186078ef88277e0190c7e1bb0fd7c71420a3027c2f51257d14a4ee2f112b2cf61ce057fe35319557e40844d9741b9deb38bebe9c0949419581620f65eb05e2d026b6b51f8a12d01099febd25afb38b15d2c4a5792f729db721ed5a755e106671a03cadc0a2f4cc23e5686948fc58bfb44ef8720bdf95c8e3ceba67b1853f750d4db7dac1e3393daa3d51fe9659a2406ec8c3bdae3861b9dfd3c28acd484230093e2cf7eacd3ed6920e69609d11341e9eb9fb445344f114da2e70d77a40797743e96e6db611e2093bf8f7adf8b677c41d441d255ac01377146e6c52e3935b468a9ef3596154c9fc2e781164a87170010450a68a0851f3b953c49f8fa62ddcf9fb2ddeac306c7b6f3978382ef3f83b61fef9494b6befea32660e113d5d838899c51959ec64d79355aa0e1f6464d2d960536c081a58460c858e8394e258033d898cb2b9ede158e651e46ed5bf001289e80dba61149ed4408491223039689623a40dcfc16a1eccaf6b6deb207446fd3db741b7f6bb0b0786f09e4941b284544ff13f86687d48e72c51b54d544f18f89a2000a7be04d8ec2126b25b66749f709d5732809412b31231c4370d6a80dab984e5837f548ce08af858e8ba3961625ccbb990c6785498a9f7a90779ac7c43d79bafd705e9d97b944d32628c44dc0b346c1010e94daf7019e6781d60a0c87102eb56af399bb7d1c0c277b6d7a7aa6c027c99afbabf8c11b12ad567c8a47989bc54880591c1d46a18e3ccc0399a1cce64c809bf5d4de8e5b6bb3e246a052c9af69c8cd473e27f012a118dd7744ae4d915b4b23a78d149877e428977f029ce7026fad3e169243ed0bbb655f5faa911b67eb618805942e1109a5207d50718250a3db8b3f4de5e6a9e5a1da7877e552af891ac957af801cbd6d5f678baa757cda210cc8bdbb368e35266b27967c71ceae0f1c19752a3ee156b530206fdecb3e51302b03a930420e59edf84265e926db99c09880c7ee24e5f98509700d63e921e48cf5b9096d93d3c6e68d6d4db7c77cf5ed5cd8352f590b63ab37d7f820bbc4261d6856c02ced5e1c76cdedd4203e80e32ce2cea446e2d05ee8b9a72fa5d0d4e4a3cca4723fcac7c13256f4285a9600a005921a479bffb06acc5b8bd9239bcb24933a474c0ef2ec07ddb074508cc35006d1a6f924363ddafb888df5d77cb1d8e0042f40476a38281da9de802485ae729eb0c7eb989d3ecccb306e425bc3882b85590737da37ca20614bec5f669a33cc1276f9b8ee5cee5f14c0207893240e2137e441378200d6e3a0dc36a82b40e4e350ec9c56671c3d6bfa58eda974603512a0b75051b0c2f57175527613a9e8c0359d9daaa1b7c0b19490c4aa01b5a6f8c6337128f459629dfcd75c1eead2f99a33cb61e85a005e43aa6c00f507230b6441d6c2f767db5875bb5c793f9aa1971e6577ac6d06fe606a70601ee379c0c0ea26fac9c202b5f5d56a90c2aabf1bd4b1b429bf9e6a13a67116493b45ed850437c31c08687240e4065f105b8bb193d3093498c1d62d90ced9fa520775e15e37f5f3d955ba6c5fe3daf6415acb1f7080112b391b73216b69001e0bd3cae32b6f4aa6be7116a1177d79f10c1ffcbd4afe2655e29dcbe5de13044f85f28ac2d7384040ff808b8bbde05b15e6eca734fb3127093bf50612e3564f709287788f2557758d09691e21fe5bd1043a7f8c7072aaffbc74f107d2a4952fac14ac5abd2a4b20219eeae6d26fc58f63d83bbdb67340f336060339f711d59fddb810bcdd9f025686ddcccb037dcaa814ab5d86fa12487511af9ead81b5f84ce1300180503774750da2d8e4b3e8562f28e4483b17cae025207a7f737f833a6f58e4c8e0ceb27b66c5db252c04f23b59417e5b7e18db8997075cf64ce7f5c51432cde664419cd61b5840e829783e2ba5a6a34a918a7a0f77080bfe22e0622dae0bcf7ba7bcd83bcc3106a48038cd6788c68461a97f0a56ba764bcc316af112e29c364bee2a70be2ac25e6d3ac326ce143700e9b2499a1cd4a51505d219630e567c1337b21673eb062ff626d018f259c21f2b5a69948278b159175632d1f32f79d845dc4abb7886e1a08ee3b88040072105a9926181e818ca2daf203ff70a6562888fa3f5a9e6ef4c38eeb65dd3a6ca8fbcb9fb549ed56df2335029a0614b9100052b509b230ad9a1cb8fb5932e4ae32ca8fc9c23c8067ecb0be654ecddbc4e382d998db6794000276abbf098d6a790a11dc838ecf4d000715c357ffe50aa38e4666f2e0a8ab14aca5ad9482220a88cd2cbc4d3db53f4388617aaa4309e569dfb303a9f67223ef35a3a06c58fddd0b41a23fa72bc75c92e87081fb8d20967be2418c02ac28de8fb340058582835b2b06349d2175dcba9e8e98d72112dfc8bd8190c2635ddcbd5e5f45d2d0867ba4d578f560008720399e36f0c0016db4b11c1f8ded6d469eefe43f7cb5ebb0423e77c1f7c7d4c9c8f0f6faca36136481fa58de5f16c1d85ec49f3afbd631064294977b6ea46bd406a8a8513776c4bf8e8dc5fa51a956fb4fae503cd196334fad5e7577dd2d8d80cf42b28a8a9b6c231e0853bffa0c8d7632a42e6f5e0d572a28cd112a61809ec7184bfbac717ea5b701a5c82398882526f697f14e9cd92e74680c96538cf10c830af5c9c025fc37957ee3bee8dd302378725451ead038bc19d15b6dcc13541acd269e56aa7e7fbbcc0dbb374a64591a049196cdac06c5072528cd936faee2543aed76e6976c988b123d3d0af907b0935ba63643aac5c609405494026470576c7ac97814c6319427f0980aed844e1ab575dda6cc9ce85b09ff34a0c7a0462e44f1d12975fa53a8f808b09176eec814e47decb90bd98eb7195897c92024e032f12b2619421f09d0cc3b049c959c260df7d0beff951ee4a7d0c09191775b9f93a56e489153646128d0488f242a1e2d2d13eddd57c9f1014c6fccb2d672ecfab197e314b5d9c538605cdf0450106c84026eb8355c51ee643ed6e139c7dec81c50363132b5a43b0e03292f604213c9a74dd5cf7812c6b1c3c7345d1c09fe022637c523651f45738aca92e21a5469a6136083db2093eb3d65b71d3c09c9edd66b3ac95507cb7b01b3bfb476cb7991f5519969f6e9675024464c4765d0d284d2b4a2bde2b92ae7c2b568f3b87f0d7687bb1eabcda4d6baff5d1bd1159911fbc7c1c8d7ccc82a244e24bebfcf622afab7a5cd71885ef59519d1026bbeab7bff29bbbe050936551d85a072d65e48bf63b4b59e80eac3e6cf47f1beb9ecc9d2729ffb9275e9fe493f33579b7362750a3b2f9e1a593ed3461dacb9043a7b54e7a6d695f56d9a72b233a8e88b78478bfeae62384cd2912a7fde98bb540b6b8667f54afc06d05b2f5c7377c2386d2fcaff74596173fb145269c229bc0b89e257ab08c7d2fa67ce08d66f582f74650732ed310888c0cdd439e4071daa714827ce15dbcb604c0f90e71e499549ee8aee15c1a6883c97a7a44150832f8630458db9654581be7cc316be3e439ec88a2e6ea934a3be3a858d19143565159314905920d88e35adedcd38574b87c115ef9c1887eaa9399a13a59011c2886013089823510ed006a4a0095560835ad29abc02f4155509b995acd9171d75667d1f82cc339e693d73aa6f36d9462f86ce2241a62c1c8209562aecfb69e29e660881fdc7f182c064da0e39426dd50c23e2f49d2f3392f0a5c0b81b966a6b150c79819bb3f8453d4d681e8e299c05a29173f0c4e836fc8c2477ff32178ae62c20f0dc3c4cb209e32636fef02463282071fcfdd1fa70d7e6748465fab71550dbebba3e1046475d687551c061db1c2c42cccda9beb7266272bf8a2857c6be3491f8239ebd3fdf49cb24abbf2e5132f52d63f533482a3786d8406ddbb1126288c31ba849d1fcdb6bac5e76a5e08556c034b6fb7701cd311c70be1106643d16811f45cd0427e12f73d6495ee02a0492cab80a387d9f1331f65a3d3252b9fa081bb16f79c56589e1b1dbbf0b97f8cfc84459dd9c3e5310a15e3f213cfee6bd404a1d201599fe45b05592378f1e5e2312788f13a4f282eec1cc0c514c8494028886ef223cc53ef158e0028f0b1428b9cb3b8b7b7034b78eedf8db48b33b8d9bcbda2acedf96a156c8a210390aec5d981f04541dc9b64b3679ebb39d278dcfb81dd29c531b9b756091a41c4d6c8de9d938bde653ae2b58fed99c16137fe798a9789fe25056e692721016ac4d4edc1b2409bbcea2799eb42e3687542252f9d861954526ea86e276df5ffaece88b8c02d6db0ac42b8dd338199b42ec5ae68f8f9024f1529534262e8da8a98de45539437618f83b384110b5ff1e08e2d73eb5f892f36405239b6415072f319a111cc6bf7ebac70e21848cf600555afb8d722dca12fffb9b28b7e805407d7bc8b682d088b273d2b713be2037a74eb8ce6cdc39ad3278dec6d06629b2f728eb09b15d1499b76a4f825db3ff98a85673eba75da82baddfcc1171dc707c87da6b0372044caa61cff99b1d6692ae52bd1f164a35d5157df1d232a64855710ea0c909d15aaade278c27954df94ebd23a55f6f00e6ccad916aafe71e6e1a323fd6cce072248c1b791252e87ef3a2c3b8266dccf0a7bdcd80f84bc21157f16b607326a740f2e90e75f469d8f960e08070c58ef2462e27777b12c9697e205d35449f488084900b982bbaac32ce2dc9a5790a243af71fd7d1cdf286aad156f32c0e34e9bfca28a6420c1c5985cc296459651c12cf6677c73c28e1f045c71d81208c27b0f8ee61a517678845ef5ff5fbe77f8211db21f0ff57e086bc49dde893c0743ad69b1dba439ca958d8632a3d6f12fa6638a41aec4051fe05f319ce2303a37aa9c87f599d6755116d77709f29c8889d00e4c22d169e08d8e4c2cb41f85c006bf7386f4668b27a105f2d7b7b2d75b62dd0696deb899a007cdd27077665bd7a89c00b46494138ca7353c802c74297071304ef009f920559af44f5afb4ea65e8e287587a471f735a7cf83df28fa5885847367a94900f25ea740d1e67cddcd70efa11e3e1fc3994c0647ea1e776db12ace6cce67d8ebd4d3115e582a662307379997cb02d3a237cf65849d1cfd2fe544126c1021f511b19f1033f7bdf8ef48408fb5d0bff22a5b26d9564b0610a65ef6e802667ac0be668acc3a40b79afb95a8127a511015e8a5ed52415b488517486afda890f7f49c0ad3fb32809cf34dc3fc79941381abb0052f03b1bad25ef69632078497ab16ce8a4cb90ae7cf148b9722a30c163f8d1353ca9bff602fad3405b27e6ed016b3c09356c36a769391dd8d64df0df777857f4d201faa95677f1ed5a8fbdef26ae6c9510f0f7302414842f5fc508d26df0c0168e1aaf3e473f93276da48ddab60ad93dc4c1dd3fb5e302cae528556934446700f379f16d6b21a31b5de3c1bc2958259590fcb5aaeb6ba26b3618512a50ff63617d8722b918371dfe78fed85c7c29f86c1590e0378dba80553692b1e8ec6b14bee89883ee4da719ccfb02e0c9c9363860dc5a38d0858fee1f118bead6be7a910cc1fbbee0ffb28011d919d42b03d6d89dd4a6b719ea2bee8adc2761774a15470879fdfb3c15c64c36c86d63233de76ab76f5b09c58e1e5ebef3b856036d8009142e0018ac39b7d85db7b22f3b80b59dd85df3663b3c73741490de5b4acbeb38ae599d4ef6db3e77e27fcf690d25be9114f76b81e2e44a268617ccd6286a4d2462c4765a3940091a882444f0414244ae4b814a910c8da668da567b891fdb9ac55d83b330b24bf507f8f2bba97914d1dd8a4051e9b4222d34bff2947b2b692fe7345b896aa53e03068e3b0c2d7fa127a4eebbd603d2b184c144ba19afc62095e3d1d33e02f91c16bd4c04b1f51b5e269a3522cdc35f69edd3a6d72e8d25a35cd35401420200f4874bda31bccc8f700da681b472191498b526556a83638ee08eda421b7e878fd8e223fd5eea9e33bac5a62cfc67afd316ece7c1144972233609e39e1b49aa3efaf79d5e2e6e7db78e3e516f02397ef2131abb6c389a7dc2ae692426868da65239696d2605d51ae554603c56704d7459f52aaf55d6be46ff01c217b896cb7c46677e199a912a350fb8ad0675f022984fa57448ee4e2b0d0e4b612e65d54736b8a58ba4c94a52c312d63137496b23b47ac4a654ab314e4e54fd27859cac94ba5e5cafdea1b26008822985b7011c3766a037f10fe6a001e053d69665c1116e09b04208a7885cdc2162885e7ab5fd4a2f49c1dceb6b3f33298a61e74386deb6a6a8f2539625168019037718ab3aa2216abc181886301fff10e4559666fb47fd9698a94fb04fac21fd718b5623fd870869b2b57b1493ab21f48f5b2612f5c180854e273a119ef36d307561d55f0efe5e2d7c8a0d44ad558845a5229c6c47e19f67e9e4665466b0434e87dc7f8a657f98c2f1740f94605b78eb416da9038f14b0051e722710ce7bd910c7052dbc412199af79196f0947e70fc970f40cbd1389c7c4ddcb5194c001a186687bfcefd88d72a9c08d01f23dc24d46ab19b30a16b3891d6347804efe8bde52b63018fcc29279ed6db69486399460074988502539f5f191688141da9dabdb0292fc0a619d0964ec0e8472cbfe4360a39bb91cc1ae75535683a1d7383288d36a9b32e4c26a18844b47c260fb9516ede85faf39bccd938a0f7fa00501c36245d07a87d89cd7cf3719c861024eb4284a522504a24da7b20d073508e0ba22094a407f1b7f7b4f58e47cb96af09a5dbd3beb46928a27adb9936fdb868d3c882938e38cbbe3f6d42a63661b5896044912c2ca482ac0b654e6bd5341db5908f9a4e0cacd6a659e392fc02136b6ad312ca0f69be9d66cb939f409b876dba9bde4d4f87938bf9b5deacb1a62f8438293bdb2281abf83885d778ea8046687bf649d024331eabd270baccb0774e50030476a5f8f8f7a7972eb4981b8ac998b22e9cfae0a8bfe9ef948a03fe9d5660d6e737b08330db4baeb6e9d06391171f73552560f665b6e90d095040938e3565dc6e72013e2c9bdd8433b7efbad575468d5e3c436d70d24635094c4b7c52c0e90668db8a7d5f3189a9ecd427c26ef0b8e84cebe5a44c094c048ee002f0724df1cd792a81fad07831ed916700a6e86604ca5c5101b8904e902cdc618411e2b1ed3a3ebf281843a504494092169685c13d717f2e29a8ca28e3ca83b4e63b90c90c46864a2841bb66a3b34a1fa7fbc54e2adc4843cbed95184271544ad1c9fe634730e6331f6627d6f93003998dde2c91dd3412af0695a7c59780eab8377b4aacdd06cb1a22634f88fdf604a828b06ed27248304a8d34a592636b60a309d6a0ebbbd1a10a894e2fb3628fb3da68cd5add5e6fc4a86fb9fd54db1edccf2f3e8e8f88e5e4b84e68cf3a1b738f2a846a0bcaba93a2cf2ebfb8e90f0c7e171be84cb5b949bad6b19e036bac8febb387fc8f773d7533cc0701fac2fa77e0d645ff2cfb493edc87e8fbf2503a961c1fda97b9d403c5a61ebd13ef218b0af0a0f36482cc4f506fbcc47daf07a6c525bf1f3dc08aa77d3c90ad5fc3d1f1620280648c19a33b191c8259fa1ae18a4bc8f4d44d0f203571820a1662680b5ff14151d33633bf1743c2c33463e8a0408762a149f55f06d0c4d2f69e2c25b6f689639a94ba484dab52fd6e1931835e517a0f475efdc235f50609a6cd99e2817b2d9e1afd4bfde743b53e54a75ba9c9c6c17960b317e1f48f31b07fb1dd878e8407f57c187c02d36e4a68644f601a1837c07ec6453f9a6b99db00b714ee93680e86ad204fc506b8903aba06f8681d4970999a250dc5c85f1dbdd2c4316ed115019a9e6cde7da92bf0c24da9159873379fba2a926fb4332dfdd6ff418cdf024ec9eeeab2668ad1a3c1d3e2b1de09b6ed19d610f6723abf25d1c8f0a852f2ba977d66ad80bcc90bfea283202a8baf8e7e80761196dec82277ad5c86a4f0b8e0cc41c947983fbadeaaa711192e7e161b61b594baa5f39701575237d681b79f6578cdbc74d526b2a0534071d78aa9cf49f6d818403e4d82a3cd1e4077dcd281ec2b0980dd46af6f461a18cba7aa4392618c56b415ddb936ab4cd961e999b3b0a5843914d6538f0a15fb0aec51ac2932c6d67b824f2172f1ece4166c82b91799f8eb5c40bfc3d4481d263e75bbc93dd6f22d8922633e96aa3dcc16e730332bf96f28512ec07367cbc8634b846ce63c825879ee29ea440fd6a31daa6b751e71a7b9b11aa264871387fb8892f06914b0a0ad5d72cd8d81f2372d873548e587a4df0747459ea1e2e38b2e8d6de5bde3572aa30da6601b1b39d9ea887e2ccf88382430831aa4fa1e04667fdb580308235259d827520807d3bcc5a3ef169d46a2b8eed530aeb63ba26590bcab0325bb8cce3518f90914418c2146587270d13a2ad53852a90ff6072f7a3089ad9254dba052bb00f0761e063ed9b21afa1258710ff433986a577b0e4b63875d8f3414dacd41438a8b196b35a790d0713fc90ed194852ec02ae10dd6a1019d61ff630a9bccd061c49f68057ab80b0bb1d7e9baab67778d4fa88b3d451937f73061b4951840d3e799182e6a1cfc80332f1400457234390e330bc35b72db5f9d8a33cf2a6c258d07b0d35923cfbd8a098a5abf8c5647553d071bc42b48329ba099b943272b135053d63951399062c1a7688f632417f312e84499c8c3c1aaa45c1154c69ae145e6fd21329fc8146184ef290367b1d90fd49d176d1b714a4d1974175801e2059ca0060488493d96726b6636525d3e20d08aeeb2a187a81bbb9b59429ffa928c4a0c2979b3a4aa2acd2d1cef448c884c8a465eec91a5293bf6a6a8772cf1aee24750a28651f881615882a36801cae01b57275551a37ddc9d86413b67b9040bc4cc871ec4faee1930b42c3c62c03cddb3eb04ff444a22110c00258251740890a001332d22e22dadffe1fb40c19bf99eee7fe203bd6bd4c8dd002d2a753b29e6832467dd7c7a6715f1922a1dbb0c3b02914b7ee16d208449fc55b04ee6931bd9fa6ca82c2889c28d0549641693eaef3c90081ab74efa6900b90a58950fd2ed454a911b8ac5c8b4e0f562b882f312a7be03eb963840baff3fca946c51b34c72f9bca90ff910c839852391bc45610870ff926e07e6ef5f9031b0ac9c28af888dfd466b486b1d404320380bd8dbed291c06d36bfe8a312e13596ac43030358b554c5a01231661cffb8cfe4b2111228010a9288ca4117966192e0719126eabb97ce01bfe46b852df3f65c26b73bb3b28251a4bb3964dc36aae8ef1e63b444a701dd6c4e31b3c55244de87e098648142683385ca3870a9908f9faa83ba8140a4212ba004b4f9a73060a25e98715231c0846c4b6fb4a9bc26d05daf58bfcec5ee4f970c2befd6dd9ea146f73b9578fe952ad1482892bc69f0c4bb88d2a6bb0fa14d4cbf2170ffa656186f4856a619fe9cb0ef3ee200e0508460df30a2328c85b30192feafbab1007b58ce8ed512c7608576182203f418a3d82245e2f229730a9fc436fd3aa19b6104ea96fb964751e5089d71381cd183a4370faded01970bf11d3cf9af4bfb3a34c3cecb315bb03ae806ac0992e65ed45e1f745c129d7428520c0b8832389a1195824f170a199c5fcb7ae6ea0f3f20c1e666d7d0dcbee659f790400fd3060aebb652e9debc51c8341b46280c7fe8016b8b3612aca83323ae61c60e6a490c40c9e60edb8823d48acc8a706b75fe8fb9c2946245bfb7f9b60351bcb8151ea0bedaca95de18e36bd740851d5121b4ea49b70dca3d4315906f6f2d5149b1b2ea45f0659852bd57fb3cec108646d8bccbe01ef077da0576a8a16914b680119c8c5348d25dae6a867eb3d94f89c0578908cade537351c0b5200268a888d00d62f74572d92105038b1a169e128b20e45ca24d7ad1d54344e0efd25120e1021b97b4df20c2bf90fe90f5e12688045fcb33425ef76dd865e3bb087161aaa82434bbc8c8655dbbb0d81acbb41a1efd6f5e11221046b4c9729e9fed43dac66d640e8a915290d5946d9f60a1dfa42f61233e5d75321c471958a032ed840a5d24763fb248c7cf7b692bb1f46e75c840bc88a6d0f50b0382468104009121ce7930f321686b124f24e043a7f1a10e13eee1b69dcb12da8be02786fe01adb0657890f5d44b07c43a2951926b45ba41181cba1b18b1e24001b7d03f40fd94cac9d6ebc2e23553692775a1002f55835ad6b9fc1d12c0884382f6b17cea47c732b8ce48d2461b16196dc7d12af00ea50af2293fa154e59933ab531ed7cd8ed52dcbf2658ea9041ffd1e0c3661cefb954bd405994a440b3a62c1d0e1438cdf0604dd45a8e5f4e28162bdf174a0b7d0b876dcd280c5c923222a9dc084bf281e7fc8972fbfc171c2ee5f03b5b9154bd130fb4f3c902ac21a0cf2f17e02aa6be69a11766615fa7b23ada6fc2e013ff8bc7134ba8f8ff078d2f83b5521bb24b78b484f921957fc1f1685b6233246e1eac421c893ac1b8c5d8ee88d8db691e9ba88d340dffe6338211eaeb7e9fdb10021f578b1e4e1faf1943e2da422a6aa2cbfcd86e7f738a6cf5cffdfc9d31940e982c02f8314bb691c9aa1049b286b813fa6c2ea7be9174b850ba7822855ac157ad755da38a63b64d61f80ddeea7d79ff18f1f039be81d8e0a1a1c5d3cbb1a2253926079a6cc6c6dfbca8c7bea601243802079bd29c75b9a50cecc85a31cea1200cf933abb95e26a59dbdb2645a4fbce1d11b73412e477c2390769cc6baac9ea232b4542a85f91d79bfd27943a7d9b747c526aeb846ae84d31acda5da4bf414ad612727e7c1c959475cd095136d8eaf0dd07766404a9d8a1211e1f5782de066bf09de42ac59c4f866297506face4df046694cf94814d3971abba3af18ef5582b8243f783fb477e99960789f5729e207be748bb1f6ec964b8feee88e2278bff93c7d162c9fe794d8f34c81d568f1000bf3424cb033336b9ea7917aeccc41b40577d385e9cfc17144053c9e648c22172964d3c471381c3cb2a877c3fcd562f29ef1de1accd196dac5772f92d400b94c27d8e4f1f6e5a92ca6c00128aaea92319deed46b58aba56579af5d3c7781f172c805103577af831042276b78c803cdf799b309ea184fe5d44371663cfcf5b5b4fb495203a3c658da743c48f3dc78e962a9699591027a0062515d46fe5d3741064ce0538af91a747fd1d0c49fbd7ccf81c552f46fcd75b99941675377cfe0865b3b63cefbf8313514c0b2f9a037fc542cb3a46d6cd29d4ed114796751ba168f0f34ccf8a8a4ecbe0ed52d69b649a7e875f00e32967f6dcdb44d822abf6c142e42580d27bbd25baa61a341131dd0a6a68a224bf055a4637d3bd6bf7f7fbe5b509081812522545d3d7f049d7ea93b9ca22527248f5094e4538e9c042980d89ec4342834e846f3c7c7d01b47913b1330cfff2bf9d07be0f43cbbd1453f4e42316954cea6e4f19683cdaefac2b75e1fa07a6c3172fe4009206bdb586759951d7fcb2a17a9b245af9330666b52ae46b63f82d48dadb62533744e7db1b67e0149ba30b62cd1446bcadaae12f94d99210f2700d173d230354a6c68213818b08de796044d8ca901ec043f570e546786870a366c923bee48e284b78b8a82246e1b2ae61d666baf90f96d8b6f6b6995b43329ac904bc701c207e82bef26f4bed9865966bfefc4731cce3f4fa40f687f0709b1e9fd99e7e06b1d0763b4d2ae99284e90b96cac6b44dbbdb9d6a059afc29010590fb29d071c20f4e1e41b7f178091b71f3f9098e653a6e294686b5c616fd6090a839b86d9ea88f911c12953f525719d4a41f177e893f9a7ac8acc5fe2bd09e57acf7122584b2b55cc30490b51d89ad6dc7de20158809e89aac40d6b673965784c0ead222d564e8f5b33cb51843bd737cbcbf53a90546dc84868e11ab170800f2a4da4f82904b75c862909a6a23b421146ef8d1714f59b4db966da56e4088872d88bd290c96de677dba023c80d553a1539aa10d80d3e5a7a50f5f6be924adb5746112803c4460a1be945472bc1b477e654de7760e6a565e0f27fdea477efb88efb9a77e00158db10ff1d1fa8b7c2d336d7f641cd1153a3af01ad90d6d51c7dd58eaeb75b369de120f79976221c495b0fd2175e7067c1dabff0c1082aba9569e5814812cd96694d076f017c345ba8a583955c7457d2ea812a5a9495d5d20edcac64b42daad5c18b543457d0c283b4f940a08c6aa1d60e2249d169252d3cf84445555c772f22dee0368a2d7ca841796af1907ab5941c6dbb2f8d0eb73013e9d5917ea07431f34af9d626e645b067519dd00f935eb09beea30973542024834b8b18e0eaf6444b171b753444f08fc5a272ec437969c0a489952fcdb2a09f37bb5ab4552eec9639d15bf6b9709df45a42bdb0beca85bfc01b6238f7cb450f601fa859a0dc689fc92617d0c314648463276b1e1df6040760e9f85302de4abc0e93279da28548ad036bbd806a4e1a4b5aab48db7e6a08412dfc76c97098cfbd630e029fd7f1be60b858e9f37fbe506bad4e29806a58b4b3d21fe5091b33a7bcb86b632ff3a09f7a2733452781434e4ac6211eb3d86ad151d3260815efba86ac87937cfed81d30087b7720fea14574284ee6b7d59c2c9578051c5747c1df0a928b5eabcd802b610eb936882bdf113a6cf6023d9e1e311e39bbd12ef00a0a8dcd0cb54d1ce43b0d7eafb7f2cb872db981145b02bb1a41bcc7817dfe4f8a945f5e55605f421fa879ae340e769dc1559d500be2fb690761c6f05a7fec8888556fd5ed02beb4438c2fbfb56786b8ed50569b414f2dd4746344dc8511809494669429151b1616d77cb78b8fc5d99a768a3f1356b40d9198ce7f6ea8c8058ad254948016bde7b0ab9fcf54c26d96e170a150b7fed4168d26550f623ea26802ed1785623832a68a2473fb27a45a91c15907e4605027178a58e032340ddd63be8a63b967735d545cb53b8d2307a536602fc45c39aa5903a9a0a7c1ea67bfe9d82cc52c88c6cca68fa53df8e2bcb85954c70f1dd86ce30b02df353c6931131d7f80a6b3c707cb5b8b061ed08f559c93f5a811f467420868c75270c366ea1d76b0b8e9488253aa5d0f9b9009fdf624a917a9cb2ffe033fa8f287473ec6f2f47ded260dcbe6622a00b0cb0e218ae15f0d1b8eef3aba6c80d97f783337379fef70a8aad1b1df0eff3188589c15e4d7666f41b96a58df1664d9962557ae6b3f9084a1de3aadb9407ed5013778713c372221482ac2eee465a9b47c4afadba01629a603cfa31f39b9ff4896eacf00c39260675e6908f8915a5737d28e55cbe8634b0aca89c94710d17a9af877de4b32f1fff5520b1aaaeb09a2067658654101882405fab32754d2856ed7f455094351eccd5da678a33209e63f09b50ec549f1f08c0e74621a5942394e78e8809b069f8c2fc47cbe5a6b602369c164c2c249337b0a9818daf96776763b2c00a980ae6479946a523deb515266f559dbb6c13f17013bfc80b21736987c1569ef23a09282ba7442bf0d510fe201fc486b771c9f03a66a57a3f0bf8b9b28803fc531b3813b067e80cef25f575cfd22449f58a8eebc50b5e39d599977cafd8ab58e53aec19770ee54c0437ee9ed03646ef46dd158886687d7224636d72db32d85b41a5e5db4ededa21170c4ecbac6b7fe8e61eb8f4cbffeb673bc11a0d5809d0e2cebeba0ec6fa1b74448d9fbf3652bcb9a7b3091747662be3aa9c9b60551f80e18189df2dac0d04abe11b198c8209055226fb705ac9cbdf0a6dc474aabca96d86f4415745222ee79b884b0ef0eaeb4ae613d5521ed690ba62249cb85f6acec030a49c68785cf941de45ba8e9f8242cb24c09007c9e311a6b8ccb90dda25b363a59fb8693aaf7adf2d7e934d4f5f537e658306b7a3bc9f0a74b4e0949a7a91119f36518a2400241da868602f06a18000202c13524cd3f39398442a850cd99002ab8beeffb1699cdd0719fda001a4a303e116f38a7741b91239480c9861a5019e990d300323aef2a029e8fa8e5c0ce754b34342486aee483b89f9117a7b05b755c332ef0f2292d99970d367df1ac5c4aa82ef7b0fb4b08483aa7c1b11a9b19d75213f7b7162d589aff9ddcf5e3ca01b3c1589e7cc7f086a3b8676b01511e998605f672073c2f37db956c5daf701ecfb6d8a1a0e2629b509c426bbe8509a52d510a32fb8d5870b31d92b8909ce9e33feaedcf48328435e16f1a88ffda92165310badd6931208ddbd000c60ffb0af303a96d6d9d4d7d000359e4777100b1f19f0062f5626d0a57723698b01caacafcf42401b4123ba383fb1cca6c4c602394259ffbb05d7e6d2efd93012aa37dc56374713786fa56b0b5ba582559255f0936ec2277d612492f358a43bab6eced8ee3ebbd85e09e5b47ff87217ae843bfc2639654238abdb5981235baca9e81432ed4a538a135e9b1c412a0766d4052fa2dfb5d5f46720cc4ce066240ae5b230ba78875a95d09c028da1e6829cc99941a6ee74591570fceab1e734856d2488ef8c28b5fd088356d65e281cb6b55957a1a3e65993e2f62a79ec7cdc66fc9614c7b5202d36be0d464e592b2056e9ff41b380b1b0633d57c8ed464d4a003d8cdc8c18c46d3a3e7fe4369c712a7839ebbc0ef759e71dbe3be456cb0d7be33add08a56e2a5d4fc7f56d35193193b3b8999bc468c77bd449d14120c40ef6064d7ee7de73305b99216ec9628c80d8d62c80b89348f50adc7462b036b40404163d7bd04592b24c780e471851b87a09a33ae381c828ce4eca60b06f62f75293fc011772bc6bedee7b6469a3a1614dcf48e578cb5b79981f1a1c8b13664c29858b5a53844a3629cb691f517d28bd7c624c36ff78e8b4327019113f1cfafc8a6f7ea9734f269873b8428ae843c09265553e22ea495a6bc7d2e57bd50db41018753cb5332b8831ca5cae08b3d1b84b834483a5959b1b11149ffe32d7557455dc1232206bdd3c091a8e3aac9dfed8c8114ed15541368c95da3888ede0981cdbbf8ac423e9dc3af6738db74bdb79370b8965392ed8161c719cc44db4ccb073e5ee4a3f3008b671f608298d0e1fb6cebbc934e2fac7bef21934a931a00d3244d8710b6e116ab56f91bad0b82f8bf64ad19b548a38f2b0150ac026ba223f0078a504d9550f301702b5dfbbe893e4752d702910d479dd9da820e718bd2edf4340049680f8f5c4609d6a9110fb878b918400158b390d2400b216ab03b095af4d8f767795332be4da14273a49420e3ab3e65b7f4cc6e0a66ecdffa2af7ea7e459fdc0501d74b73ca6bad19eb60a1c629ddd50f9471e2f6286419e94ba7ac0c8195de30e67f4996683a67b15607e3544e1ffcfd4a28e101433510b47bac0025669d3cb149fae2025f16fa487be1405ebc68b268e44109dcb5306733bc8fbdb36d6decb049aa1c370bedfa2a3143cefb5ca4e1f58720cc00d58b42cda2c0a623fe2936b18ffae79e5bf52a13382f81d3de2fb53a5f45cff5057d6414b509b142643984ac32323cdb5c6e0e167e06955830e17b809c7a82dae9157e38a1a5b1935b30d22c38a52a74b8c95717c17339af4fb8fa4cb884472375ee10ba9d7b4285eabfb063100cfdebb88ea49d05443e1dfaa2f2be6e9aaf404a3719ffc8fbaab90fb6bc67f2e5b3866c36d3591012904029bd3b7e20139e4e51d56a0cc480a93e5a0feef701d43941a60d5d1d1c1fa0d9a167de2bbf7a4006eb69447d51bdfb8554f997bbefca0dc5b610c572db8cf6d15abbb7bafe577de45cc762db760fdd33a47d0fbaee4bb24f4ce94bdf56df9d09680d8f6a12f9c91788070ed8f933916ddf7c78f8222abc4f18d7d8cb27c1222b5bab5e6ceb8c70f66e44c2e76aabe4241cb2612bded706d3ac4fac7b50649227d3c3fe96a4a63e9baab349707ccd0aa4389f599bae6784ff25927d9d41927be22ec2dcc092afdd36d4228f2d6da2227d2bf0a5e918d1e9cc9d8f0e4f7d6c9fc795ba63964d15bef708902651c82fb30a9c7ac98c069872544f380050c2c079d59b753bb66a586d1d03caa9804be3c5edb3bb99062bf208007539368016f34c2692b687ab9b6e732e7ee74275bfaf3f01b12d980e9ffdfcbd9e774b92dcd11a55084f8816646324996aa9271f9c88b780ceb55f64258293a6aabe339189bcbe4273433b99518e4dfbdabb6f96c5cfbd69e3bd03b742028e894c56a49fdb36d6f4c7e155ffa21f4bda1d32dcc1dac85a78351ecb0f4167137ab10ce18fe3d1814fa33fe07f3f175f86357d1bae2b57882b5e372d76c1f162e4016e1c92e1d37801a27e94f85b82ee9cf10d1f99cdf2ff94f58f765d1d537ed0a85273942362785c3281ef7a6bf0cdf5f26e5e28da123fcdeb55013704bd34996596e6ff99aa226552d53972d73ca00396dab7fc8cbab52d1f0ae6bf2d3d8419f96d1d3641a5728ed18aa29b2022478188a19c54d9dcc5eb0db4104434ff7427eb72088b82d4d59c16981e5623545951fe0b6f701a2e3e4f6a7a1f73054ea651efe529985fbf19406e2f8ce23c6dc7ec0adc7b75850392b66dce061866942ad575c276f23971c63f9a798f2b671cf0dd2f3beada409866563c827dfee7a8933041a0d1df2fb9e080553fe7902b78d6db5c7842b5787f05bdd8d84532a98a58a3ead10b92b54a6d129d7516be17def96c5b636150845fe0bfe31a06b3580f9e0a5a9d0db4f012e5aa71940bb6b7f25b3786ac05e109cb11efc913d033688f5acdc957721d701c3430651c97f873f56aed2efc9fa467d88b800ec7efd96d6ea03026f5c26be6f4a6d354b0d94e0b20dd62d747e50188994c1499d5c793a687900ae18152e574c57ab14b0b7dcc5ff5905311866838dfc51b06a27fa44d0785c74f76937e55a83824dc773370fc1a6a35cb0e5a54398dd79894eaffd24e1e238b43a9f463ed45a29cc7f5a604053e3eff3fabed153a69bb02247238bd4b29b3047d17daeda575c412be79ad227e31bd6f6df4ffa956ab214cb95a46dc96348284742a2490bb8b8940c23e05e795a2709d514345fd898b3a0b5383157008696ef5fe0ce34c13b995492f8c79554a23fe036c8ea82b93cccbf175a5e3782ed92f43cc5c843d2c143b0c56d74fd95304179afd7c0dfa8dcb2a185a7a6e5b2b8e442e45f3f66fc17946983a9e9a99fdea1e8fa946c82ac7556c04415c1712c70b03ded7d7b6123f6e0510bf5835c4407cc9675b5b4717675a552820ee58bad4045926cf35ebbf96f89ff48a38697d15ec7b24c1a1297a16fd1a911940c82745db01889c39548c184d92e33cfcc3617731e2531401ee7590a4a4a92a931d99cd93491fda89380f02ec8e1ba46d0c04365f372dda7b04a70937074862688f628e05cb387ad52a3980b00b612ff76667f0c20467631c0a2acd9d7c02e8a3a1b28edf9d0344e1f12af08602eb713a0476a6a7a50fde937000188eeaa04253f44ea8e956f3286ca4743b2d9d83dd558ae86e6ca8684949117b37fd6d3b8a8909fdefd0397760c94f34a099110680f631ffbd46e48124984464e4aab83067ce478b4479ee9130bacc787d0f1eb97340cefa95db97b925989fccbfb86e6430749af7e1b56d0e6b058324a4128c1243f5e6ad038fa91e903e76dc0161bb565939895063e1d258fe36f9230300dec879898d81fc98a7d99655a4bfdb6ff9d1d320b463a4a9c01117c96114a1d53964543e7afee0cac406e4aa069e3c6c7125196f3bf9f17a209b23cb480cecd5434fe08627c4357aad90f3194eab7aff140e18c3f0329781449bcf42448f3ee96c8390c638a0c2334ad749431cb121ae0b2618e39a92c6db842eb0b5b1f60dc7cb34b67e7164a83b199b02580e1fafb3e26fb44b15f4e36d44b6eae9c3256faa84fec364a8a4f83ea0493bf54ce926c423f71b138d0a4dd5cd1d76c079c0d73c97996e8545df6bfc85f177b713798481c681e8b90f4f5e0a9bde574cb62f35441c56e87dee76e4b09e90e24f2bff7a89b8e340ce8af0cbb7ef94bad9df15dab7d104f9a4f62324a420ea89277d6da438dedf3cb2e8a657c29df9318e13d042859f79643b3a265e720349719ec743e69a152061cc6b3b3da45c0f50e1ad0b888875dd23f5413ceb1660891eda8c4294a8a43580a7a0406248df2183249b19d8a1d179bdeeabb1ddf3ce6bda84894be20160209374f69fec29938fe217aa02f6b979d9e93e26f49ed5ae8c69609506f7bdbb21cb9cc6521d2e9c738224d20dc7a3bc4b8ee7bf696f5dbb9c3352aee739639aabd800a56591841dab86b49de22301d3de698b03c2eb1b310f84ca42e9bb6ab3b22c4b6c832e91e9b2ba7844efa8ef4e2be829401610824e33b440d704bb861e23b39345db6e394931311c6b6f5c2680911f0c83a0cb0b6df7674f691edc841f4da30dc6237e43e882e993586c44ded6422b2a9dc52548d52ec919dcf806472f48804a11ac7c511423f20f7ae6d9c65c8694d1e94d1e970bd3933396204622c33bdabc8050b35eca2c1d8e4436e429e4e83eac9aafb47a5b0f3654393023a643e4a4d61a2de5e945772601240bcc1a7f30076c120ced526559aff5d977274be355836c4c15819f25502116cbef787a69a8e48d06e99cf41ccaee086e5bcc1d3e55677236bf35c7540df936d6af2f831280ceaa735128f10b25bbdf6435fd6dba974042165a801a4a5f4db7254e0327db6afae2db40c02ab0ea6d068005ec66b24bba300e87adad2969831316af6eeb4a7cd8bfb602a72c334f1fe1b6c914479d22bb0e41f4694bc74b8c4668eb356a348b6bea2ab2449b17318777cffc491d084e44486e92c6331827422dde812a639441d2b68605096184ffb664e49a3bb05bdced10a816898807f5eacdae9513f41233b607966ada606f86df50b3031504e7f4cea8f2a6e6862ebdb92c9d643d89ac1f15317bd604c3e29fc462a1ba7ddf2ed1f4992694ac97f93c0bb6b2d612d6d7a217a1ac206cc64d855889e2e1309f472ec13435ae5f315beb6bb46259bf07b5ff90b09d8b437f800b7a46a7ffeddc11da0647a5b03157404a989dd7a44e80f96a5719c9787065265fbd58744ab273769fb22553700f0c00a5562b7cf3437631326a0e2906651926365742d8d00009845e1a294374ac42f43ffe7e399e5a63b7de715b22ce75f9158402c5d1c997f9df945b7c553e847b0467b46707a8302f19f87701031563159f50f28573cb8bc162aced081219757b3a955230c26f065a04e8bfb10aeae420c7e02f402c4205a4dd65c14deb4c340007f45abe6d81d8eeaca8eb2e33179f58f7ad880d31d1e10d568c2139f84c95436c72fbe0f54ba83a76d3b47d70f489058ff13f77df26ddf1e8ccc0d41591b5c20ea52a4e83fcd77014b94879aba9ece901873ba630dfa3ec60d9a3ba7927c20bd0b22de23456b93b4e2fbb1792ca303e6d37b02175838d89008c57fd3b1fda5862778491b0e73718f9084606ea8ecbf17a70eda435f7ec877c04d232c08d65d917386f6d6e2750ecc2ed597c6a8bf3685f10c43f0ab2a02b59febac7e7b0c7a80913e6abed3917f4764a432c5095569551268575788b22d98f87e26c0ce76a66c46d420483ff0e0e299a55eeff0c33ca41c70d2b27bd47c8de75dac1712ddb5c58559eff05874f90d8846c6ca7ffcbe95185c233282d3ab10a2fe83bda4906f4e4bde3d33471ffe0e1284ff586956c7690fa85c1435d73b0901772d413a502cac518437e5fffaeb5d2980a32d5a9654a8775a3772a3b7120f7bbbcf8727ce6bf1008db85571e4f9d4afe0b6d608de548c6d9801fa2d86e540d2236c052f9885f4218fe9988e672a04443fd8b9caeffcb50aaf9e86eefa66a30c8da2ec69e4ff58ddc6e64f8ad8b743a164fbf3d934b1856b0848a5dea6de4882ae3b5e47c5b7f9f8953d89d94359b7f5a34a50e74bb75e91b688ddecdd746ef6fe445426145fb1300c8451a4ed5da56df74970264c0967786cda6c81f9f387f4e02a97bb8199f16850786154ae57ea38b4df9d530bf9a85749341f831f2dc5853315a65f5683c31c6a40a67109c00d39878ae1bb9784009956d231217b2b9368a0499b9d153281739c7a80dee4172cdc9d2921b275ebcef1c8d2ffadac0a67234ae44d0f972a165413973b507435655eaf434716bd18ff321d0adb18d5bc03050fd6031ba318af09517e1d38d3e1030315f2085609880cb7dbc1da5e78353a1819ffbc9c79b3e73792bd84ed4e7fd344faeb1491377cd67895a940cf80b3ed33865f4c87bcae9d6d3fe8fed7d391006fc08141478ac988360b81716e7e49a4641c90264463d9a5d42163539bd69bd3065f138eab08d7ebcaa43521fca540423e19777f4d09e162f85948ec4d1422d0e1c3db79d650da8b3b18d8825a407282f67b0886a26948fee500d6512ac1cf16ac0cd0d96999b050f83873117f296a30bf83768a56a0e911645532627729a44a9ad3b8bad531b7cf321276234897c265081fd3f967815c200043434483bfa4fe124b986361ba2fb004b1cd4ed70c383443762923fcfbc0d00dc1c9aef1aa5ffd4358d58054caa5a916e36616425ee677745b24ebbc82fba500513eeeada1516c793941c6c8f7654b20fcceedb089c1b4f0abaf12caa2e045102c3e9487c52b1aac59f8a19ee576705d4b092a9ebfd7188914d71ca0e34d837467fee159e03e685bb305646da44087f147066830c7bd07ba3c170cc9453617f1f9fb07da5b65948322a733d897698624d5d2420dfd0e064dab1fe31414021cf968b5b06e41c7d80d7977b38364abffc68ef858a93f43b716a276ea40c914ccb22ae5f859b5ade943aa16a833acd47f4d95d8bace19d8854a06f8b108a40130ba04566b3b3125f7d95bfa0f3229a9afdf4cab3e8e051c945239bce60008ae7eb4cd6cd4798c1211aad38cccaa0bc7a7e098ad952b6f754e3efa56217729f915ccf7084ac22805d1b272629aa3751fe7624a801929c676a71190a9b0647182a88a40ebfad781dabc035a89d86117e9543ed478cce67426b7013bd9ed5f8949ce1bd27e0f35446a4c4e1a041aa9b3eb454a091964ca52d9b42180247e7b6a072cef508881f37a57ad482e68f3e1ffc0660adad216eff2d97ce26f47835661bcdf94f729b4a74e995d6bea74869ba7d13776a90568294f5446c0ae0785e174355bd0e926359e15c1a35a3f96845315170332e31c97c26a092d49e975ca02f0be2baabfb67979f7304722003ebd9761f804ffc4c64ed900051160174d91c280f6764aa573e19cb1872786ed871b1db3b72e319b6d789635b2abb017451aeed391f5f0bd87af0610fd5d957611f8c375e2890bfd60b9b37a911d9166fab96a5d3d017315fee08a809360d1d026d40057be88a165d8bc5f40ddd912400443f1f37653176bbcafc24aa47873cc0ad55312160f677c051cc5da4e549df151569db359e813289cc8cde7365a81a69639d8eb4f40b3c3cd4cbc31d0ccc9f8297e92513e5cdf79bad09fd1ece6c1e5d72b167e216c0073f8d060e19faefb8d3cdbaa1a3ef7c30f9647646620b7a592d8e771eefbca2e9baea48702d83d1be0b31afb82d91d89208640880acbb6545b16bd9940e011611c65de1263e4dfd2508359935aeda1b384803253b5430e85eb49d1e63017e5ad9f8689c206427d72c75bdf46026ec507b17a1089ec45e9814218c6c0ab6a130a3cdb7da94e43cd27b3245c73cae5e8adb5f38526dda695770711e44a9f270cb12392bf30519867ffbd95b84b324388f4e73921e15c782080e2dfc2f66e58571ce146eb1b27cd8020f30b47c0173b5cec10eb8f60e76f5e3120b77855c3cc9c00edaaf2b3fc7c10e79a437b8d16a09df434118a26715fd66e3ae5000263f0788dfdf2e30ef190c5392dd4b65f757cd55b848d2ab091d0586afeecaae5266d94873353f70bbaec7b94dedb99794c202282f5e179702a31b2032de44090878b9f27687c8de65458e28f2c506ad73d4a80ae56f38a157b6e4e641a60e9b4614ba5b9fec4f4d722a8b6f405221322e28f1fc81f746067963cdcee6316d614819dc92d103d8704954f4dd41843657caa2e650ef524359cba7ac4153cb8b408056f67c5188caa20165bc9d763bcd100cda0c695bada00376b2bd63a62b6cbebfc35c5bd01fe6b73b6618137c53eaa3ae9c7cdf610408da17628c744b92e0e89563b0e1a0d3a903f55ec03b93e0e3a8f6b44e3169e3cecc77ecfa60bf0ceba610c27e4994b02db437b7b30f20484304109e4a208b4825e003acb9f5232039df566a353fbc4c9b20507a3fb956eca5640912a1443a61197bb4935490f7b42e10754b4846d81fb4723da2438577671c44a53128c59dd015daca4dc48601c700f7bd5407a0fbb8a80240b73003a8a478e2e426af5d90d5bb15a2708631a3588e37c2bba452920d76181dc054d969c46854b9ac4526ade2a6d841ac012a75e68f1d369d6581d9c26a10c9933a2b8972c1dc2c5ef1812f5d772abbe053d179a753f57f04bbb3c959d90a8c451b760afbeb7af669233291fd4fda0d45ee99985ee0c7aac9e4ba3d5ad1d8707385aad019d1b826942464287a930fd5b45fbd0ca644356e87d4223d0636d2ada83b7228d2b424a0a0bba31a246ba452118039d58ab8117591a0e40105da2dda462646b234fb526c3de6c882cf24469b8b505ddda3dbc0e8f589c05703b0b420421702d239cc7052660dae3461ef9d61284faa3e021a69d77e427f609fb8a1dfb1313b0226ddc1664dce104dad78d6c21965ba5ef6260d99bfdba750179e9c6e6fe48dbe9134a2d318b51ce05316d652151254e88b19e97fe2040e98558602f055562b246dda17a8fc6bfd241c0daa007a4e232c24654fbbea54d8a9c693ba86eb989f12eed1566a7aa8b795019728566b5159659c8dd2049f2f38dd819152319554c508b15d85d69ac0ae9e5d551e84919aed41e195d4a78d4c61aacde19f8acb6956ae09e32c3ee206178795082549784158040ec2da298aa8ee88d37e8fd71f825e8be2b0830802867d5bb42fe8613a5c0169249078e967b17065b51803ff08683d59256135522152a422709ab722d65f6cbe553814f86bb80756bc3c3946c9f7abce3ea7d70c804ef531b17ade2f4f21f3d2adae2f1716ff43e940c080e7a4434e93062fbb6eedc752065f417757f79b0d0943da1f4cbc53dd07ac61338a6340e50f9ec2c4ba6db4d285e37e87765ee3ac1dda13d512a46ac473d6907f244ef2400745a200ec1c863e5416c549d4be7dcfdae03315bd6231a8c7e138534607fb45d245f4cbcf2582e74d3c6de6150c7f72203b9be5783e574df67826f3eee9439b3992d1ea1e19e40865a7178a54ee4612db2b765066d3435f2d498bed4172480bd20e1df6d32e1a689909f464a8213d916c53eb6cb73fe7675fc131813d213491206e286f06be8d8bb225028bcbd1224c3422c54f1cf62a0d6df43be502f16cd8174bd61b5dd802c65ec3bbb4c0af8f13d5bc3dbddf89613075094eb337f6a02a347cd369277aef60672510447024675939c78c68b5ec78415beaf2a9246ed29eb642c92d8129a0401363e8523e6195762b3e88dcb2a1b97954658bfb8c186fd98c63b452fe81f5d2119eb40fbd9a4018a3dacb6e6790e3930d9369a5c08023394b48278900221371955ccb3ca06802bb0232fe7241e27e42ef6c5add4ff062f043efb41fd0c51def906c0e4b230d19620677522564157626538a6be4148267142ef97663ce0dac12e10bbed816504f06b8ed0684d967177377ea0cb4909331150d42b92efce5abfefbc7c9420403c58aca25da72706ff24cdd940bb4c78ed21f56d7e512ad461feec04831fda26af999e367c9a692306dfa2c3e87e088c1990ca7baa75b615fbc1251202fe9f108674da82b51328db082e6ba298367a4af744b74b2de8df079e7f50474ea8be5638a639d601a3add439179448135f79e6bb6ca9c4e6879c90cb67bfda58b30f97ab2f6d22d5d731ad03bc28534a9d56820637dd50e60150e1ff10126399930686bedc55d77838fe6ff601f052256fe4f463e832fe0ab07af6ec8dfeda5cb9a982858650977ede035186cd37a8fcd6c3017002c0a2761b37c88b324bc2789409655a0e9563cc77ee91c3a515c8379e8a1bb4da68e4b28edd4a844d6d8886b2aee2356bb1744e8dfcab256d55d10f10551049ebf13ec0ba09c69e6a4a06c174b130963e6b360b9892a4816423a6b5a050ea494dd8dda773af7f0ed510e5e67c82d78d657118a9c23c1433ea0c333e5b743771444c63edc84c02a84a7e449be2eee2534add49cf3f100f50ae2d02c7ae237a326fefb043e4dab5464c81f6f2d933a0280b1edd4b3e38a4ec2a712d18d45f91e43fcc15255eebd714a4e117e8dff15a5136a0437d8135c78f7cb87f06ce18e87784715ee8489d41eec49033c99e214fbd8f1d7f0000efffd508b4479be63649592ca64eea62b382738c45fbae1945f24feacd1213a3fe8ac8b03a1b383cbf93811dd13bbe195644c30c000bd2215d98195a50441cc94f8f44d897d6611da083a7482f69dc1f158ef791a04282f8c24a8aa859bb3fdeab332e565e282a8b11a5c8abb93bcde8f58cf68117d7800ecbf84c16c8e458f06fdf6730a551d49f03d1032a53d12778895b8285b10139e35b68d96c11fb6e6b3f06d13cdb85c98543c9e2885d64862a71e19de692bb7b960c1a2fcc98072bd4ea3dedb22f5fc3a1bbde2f7fb753aaa287b3a0fe909a3d18b1da2180c84b662de646230fd8188356c6fab1ba2fb429c1d454c814228abb35cb0fa9662a5146443f1ff01508b1970876a083be050f0823baa6aadf38ec707ad40b98f2e711a29bf88ca2c32a331a4ac5975762e45e953b863e826312853eaa631a29982206f46b0e9a44d0c5b1952928d464c33a385d527ffde0dff2d3ac3d8a94c5b8ffe37acaac134b5d19c5d5223a91ffb30729ca6364d14bbe68b428de845951b317a33dcad4c586088f84660155502829fd9aed878df1ff9e2d57eb9a79221b9afa5afece26bfbedd5901e57c90a618d8e2544d0ca28ee5cbd22af637185acbe63d71c399e312815bdffad0c79a8e920bcb5895043c7d508d96ea3225ed199ddd57004d92bfd01bf4c3e368ea60c61868b9f22fcb5a37476fd724c8a70d6cd3907f3c2b60c9585f7f2cdbac0d1b49fe30578b1fa7f090945aec926be4cffa170db61a5780795ba41164b1934b71ea9e11339ed29652d42a6e74681a8641b6d4c9e0863543c6005e93c94f8d9bd291284aa0e6e183671ca15191893b22494db0a32193d2135fa6977dcc935fc6cc72dabff358c5476dbaae49439ef3873c116249292bd5140481b139d684a00844be00158a5e1f16c0ce3cd75a78d319c4496f2ba62e4d6388974c744da645ff2f5ab452b3ccf478609016876fee5208adcfb40afbbf015d42ec88f56644c5b5caf687789493edff44f68e85acc048597aaf6f48d6963afbb425f7d4f4a7852b5a8ab76caddf6a36b21e0fa4bc69e6538e7088cc4b87c77a758e60a63f1e9220aa1374bb9a86c1099104312f0301a65b2614994a44e7c7125736c4e6e180dc4f38b580561866e74dc2919604a2405de2141a3bf68817df40d3c8b43daabd131f53807dc8c49fe289069b72186cdc3c9d2842902d06162d7a64b21c3ee7daf0c608c2592c58c60229d1c0868cb2791cfe019df4d509d26f199794528aa712b1d135f229f994cdbb373f807412e2911637682d228236c5e6aa8f92114315b2ca2af9a4d3d5ed47a293dbf2fcea8b00d812e13dd7ab04de8ac78d0da7010d962ed0b5c64803ef5c7b2c262b4935264fea53d2fb2e19b549c8c69d45635c909bbdc9293f6eadc0de64c13d0b5939a6d30ece9484308347219106c5c646d0acfca7207668b038bd50180b61b8056c84f0a1e9f02cb3c95aa6e208bad3202ff39cdb933c64304f252f3070862921ea6171369faf4e1a57dd6b431722cc2ca517460269450d329dcaf0e0632005302351ac362018aa42e622f9166378a1621686f8db050e9fda066668a90c109941966eeeb5a982d73a8310a9c0d88aa6a09799a2b0bfc4489b90549677847f252e22af290979ced1755ced6fd97b6498957c1120d190368b9f01e6559c1e8ec3663b529c2c3e09ad053612e663a5628a2ea6fc046b418bf231d5d7c57365a9e28968b04330f9b2647f67834c96800dc9e19b92e694dd7968a4d12359d1e96cbd7fc934610eb172029c0f36955962754715a89550884fb77a2911e21c87838d1bf987a6f84754e4914f67bf269e984281e56a32b2e251a9e1af07312233ab9c3843c2f58c4e05db31c8dff88fb5e088704327473a200bda42e1fa43fa672823c488b31dd90e21896515c6654dfd7ac361474398be6e9cacd45c2c7b3b8dded4c60fe083ccce9d9e22418b89fd868913affb144a840ffb5e9ca97281cede2c1661ebbb144a17c7f0bace85fdee8dbfb45657b5dd8f21eea3c3bda57a32b7f1f0c5dc1d7a03909447e1a54796883c3582f9ed17a00a1fea0aad9a7ee391d88f85578a908de1885391048af06f425ea0c3eca24df0b501152a220f69e43c099ecaaa55c249bdefd30c84f0fbb23ea3b14d1db6206caa1483591aabf5919cd0779014204ba25d538e33f526d6e065cb00d3a947e1076142f15390f047b264e23183bbfe9bb917a4d317460aa2a5974d124058a2274eb2132374dbc079b61484081a91de0476d2f0801817119817edbb294af05a7645705365702b0334a46a607e7bc4c69ebb976980131a1cb0889757ac12fad530929d250feffdf23b927d00e022389d44a62df3f593cc1d9f4f17eba850e67a0770e8ff08fb6ed650e6f5e3789d2c31e50781e2b23135529b8a448bd1dc397cd0da31148fd17f04d88b01619fa3a437ad9bf0969bb27821a89704ce3e40c7c38b66ac38cfe13685f9fade91845f3d6b4ece6733cc16fd86e8e1bcabe5b6bf459e60fd4c5a757c07a53e2ec6efc5e6237f9d6c549f91414ebe6cb12d88cdc6a178115505a34b2a94524588c928f37db40f6bf7b37f4076ec3d1d09b2883f111ff71a1439d793c77cfb9f0c33ed45c1ceaddb20ae9a0432bcabd85ccd45ff0d6c04dc813a24e8681c893dfaf3e010d000f9df9025aadec73c008e3845f4fb0a1cb5dfb1ca9d1ff04721b6a46dc6aeef312b3055cbf9e1c6d289daf2ca40fdbf0ca1ad39c5a0dc480e27316f5edb6a8341aaa93e531357e8157e5b64b3c297d68632d83a064a4eb2049a3356dbdd662a115b2e1dba80f1221b3bf91e30c4c9617084d725b39c8da73be9d060bd488182cdec350f4c62de6fee4321624ab54de56ea9564923f51792ce7d955858792007717ab9e5a884ccf0deb87ff9de7f4b9a31480b44442b88304eb8853824fec1c85f3dc23ec7e30a4730b746d48a46788935211f60d7b0153db1c25f137b0cf33cd3d6c19bfb3ab0895ee3d8779797c46b3f1f595fb0f7c1dd3242a4afdbb1d8b06ce3443adaa36a8a8d15ccd8b338cf5d48c6c4d82a16d3efc30013efc7a3d7523a21251043205ad226d383b0a8b5b68a7e44cd337faab371a0dfc8cf6d538d4f5c082b36bc4e79e20ab01042f395808b76f19de364850f6a58a8937cf0f60fb01236ef16004d9c4f7724295e9912f591e21f0258176c830dd8a5054226dd17a950613a5850ae2dbf3c1a847ca85259268b184865732dbb0ff2ee9060b81a52fb81e4976c92f14cc42045ca049cbb9314db1bed0796396fe2c93ddb03a5689bee9d78a2526bf70fe98d50759962d13d93307521855e2052ee2428637aea59652be6a08bf701ae89bd03aebc697f936021e9900ff69c5fbdd1741c96c77e03aee3ee3304715d8942b1d697f97fcbac49ee8ffb620fe99aad2e6b7c1c85a5441a8d237dc069cc32917f8e84d91b092953a00309a36b6eabfa5e8f3d1fa9f32170700582463b551be6498094c1aa3c1350a1c24c889c8cd4ab5f043e0962f9038da8ea145f4d880c35e078588338b6bd29103ac3150e52c1dc8cede213c6609d04e51b37a468318860c7a43c9770b52b56d559581e1eacbb5c0152b131b9b181da220204076b1ae32ca3e28372fd8c9f4372698c84289b2be12408a17e8aa20c8a72288cc8961a3564e1cbff801a204f02555e1538d568b5a6a9810fe02acb427a7c5859a2bfcc0e08bba5d2a033ea234a92f119a228eb6f8bfc0b993b07eb2f68a475040e01bee8d7f6c792637ab252ec08be6b4b68662754d66d37cf6d05fa37e8858634550b51da33e330dc9bc67b7278e5185997ee8ea315934a081f8728bc10000fc36d6e3ca970e2f16a3d90fccd686ee421eb93677318e2600f2bd185e99946283dea0a002662f49e50b1682ede3096d6879e3114236a1b6d8482c082ee018ec3a7a28486b0e6ba5b14b12d36f522d38ff9f25611b8862ef9489c8b3038981b927b604bdd03b208d73bd723548bc2519591338eef661c1cba8ca2f4d3160bdeaa21dfaf440a4a742aa4eabbc8cc4c6938b991c5402afc7d9fa7a56c661b63170e42177325896c3fa2fba0865cb7306faca8bdc56b00c5feade2f30ffbe08e72bc11b260fc12b1ffae87a0a2a26fad64f7316ff578dd4dbdd9a99bdc60001828366a5916418f72ecc6b7a7adc8bbb5dad9bc1035f98552d7fa657c29e612d898cf07806815dec55c781460002edb6ac3a3060b310a663dd780600b0019363510114a203ead45a945920cec24a075f1fd00b3ac985d1d841d9c327d207938fe123091a38ef60b70ef480fe2ca167b287411a0e76d48b0ba3437772ead78059dfeb697eb128eb5b317df555b08bf1f4e7be234c0b43e210642364efbde5de5bca2453f008ef089c09417cfbd02aa8e30d9d8c63eca1715380dbd7b3bbb3bd0c4bbb596b619ee7d96de338ee529f39414aa90541109c370a285e7caec9662f537a003cd79644b5f3122848fa043c2f8182d983ec81db33a698acaa2643979f3550d949981aa8e4aa9f0d54d2191da281a6d34fef21d4d0d9f4230debe252a5f649979ebd1b10a69069187f59b419f119eb211a369ba961d37bec59c3e6f44d8cdb491a8847292c5461e75ab83e1fd88681091850f1ccb072d6151191273291b0cff418a29c48ddf07396f3c84c152a227e3a12b1239ca75bf6ac670d54cea379c4434668d03c3aaa324283e63c0ae2fa4f6f5a43f58c06f99021c6982d4c68aa70226d1ca520055d5c0942cb1139a99e9dd23a24c039320290de3ed3db3793f4f61baaeaad14f7e45cb9b334b261dd90cc3ce761776b654a7aceafc8f154a566a09ea35ec29cd5aae7bcecd853e7c41aab5031da51b58aa59e73b11fec90b825557acaf992a57aea5409ecba50fbad882a4b799655bd6e2273a5dd29409d2e5d74baf817b0323dbb35f3ec1d4d7a768e7dabecb4759ab8dddd6dd9ebac683a67cfc902167013974cd66db21e97b91432d8989f2a5a0c8762a8f71c4527e54a696d1aa452ba825ae90aea9561565a5d94c995759bacc7656e858c4e590e4685d7fd487d61155f14ac94d2d5ce14b7faacb369ddb8cef3587564c6315dc63ad3bec5ea6cf302d01b52d17bf0c66eb11b1e425b4c280a9b2d86d35d1d3f75f64386556733b8299b1bb029d80b5653ad8dca583d4e65bfda99bad4a98c466d1a8fab69aea41cfa20d54fdaba546fbfbcdcd170a7d7e85568a7d2dbe974a33a4c5cba8db48e3d40255748c55775efe7ef74707439ea69f5704534eeb81cf5763af123e7e7d88371f417a5e3b1a8f7b215930e8b3be7f8a58ed73e76e4f6e97e385803f5d390b5e496e1d307d53c15b70767d8c5833d297765dd308e762e5860f154f41847bb47e572547301724f39a99e7242406c1ed4498083bad1b60f8d22f4e175b77763f51e1893a54155c641bdc372cb290b52a4a8562345a2a6d32a3aa0619406b92a0f1e3a74dcb8d1336525cf97533699aa081567055c3171673371a7f3bc94524a5f1f3c1dcb2150dd954be99c8ed374a7f7a0ae86d12bc42defd34befbcc2715cadb5729b57eee15008634f7d3a7d51ca4dc562b11578603a68377efe08fda4dc500d54f6ec27ad81d8a7f7d39cc197e1ec190dda7c7a33d1a0eab3fa6a846db4d487a90fd8623999a6a55bc09286f33527a8445dc883200d549f3a0931a8a7524fa766ed1bedf4699a2fc35a43606e0c6febe9eb83fa327aea2114ea40a8ff0805c162b1d80a54b118498bc5be4a01720f08e3a1061947f5b23dce519d7790c03e8c96ae6723921dc643f3f6d8cd6e7b8faed4bba74e2be03ce24ea76bd3813be70c774e27f706f8e472cd8633ef59f15cb341eab96603d4b373cf351b687f9f6b4cbafcf4f00260ffe6a3d21228072a5dae067af1d7327ef310caddfc039b071932fdc57141226d08078a1c71fa6ddb98cc6fdb5635635c4f17193468882bf69b874e839884fd08fdb605a13e9b47fde63f9b0b6dee9bc3b607e18728905bba7325c217019bc2e79e6f7e69500ad63bdf1cfc2cf5713bf2277aa315bba9d4dd9d015128b23f9d7b16198a5252c368947f499374a48c39c194269c44b144b653291ac45d3ced5003963449c07042b6531a85ead6a8893dfbd8cd2e7b8ffe009d5edaeae5f5d2d9cc6f54dd58dee8f9e6c69267a36ad9397a23539f52c7f778e34b1d9386520ad074ad35a0ac86b0158149d0e7ea842153df0eab1ab249519f76d94bc8e7a187e311ee1b372aead3ab1146601ae4734fb4d467e4d0ad11b9f9c6297d4fe7943a68062d168bad304403d1b82e0dc435264f75aae4a87c77b49a9231bee498943c7dc93d7d7350df5cd4971c142df5eddb6490b2ffa8cf9b87a3a54242f7c6235bc9c94a2e566e54418ec0f187fa4cff4617f599541bd3469b7a33df6ea7f8f957569911e9892f219e7ffe8d472a12f559fa722651d1207ab72ad7f58d8a527d6f543488c9ad2a86546e545c12a5959cd28c63e294b8a599449f1ad64a502d3347d33a2b94c651718de385761bd7b5a777cd6d550632618ba72643ec3978ae29f1f2e0734d890d4cb3008df1de5cb4208303196986a891a5909dee1ac2c3922e62e0e1cb17723a1494174f5b66954f174d889145e1456a0b72ce90a50c2d9e62483489424e77715902fae93cdd569fd6d9ef0d0fb188001b487a84a1bc68410b52854e062148db08986eb540a911825481abad213b2e55635441aad065e142762337028cc89710eb9e7bd688ecc6d7089d7bf63582eddc1badabd02d51a5fb5a0b722ba25aeb484388bb8d08285d3f2f15addbf1881d8fb01266645842aa40ab203b3722c1863502e804b915519d3484b8948ea1963150dcb04992be3decad372d40ee2979012e2fc3cf59d5e0d960b058be123df0a007e825d3687036b4e17c90eb07bb8e72dd360bae56e1d7adba70ae8878300e0e6ceeb6400f74906e22088e421d4fca92a2e33a630feac33910d101edc3b90b8ae79c9bc1a579d093357637f0e0217ecead180694e7b7dd06822048043a282507b444d78acc0a5961af2010da88c181017237cf5ad060f12db7a28de7884755aad0b80183575272bc47afec8d387f85c3eac6412fcc1127d912a5e4b8cbe5355c23539f198ee464ce0884fa741c8b8608a461f63aaf6cc61e0de33cb8c1bb5dfed2b03f3a6e42fabcc50a99af37cf5bacace03b0767684123e6ebeac77c29393e57487ce7abe72d5666df39b8b14a113c38026918b7f2d18fe39f07bb01a301b65a2c160dfbd9d0412f07bc216b884cdae4884ce274a115f9bbaeeb4050a881a673365fd7e44b9e82a76e8f65cad478887ae18995f2c44aa95501254203aac8c23efccc3ef685aeb360d7cd1342cff3bc957fe2e7a068d97eee81111275ee75a3732c16ab7a5d188621cb57be0a576eb72f6eb882b1fad1d330aeb2c29015b25621087a6118dad0ce300c4317cfb7fabe958fd0ca6fab706421dd9e950fabf3a08337e14a9c1f861e86ddad42d079f0b3d65af6a6e7cdf9857415b244feb08c32aba732a4ec0803c170fee877bbb259fdd05985a0f316fc6e3e9c30fcf83dcfbdfbe5e4e8f084b6894e0ea0652deefc39c5fdabc5652a05141cdf0150909d450c9a685295c4130f3e90ed6cb7d9260674f63b77f0b398a81245b6084a41728d8913c8c8231c194b55a40aac841654948e742f205568fd40d2911b01ac050c104c243bf185136648ee8202309648900ba938936861a18a6cf1670812ec2cab34faa81ca450225be4718154a1e73c02e41ebb7d2e1eefd968d84c134bafb8397bde39524b79c44beb18b264b71d066b1f1a0456f168c6aa7cde5c58ed832293dd4763e266583c9ca6cb75dc8c27b7b4944a01375a41af41e1b86e04c7db3ed4614f7fc5825bf2930740b6e755152b47e056bf41ab6f0f8ab57da6c7511606178936b0a101cf6b47c7552387466b06cecdb561ad42f0f36cc76d95b614ea3dbae9c8ddddfd82eacd4ee7a4026edc302e6f58b6762ca7334ffff6f9d35d6a387a17e75c12d473dee2409bcedbbb9bd61d2814d53a92c0fe2c4261fa8bbfe7c401e3965787875e1fb47b8e82732b9fce390f0fad4cf8bc9d73ce5d1af010cbcb9ee75827cceffba0b801ebdb59acf7074506d8f8761b361e6cda9a197b509c59fe135f1f2ce0db17b08007d98ef35fddd85f7fdb0232df8030a50ced58b8257709ba43ba4ff0ed30333f1fc8dc61bd1d041b64ff793ffff4528399037ac90a0abde49e7df210e7b6f3b27e38c228acc697b01a4fdf470f19d70173c7e6edf3631c9c83f34ea49c63631f8ee7392f19c0ad9e1bcb1fe61c9f33e728ad77ee8086f57fa31091856b4714fc39ff41803f81d7a8f9ed4739be88c20973cde745fd2730e0bf71328ee99cd80fd6d08af547e0fa22d76fceb4fe6e24c16d90200d6be187909c4ffb5dc98d42e6e880cdb91dd04193dc605e7766b63c9179def2d4e54ba12d4f4a5fc3d353efefc9d178e3aa73c3b69f15db152ed76a80e24b1d3c5a4807f5929d739045b1d95b3cab07cca7a3c8c265e75caed1355ee7780805a63d09502081fdcd8bb8efe7a8cfe74406fc369ec06bd67c1d4158823273f0f7686f8721893aaacce496d6bb851a0d49b086f10b7a0ca5944ea73da659b0f926b56d4e29a5fd85524abbc7504a698bf969a91e4a296d312d4a29ed31422e293ae7a494523a9b8ae17183f4b4030f30b32494c8b2cd6655956971a14a6a6a4a0a4dad810618269a4dc6258ba39f5e448b284b814f1891c452b5c110691da0862e59106931c1cda652940fdc4c8ae36e2c16f352b4cdcd63b19897a2cec662b1a20ecc44ea6a54783191c22f53befc4024e469a0a2cab43a3589f0d407df972960befcb83af832058c8b084ca70b1643c03e1a535143c1476b019db5952198d0d90f8d295f7ef829eaa20e43574494d6392b0c733a097c6edbf43e014f3314004bf09b79f43193d01a466b994d35f2d33ead540d33fa49e9c8d30b48559b61ea07f05c73f205a8695b70aa073da1b3b445109c39aa53af28b4d36a1b16d229bcd5eaadeb7123dd38f690fd368c568e993ff03afe172005c11e4d60eff2f38ec5b29e8d377e2211d1047e960df368423b7be753e438aef5f36dfc441338e7f7c2d0ae44b65ea7b3fc7b502245df26f07fe32b84af23110a72e0e6d337e7baaf8e26b0f3b66dee7d2347bd0ffaa7ddc4522c3d08b05f6e55fdaec63b32378cab62f9b54fb1fd134b2245cf44c26f13d8b9f2ce741eab09ecfce0bfeaf841bbbe646f6757fad0801f8d899b61c169ba74b6999a0d69c4163898d93c432d65a1b5721c0d55744add045fbdd6f905b86d63abb6d3af7d2d57b7572d4f68dfed8d3f0d136a981d75346c7ae7610ccabb228b6e16849eecc7821092932a5bdc90c64c17275e3a043f1c71e4c41549c83085ebb9e6e4889ff15c73b21405b496991b6d68ad738fdda132cf4bc76dab3c5ef661afb56edbb6b9a0769e1fe1d95fdbdedab39d1228a880dcb37d9f77b57eeec15c97b7104cc09fcbd57305812f040cf43c6742577b1582099ef3aeb9160d775615800c63d8d679c90314c29e6f3cfb0d214f7b604358a2f790f094c74b78ea3c1c78da727de0a9b7883c0da90d8b9e7246ab5963f0bc157c37edd130201e58303a485d4ccf43a29ad1828e1d4fa0194384145d8cb04296ae77e1087461c90a4659ae54f9612a298a1cc2f86c8f07401cd0f32d04fbfe6902c6e561684db27c8de75a9325af0770a7aa75435b693f51426ff4f28ecdcb5abbba18ce1cb384d6b66d61156bd1f6b45ede38e78bb6a74230acc7e7c653b75a6b756d636bab1c477d736e9bd41b5647cb2da9d54614b74b5adee9a59de36d585b1710b889d7f257cb9cdbdb47159c23ec7f7e0ab5e89c1da5455c6f95735a044f1ec39b65165525d88c77468a106c460a046d5a7776df1f6125aa1c73dc6c3a7ba9a9cc96e8104cb3234fc7568ae242764b7bf62f9ceca1d2b3a3a9aa4a83264d159aaa46a282eaf2d4250aea090a0aa928da9c497369f2192a3455542580938710d14f77a59b525a6bddb68dabdbc6715cd775d65acfebacf53ceffb3e1004c30f04c3305cad562c16cbc666c562d9d8d8dc7b6f6e6e70eecd0d0e0ece8c19335aad160d5b5aa290c856a26e11e9541d1dda5387cba9f12db21b2009fad1beb72daa0822b020f1829a30a45195355e40b1c044124a8ec8f2e7b7cd81d0a0cdb9c67e73a10662f29b7bd040347e8ba10cd3115496c898e10ba32866a0a4d1420a1830c103b9d55abf59c3fa1b625bfaf6ae05b7f46f4f8a71e070cbeb49f190f88de4a9370ff5d3ff5c2062c6f1cc38ba2b9783222edb9f5a7ccf17b0d495f22121093f44ea963ff6e7c7fed81fefebc05a6bd9d9b2540586b017ac055311db6000d93798cccc4c99a03acfd61b4b0c88de4df6b1cd4e9a827a9e75ac6ae967678c3b9da3ba609269d006a35efe5467d1753b11e69c28f4e38d1187509f20d46792de983b7df6aceaa91ff0307951a6c79b5eac9d4bea1836ac15ded695262e7cd8b526488eea770facbb256a7bdc56e914e201c4248de73dd7988011031b52ddb2d54044845cb488fe0738519860f2d3ab4844e8c17cd6760f9ecb13bd615e377a56406b6d0e1c0f7387dfb12422049be3b7e3d678ae3121d369b999138b98ef99ce8dd2cd689c4e0d6b1b64a7b74f280d54d430a50e32d23eed3b4ee01cededd3061e1201e368b71f7645732c227581d0206f9f766bef8502451e9a3ecea09ee4041a276cbaefece0fcf412e74b9fdf4f2fbf2f9d839f5e72f0a5bff760af7ed077c6d13369d6c03cb4cd56692acdd9649a4a5b969f1e3f34d0bf929b3dc7b4d166505f6e491bd226db903624a4b925fd44da6661a484ce2fa463643806a13ed33b4072992c81faccc96548263f2f796a84d0bff115e473d099e45590707c3555c3a6d44f276ed952964984d2404a34c832f592ebbacbcedc4e4d251ac4e4d28c89f63da33ed3b5cc6c285244f5848740d0b4f165e40857d5c043d4414084cb7ca58ac5be8eaf193be232df2297f95813a424482d933529a7ec35931a06a561d3a79dfd744bb35076c604d2bc762cecdcd8d33eeddbc8ed039633be79689637cf227bb70bb53b6c8e2ee5aeae5cdbb05603720ff768e7573b1bad30050b14588144062b2041e22cad71618a0b25514690ecd705c436793210fb9c45da8d94d0403cbe6a08e5b6dba5bb25f15002be690638e806fbb4d3a4f2c65ce1fb698cdb801c1ce4ecc3eee59905df6510034868587b0d9a5fc43e50b4a1f99e341f98f0d4168392f42557f970f4e53c9a48e594550a543299573bf9ee2637bea78ab41b692fe1034d4203b11f6047adc9cd79e8073f0a2ec651fd868b02427dc8b265b46938c1d4529f29be84ccea9cf812c2d5b2883e75119a742adade1310b4997af6263345a6cf9869a986b177dd78709df5babbbb44758122aacb2423c5e18a65d34d65466588191527a6341d4bd347693a095255541728a2ba9091829a4a506694096552994b7d060d159f4953d53c9e6a17289b7b736f7066f8f0de1bc6de59cffb3e100c3f300c572b16cb66c5b2b1b9f7e606e7dee0e0cc98d16ad198d1343aa76bb872dad53abdb313f68ba7f2f0d09e3caf904516cbcb3678830d4276b18a22ed29ee842d96618b3c618b1aac7ecc6fd1c6ea878db0c50d5cb4a74f6a831b461d64d774d769edd8bc2ccfe559f9f05e83296cdc0d36709f6eb9dcd2ba36e099d3e55c6ec9e5b283ee95babb4f9fb6c31bb2f768cb73ac4c8c837d4719e739997d12597b03820f68e6fb97d7fefc940c3e3fe980829f6379b9e725a4c0f8f2e7d981f46007c2fe23a485d9a5c36d671d2e7d5e116d1d38c4fa4001473c79cebb0316ee7d5ee24bec5f60af7edcf75cbc1f276ee22a0c7329141043a158bc0775203abac51f51a861b434f2ea2203461d088f3d80d019cfb52525de05757f7c78ea3a7e9ca903a1fe23c489e1218a07a81e98bef4d9c3ece7df207a05e117428254aca2e83a49419e3a8be58fd22dfd87d020f6c9791ccc1be645d5791504f4e9451a367dabe1d2757d33b8ec3b600e9743174ffd6c0f55703767be3ea9b3ff70a57fc94ee4e737e7b1a371f6c8912a424207c723a087e3915005aad24829480fdaf126726512149924f2f3f36bbb04d8a2d96ef68e9d63df2a6dd1babbbb45bbd367d91da1810d271ea797d38e938e93cba986538e938d0d9c729c6838b59c6638e138dd386de04e374ed7c9c689e5b47272d169e5143a814e9f93383a7d4e9e93751a01e0649d3a2700f438754e3d01700a0007d4298d235a37aeb3de07862b96cdbdc199d1a29153c3a5b3f3e2d1c046134fd3ab69a749a7c9d554a329a7c9c6064d394d349a5a4d339a709a6e9a36f0a69ba6db64d3c46a5a35b9d8b46a0a9bc0a6af491c9bbe26afc9368d0068b24d5d13007a9abaa69e00340580038f860bdf6c5a37aeb3de07862b96cdbdc199d1a29153c3a5b3f3b2b1c19452acce6c68c0f3dad1897dbbcb450da84c698b9a72d5c8a1d1daa2be7d8638f228cdc0b9b93623005e328eaa6936ac5508809e1d5947a30ac1ae27003ad3d977a68f53e993058003d74fbd375bf9c8796fc638da5b46dce9a5c7418defe0e832e330e20a20e7d9415858673c64c3f358cc38c255085f8cc69528503c2ff15c8b92c486f53c64e365f85ddacb9fa7f988d74bf0f97b16e2d140349cbd4703bd5c359c7d88071d04a33e3c34c3d93d1ec271e66ce586959c4fefaab35375764cb05e8bfcac5567e43167865b725490128a8839428690c0810f3490cbdb8934500d77bd5ade725ef9b0ee79cbf37cf3dbf25abe596fbef597688275eabdfac08a9b839eb76639ff045e53549fbeba4328d7759c7942461392138ca1831112621c552dcd20862cba90ed4186581a6487739dced9d220170d428360f435ee8cdce88d1b882e714269989238a3d010674b9c47a210c6d18e234e8071b4df80f9f61be6db6d44661c2c31dfbe1af3ed6114647eca6034c802ecd39c864b185cf015dfde5f6e69e4375aa69ba0e7f90f7ecf8d36b10c7feb80855b8b72f46087dda4de15d1e7c659c5ccc15275ee4c969ad78bc79708d5371fa153a822847a6f9e8233599d49beb4677710b5fa7daee910e599812aac89275442d4ae9421250164b4c0420a7a8832c60559ce30194208272c2081b951907941131e920843071734f1c41349b848a9610c2334d470c593253f342929e0881a827c8099b50ffb00c3d4307e9fd3612d7bb7e8f0c41214539cbcb085acb76148eee4a2fcf42b91d389da5eb965c8ddf3470dc83d411e039e7a79f35c3807fb50970eb763314fbd5c3dfb94089b0f9bc46d1dae2d6d6c78e8e7725001d887ba8e0e0ecef7658ea7aca7391807e592c33a39798a62cd122eb0f20027846821ca89345864d093322d2de578ae4919e3719e6b2a2863d21a0804ae37613ed36c4929e9e7943552c3a611d717a114898e93991cc0189106881590db886473b24295cc8b16b8f00559c712c492a7be4737932f6129f89269327cc952b22f996ac9971349c9c7f0e56432c241aa872b5cd4c678c9822c9d0a1596a82a5ebac8aac8526887091da65e903d216506241da7142e9aa2f030554613d963c96612b003172b9021031aa460218d8eb43439a24c0c5564b090e54c02e24c11656267b620b1429673f63389110f5b7688010cc0c0018d12520c630b1800110412515c207d3c9111ab2931431213c9cdd0454d0c35637c7042b2c64802c60c3d6ce14316d2c8698ac674250c2cbec4d041196334e9b0c5122ac0819c3390806189082b98c4408a9c3e976890d10b6366556081a489531a72d2b8305aeeb2cfce2068185e3c410f4948c46c917d21a70d65ca8c4942892921b2e002fbe93cdd4e774d25b6d35d5c74e8a891f19ef2a3a25d56ba4bff9df9e9df9906ea59c3e610b4cbceab0945aa8a31bcb0400662cc5ee028283f5489d142104014e183fe9ce4c6d4c1d1dd64349be302292f489ee0e287353b57b03c3902ca0b4730b950685bd426b5d136a88faa2a81dc536eb36f7779b9d4594c3c34f4eddb96ebdfb37d93f1d0dcc00f5496402246460e515640e54c15573ca1427202755d56c40b6aca08824a88a617a6b024f1650b244a3421d1848620d2df3ebc22db9496da37d9963421505b0269498dcb0e3203f4d0430f538c5822c6096ab8de0310024a2c0a115cc8e00b18c040891b76a0a1d6248aed06842947950331c87285942e8eb60422531fefab0e564b7d2a110e94612a2c60c7f39ade737c89103af51156744ca18a90f6d5e7de370671ead3b9a42e1d53a8b2790ad443ef3185f695afc617e79e33b98d42da57e38b1b837cfee27ce5fd122174eae1dcd13d530f5d48574b7d3a1be672d648c33ad1457d3af73a0f97ee91b1a8619d7f33b83346053801237273ee29b728bba4e3d36b140fedf829fafcf4497e6e83389f1e049c0c75b439f3346cbaced06eb0873669380d457b9a1b6d5ba241d596f72be35872bfd76b84cfa98b522b5cc883a89f4b5d7488e1cb9e1ccc7899fa92c7cf9269b4b7a5069a3e7da3d240ad43775371517ad439e7b99500939bf7e88d8a088a9c5827694526ebdc66db926b5bfae9bc7946b4c31840ee2939d98f00fa37a630a65045c8f44ea1992df8a3e346247521d03f67ffc623557814f2b9ce78a4867f9f1f713908ba1159c488e8f2f086192b62844cd4b314cfb528c048a1460a5584d4f0e929b85e22b8bc7d488d309749707c75fe12327778bc4783acb3a374d98bd0a0975337425b4e7d2ed1a01ca75ece5851c3a891220d7be2aa489d0367c82356890093473baee32f91c91dff441d9f2ba297084624e8113022c1f1881179a48a101d077dc7851cd9a1c9991548703c726487266762a48ebfc4498247335edd8e8ef7689eb9b20e76d85175453aa887368f1a88675539a3d0d9144ef6a464cb97134949d24c9a4a5d650e898b35103f29913d75ee88aa808bcd498265324d020522c3ab5bbaec83f5451807753086cb5e3295f51f5c5d45dcfa2854145edd18644727c8d1110d9fe1472dc7717047e4711df1e52ed1edd2652ec243dd53df967868c753374283a65bd94da214741e17023acf78a44ae747da41ef46219fbfc6237347045d47fc1ce444fe1c91491a22932d91c919229338af203dbdde889ee788d7698836de1259a15731024c1e1dd9f8ca8f58af20a0478049d047a064b660b286fc9c57db18e4e808c9f5a3231b3f5a39e8472c3f0abd1aa13e345cb16cee125d894cf668a19f8651dfb15f2ed732e27a460b40eea9529d29dde8e64c72be89f68a94524a23c0e451fbf41ac0f971bcf158d65a2bdd2847ab4781986bad955e4eb41c57d65a79db782c3ff07cb3c59d4e89b888d899d68edaa6d43650093275f6c99672fd3c0bde2b46d3aee321f43db86d1b277a3f450c88dc175aa933a515c817243623be7c795b9dabf75bd87515cd9755183a55ef033d6ff2101202bf073fef6b0834040c88be6279de9c348461b15644b47605ef5c3d80f3cec3550826a8e3a534c01a16c6e67ade9c2808736f3c6fce4d863037389e37270d61706678de9c348499d175cc5aad4228c17fed5a734ecf9b9386303442d68a0504c83d254ff0d9c12ff989879010fd9e524a69ad9ef7936b2dc137ceeaf8f9099d9be774ea80864d0f6e3cc13acb6d2edc1e77eb6db5eaf2b85cde575bf70b6dbf655ac7fa6018320f79c03f3888e34621ecc4b7b32512d2cee0e7852153855e744c4b90886bdb5d8526460ced092beeeab9467ba24feef75ca319f153a35981816db54a66545c9be71a4da981b8f7b94693d190baeee3d8dea92f5d31eb2aedd7441218a29c647824a9599217a054b0040625254cde0525fbe3c50d6daf0d6f12a9245349cc5c57982731d06280bab51f96c4da87ff5f406a1ffed25e297b5ddb732d0b93b5c142975cd773ed8630d3bbc9f52268977bd3031d7383932ac30d2f6071433594ea8260cc2e6e0d3253cdb5cf352850541a2eebb90665891840a135204bb3bdade79ad2125f9f6b4964f1a5cb07b09c3ffdc10e27f5e982e1cc17b5c7745607b9ea53ac953e58697757313620f310bbc838d83dcb4dcee5ba979bfa74b9eead75a4b4e956e79cb39b99997396dcd969b9dc7d3dd0596fc6d2a86706356983ea96364f7d48439dbb01618a53c3489f3bbc67777d60638b3be3994b1a2e4cb0be6147b1cf341de49add51b1580c095936d4b7b753cbbe3bf42e1bcab7779214df6527f911bae19b87d2971c55836692324566f0ddddadb4d4c47739a9e4f0136a76692f2714dfce53627c370e5fce2adb59dc10440e4da8ac210309982b3a8a2fa8b058c1821223c874abf9420caa2a29a7318220998a2bb82079411661602003b29c4c4f684e54506112660af2883440e040451926a688822c2715104d645e284181171c66a40e2ecc344171c28a305bbe167cd9fa8fe779beecf96f06fff9f7f995f29fbb9008e3bf249480ede8e043f7564461f3f47c79d06b03890fba5d1181b0ef69d8e471b18ec0d060503f514252ede303cc54fb38c1f09e7bdead88bca01c61b4c448300c2a1a696f77c4d277be79ec6b074680f11bf753197e698db8a2e3a9cf2eb7743dfd741a4e447d47ad7600419e4debc6750be68c12b29379e42f57205951f3c21251c630da610aa4265c68a2a6852886c2c511373b5078a88d40f2d479ac06ba903561841451bc28c15b8c61c31449b4600a599ab6812a0a16bfc6262b9efa8eed42e69a3a3895363d41c65377dd2bbe084363d6f0c224e5a9e7d020d50316301011234389d10d6b909072f002c30a54e4132fd4e0f0108df9a508173cf5169d92544412468ca9a10819499f7690e254a5c915332491b483a6522c167b81a494d6f094524a29a5142700fd4402b8e4f1cd4f7fe5866f26ae6031040c434c41c4ecdb7f88d0a28625cbd78a4801518361e59b40b776f1d46d5644d4b2e09661d9e2f9e6f2c633400becdbed0c06dfee0a2288efa820aef81662f62dc475999d8047734f5660c0f3eda11461701308ac5aac2c3dbdb06ab9f6a443142b202e6f8ae9ad889aa84e314fbd52efbe007185836fe75644dd45ed6e1c65c553af4c45bcc005287ce0628d1259de0428295972a44353194e644f20d4a793bce001ecb25cd24e257e7ceab4d56ab731b0e1bb0a19528213770888004fab30794ac52d43174f8d8a98a1efa9f187da0f4ccfb51f96be04b3fcf41bcfb52969405a27f44951bbb9abe7b6acd465de68d467ba9db1cf74fea4e82775bffca47e7663df803085caeca99642724b0cacf9ea2c7c3d2a5b0aa7eabe3a073bda549369a9a8eb521b8d06d920d8677a1394123f9d09a99f341ac42454d44bd919e320a27e551d34a1006349c0a4068ad2405c9bd2a4d401ca7ef67cf955814a3f4b7029244b70966449366bc25403ed09940d51503accd4d19685aa81ca0ecdac6aa0d25a792b3c14a581da49f84338f574d1f1e5542253e60c0d5f4e343f67f872a6f97bfdba57f5c5ec4ceaa777681aa8abb2b1aeaaabeaaaba2a1bb34856d65505a109a8442d1755410b15aa190900000a5315003020100e0904028138301e8a9bf914000b80963c6e469f8aa34912e3280a8220638c310a10420c41c698192a1a07002f751e92c83a4bdaeb979eedb5c708fb48d241c945e54ff49a1368c555fe9f742d849a58b1a11da42ee0ab66e675d3e580d841d6e342d7e06f0ac052d05c128f187ee149acf001e939d7c0db5a7cf9c22e8cae595a53820d13c1d4ce347149e9b9ab68093d4f168743d8dd9fcd3f15d603def3096f4ea0336509f3234030b4c376fff5f16710549d6390c509dd7e5d589399562fdcf90f9acfab43dc511132a36a6168667b17fe565a9039888236966a7969c13c8208d21f24475183ef9496a1c112fb516b2439ae8afa7f4d8a6c68ab35c4f1d9f68e29e055b6be3027017cf18a1f36228f4fa9025b71919e82ea4c029ace74046dbd4921836633a2db83685c538024216c48eaa957f6a79768d966090df8d5ba1e60d2feb63f5b6052904069108e5d6bdda57810a1fbeabd8e532805ecabd8fb32e20468845f083f7fd9ec92b0b47b64e3772b6da6767fb8fbcb18f7460bc2bf80335b1c99722a04bf300ab1086a1752dbfb8aaeac7151deec0a33f02f331ee5877d3f3e830427fd88f01b7bb779bf5b0e193d1c32d173c58dca1c034ab7742c9d2723105c3409d88606224c12878706d1abcdfafac729d918dd39568fca1c61a247170d6d7b9157749d0d53d220a7d28895304d0622ba35fe5a6fc37576dc8f9c8294a3b94e95383d7fa980c3c9161af4765dda74d17fb8d6b346f1d4c5325d7c75987b656bd57a341b36c92d9966e23a5850c3aa83e5f7a985e8aca18fefc812fe15428f93ae569933902a44ce9ed909c6263a65beee84243a7298791958088501470b7e590ade2a9f25380a6a1b4281d45620557137b181695f582d42db0ef0ceba76bd72ffcf81018a64df9b1481421d79d561b4d7f4bf79c0cf3df50261cc1d2a0bee00705382351809414e8d44bd1f2567673a601cd7b2898206b642b0e113a996fb10596ec0ce7c4f9054e8059fb4ecba2151915ddceea8df6c25923e1d518642c09aea47f4ed5ec6311cce2e94037c16ed15078025b2ca351481b1965cc6b20b79a8870d65d310c6e6721bdd780a73a5d5ae6beba6f4f8d3123a52c39139d46d9d22d2a38444c1e08c428bde7b011c37c3459afd1d6774c9ff5107200f3a55ef5b6da55020decebab204c702ab964c0c4fa674bbf278e25d65f07b9f31fe8b65546461db0469a9743352447165b2d847deecfb74926530a6e434bb3575e4daf00d7e5d886fefbc4ca678483c4565e38096abd6d565dc1af2afac32646538b06b4bfe02c0cfa8059dae901bf1952ac666a9c05428b7c550ca2ccefd484516ab69771965a1459445033b37cfe1320d49376722e6b340c3c3ed81cc4c38fdfb7da2e873a351ecc144de01703523d4cf420a0d218d4e0141b5bd2b99e1ddf4dc9b4539165fc927204b1ff38af237a8d8b7ea2d743c498fb01c2711bf3adef2c7c48d0f4a82ab86538a273828884dddb63afed1e02bf8f774a752258f99616293844d9de934009d50747990182676fa1e9d85ee4243531ca5ae6dbd5d4298372b4a7483930715f81da5491e1624fb4901098045f290e07594216bbb807cef25f26fdf1ea5e91ed32938af08222401bd3fcec42122052503a372e11e91eadb9f5502d3f50138c6000a847b02cdd358ebb6bb0c0b0f5ab736226635c25f060c8b42c5ba9492fe26b551cb677550410921a29801b482e1c21642068b6b6a76807657224b247db3edf84499ca04f4e045a70fcf22e1f38ce3f34e67776c77f969ba20ca286b59539cc61257705483f413ae9e80ac709a9ac5d844bc979900231088e68ce3f60fa90af847318b40f717c7a44f29c93697cdfc98cf96c9856def347ca83b1b2838888258004218f76066c24106358460ec284d320785ca03d5d80f05c90c38f8541d0f1121d648f27aea44210d55e7d9a8724c54d19e4c43d2edad0a4663ed076eef05ae0aae06acfa354cc8a03ce5cf74f1d8e3223b43ed05e52e1005f11231b9473f5b966747545962d2b1b10929134bb1cea8a6952236101348602d7af94512ab33db9d297e1428cd3c39b866a7d6e693e3daa068e41218cf7af0d4a09006be841e60cee060ef943e4a35a5da3b06c0bb2286a861a8649b281405dde4fed8e09521bf3dc52953ec3cee2cae148ecbcfdf6391f935af0cc53ab78f1dd50692e4dcc1edc51db10ee1364ac822a772f39a1a237625b3a1e426117274e595832351357ac507a3acb1931b6b8c7eaa4b0e427236aecbd555d548ae1168bbb7a3e28e8a6b6442096e0dd543d2a8cfcf557acdbcecf6b26816059543feeb2e6c11832cbd20a1fe77d409f681c1a9317e25a52083e52a1111887da780bdbf0279b532288c109b1e91418e4effa995e2f4414580a2627eefbb883bfb8fd6789d027f5d1d48c4e6bf46bc758e1d1c7c0082dc6ae534e1717708910ad9f7583cf0393174ff4186548955ae0590d7f7541566008a814450120ca1cc6743416b45e6fa5aba009e4babd733c3ed612293d4155d1fa41cd86bf7d4da53caa46067a259f20aaf17d60efcd1e5b246d783696f5741ba4e5c30c398bc90657abe5445e91b2ec2b540b9b557f302c1b9d6b5dd483d6d98f80b39d83346f6a73f7b764e4b555bcd7a629faea5d40e85a8a0040529842a1b578fac2fbfe9b01de7803c1e0d4eaff3c0efff295f88682655abdc0e6408ac274a68d9fede0fd447bcbc68bdb8fca78ca1ced5e4f058e0c2ed71cff05b092189a3b464830a0f30d6692cf54962cfd0cd6310fa4bd5665fb1660e906fd142f12e3282c977b37938388e17c68e7b4fe97629e9f9750efd65cdcb149308065fae520153ecc548a1e3c505134ef47252d3dceec0d890a01ef3bb0b68590c5018c8b81032ea8220d00001d2fe29ee451cd1b1548be5007f0ceb3a5b589fe850d40884d13d01631ce5cc5ef21cc80f8996c283c6d5e676ea936fc4160f42a84202dcb382be863ec1aebe9a8ce68d356f0cfd45027ccd370f4334cd07cab5e26b614109ec257748b2de36620adbc0ab40c57dc516a8532e1527a8fc63c177770b0382ba8464665b8acfcbff22874b873cd241f82fde52c9d19aada7c3b9ec488b1512efe0b572edc0b9a7dc4c692f3459fd5450b8299bcc30054d5d20557d294054121d715f8e655e09716740ec6720f7117c46b8c5e64aebfa06eab62df1a55865c20a09ffda1c23a31bc37d7dd733d1506d6da4325e3c8c2bacd6d26f33ef3604dcf47dc3d219dc305e1fcc8d447529b66cc15fd06b7e195ce69834ec9f942e6ef6fefa66ca245f8006a192d23b6483a73957b7f1427d9b7ce20c79a7dd4d90ec692999d8326ad0b7bea4061341ebacc0e3b82662dddb8077fc34d3b4f3a9d13279e064d26d5ad922b0fc22ae10ba73ba167280769722fe99ed6d6ec34536621fbbf4dd2a3c667b8311f3c66810d128206c952efab12ee5112540dcf36d932c16b8813fbf2c76deb661d26a387ca21ea251981c532ace274402b50b57d181ed1204f3aaa45f778b122081722c88d746235b4603544f0e2fd273ad38291f49e8343c37b66abf5f49ac3f649dc18a5417f7f07256729c7b8c3d1e6869c6f2aa034216c061c7a4d55fae0f93eeea96d0bb379f9855d95f082ee75b8e050b26f673612451e6781a36ee238e81c1396ef6594f18077d16fa18f77165b7a5f73b8cbb9d4f2942ac992b8afa5bcfbca9c55efb0f7e90d5a64fb6af9f1a8c10c61e3182f2c9a56dda598bc4b3961ece06a93ddfd0f54904d0dd7e2c8ff6b5fa2dc806937cda5bb413b825cadac9ae47991acead6798bd872869c98c54a96ad29d788f9c6b7a2d642911bd3ea38e44c286bcb5c40b25ce4facea0749c2b9c3a2e5bae98a20f3263731e2234e96081ff51193a8571715f5dbe3cfc5fcca0a6e35bf9af36582a4ddcdc36691f88a9272a41bb222905435be7aea2e085d9ee1a2d9d3147ac5b5419c8abcee8f760a8f1a8534fe9dd0e24479f08bbf5d270b72a5a3ea8fe6842182cdd46fe3b0100430f100deea5dcaf197923114b6b60ca47fb9b78d148d540587317ce22624dffef3d1d3185c004bab92c54cc574a7be1c3ca2d7461bc2eabc1735e0c394af641776a1d5c5900ff16aa73bc4751818bbcbae21fab19ebe20a1226278ff4abd83d98a91066d34c989177cb47ec613fa93a4ae258a08398ae32d7570b7e5b0b2684ab050f3727ee7f737661e3f96a521d7ecfabb6c639fb2ce85da3aee32136878227f140e767e71cac7e5de07bde32d03f18df727c0fcfdd655bd466c73c7a9ff7c85411885191786bdecfd10dd783af82fdf8db0a6ba5efe842b0d556509e5e90e7bb9632358f16c5924a92351d9d9011d4a7b90a10b2e3e7382f05e237c6c14f7650426b3e79a4c224f4719bcb09727c9da23076886287f93563f1bc799ff05b78c82563bea62d66f6933ec8310246c7a53d191a39a549f33c5763851dd944108616acae6c23f5f5c6132331b86d74042e06afbb49e72a0bdca601ae6a519f469a1045266c2993173c1807d638cb92b11f4fae0600e731825cec06120e0b805270a24ae970526d8d5be1da73d49bd6f68cab6ff9474ab15eb0518893624d3b04c9a4c6fb0200b24dfc1f66e7e08fa95c1967808805c51a627004d9518cd57b0888508d9058a8ae7d2e0ed93566320d26aaf5264d3ac114c2ce802c3211be2ab9f7f1b6003216854a6061987b37bab82a48b68467059de3c0e2d5c4b04dceda998193176d1c6f338e3d481fbb009b97976b50eec2b26fecd7ec6d760427fc5379c5ab14003d8152340c5caa45b92ac71d1d9ed62a24d490ed8dd4e14ddbddb450a1a0546096a1e46321bed216e7cbae70a5d2d61662c486812100909d7f8e41db1aa3684c64b7efd66f34b95fec04cc2688343721bc29963ddf260d93b06c3dc9511acbadc18c734d39b8568f2db327db2b0d04d3bf828217d156634957362b28b61754cfb2675084af8a0a7283d35724b373f378a8439d522e231d322292324def12b777f51969f1a0484ead82025b2c128fead96bac337ed7c4bfd12a2bac9b0bd99fad605977b2d8661d4a88848db87e2305a2b7a1d93c66204ce4b626256866cc938a255f109fa1dcde9a82eac1567f3ac83a1732060e8f19669c1ff1013761050ff9d49c4d4672c5aaf857680785c48a078390dafb07b0895650a0dbe0b40aa56f827861e5b2669e5db0c2158f144f383dd10a1254c3f3a70ef206dcf06f876b845c1cd6b6c3c12a12eed5a4067325a70d76ee02ec8821b76bf54a37dca496f2bc21e0117afd6cf2de6bbbe57c3f29464409c8a9fab622e0cb9bd0d287150f29e028dae40fb0ce96be529cd331d0770ffed5630042d631cd81941e02c8016bab89575032e2a81415a4e58db75b57ef52ab981c38d10412ade7687bc14720e843e462c6db92042342900290d60d2c363986ee644bab407f38b0181a9cd308d8d33476494ec8c04bc6fb38bc8ec300ec05be418eee20964cd4090cf1f406fc7cde7551168a419b97d9a7d5aef3c1297e96b3a8189141168af7a9a2ba01eb11530537f7b10b90271b95c45bfe1caecc58480ec1d20b868dba5815a992134700e0f0d1ed51ea44fc1c51b2efdab16cbae5b64be156765e033988eec5697706b8dde1e87aa7500829df9b0f264573fd8f5500d609986307329a7a8e565aafc8748f5168cb729ebd80c7ba0a12d5fcd35cda6b6d0e35bbfe7f95bc86ee8853f84a6f395562ddb5edcfe57a8438b8ca2b69fc7fc73693f2256d678cf0147f9ebc891555f6b80a86f9c2acf8cfbf586ec395e5b820952fc9404a1e12cf3e166b0160677059bb10d278926fe0fc47e4e9a15b8b3996d17c966c5a785d9a70a51a562fa611c7150ef10102099e2528d89eaeb2ca8710c92059109bc4c409e6f65301045d7d5e80faceb0432ef4d200084459b1a88d3514804aba52875db457128b23cd8716707f3247788c55e0c710e0f1142ececf59650d6418ef9610a4f0c168b4bf39b3b51dfa611bc0cf51a507eb824b0499fc36d1f856bef2372cee5866e0f6819dc776c7d49e6da2889f4e83942db9d346b687e5d0cb4aa9b113f7aac1651ad6f98ea1a6965064c36360a4fcb88a3ab6ab82d2aa0843c626dded97ae744c75f9f33113072206c3517b982a7cb6d04ea12c051fe6d2026c654a5de7f162b361f18a2816d5b61b572e232fad55943ae3909a81bac56f8f7e09ab9322e66a8c29e8340706bb6ce4c188d86a7b03c6271ddf9bb6cd912ff429ffdfd28ddd2b032bb90d3d6382bafe633126763a621384a1468b3bf90174e7e1f02c9184a96a883a0b4f8fb56722f6c743515574937bb29c146ce50ee94e704ca34f4eb411148f17d2c81ca352c6248064786bb5f420d0b1e845ce8b9102fd16fc9c7210a39a0a42dcb10557f901604c5107c75149f43fde852657ad7179646001235d79685150ec052265f14171a4612e15c24e9ef9c5d140ca414a1786cd24c2a8350e64f0565646819b5e48a84818ad425d8890c443df7e4a5afd2740679f9871ec08394509091e9cb952f5f78c16810d5c2d670f8c71539348e2abb38d3e135f22b483084d3060a84c1c4b1aa6c3c2ffed6c660060f172c3d70c76d5574614d6134a174ff450a8930c8142a1447fea7923a08b13b02045c07c30c893c0204e010f88d3b501600aa9ba554c69d8a5a215859e503220d8887000de8e6032403bc1dc55b4cb5dc34073c7a40dca4d089e2e452684278d43bc2c45149b033a6dc79a6fb2210fe68079984d85b1ce5a5eb1bbcc679ee305ce4ca60390dd3e3aa05b2cfc68ccecd9610382b43fa790216e91b6660de5ce442b4ef760831a0f95ecf403df2603de5607069dc2fa81cbaa4bd4b5096b0a83d3f16faa4e1edea5d9ae6fe468ba7755021b53ee61896c844bbb789a758ec5a07bbab24a82067c5359dd90ac2357df31dec24b11367f0c05cf76663f5137c4f279ff71d3122ef7e640f958d3575b51a843dc8650b93969d95bbe1a627a9de8ff421984588f1348a5252a1b057a5e360abeec445535fc855a381d4b84732e208f3aa3e141e20c48193f9b814fe2941d10792a2d00b2c4a539b721df1bce830d098c03301a45b76734b658d4082bd3216fe16375d459a0e7f8e9b50645833658f956513b3b5a38025e3bd84b302a4d1db916b991c075e8bf32befdbf53f34294833159f301abc58498d4ca1a20caee5872a71193c3c37878429bef1063b8772f9ea84a10558474b1cd5227d448889694dfdc19c42e0769e89551e85e0ec277ea2ad4066127a7fb68d7e467298dba828e24c0548a1e26691f8edc5b46082109dafd49c6c6ad1a18d531549eed449c8a42bc31f7df13ad91ce8ef5fe3ca821e0e744a78fc14ef9a9b9042608fa3a4b2fdc4b2bc84f0bc755841b97d1874be20965b23418ef4acf8ac60599717dd25bb1cea870f621ee8f76c701a6b876b4a02548b21e718b779a969b281846563bce0b00cc63c0960db770c50ef2fbd255877f4baa514b4876c52105d27ad42822aa972b007790f048d72b11e0d67b224aac6a14f4521777c348121ac6ba1b5de2b3319f47ddcd65e0b450d63fe79200bacaa597439943fc0f02aa15473504a5d05b537b4199d00d3bac01b58c8948dfe56a499f6c9a99f96b1b160d973d6b1b1b130ce97633539096e0be47c0c5ab2889c5dca63d3a06bb3b9a14927e730b06605a3b765f49b7ac475e35e7c2ec409e52a6b9f5183bd4a0149d05098cbd9b4843324aa0ab770c623968fbcd01e313ea74ee49f29c06db2eafd48f4b9063e3e066a98ef4c9c37e555b465571171103ea3ab8307c911dd45746fbbf805750eaa7719e84916254ddbc20ed3c2ef591dd83f02f09c547f70217211282bbfc707f140d548905c429458e3a34dfd5c24b3f3c772e0fb64221b787fa4dcc812454d263f0708f4a493edbe1ed84083ea079f56413146b0729e190774ca56e9bddba3e762253c365d2ea2055868f1a9727c6ded3d7961a149ab2b20540fa6e658dd639610f46c691593059ae4d8735ecf45ac6d062d6dcd77fe2a8dea7d1ee53f967aa1a83812a9b4707551c49111766695845f9730d5fa314db87e98101a8578716eb0039c48abbbeb3c17cb595db16c114c56decf790f09642291258aeff494015a18fbd778d902c1f088633ad060d5fb870b1610164f0287060d764f23912b9042a4a2800785b604b1c238c05c8896d05592bd005c040441750ec8e0b35bc014e965751d33de00048a6197a4eb1a51d5bc4048ebd05e362a3db4396dd74b9f1f2b68cd32c91af253babf14f8053884451fed0e548cca5bf8f5242b1966df0ade697090239f8aef8c03173c27fdac08213e6bec0b0f7e9fe02c8886cab825768ca49fe1429973e56b666c07b238e5ab43e02a02dd431ed21e0f99e2ff68b7097748c0be289ee4a95a2c878ef4897a1bf3e75065c814ce71997db8e67ce7c3830b41bace56cca1600f41a26c2b04984ba5928bd08c62e63923481246218eb22fa568319a40c28790f623488affdadbd3314a2528fcd4107b2126ac3a714b02b0bdd952a4c1173cd92f6ebe25429040fd6a297d5357d42cdc0722483e41276146fbb8a00f994fac622cec974420de3744921f261de9ff38181a75461863127a5f4e4706de1ac6abc60d119a829e354ebf9ab980aca1dd88e58851651a0155b473d0d9b071a06c20b2e3e552ded146f0834e3aa951c776331b5a9811d0e8f8e7e16d83eef0479144aba9cfa058e38c6e6babb928174eaac3e28bb8551734d9e5ab04666c160cbca1cea14f232450138e94c69c8b2937a444497d326c1f6efc7b7a168a480f481387f293cad277540825056fd874eab1859ef33e4a147d6b106b5e061fe226b4ea9f705181aaa064e1830d0917fa953f4fad25158abdc165552e852686e624fd16886520137a7dfe53518405ae60b1815df12cc59cb82d6ee8f817ba392236a68a4cd1183bc6cb89964be4738e7ba539c389f1541df907b3c42290be8a149f5e01a18ec892b2efcdab83699d9f017d2aa1f92ac10e6177daa2aadca2ee61f136a654f00be921617beb2d476bd2473d57c834dfa9088de77deb99925e378db6569ff84827ba890eadb4641a5c4265e6aad86c652a22d516c66c4ab8722a5eed5333340c63d6eeec2baa92b1b9a296ff44ef8af80b8e93250b44f923912d266981343123bd50712e611cf490a150581e0ad8e225cc6aad068f9fa81cb0ec2efc00d787ee49cbdeae0c3e34ea2a147246a293ee10399c50e8f204133b9afbce1fd9c30127535ea31e8a5f91fea91fa87152e22d60384c24d6146da870fa90938ab46c88a8e53bce5ff99b3cb166c734ab956c2b95c5a11660deda83846bac956cf0543f7c275db01ad7baf799148f95d4f525949b868a5153e360de22364067e1a19e9ea12725f54d508b652210c8ba3980999af77e08ec0262c3833474c2406e36b44b5a12c0e9d3d8d504ca294638b2e77f4cb0b860ee5b87ee5b49874d1b5223711d0634180c5fe41ae1835dbc072f600ab25e684c5b140786429770d2413f7fef12a25e97d07d451afa2412f7fccd668b0e3027765608757d079b172cf896c02f1ed646d8b7497a8d2b822c0d09a23bc1d60119c1446a1690859d931577a866d600b5e8c2714108d4f090c376ea23fb69b5d1cfde2535d6a8b4c8dad9410e29580afc256c3540fdcc94367b62c2c75a818ebe0c208ed99e07fbc246d5b819147acc6201091b1058506f5156c5b74a535f4db47484da00de45ed81422b7cb3c342934973350ebc9eee78bb1e9ed5df5f8eb20b6a3a89ca0f9b41b547eb247aab8ebc7125195ed5a2b75be65edfe0ec719d1c4f557137ae25edac6ef4d0ae37410f4bc9b9558adf7035696751229be5965bd57837d726eb2ccab20f6e71551779db72f2f60d74a35f958893ad6eade4174a659b4c2a545e8a20cd0acd67a174580f72a1a3d22d9bbcf556511d99832060afbba9eead92a94b8d9240723c0523a1aaeae932a97e15116e2d4aee5635e2adabd9f31b0ebd5924cfaf52f4d6b5c95dab47b898ea25ea7d29496f55a3375d27e15009c9b66fe65631f6d6d5a41d3582eca3db4e55636fbb4ebddf00dc7155157f32d64fabbaa5b26c10328148d5af07d5426e541f3b5e84ab196417be436a8a1b179a0662a0bfb3b1b6ada509169aba380d4684be8fc94ee551d459c5e591fdfc010d9bb93bdc3a719d7a90d39832d75d00c2ad8e8eb5cdc488bdaeeba4cea06e6cebdaac1fcb746293e562e0bdba0cf0a629ed89b96eeafaeae6a46ec3ea2b9e5e69ef0645bf8eb94b91e4262ab2d81ffde5896f9dafee60d441a3d70ffaa5ecb417b5e7bea2142d1b74679a335de2e63a49d6a973879edfc8bf267b4c6f85a5d1b37fe411283ae1e61739824d1d3cdbcacfb0ea4c7da98e28195568c2fd8e552cfd75275f5cd5814527db4dd38976384b122bbce9975b9ee96d2b0b1af49e1ca4e1e58a9f912b0ec6e4779c4a11ed7711e441a5e23b6c9b732e0b3efab219d2c33765caa7a4e734b05059ca36a4a2f9904e5c77bf8204aa22f75e014810d109a515694bb07115c0a53c78ba0d459ccf359d0a46a7f5082133ca13bc41f9191094af5553378b05a55d2519d02cf41398171b501ee21466028b5243e7c5f103f0406eae48bab233ccdbcbca5d8d345612091b0243d962f6995fe6e389dd45cdca3984b45baed03ca8f7aefeb51c7ab553847d6cb14189f012a7eade9375b3c4743f9d67b89f764409f1b58140b36aec80dd3255fad705170766c42344d311aae17da3dd23601700990a04af0cbd394f5a440ddd5712bd2914d26797f38b5d5d498d8beb64f92d2d5aa00b01463611fde39a013b27d8e72b84631031c01f9390693cab5145895c6081072929e321243d9bd668f99c1fdc23ee294c3b03b13f548b9b56853f8bce5eee2927febe0d7690e93d348a2f0fb1fc107437fe45dcc23c82969487783c914427deb5275d3043b54ffac0572babe7c26c154fb1f2c9157af25db93df941f977e88ebeb5f69468df9a9680138d3f3bea0b931b9a709226247060e1137b19cccab433027c6b0a4b06b78934c7b5da1dbac9216a4392fe6e88a16ecd2adb4bf85ba553a52efdddf7d17f25c5e39a20ccf5e15b41d205da9952c4c069f85f4f235d2675ad5b20439b29e23aaaa93f60f2f2474581f6c712da4f5951e7aa25721ab6022074ad302a2e2569166684ea2812c9e035d14ccdd48be527daffa34d6b8c655f6ce2aea03882bc5868a9101b43aee9d2ff3516d0dcb5e8da246eb4bf83667f167bc505e105ff3da91e2666c434f661d97542a37506b3bd78eb3d0eb99e5aca0de2a1f7515616329d3f0b5aafb2f235ceca88eb8c69605de24279d814d0e1bf1f65631181d99b5115894d5574d6e1aba71aedb1ac42f63e9573dbcaca48f3f6958166c4b84bce5e0de99e6079f1e6444dc8aa0f60ebe8cd4432009aac9a548f16c86647605e8a584e41ed8cf5f035779b9b2e7d418260672a9931ea8c8680d99c51bad6f53c86eebf204b8692c5b7c2b703a5d690baa41b247f76a25e4f3dbea1cf1c39758def4cb43a3bdccfd9271b2f7202381ca7744328ab80ad34abe03aabaeffb2ded3646402130a9eb564cc60d28084b779ae10173c8d4432714828846c121e1571bb92a372209294804213db70f4517f06838a869c9cf424c410aadbada5fd46c880340ed3e260486540d5522b26ab5e590958ee47c9c748c949c173a917adfa75d6c45291175c08d711d270498bdbe334877a96e61fe18d5519e5ecad4cfe28dc7719c46c14fd44ed9621aefa5b880e4dc3da8c2c824f6e826ff6443c4730e270d86133067d70499e7e0ddb56b01a40a8b8125b023046c22402db527c007abc9f99b49e28b3f8cd530676bb7cd6dd2e8f96a4670ad7f6ace161cb161663a29e94f747fa1f75b3c9c3618c5dffdc8a56d6382c21493708e4e5707efbc37a3bd468353b051af851f45f26aff16368abb5ae0c5227e1657e8ba18df8a04bd7cc84863d58191f307ae39e74d59e36db04e6d70b6481fc1c98fdcc25a32aa9fb698246a4b1db809b2016b0c37c29674fdce70ac241d8127d9917ea45ddebc5b46d1a1f1414ff46151b4a29e2fe7ffa2c96c36f9c4419372353b71b2e85bbfd9bc26e2aaa72b7c255d10d261f3046c78dc0c0a85a8048b36adeb874edd864cd843b92bd6dd0d9a808f785da9c174693843dc435d0041b693f7ccc9aacf24b6f88d6d20cc997647fefb305dfd8acbccf86f89df9b2879b4c0c2aec8bae18ecfb516443d01ccc1e8e5137464b2c7c4d0511afb580d8ce026dd0fb479a372cfb5042a21e29193c30afe4767c37b7c587fb382c3f318fff581067c17f7dd75528541fc3b4241b6eb380c90cc1c605eaeea3bfc2ab4e316a9e14b6ba07b9ee997decea12dbb80f4dfb1b1736b003c568c068801fe48b51476af0d1982e3d4b5f2c7fbcafa79774096104acb0e36ea2e4a530f8bddad31547a40780e30183ecf57bcf7a7e5e43a35423298061d328a585a94dd0d93b320a9e3443a99aed49aa660447d5ec5c849e82e113e3c5db1569216008594285e21e55c9dbf9fb6f5c8c879768806deb1744b7788a96ba1d1f4862845b9c2f75356f2897585784b87074c0dc95714e96383a5095c69be0f641f3026d7a2ffc82fd5c9f847b020e3b6708c1fe643cc9949a46a0b258370d481a0febd691de253e90e42171cae5a29f0e0748ca96fd4c8e1bb3035f2974664305ceb87053aef186d48a6fb0719b5afd5565dd44d58b1a6aac03831e375845e612f2435ac773f5591631036c47af440e8e4c65cfdcdfe338a140fc03173ce2f46e25e8cd8cec1ee071cac9d40ca99593306d2938b970c0e08af05b3f85e76c85c240723162bbad7de80640ce17257409164d9346cd9ac2e470136b1a0af6b7bea4e36d11409635e95f6409d9a45715933139d9f6a886c1f3eebfd91406f47bcfbf96845eb5307c441bda3965ef88ad94ac9c526934ffd8dcdfe56cc2603ee8dbd6b5f8c989bbf62ba8e6c2af3d5986624d2e1ca1fe3f048a38b7704c26d9780edabae20e649d2f90169eb04b68539c318e86eb9e0621c5e279f99f412151edbdb564eccf1b1c22af8d30d80d6d447c0238cc404c23c624d112da46acdc8b8216caec5a4f501d92c61f542e8ad291fe9a01f960aad20c91b263051407ca607c4e244dd40645e459a709169e0d97fbb29ace1dabe5901f5a5c777728014f44372b0dc7992ce3bcfc597555e9d71eeeb5880b207390b00a4b93d6af5e55edc905d8b4ef730b53153de33d4390a60d019065d5db4cd0356b47997a60b4d01b955ce82c84e5b86d45672a131819711b94085c50b1c58fd2c84fc5cc0f350e674a7a8d18f126f874f84036631c6906a4ded7d5ef24fb8336b5725c9bfd68557048539b5b2c40bd79344a97af82184d9705006d96c7e98d1b0314e5eac9db783c96c9d700f5bcf09f29ff2601cf84720271398f49005c8d3436098dec9c0e28ab2a9b5f85dc97c3b540339bcb502b833203114241ca65201845859f943870314c5dba169c148edda79b2e8f84d461083ef63a28ca04af78db9903da2c25b69449ec7d1e9eaa687714380f498cc4077fc4b6987bfd19248b8df16ee9004013f3a49c5d8caf426cea5c8ef7849040bf4cc856d04d38b99766a3182dc05fa90b4eecb24378ce6bad33e6426a403ec34d99b1b2461e11c10bd8b49413d9a309ff756d6ac44a53ec2fa2821305e2f056c0875d6e7bae95018e438e95182a46352724316499a661cf96cf67398934013e5c61af89eb3ffd1837ce8ed594ddf12e4e99c100339aa676f76e18280b79361d3bf062741d2542cb08b563e2ae70d9ab61c66604717f23b8c8fa47b9845d77980e5dcb30d34626f8ef0055f1a24e4e6415c75e5e90b4b80be492df81ece3c385865537e9afa33c2ff7103af3e87471b18272b438c2f3bbebdcb91170ea572993ed1a3c2caa65a2a07c4a9b8dfa37e79a347e08940d3d7b1f253cb6ab7b398ecb4647025617861ac53c05f20ab553ffd9a66229114aa584a78a94ff3bdc73559ea4f02d0ad2584f5d60798c9e3bfff1009492c3824ca4b20ef753cd9e787cba9c087059508428fba152ea813a92c5fe2c7901f011ce7139349c97c88866fb4b2246c6a0ad9208811b5f38a35959264204096357487485df481d7a91d9e3e889260bed7a241a1e2a2c08df44177e7edf67aeff1627afb95dab6f5740012d3584ec7a8f5ec6090920bdb06b6acd1cf82cc577892ce845f3488a2791bb7233510ac681d13a277beef896d966282f82d8a40d3988186390405ad2c55568bf36db9eb5458537d3f4705ff7f7ddc2f24770c50e29e760fd2ecb9ff474e1a056185db0737411cf1230d7e2deab4cd5ad826b38e76039a750e1061d4f00cc281405786556a73903025315c2071a73403592e2475d3461710c9ff725c7e4b206f5a3ceb329bacf4f198432737c223e298d41e96b46ba54cee99398eab4d400e31c783728400111f0e97c24994aea0fbaa147bf443052e0974a804f18f78e00e7c8343fc05cd2751878f4b8e54f40f9115008763d389cc46fada37425f39324e6224edf161218d514eacf14d3824ec0d684eb21c1ac1c0560b1e422b9e7cb90beadfdfd43bcf2cc77f3c9461395301df9a0007d569878711c6f1de0f1766b7bc12e7a44c5d5bb1b3069ec64ed3154253ad3de9be288d6e130ae13bfe62c8346098e7f90ae053dc0d5cc08a2edfe61855b82e32368f740d92cba04762f9be936f0e2469463534cb9ada90d45472bc30985473d385ac8930918b4884c6e48acf01b41d0d2754047bbee9664dbc07a18498616a0c22796ef62a8b4351a2eab7b5b3ef9fdce028e7d1db5a1b085cc76d5a6a43729a8ccf2d6d901b085f6b41a2874225b19f535fb45a41b96dd72e31d916af339a611995c4e0bfaa9015c7ae0ea8498a1e4437d7937c1d61b498cf598217a72ed0bc5698149f5e0c5a53526bdd8332901decf8f038536729bb16c895f8bac87a58b732e059027f3320a200f23330ff1d56d7031dce7851e98e345b99afd043394c59ea18a03868ccb45f25cf0e9eca4d14000a7c58ea9c3ac5eb84b1963a22dbe916a3f13b1b3fc48123db596746395528f1ac9a6dbb82293c42d4b56be57edefb95652501efdb725c3ec0549eba3483f5a28828f634c91e8cd56b6d506569de1c7d0f47ca8b5135656717a73d621299c993fdedc60f02a15d68a2a8aa6583c3946a54e55a9852328078f357d43d0cfe1ec9009b959b6604f4cf8303cec9e423e45e21c820ffa65eb0fa0f7b576cb77be938f52a16e3cb63993affe71123bd0ad5621d28265fb02898bdc5d61b975ba9cb64d5df2c9dd1198f3a25efd706359f265b7d209a6830366225eb3e347821eb26a608750023d756bb47752eb855d89c25e85b21a425f5fea14957d773d0c4a274bdf9efc20d6285d2699bd9cadac758ebe8bc4564717db22ddf7343b31eefeb57843ae8f624313de8ffcb76db365aa63035aa0ad341d340376cc6c5df3c7f14c36eba91728d5b45e84bf618bcb2cf9cf2b29bd995c96b270e2afb2df524f2feec6a4854b1cd6f9b929f5ce54e6ab4676fa598285001d5d34054fc511eb5c28dc69fa660682d5b5d6416d2f4b92c2d77772939a9bad90044a26fe1d765c03f2149a1869ba5260072ec13617172a170d9175dc6aed5d71929639540ec3024571fa5ed4d1a348b1b571e58594e5f4dba8ba4610abe164578fc120c98225b80be736dc57f0ae2e893db3a0bfdb111a4c03f141e2930cf6f5ce8840be17bdd45e0224c0b5c7af8dcdfefa5db1cad12748a26c1fe6c69fe6989a3af82681a0de31305b02990b01bdaabce676f21ac8630c11fb466a47802a28156cd3d38b3e490e5a6c20be86387afc0b961b0d117828788482c47e971260ef60dea09d35300a0336295767b8d8619d48908f20a73532497d13297c1bf0b9ab6950868428a9aa9e5a40cc672f384302777e3f226bae0b39be0db81ff4c3b99b63bebd4b990db853210301a83ed956827b9b5db3a9986dc79fec3860585b619b7f2107d713ca82aa1dd071a0f08e805c05168ee75c88646219d0c75a541bf0cfd4808e2c7d7c62b50bbd2ee6e171e53402c464badd70041a7640caed574b86dbb0e752306cb07fb9ef55b473fa72b903469194cd46047888009533282e8afc7a36ff48247139a9639f8269670b96ef758cab3410b8f2dd423e2bd91f28d47a80bac66d9c571e9be5b0d27519d080dfcb690eae41fde17a48a94cb121aff95b79343a7000a460b9bc0ad96a5c9380a5b6e8daa181c77a92328820611ec0937124c550b6aed9d558d9148f497abc5633c4529e1352809d2ac9510a680eb8da8d07c4c11b654aa25569b51dd0e2366eeb9009e92d20bd8e66be8d702c1e075c46f4935727e32be955bfb7f0482fb33ff083ea99e026ea6611945fb55ffb9ffa18c3cfc6290bc13524109957048c2d0d0219ef748fb1417b6a6cb0afda3f3834745a53ca2946e11664db36b3ac381197fcac4b6494300e4887d065de3ae4e5e3f0ab272f30e98abf854141ebed4d4048919364cac315c284e45053e1434f82b5617ff3f5cc445a20539c02b8cbb2d06126b1ab75e071d41f03430578305aa54261704915dce14a30bcffa4eb5a717ae478cb005e452d5045b0e968e5eaddb56ef77f01e61a00527ed70165cfa04e8eff042127de058b54559d3a0502d178ea17eadfe157df8f0994a052314f9eb991196137ef0a2a91821688887ece2201bc1a0cb7c94d097123781f3d7a5bd175dbeffee2f4daa4b0e62f44145cfe9d9fe64f4b540f1fa19713404dfdcd266f1490fcdf0327e64736365930144751737801edf11ccb476c6241345e3e1f160e7beb6aadd19874e99c72a71fd3b4f1aa3125096d3c85c8d9860a2e944602c0582c3475b505cd63d2083c80c5c4b41254b165fc02195e858191c0055a60eb34cf04e95e7ee70a255c82e28093d6b3aaf92d4b62f597c0087da485b1d873b77abab3b2d55d056da414145e57706bacf72cbc465079ae9f3fa05a508eaac305f49fcbe0fb594cb2fd9b275a3c472d5e98d520a45e68ff160689116ffd4ac4a99953b94fdf1c15bc550afa7ae1783d8c4de6b6af2fda85ad4b9c0fa8ee4f313256eee5e9003a803b2787176b6fa6d155cec3ede2dbaa9f13023035b6dbcf46393a8ff5e7536ed7714d10f7a52596eaabe9445aec12e051be07237a937ea9360cd8b1340162f863b52665b29ddc17853f8ad3a8dd6f7083a4f4621abbcb1a04d8fd7e1d8e11f07c8ef09362ab45463a80d379c12f240f8d9acfef06e9fe9fa32239b215a58e9606fe496e26a086407fc8494e57099a4b582872f17b57e42574f1959b3e4e48a785f7063313f4e2d43e27081f0205ccce3a56194305c2cfa5a4184b5c96ffcfb886166ee92e25fd169d1f057066bde1649080eb8d0f86bd911a9781f1d6c51a83e217d5dd1bba566185001d6d8073277f2865f7f6b49ea76ab3b65ea887ea476843fdcf95e4722f1da4d25283a039c5ff475ab88b6b44d3836dd3c6d27af160cc12b2971950ab404d1d285edde6f749ecb3408ec12cc1aa5db89d9f20fff98e33572b73c29c435216271195ba075f64dfda888bac5593e9b51430e9ee1ce84c2c4c412d87fbecbb7c0939c9bdd330a4650e2b8adc5391d5a77a6aaba4f7753ebfa282b05c37001c38c33a1432a15ea9739421f7aa39636aba9d5301fce1b8d3fd290ccb829b504b6fc8bcda48f999a56a82a1fa064c7c24e2cfc2fc820aa5e14bf45ae46d267eb6a92c734ae126245cdd7f96a4509c9261a535a35c3038757f0ad10554d20c82bad27f432602035df6e4772709b0f1d0234998ebd6d3021e10ff9e6fba0ca2b852f5d7700393e2710c2854dc482e54c44b627cbd0f83c83253d29c01d768413c8978bbc049dd802946869ad3773d5801729f869f2eeefb551eebee26c6ff31b65473e4a21c6e26a7873711d3170e86f287f92b38d90158d11b0f7461af7f0567ea28ec87bb093eca40b8e26118762f0039e01ee36fe26e147f6376bd7add132e6a694145c2750457b774257a79955dfb00ca672141f140ed9a1ef0e9ee48a74a219d5b1f3c3b46c67287326789ba0f533c22670958f03572da89d39ca0dc44d9096953486421c82edcf3cf365972bc966ef40cf1cfaedea94855803fd4682b4d6c758aaa039240ab39e49cec4a9fd5ff4b64fd0d94f0b38a8f53abac9d6f54e444f33dd191e88a63a01fc1c4e316a8816f81fa94e6751e4dd106c4bb6f72129b9f775fa38a744a7cc61311c2ba59ffba8897c22e1c838d0300c0df80310268883ea6c36e875191507afe71cc14f7d9c1a4d1244e3f0176b3d4af2b6d3c4e1b7332f95615bc7dce29b7aee5acf9fffcf1fa0d364ed5c8401963cc7e2c3d03f8d533e82527cc7dd0c5f92cd46cd9c2dc514010e0129c1be5b8a608800ef8ecd31237292b86179bf6f7931fb21a5a55ad8fef039651dfe21d7e780d363bfcbcb9a365f9d375ffd577713d4380281a7caf1b8939006cda5fa607324bc08f567a199396bf427ca366cae4a281e4dba79b5974a47b9a7122c1484a15a521ac4895bef246f3bf6abe6ba471614780d9071a7886c5396c77b4227510c9e99c68a2a08748e38151990c3c2ccfe7fbf0f3da6777d5aa87aff0446693ce68235f7978cdf9fed07080d894ccf0c968d92f481cb6740e4ae8bb2613aa2d00454f26f5624c11637c6b216e31c54da173135abfc05deae09a4e4732025b687343e289096879f88a030aecba882788c551d25514ea3c1cad46472b9df5faec8560ccf90cd2c7401bcef5756e46ea1fa231b2854f1dccb5aaac8ee027b4640ec10b53f3599494b2a9eb95cc483e0267d59bb5faa5202cf78ff9e3876a3b3d42b78ca0ed7a4c4aecfc0fe6451db9a193bd7be6fa209b0fa27e7afd5497e639c8780bbaa55a4598846602280e4bde6c351dd3871babedc17438d0e8589b204b24987c8bbb3c83c35a09fb9919d45cf0d513c8316677294ccc47f076d0f29186f6527c527e70b249548a563592f2d650a10c06fe78b51637fb2bf549cf486acee4f3b7ed745024c50fd5e6cfa9b5199862d24443daa09b752690cbbd1a1c38d72e48e953c771d3617af0b8066e60ef40961b84af3498cd8f5065b7b2d3bf1f3c5de849f3f56d10266dba8fe34c8f811b3fcd71e51eb5b2e0e9ec376e4c6b7a3995233cfda67f072d69fbf46a24628f6c340950d2a60cb53e3d89665223c9f40cc525ac00f58472a5672f4132ea91445650cb197b4691e5d02c67e5c06c491fcbba4fbdaa2c811052236f57a71d0d4aead06107a382e63d14236345ec4c2b344a9603a6a53c645657d300d14a491ae18ac62cc94a3a30883b621f002b76f4160f894f03882c27f7ea86ef52093d755925a1bb1930e2a44197b527019379c263523a01565f42b38e11445ac9841e9c0b953486dcf0cc89ce023e318db9c6f72cb9cf8034d1cb2590e58a6343a44e1911dd4f190596c581972d31c09abafc46b52e3400593c5cfffe14dc3f3915aeab75ea9ba8a31efb80566cc0af274845aec5d493f17ddd7abeb887aa0b0f8743bdb1c4202ed2ae23e72291cc379e1c4374c17cdb87f2c39360be04a1ce7ee08948207fecde49c076fcf37751489d883666dc604e3e3f772250c13fb4ed2467dd7ff2d949be49869488bf9d36489b726c609b72e0a9dc3dd03a9191dac27a539db0f3edadfa14489a97fae2907482febe6f302490b36c7a1c21de1b974c2b164e40718e4eec9a8de34cc905bd8ab5c3848c2b27b5ac4c4e56ac1eaea47261312a2dcb0a8830ed12c3a5a181a9a97c2016bb4e7a93d5d726071b4b8754a9b980109396d54d44d856c9e9dad2c194541e1c455d77afc9ea34938185a1c2ead44c58885d375193a07e4736d278cbc25c9e911cf38cadfb337da83993e11fbfe49b4de2d7bc9726866cb2aa6f88c226d8109b84f34cd2db5585be26e60b0d89aa64693790185554c811743eebd384edca2cc726a182dd2e2236c626fea0f63fb9eb2a2e6a9a33554f0df26a78191db3461d100f02aaa172e4b8eef358aca13314ff69d5d0c7d3f565d4b3e5c5fef2a0bc5100aa904e7e61097419b1213f197a7f2912b3b5a5d2701df26b49b99aa1a654e4b0982712b9ce7c0c3f3d43dbee407a68fe65b87af9edee5006447415386a2278f15aa16abd3a437ee700e62845b661b0bd4d669233e85a8239b001bbed9a161d687da141b6528757d6fe38ed038b1433358ef82fe13d8e8bb2b22ad4b37cce09f243e9efeda6f0eb0bf3e53ba057bc5c5ea65f8002b0c94a14018f9837cadfa98ea10df2a75609d8a022cad00ae335cfa055421a1119ca5a445abd29ada1dd433a42b941ce6246ef0fb5839961082307048034c6100849cb109bf1fa4e13ef7703a019d2ac8cd66a7f81e9709e9b95140aedbba9528564a6ba52ac7934b242e532f9f5a9a673695ed4e85f3863cb8767173622a7ca03874fc65372ece96212420292a6be4361c753976381078273d75dc41224f380525592820c4a932ba4659fe19d9ea3ebe186d473c33f802f31dbdda35d2f0d22fc2bfa1990cbe97d07a5453b20a55bc0f90e04324645201d574aaf71973fc363c89a4a38b7004bc2faf117d2a24069aa90c9b1dc1b3111a9262abe89c25bfba7adbd161493aa3fb6263c6586b2280bd2816fe4b84e30f8f58e8f784b3f6ab59b36b6df135b12e98be2e030bd160080446231d4c38bba6ed09dc2c0f6e9a4d9c798bccae1498df59689455a64c66d073e6c43f2be80042977c5a2e4395600a5e82fc1047a8da7e7a9bf7c89882ef6e7db70ecf7d56eb2f0020ecbbfab1ed5e217adfdb3847099436b14fb791f07de3b2d1b31984e874d65c2145d1dd842ebf53d1d4bb73af49bafdb32262ecea02bd4424d6453c34a86dbf2fc4a703ea2cd454aa699940857be2f7d14953f3b936982cea5d22073a27a82df7df2c92ef057bd1d5eb0c07f889f5032b49f013ad1da171a83be0539423298b3717cbb8eafd659f842ce94c44efd73f0ecd8718dd4c6388af099891cbe70953949862a81b539c9525699f5f386824e701b920888b651d59031b1c60a13c7bcdd2cc09eb7d304e665474079e48d35b7d9ff9d407de85ed5568624d6bbbd1389358125968606fd235111bd78a87a988bb6e5a6089402ade5e9f1cfc580e021397d981cb0f011e7462c317e222a6fb144f4fe2f5139ee67a64a57de9c2651991c91a98c5e1395fefbe946a367cfcf894a3cd10e106a95bfeca26a0c73772393d501b0e80d6cb0ac9f79f3b4254ccd2543ccf4958fb6554d23c529abe29a6a13ec37085dcf477df231f405a57c591b7e36fdb3274b87e364cefec3cc6e99225777ae302ec994085cb9efd778b3efc692a812c46521dabce3617198e5a5f8476d1672839e5fac8fbc22794956f9d3807d884fcff9980b71a708ace3d61cfaea8e85e17a81291026caad070bad2eec2f589542ed2b4cf9a373dafe6037bccffc1c7c85bcd762c45a5983e079c0825fdeadb541163d28d58f2a81284dfe9471cfefb93cca978b95351c2f072ebece9ff337d4bb9aff2313e39595fa900fdc947540bfcb43746a0978ad23f3c0efc2f49ae6a81c847ed5f089d26421814c84d2b21b03b8fe8014fecc0f624fd51f525b75cb465ef93694a037bc06765882824656adfa58a8e0b836a0ffad35fe65115c6196c894cb8e38f0201ebd82bdb8192064225ed3432d5c4263faeccd68374322f6e525b39672e6174556f6a0a952bf6030594282bbcd09dfc1b45cf8c8f9c1883a43cc88c048ebeaf46b737833605ab5137c3682696705207e04eb0fa77c2f52e87463733ad6c33dc319ad6f69eddc91b09e0d040d2db39ade823a29d18e460d4851307faa27e6c03ab74dcbb317686bb65397902684d347919760c8cc1a982652e6bcd92b373d03dfe06a78f9e55ffd14f20fa52994b09b13a6f62bc872e064d4626f848b69f9a9e8952a9f26efaa0a4a6edad762e4bcbdc6a28b608d70e05b16864e00030b4538cab9632d1fd0b4f44257728c330ad8e84c43eca4f6d4371add9a13ab1fb5589594077b13460a920e2e493d15952b78bca96f66daf9d53dd0681aacd428d51377a25937eef17e7b8d2406ce88c77ef082d1227e1166f2a43c1cec040a2c79bc69649feb390e155cc7e3b16cd9d54d8a635eed63ab4b5b47d1424afa6708faa9bc40cd12558840f12613226cb3438c76162b44557051360a51cfbd01d4f5cf76a79f2d1107d05ada6f57cd11a4a04632870435abffa5664b2fc96667038db777e2e3ed15b4c684d3f662541ad776b92b13f021b287703f0f0ca6729239089723a88b19052771df657db5b5dd44f3931fe0010efb3877526380db9a606ecc8df19f7c224123b81dbc0a2d9cc068198dea4c500e4aad40732edc50c3f338a3fe183d1516081ad0f8894868edd8ea79861cbc1c96501a82926a891227e36a7a54fdd4318337345c7275552f9735a8e22732e2ec8abd688306e6c167060c1bc99d59238a4a57fa459040c37cea4a425705611e58ca246ee1b4124f2f40f240f4bea216708278c5f92bf1e57d9e9b49b01806ca8ce3e59891fea0225e77fb7d349eadab53cedc3be5a9ae6223a28309d76e1d27fce5743b679f8a00ab62d2c4dfb91a8bd184f2756900adfdb2afda195582c2772f32368ffeab16945c3076465900ec82ba7d9e294e1d55fd5ea0abf5175b478ab2b981138d12565f911435807ed223bb35c27d24a8b07e5ffafd92a69c5e8c10083f2d5cd91faf37f48d244cf3b2845136547ae3665bb8ecd3dfb21b033645d4b08395c4fe35be20772ca6d2fb671cdd3cb2b9c7bcb59e825dec2b604b13520fb0c27be4b687de4428e3620672aa27ad96737777d58df347ab90a80207c656a9b139dbfe1d5b7d887b40739baa07fde4a79b0faac11f43ca6331d10295cd135198c13e0f321d7711ad8cc314e5df2a3ad71380974ba298a19eee4bba32705d4bb7b6497615279beb73118458b47f8377332adbd6dc56bef9d6641a19df4aa5126a303d1b5762552e9628978b9be7e0850f688cfe5bcb56e32dd7ff8cb31537f78c4312c5bccbc2964495d8ffc680ca4ffcf4449f0232b26833a2fcfcbff1bd812e67eec3a6af41e9ae928ee7631b35f7a3dabb89826ffab88dd8266c589b96e90aab73340a1ef8cde0ed91687e89ed94a09410c270e37844580d4cb422665e484bae907c9b597082de1da808f61097f9fd6a4d0a8fc1a7fde3cf888098913175d709ac8e747fcb6e70dc1ac1424fcb0b1699a5ac019b017e8a3a8f04407d47b395a1bc9786a50ea4381b7f12261996f61071d59c09557b3405fb0812008db6b99c67fa0167702aa350d2d01335b1c39bd875f1f3595d41fd5a30368730cb035c71ffeff893602ae54d6e1265c7a259bfaf617480d216caf7555ae89a26121da226473d862b44853d0cbdcee12d788679145aa1484889e747fe5d38f6f3af2d0836605389be3d7df41667937cca1e09a720a66459a8b93de29c93971e428741c3cedccf774978a4389eecbac7931eb9ab488899c049f83370a8190569da2405af27b55f83549ec04290d639d224e4a0832d9d393435480b0a05ff27f009ff30c26c27169c5c757edfca4f0cf31dfdc11cd1b853464aac4a0c3cb308a9f33d8369989b2f432b273346840e70ed2181dc219b3ddf6dfd2fc9847b5894809f30497c06ac8caf998d35118ac74b00337a96e8ba0255e2e7e870eeceaf8b5fbf1134bbd85dbaf7d7444b47645747ea2f2323da34bf56263be0fb81b903c6fae48b571ca1084213c57a604040c906d844def77dcc6d283027796a5167f29134ca74dc21eb2dcca56aadf308a6d4b05c955845d8cf2daa92cec1b666ec4ecb1a474fc9a6568c8d43429a7cda22aac68fbe7c64a38784cd2aa88527a5ff209e4e0d445edbfca51cc8901821447150469218e1f7c3f066ed5528909985d5da49cc4bcac4d737f24b328226929bd1f9ebec52142633628b110862c750b639f70cb90167b54614abe0e03585b1b802820793de4d6593083ea57793790bbbd87987223261a73c251e7cc66b25bc9326aa2a1b0bf4fa3e81f567c2dc4a0c6731b4828ae5b5371f9c51310cde20065842b01d2aa577ab775644220796e52436c31bca17b7058c0b4751261adadf7a42705edd731f2607db23e131a48eed93f0d651ea7bc376d61b71b4625d79584e8fdb5af2d43b91ab4871b75df55105d24ef16744bfd78247a81a5890668bb4a8ebed0cde3599489f6944dde0885b521a93669f4deb13a62b0a0720d45cb3b0b96f077383752ce464f8f56a38e0ca25c5029f09d3bdb6bd06d18c6c1b6e88a7e8b843ae794da458fd086e8ab02db6a99427cab0580b6640ee87a2fff6ace44cc59f5d4a9712daf327409f6fff82d13b35b71d917a150edfe60d9b2b3a4270644f6e012394a90454182d92e4a4d7d1a6fa7e8b1da39494cca7970270770d95033c51df4fa87a3bcc96ef0dd5067f447a0a5a74b4c98a90fd8a4b87543509926d4ab704ff87ca8571971b1d7735c0e8c0cbda208f7189a14900a8cd66da1a2326da24218154de3343c874fb9e540c8cf576775966d573c3603e94570c74bb6f9979e855448cfa3eed96ff280cc8af22d8d27590374176cd1a07c234addaa3814913bea05530fe35f733fdfec3760e3c6f965dbe71d7baaa0b018ed5b5b73b91afdba15f7561c40fd5519eddc13559ed0d0dbef35921f68dac1d2bfc5a2e1ac718435b8d9e759980f40552b1a97462b1b2862fc972bded94cf679da3aad7c133142f310c5b69b3a04c0e18851300c181adb3b7de384aa59aa8383a92d51b469117162c85e0ac9b5aaacf248e4c3446378813e34a829cc49923e5f51a60d8df94af45a7f2cc140d8d00a00bf80d89adc9ba5436328df758ed945a73796245def250c38a87575a5402efcf28050b35e23c5752af2965c5095fc38ec074e8962983337cb630e6891307355c5ad6c88d54127dc135748d6f239c085844753da76f0c040f9bdad62a75dbd4c7776d139775b8550518af8a4d8f2b55872f9e66ba16aeebdcdeac9c448805420118d279fdbfe21878f691d561059b210b8158ac02caed2ef55083a5769ea59a24f15bf19bf7aad14403a082eedb7dd07a411401946315d991978547a313e28d177e5a9b5647e6bc1624c35e7bcb71109e8d7921e4ed576881194605581d0296733143d4207ad709a54ee1b0f3cd15830cbe16896998e7da003a87067b7dc6a4e65d270943fcff3487ce5a5d0b126056538a209e42c80645053a185e288e65b07188b364e7434856211268d1a0e9312f7b9030347283b338cc8ae01249e96ff9afcc6386042bcbda30b60cbb2f33ce4624706b88cf4e5fcdbc2f37d3f18834d8a378066382293003239fa7b8d8ed23c5152c3896df1ded8d047e5db851691430ac586ced7dd0f8f537a2f73338b95d6c8ab52be762a12b6e4c43c1908fc110c4ec3092b33edc0b92f343838f5ed63dd16e61e499c42640cf5c64c2699602f5d6871deff01126da61475fc71fdd89eb71fa486db0d25cd043f410edca3a5cd3a7902846c74b12b2c73158408bc411a739a54fa227fb74007e850006e7028a7971c8e27612dfac00b500ca9650475a2f9386953059b33989bf74945875e5a38ecc43daf59e2285b6bdf606b271cd55a6e436078f8c58b8d563b4e82e14d962bc5f3a795cfa169bf84c11f6b189608f360da988cde942d0cb21ed81b82b25d851a8a9620aa62bd74907656263e1293df62d3fef0c85f4c567f4ee5e41f7b00eb567c63886b796259a7ddc820a9bd1a122c41d28295fea3d018705d662f3d036493dc27e19fa04fdf09594ed0bb85b4b997bbf9440e80f8ccbec901722d46603b5f3082841247656cbc0f67e3d519988e60169ed7a9b4d88709ac18803cc706b2327c64f357aac45d01ee0a725a5bbb4e9c30837694dfa4d2dcac6a29afa78377152f5f567178a7ed7b91b1a4779f669d724ffbed9529b26d46be4bc65ff9ff1dccc838bf35cd9c93bddfb49e822e0146804e68a3f5ba8d47cccae6173e95434a331438374be27cac932f3178b31e063c5c91ee7b87b6cb2bac7ac15a172d510ca7ca87cb18fc51793297c3144908b39ce2c8a26eae0bcd3372fcfac88093eadbb26568bee2d36e46a806d52642c626ba458e6907744464756756a656b445d9f4cf9baa6b2ea3b4de677bab2e923a07990958dbe04ee121d0d737449a02386fa8c84bbd490cf55b4715a8446d71b6daf7e88cb7c84755b18e95bef012eb5f6626885805211ebb585ebca63e91a067889138c8e1eea2a80175db5a05e41558270a4acbf8a68f41f90f4ee9b28c4b96fea3451ee3fc699caf9c7fc10401d879ecf0f030ab522c290a4cf34ac4e82106bc6c566e24266584dae50ee613bd65002bf4e8c79163365d534acda828ad64b6a7d8139072b73b7ab71e04f51ec136d128dd0c75f0917f822fcb64249085f2febca9fde8fdd3d3afd3a222f63d97335153807a84d73851f1c598a48968124228a0851a8b24c869565e0622b69d0ab5664e1d2f09f7353cea017729441435a0de93f3c6d07c1763e84a630f4aa1283cd4771fd384485be1a9abd09431088db9dca183800aced7cdde946dd20650f55623cc3d34f3802ffee8711b9039083c768c3ac7715641727953c7be0fa98e91d9a12705a8eca0aceef250c3a8545b32a1b9a731bc8ec7fcba9dea06d922b2d46461be4f4a66d4c8ecfb6378d86977ef298819c35ff8fa6eb602105597444b00a4a492f4a22a669a67f02ccac07b2cd990a9352f0bb15905faef12d541f990c1ea5853da7e4bb223aca5221748093f9d7fe5ae82618a30232c4342e72fda1a93969ebd10836d40990368f08599ab592e3a1db793ae7119ce178785c19413c1a9bc2ac2d1e64d0d70f2fcef39e7cea00d9c2c440ff0051d5aae1617ceac0838f6ea4ba4c31d00e00798752b31b21dca04c5aba0c6e9a3b2e35a0c9bc47616370fb8c81075898282419f40a241a51a8a00d63b4d513af9d9b80d9b4e0e8f9c9ce26d9aed061b6f5e717b8fc0a250c536c1f099bf558d6ae5d30672d2d5180207131987e0d10e8cf48600fd43d3a5cf4afd1eba399feab2d734e3e8a655347996b593424bbfff162d5e9783fc7528f21d591b1c3027b7b40fbc2c804455f4414041ec922b1bd7832726f17021ca6e6655d02fc6202a67533c20f218f20ab061237f20664f58bc3f385dfda2266a013890a96d029e46503c75ba56f662debb4429d89e1e78feee4c3ac31de50003f2d64e72850eeb91b7a61346efc057140392aefb61f82fbd5bcab1a2526195dfdfe95a345d24fa9624093bd72faa58b9c908de8efec9599d53e890d0b95bb3c48961b817a0c51af0589b743166af5737c564cb1b7af15ea2bcc61cb6107c55e82e89035e9d07bf01445014d91921ff8d1c182a5ff0c0461390c854c700ee9d5f8e9a748cf0ef62acd82fd498d91517c8e6047c89774e9f98736272098cf02fb2d9f41e3f153299cb0d7ffe0ed69c5a2bb019a4f514baf947f5597fbaf82c02f0e7aade262fa0f5fff2eeac980b99f712e2175e3bec1e4fc85ff42d9831d9a13db4dbea55c65d2e15ad7a0bd88cc21f9b81594e3c9551ca6e29d22c01cf02152d100f927373f155150d036ceb0fce1609a49fe56eef4cc0f66987a466dc095fea4ac6a6f8af0646a1b25dfa778b7410a9c6eb6d2306470a1dfd0febd68b79611441729e7b72719df4754a587bb032396536c3d69bdb2684ef4c034bb0c8006c503c9c6f990311dbeabd7d87daf46ad9739778d2ba3ab812fc15da691d0b4f58f22f42d604edf3ce14c8590c491bdbcbc534075649253355b480e9432040712d42372d9a257c265770e624877d945b053829f295ac4c13901bca69ca23eda86cf0056e44e6c8fa96631a9f08f830467ba423125e5008651a9327a1524cf6f8b318d37ab81c21a7ee13b2c0ece2a8ac2f05511e83031ec144090f1aa18373c69054421fa01d96105bc2024997057219190104edbf8ef507cb3b2edcc8bf1475e7996b51e6ff42258c4ceccacf0ec945549e8cca67e775c02512c16a729e75808e2bea04336be7e92ba9c6139028b10dddb1887934b64d2585f365781059e90c0c0a42096c3864b682806a00b2ffad3615321fa2d92807578cc1ab28df3de370c62864f5de4406469fbea1685a37acd4d47571d29c6be2494a6ec30c6deeb64abb41d3ee2b3eb87548bd04f98fbe2d7ee11afb920a8caf4c86b64b449e329eff137a4f162116cc31cb0f588f80b9997871533ce20e7352a27c5dc00ea045bddd84ad50e7b963a4897d06622da5db95013c5107c9711504fa873bf2cb9746a3289c172f91b91f31b22450f5ac33441f0f65e062c03842504ea7a53b25920d22a4e3ae5603b0cc54767e4188fe85fb84761d92f5a38f09be35170aff3a8a0e731c7ab202fcca6a272fce944872a5d2110164607f6a691c3411fa2504557d1ee35a7ff7a892a8d15ec11fdcdd65a4208219becbde5de3b860a210bff0a930564bb489cee851c25ce7c61c6143a9a20e44b3a912d2aa9cc578f532c6990c38d47d0eaa1cc42f3505691e9250ef2543ae90116a101e30c656c0522992d0ac6d92a3ab2519d3e031267e6f41b88424a107399cf7b0f6319f5a537185e7bd3c3684676fc70bb3f3d8c6768473decb6bf3c8c3ee09e3a2a41779887118d09c8578c11903833202d326d54602c65d51416bd0a9441a517080003de7268b37c6f2f14e1409473a6941285b410c4a51051480ba629d9f110f7271968479db6f022c43d55447798d3cba028a48512f46419d0c61af91830c69a3e3dcca7c59a7eeabbb1a6fff265b1a68ffa6cace99fbe1a6bfaf8a3b1a66ffa3ad674dffbba2fd66459d217b214924432089feebdf7de4c798032a84a20f924666e6470f2dde00af1a68b740a3a774ba0ee01f76344d2ef66b9ba76cb6f66d9b2654bfbeeeeeeeeee6e0be6d0ee8efd8ad49312818b3e381984a594d8a249602d27814d5949772b23f5f252e2c4a27a148544284cff8dde63bfbe249f927e9540199b2dda20d7030e65908fc469225f3df248a82471be595ec9386ba03402c197e40976f54b9a4e754a297c750218dad78f40e284325b134a39036550aca1bf67e079d3e596637f82abec3d307a24f3267095f5c024d1e9aa6ed10fed988e8f4126433b988232e8d16502794c45ba456fca1e614319581989195f10c98af563b2288bbecba104426fc1114820b4532581b95c41162410fa9b28440a2920be64112e1914ba6450e89241a14b06852e1914ba4aa00cea167d97043ebd04a29750623f356671d14b2259450649214bb4cd6d0e13a5aa24302ac7abb0c4d9f27caaa84ee99e65599665dbbb7a72634e3a5fde331fef4d0ef3c0a19a655f98cad9b52f4c65ad7b9438dc439cbbece1cd1d186adc17259010e7ec977efbeab5d40130cdd2cb1ee3ad41b3357f6b507705fefce759f3785e35eb95cb830973c0b45919015798b79738a94c4fbb50394dcfe99b9f18ebe62e15ebf44a0f989e0216bc992c0984430944be7e3aa048ce64d1ae61aa2b72ce9928a448aca1a7d7e2eb84d8a2bfb929a18456ebfb6666c209cbc09c6ed17ad40181ab18758bc9a2dfeed822d3d78e0a7e8e77584172e30e2ea03cc901468fa45f3d40fc2029094b100eec7003469f435fc40e818b3ee4ab3b5a32c2f3fd2b84e955b40aa52cd7f562cc40483d309d9bfab9ba951dd7db0a9ea7ce47d810f8636564aec09aac2cdf40cadd319f2b8443699457db7b602889d3e5bed442e2745b6448d3668bfd89422214b92fbbf40be6bd813a3ea7a7de037b79f8c37c49baf529f9509f44fa5e3ed555dd0bf2bc3cbb41174231588449a16e0d798fb0a1d509deb57b46b4156495c9caf6092e92381d1812f1f223b28d25a888c1785c00632f7f015d18e2fef2bea442e270de397065a43b770e5c817b17b307aebaf7e42b244e95699381ab13b49edc302559aa9038dc2df7ad4002e9dbafcbbe28814820f22f5f6a26401ef5c40a5ef76577056f05fb80ecb6e35051606994b4051d47624c9b0692405ecc32d62f2a81ba2c518e21d4f0451d4ec8f185180168638839b0c8010e5d50c10551aa43fb56f431d77316f46ebf5095adb596ebee792dc8ec8123e8b20557e87e99dc77e7beeedab7e26eef3d5981c4c9c0d509ef3beec81a187a5f0952a09dfb4ae09ddbe2042414d1b4735f9198bd18cbbebd53dfa90579472e79d93eecb86c1f6e5ab60f5588b12634657beff1e5af1790ce16f7fee438d335fbee331d7ff2c964f5af6d097485047ac951c60e9858628a1a54a2161e4c5182063e315822d667b202895302c36dfbcbfb49fa757a9f3b7d2fdf492275abffd20343fda65bfda1d3e9a8fee9053c3d64bd3cc2500f5fbe081be298dc0cdc59fb0a56022df41db15b1c772e86572776eb26880d0c4204cece6580036dd6c92d26ab8bd87b20ca0a9647a0349aacdeeac0e176eed94369c47df7768804122f440289bf200324900c20d191b92787f8d503b38f9546c19748928b34924716a93461c8e0708c91011c8e99c3f115b33841858aa22c8660a5c9ab668e263a9811450e8e2802161f63fc8df1b101b4d67a31d56e0a3a51c896e9eb0f124ab38ad4bd0746b773dfd9ce3119b2e00eb7b2da996ce0cadef7c0aefdbe5dfb9064f40b1cb3f69d7b0d643264cfa47f77ee99cc5f7055c19b1c4a294da2d3ca5093b2bd3ba52d059d2884cbf6f5270ac129ddbe2279954bbfb8f78f98ee813c26d379b67aebc7ea967d89ead4c72c73295ba150faf69d12b8ca3670451f613b1cb8cac055f69db97d45c11b584eb76c12fb14ec75ec918028f44bc740bf04ae320c64a51fe15e027986764adfce633af723dbbd7b204fa9942d21a25dc7fb4ac7642a954a2ffd6a9ffd2dbd7b5cd59b3a90c7bb29ab5b26cb22b1ef6cc9c674ba65b9204d963d52129dda162efae0b40f75cef4ed3ba66fe04a7e7b0f6ca7f4fef69d9667e2bd2fc19dd97dbe07263d222d1891b9be0211b61d45446a9f85d94d56bbe2b60ca6693bf3a76b3f72ba86cf93fae947f05ffe02f268c7a8afc2380df52544ee75505fe9a4525f1dd1ae3d435d9a9d8e6f53a9bffc887614c883baf6179067680775ed3c2f4f3dc22c3ea15eb454ea8b302dc2b08ddc77fadcb7cb9fc9a25ce7954c974ea4cf64352c6adfe96be05715bcb09cb97d114629fd0dfde95934ebcfaea7ce0b44bd92ada497f4b348dafee6f4280ac1c97dfbd8968ba50f71fe02cf2e70ccf50480a16adc99781cb8d39d097e07aeee4d8fb0ed937986cc75b77d336b5f96bde373d4fb4e770f6432b49d097df70ddcf18e41267def3933bbb9563195ecbd6f75cfea965d5d50e7ddb202562a9365373bf07c58a9e8f8d0b7907d7886bccdf043a7cd9dc166b77427cb3ecb370c5cafd8186a9665b7fb6a965dcbc0150afdfb23f31ac8a3f10cf1dc37f7ed3ab85bf54e56fdd5f191e1be2f83f6954e832bfa7e0f0c5c51905270476392cd9f8cceb0d2e9fbfece7df78ef6093299d79e3357d9fd56d9ef6dc59fcefd62d71ae9948a94698c2f9f18e41db021fb2617e6f9fcdcc0bc37b9b0a9824d166c4aeed1a7c90d2ce63f17867a5819f07361310fbd05fcb06031437e6e60310f5fe8a7927904894049999c6651a4280427b71166654a737a57bf4aa7cf699d7ef1387d927ecd9cde64fa301ea96e7f4c1675b1268bda3a6cad32fd799a2fc2faa56f7a9e374f633ace993212cf2dd347afae6ab567d1bb8614a1dfa1d5caa36913d62ad5680b4acf4d29a5acd2afd46cd1d3148d39e0295bb1865e7a1f01648b7e7e3e4d0e8b12016129479980f000999e0359b1869ebb61496da19e034d88f9ca4b50a77bbe043da82f46c7c76775d37d781c9732bdb7a998c01d73d491c41c05aeea518f302432de513fe21d553a0fea289067be04ebbe08bba9bf745f7d29d577facc07d31df59c79573a9e573a8e30fc45d8ea8b301e5f84cd68a7c3dcc727759feede7d5eee837ae993f956f6f81116f3adec4dbf2bfbd2e7ea16bdf7a1e83bfa972f762bf5c56ec17cb15ba7aff34e474ac7204ff7d2eb77c4bbe9f643c1bb09e419dae95e3a8fe9de95e7ba6fb5a4850a4458f72544ea75ba8cd52dfa1a077d167dbc97aa95c9a22b7b17ccfb5616d461750bd67d11d609e17aa55661d52a15e9d473e74b0db4bf3dc21a5ca1909dfb11fb0de401798676b6dbf370cf6e4466f90a44d895738b4c2f270a52e79e933a3efdfbad562870d77e64fb0579ee8776eeb7f368308e3efb62dfa8edc4e1cee475c933c51466b95af5db9d7073a8d386d2a44dc7d8194c7736a6528e075415638cdddd7d43e96d1e44e263476d2ece9412480eadb5d264ba22121ff1a53694ca95b54229a52c9a158f19954c0c0c4de9e60917cad9b4da4e7e25642eebe4079379e45476658eebe487332a735e27bf9bb952273f9a39130ba9159540e27b64123277c2d854f23018dc8b8ca83971a69c12c8a9312d35a554956976bb5b39196b68d36ddbb44ee3eeedba9f042b99674b5dc599534e09a49b52109b32dcb44ff3a56321fc0196ef7704b76d05fab190ca8fcddd20a65e50276c2a795d6aa649eaa5793aeb2cd74bda3c9dfb54372c392abf138db1e6c65ea9e3b0e92b799f8cad3aedc6759e473579754a38c004ac8e76b7adb260939a953031e1cc166605ed6e9cf650d35621b871c668a7c8aa302be4bebc54eb3aef84d9ddcde33aea751f5742ae1438e5fad508a4662a909155272acb53e2c808a43ed6179b4ff81481bc8820f7252763ebabf3942b0972d7c8aa5576ed4b4b87806be5424ac9715ce7791d57a55e9b2b29b8cb755ec944c25327e17b216104cf084f4f900671b946e8e119e1e909801e349e111654ea2300011040288192e4481f86086000178ab3544368563dbc13f00058de0f166bc56a754849646b761e90f3f30712145670213424d6cc5f21648c478b005d9004923ac85792961b87032c7df0f07e0214a00b5abde4782e874dd34e5e14e04707d4adf94a850492507ed44820f294407187f84ad22d1ff2b4828b05c4d61c22444e2c1a92032ccfd5f098f18cf0f4344096e11995678404270cc4d54d89231f2f4a02998f1e9e02cb1054c978464870c2ae12ba3b6d64a5e2d2584296c5c078465850e90128cd19428580eb904abd40401843860c19121b105ff7f38249a217396211a5d82ed0044a62031c24251363278f33e46c5a53f645cabe12274649e73d65ca846a1b6eedda4f89fd680442eda3cd7405f9a3b22b3d6e8f25efeb382ab1e76ddb26a4fb91535187d2eb6cdb86ca42faa92d66995b9077c89e4ce33b8cd21e37146cf8d4c5e4f8d2ed64d7757793afdbad79ee9186fb3629a5bcf714ec08c43e469bed0a2a654251596ee9c27cb139f68d4a706aba90e51be7a87d314eac04c7749772319d29654265e612985e35737a699fd7e99706ba666b8600d81eaef27ce1ee74714ccc7430a917542a9b236ca1522251f1c39d425a9882c0208588700e2512b20a298fb284a3053ed062471969f460062cdec1c30f8248da82049014b0105f91445956e10150d64ea78d4744cbccc8d9ad4724dbb2fd81850a1918654a1330451ab97bce2b91b226ad1d715c2f8a6c14230833945025e4f938451509b4d1035212192f10238e184517330061e50926a61411840821e01eb047a4e518798641642215f1502a438a2ce8bd31e8c8f4d48b2892e04ea0c40e36d0e24a1a314c8185ae4c291165a091c3113588f1821391de5319641162898c070f320a27609ed73832a07023f7c8f4b70920caa8830654243147cc1272bcb1830e2f6cb1630ed1060d57460145115d670137d64822085464107a01169b10a28635ac3c81811b38c0e69435d0b0b50179665123cfd97509d041080829705851441111962e414fdce0081d888019499d6ec94f2192ecb072609c658a3ca7c032852529d32ff2b4a1541691691d9926894258a058606ac2ed249628f2a45dca08da4d333bdf19a5b4b36fc26277dfc07d4a6da535247d84241c76f5315261c4946cbf0853757b54145147b6df8451b08b35dd069e5de7199145e81fae3efab0b94ed59f647a4ef66b95d365500a34120808262bc90b701891327d920ec4d7e917882dfaf89910735b20be5c366164aad3af075c1ce4304691a3ec529b10852c892414894296d8ab4e884296641f04a29025f7a1ca4814b244034004a290259b0f0944214bb8004c200a59d209800251c812ef31d68403c8f4f40f884296943e42ac7921d6d0c74fc2106be8ed27638835f4d9277d3e2943aca1d73ed924d6d06f9f9ca1a3a1864c2f65904102352863b1861e049345534832599c0db82f3f04ac37c95cbf9511b9826ab228ca4a926913ba6e6e268bd21718ba26ebc6956990c9a2234814143894b124d3759344feb0543f240e8d2a0aa9a79f89af6b52154d16fd8906999e334df115a37cc1044aa06ec53e2593954402a1a61c91b8d909c195728cf6466cf5a7c4a98f9cc48143e2c4316dba78e70ee50950ac7982c3f8048712883b02cf679741fde2c0153d2773882f99145bcdbdf40e1c0a89e03830c6812e98cec3bd3b93a11d7c0cc6ee1e901cc20d427c491f4984dc2f7dde77b5609b031ea22f112056f2c0ee1c141c4a9fec2e08c5a30c24717490384f244e05fb2b23326b79843ac2a1f40192484c2ad24a16ed0cdc9dbbf4913f5188f6bea421da482e930584c8923edc3763dd6a19c764b50442b489b12fe788ac7e5f5026c59aee82b084024aa0c99acf40259305ba208174652281f45b281285c82e27c4979c23b6fa37372594d06a7ddfcce44099d4ad06ea4b21202853a8d04f0a0149209dd49f3f495deeecbca059a6c7b3452fbb5f69723fc6546ef9e514992c0ac310380c92a5e020d3868411563c66327da8424caca15721c69a5006658525afbc72260b29962b06dc0f5926fcb8912041e2b73222b303e62b46b6e847c8f42c7a170dd21d15b808983359946b8241ec43e2a42410da31b6e82da8d32dba051b65338091a6d9e03ccc01f29c947382bf3aa1d20a8394aeda4e41bfea91f44baef32a20fc5391729555d67bd319b83fdff5575afb22305f1156a3add656a36ec34786a25ce64fbf528fb56bc6662cb4b79fa57fb5888eb624d591347da4119738baccd8fcc97d3b6997a4389228a5540a8181638679eaa12b26c5e83572d3f9d3e36bfac8f593b1768263d2c83b71a96f5561be550557f5d935eea43a7eb9ea3933fb76609e7afd508079eaf508063894b19fd5230cd68f31e7f123325f813caacb9c07c833b4a3bacc795e1ef308cbeacb638e44751926431ab8937aea4c5e0e73096585fb7ad5875fbea1fa9576d57b602b0d5cb2f37215c824820fb1ccc30fdd47580c4c55653ef9d3ad7e89f5eb05bc571a751224313caf6384c6dcd6de2f54a13e54217ba8c2bdf65085eda10adc4315ba872a780f55305d85d2b9090373020a0c4fa92fc2a6cdc4f918fc4a9eb67159756140be5e4029740a86574921f97a01859acb6409f54b6e315b7d29b4a54a9f8b0257d0ae61b74c16e70487d66ec97d9bd4cf6278a2b470d107b7ca7d50e2f8a895473d1759b701cbcfeeeefe0d9149d554269b3e8d70e9dbfc0dcb1a65df3e16067d7e6e60a537b9301f9f2687716fe28275f76e02e99b5c58e9f3bd7d3f620d6263cfc8810c365ed1074b84d1860c72d0011c4930af0212b63d67e24f96be568c09084bc8f3dd176309e12b4f048409c8f3dcd661c1312c8d1061f5472381cc2af33777da2ca85a5f8a362388465bb45919b1ef3788d3af9ff11561159525d03503f7c39b70fa3f269836ab13ec5d9365634f9fc2b459dd2e27052c4c9b98e56317084aec27fb5638856b5647108db2edc9aa2e0af6f9646cb2a805b241f45688de02d15b28f4f66014627500407cd91d628b5ea57a79c9e133976f812490ae8a058afddc20a892c0524e1fb44f7f8993cad307f8c99a4960190ae0ed8ebbe66fe6cf9a70d4a06e4d2ecbdf695b90393bb941c312f4d4a09eb64f3b5375b89fd55a5fc12a44bf3a65b2e64c8e950dae9f4a02d3c74b1c2ff77db088a8c0212956dd26385541d54b1e4134ca3573f55bddfe4dff2c1f3f3a0ba27aa55f8bfa95a85621aa449528f75d3767193541cfc9223d6bac0a0cf2358298c4a19916e9168d6de810db504223a74424246c6c63c6e29f6f286351e28429b04b3fc856b6e4c34806fd7d21c75789635fc8992cfa0a466ec6623f40b11f1a62b1582c1693b108e81409114b1037bc807332259b60e6186bb8185fb6ce39e7b475c2a45e26aa4f139b66c9ebb8b969f366b81b0cbb158dc0692bed9b9e73ce97ad73ce396dbdaaee9e73fe180355e5d7986613d4c659be2757abd3adf9396790b96212afc054d05701fd89c662fdb98aa00e0563de8957600db2ba156132272bfe32176b49ba307be6bc42d0b4484d5e0af617e36bb55d29adad6989c1616a5a6270a031b3f722c5d8936f2c99b0b66d1a195946eb037ac2a627da75d36e66378d8cda37b31db5e184d2341f2f507d147da9d4b696a524e0192141aebf5f8871dba048636c78f94b4adaceee750fa82006ad97a230b4376dd3c8688eda904aa562686fdaa691c1d9d0b18dda10d3c57844ea63a80cedba6937b39b4646ed9bd98dda2063a45fbfc5105d2ac6a59766b68a416f66ab1320b6e8de79f5d28cdecc562757d2a657ca1b5bc6a8934b2fcd6c1583decc5627b66697da9a8951adad99137a6d7572e9a599ad62d09bd9ea044609a4d9d4f66be37e9570c9298c8167775f6edbc6654131243a3762b95662cb89f8dabe813226a5c8b108c48a745de7554dd3823ccfa3444230e4691fadb55aa954327550ecc6e58a75c923625fba78ea04992f191434244b58801ca1e4ac1571641409e43e06e59fca6641518282e6b51b83228fa4510c4a3d3ee7bad94b06758d38322681ccdbada98d81e5b35c99ac298b741081ccdf692485f27422d6cc5b19abb9416925d6ccc7dc804f37d334b9a5d80803c7df1cb16871a29b8b66c0f6a87ddd6c6da0cfd0fd7c130cdbdedb9b6098f66d035773dbbabbbb5b9b4912633addadf54bab7e2abdaf44c6b836b54ca7babba3544c8b74ab29c77dde4f5ff719eddbe9dbaefae4767c6dfb12fbd5d4e6f7b9c0eed75a8be8a46082eeeeee5a6b77777737fd6aceadaf75779da08ef69877641ec3bd7c72a63eee30a7c77cf8f593f9e59330fbc9ace3d12fe654f45ebe38bbbbbbbbbbbb63769ab0d02b380b3bb23c9d4066cc70cdd082d3b2c466c618593bba148b192d38007de5b0cb0bc8f5d70869079b03a46872fbf811c466480e87e43b06516e329ae426838cdc6550c9dd65782106d2c477087c053f8a7cb92dc2c82253faeb031bac327d06461837b432bdbd5fc829c07041a6148c2c99be7a44283e03a7e6ab63b1580c4a97a2f1f14336c9619021996689346ec9d4cb618ce3470e631d3df29450224105a55f647afa8b5567b9c8c8f437394574ba0042a64792c4874c9f829221327d0ab8a041cc0ba29f2dd32662e9028d202fac10929269c4725447a611cb1751647aea11a140f001c65bbc20cf4f0ac71af2e2dbe11b5f118605d083376e07649af33dcf43f3ae34abd32a593d3acf8ef0a292c1a899982ccb4c9b29dbaa649ba9cb36799cbc771f01638cefe1ee237c12f6f2f1accee3a88f676867751ee7a1b969a5fd48dff423b37add766e665956b3da73bb8f7927dbb60aeaf8cc5cf595e948e6799cebbe55fd08ef81791f7ef71dfceef51dc864a8823ba58f003259bdf41eef81715ce5b86d05b4a58a0b7218440a20949002081f29b9ad569936518a1feab06282cc758502c63d402634e0aabe37706705ae50e89bbe33cfe3f33c5efae9d475198fcc9eba9770878239e12a3ea577afd854f2e29d2f5162f7b1890be6fd07c3ba298f02559620113e4d2e4cbe0986f5c3ceb1458ffbe5f3e382f59b6098774a4fe7dbf3c0952655498ad458e99426a97a743c609e3a5dc5d01745b9a6fa5d936ae6a5f79879f7953ccffb8c577a0f6d2667caef73819e0108901565597d119d0ca460025a84b4465297ac76394a8a23e9a85f41821c05390a12647baca12bed0424108845518b4c2f8bc41a5ab4dd8416eaa5b764a5813a33251d1f9f98afee03731ef58b58435fbfcae5ab6078f5a86ac9f482f528d65c1466ae3a92d269aed3e3a58f67befbccc733f3d24d8f8f46f5c56e0d0183cc7c43da4b1f4fdfbb59f5d577545f814c86ee99f455bfe08ecc79804ce6659e3355e7f1c994beeede77c09df9ae33a7fa22cc743acc87fff2714f7da8cb7ca5c792cc5977999cfa224cc7c747869e580c751f9fd3f17d4aefc4982caa5332e113eaa72756a45b14a91e1551fad2934d141a7dfa29658d809c524a2adff2f600d3e75823604dffeacb17e9170563e36ec5c965c290a38fd0c6f276ee6e81b5df57a47e652a55f66560dbb6e42d1e2501850f599061048b971e9188bbb55dfb88b8ddda7e7b80577147fbe5398f0557f196037778327015c155dca9d75eefcd4a3c590f2cbc793b977d31592669ab660ef3ed29f40b7f7b0afa85fa76b965db697bd94c9b8cb283f4384fe6e3b67bf4fd992fc2e861beceb2ec34ebcfc874a00ea5adfa222cc24aefe9efd0ee974026316f701599947a60dbfb63d19f332222bd9507738e76db167f2b97ecf64734ed56035791477b06ae62846db75fce16dee46ddbb6edd4d3c9b6da712a26709697d06c82cc4ba807ea64194cf7e9c88029f496e56d3b927ec57c7becb845cee7e527e9ad50c84ebf939d824c86ba3329812beeb4037760de20931870c5812b14b4d31fd14eef79e8b51fb92fbd04f2f4ef230ce69ce9a9d331ccb9ed43b21d6f3f6d476d7fd99e326db09e582cb66de7b62d6ed45ba140af1d49ffbef44558f60d5cc1c6e83cd5c0451fdcf67ead60f72c7cd38f54fa6a02578f30f95d9ca4ef53e87b9dbe47d21883ab4ee61e31d39c36127eef53e8178f5fd5afcc6fd24ccc3502cb29d2d31e3d1d1487d2ee39ae47844daf02f83bddf4d15cd6e3cb406f3a09abf378f4565d0fe9795a5ceeab4e27d6dc7337e025de4d882d7855c50447bbe91159c27dd5813a271a1d1f9f99afeea33a8fa7708fa45ff4f73a51c8cd3756ca4362cdbd8a093c733824dfd37b1c09cd4778f47448a85c48f846e8d109e1ba0658b74cd6bd5bf23d773ad1609a8f87f20c75e7a9c7f5f83bf5f81db8436f5a7d1186fa224c5b7da8cf7ca9abbe97c77ca5cb7c30e7f19d503f7d2b1dfc0a4418369dc71761599565b612eaf874d33fed9aeef1fde91e75bbe4fbd43dcc054af5c4ae067eb2eee571b9c0b29efea27aec340121c2ec8e760dc4f61a78bbd53044c0d2852eb96a9fddd99e6d9fdebbd5158830150d789e3e54b140b32fc222855d29e79cf1540a579063ac913d67151b304c8e58ae60230ddc9951c7155dd45004e50a1c58b942685ac12f3962b98287a9c5153f4d059be6a043609c86ec82f117f3079f8aba087756fa07734a4839b03da2c88a28d305389523162b7ee60dd834470381711a34098cf2820b6cb39864e03bc51c036f4e483a3047850261ae0832aa0822081818555185b5da8401e38a15188f70831b5641403d8ee05144e3ba31c061c675e30a7263c49515161b74500101c4c375b1c040838cebc615e4e667e676a92146882eaa2d4f6082380a02490667b1432a29c6759fc082c38bebc615e4268a95285960f01336b801454451ea092176381901f4f204141b700c504f00fd98848c4e4fc47043498a10dec11c35783f1c9976904443170324624065b6620e2f4e63861f6236146d51439e1264c50c425469a205322052220f6124444326e2c787a0241c6ec85292b0ec000627b988203a7e5837ae1ce44628d6ad78d9b8e107a26e451e20c18051003168142f72e89a30601414b307b8bbc1bc037743730011a5e30022072d8080a1b3604f08f3094cdf6825b005422369692fbe00ca42065cab9048f866996f60ee0654075823923e20623a81b31cb1fc10b4056b3962f9e10530605828b85066c9c9adf391ea702a1aad4ac87107a81b24731e2e5d53274f9dfc5499436d91b954bca2820969e69125c8424a7e314be6646260522f2fa853662b6d1eb81871624f2981c47331d2b6944a39e79c734e2dbdcad3049a4ff39833dd2a2a5363c750982c75fb86d2eeeebeb9420331d7478f03979c80412226ef26225dc8424a226165b66acd553a1ce0572ece80c10537c061c3131dc0ea0f1974308428551081c50fb05aeb3ba4ee9e2c23d7d77bdd1781c9aa47c951eb7592283141ce000bf6294c1beb651988b7c919d9aedd848d03c3ec28d0a696d3f53132e0bbea8f69336d3290fa6005b9a9a679b281bbf1b5de7befbd5bbd96afab09517e25baa1b9cfd201acc317ddfbab81a1eade6d0c9cbd7e03433c421038bcaf0f2bd10d2d68826e21b93f26f20c2c433f3017e40d4c4441033644cf55a27e7ddd27ea578455b992bb978861cc008a2662d0431c4be4a08223d24032a2062e50eca05588ebcbc3dc81b3e774f68577857ef42c1816c936bcc9597c16f6e4ac43989b5c2bf863b2581306576293a026504e5819c99952601122160310175760b608aca45f3a462bf457d40e814309c5d5adfebd5d0d4645596691014a1619805cfd52a924a7244949bf22eceae0d8ea639584416cf5a514a1044c4289354b40e9cb1f2529f8775fc0e1cd4d8425e2e7300bc6d9a24b8850504699acbe09314b28ab2ba04869149ee6fb78aa7d751ff3f6f88ee67abbf2316d3cd7b459758f995b71ae7ef9f02107963ea664a12284850cae98c28b9ea12c340c495143d2141b4a1f0b8b22dd77bb283705763071a58932ac48a30b0df040063ae812a50b243736ed4a992f927d3f7c18e1234608226e50c41a5ec4ae88678cf1d386166bfc6c7106966508e16305094b1d61c01c1005961940a1450617ec009b77dd58283c82206bc71823555d33039bd1dd3d678c34968438a594d27aedbdd7d6396777539517ddd4d6309b8ba65faca1e006725fd68af1e468cd322e2a17b66e31bbd66e1cb6682a31c6b8d6da8dc316b5bbbbc034ca0cca6aad9946bbabcd7c5148983d00ccb4565b3d231c08bf13be7153e6e2970b2a59d1a4c8852173514c2a52a24a9a4160cc3be79d36e0538e597cac28820f152db02ac72c3e51b2f8bce043bcf45631ba170b9ec9314b0c5c620c465022ac0a9478b36cb3d90bf8de23285cee80d9000a172d31802dc1a5a807580db85cd7134de6c5b7c34c602e493c815129e2e2c30e30268e4c34dc99658816040168ca10863065cb0072c4428416584555bf74b16e54f2b254aea42da63cd5b823cf39e79c73a6b2c0f004153138c9fd4fc5c619332facd1c571c409020f3c6060801c763134bc78a189dc27c123d2780d187c73ce396d46a0436867891da145eef7c0734e36aa909973cef9a2c10ab80306b9bf82e30998225891bbcfc323d2375ee10697120acb8b76118228c08c0a8a8863c71c79ce39aff2884c35e0f064587664d1aa376280c139801d2ed8d2aa158aac0011f42387195e7c4007357431658c28b82051e28d36e69c13c60e4c456e551d3ae4eeeefe135d8a664b9ef31713414a9e5711818e3c8f3a123b8ea0b8800c3b7ed87204091cfc9071c7143c202272438e533c7944a8a4828e1e884cd7e753850ee8c0820e2184e8d9810b164adcf1859520fc00d6dd3d83dc6bb0913b2677774bd93bcc540f0a30c70cf2a4e327cf63d559ae1b2ca902e4f0c71086c8f343e822cfabba2891e7cf9ac327cf975c7db9051c544adddd2dc4935d8ac6c72bcf5facba1c6d6496942fb4e040099f2237dee876c10fe6b0b283306ae8c20958cf2472271991bb5f2402dddddd1e117ab40a4395c32063c48184107c840084108880458e2e8280459e376be06046f38850da81394c49118421387e90fb570547504a5279931b8e2472df7a44faaa6820c20c7e6240a207467054dc588207666c39030ad8d19c436a6c99734e1a20622af71b41bcd1456e38a4e456c537b27477d3f860334248e3c38d29bc480a4a6a22cfff8d17e479caba54d540102277777723a1472c7049a1a916d2641f39fcd1051b3d60438c368e70638635ecc8f3d3d5c61324259ca08183345a9003c50f5d880083157404013623529611c94422cf27f24c61d161983b70c8ca52c5e3898a0729205001630d1c721faff145ee4b9514f2658c1cfaf891860d5aa431861a4ba851048421ba14953736681f92ea44d59c32e4f9aa135bf30d86b7863c1f39703e4a95ec215751b39b755bf6ed6bc185ac0de150c64a9f6f03975e2afdf49d929d3ba563904909348137567a09bcf28c19a821831e6250128bc15c47c196fbdc3bee71b2c2ec2c74b9e3c090e6ee1ec759fbd8ded7c28fee76d62d371bc54299ac693b299c7d92e75fa5c07dfbd03e21808f3db77944ec8dd53332df359050644cfe74500765369115e26419a193d5fd15a549a6cd7c4918320b687452153628082a398c4768d491c3b885841c462e31298c71d0acbbfb26ccdcd49340b747845e02b5808b3eba548337d2efa6f4f426c8537048be60d84781ccf436fbdaceebcc2399cf29f20667efb52fbbfc26119d2bc17869a469910f230efd9c728909682622b63a2261f51256c19f0e56bfeacbbc3ac194fba64cc40aba63b722ae83b3e7a6903c02430a214d23a21009b6161f4f704881a2bc3d05a23710a24014880251200a84baf784b10929caa44fa116ea5817d1b18ebdfb06fe7e664ad0586b3f83a290ecd674fb2925da501a22cbde9ac046ba0a772981e10fd905e581e10d2f8764b105c3677b497f628dbd07865c1de1c137bda85ff108894b5214223f26a7f3c060fa095c1dc13c2726a69f40ece998c06f6815272b0a515fe9a226ea2ad65a6badb5d65a6bed4d4e111d24497c3cc1d6fef64b757b962b15cbf1934b9bbe1e18fd49b2dd25dba657b4e9c53450d3344dd3348ee3b82c3914a96ec8381f381c2cb64135ef9abff3f50c3b4a4094871cf2bcebcebfa59474981ccba59debefebceb2650679e23c77c8f3ae3b7fe9e2ce711bd881b40558e6985599052bed391fe58b1ddc7dd0c8a654d5612a1b3705caf41c125273e9a4ee4263f4a7632dd4b17ed5d37711d1a6bf88aca37e55b089fa0fef8f8edd7b338cad4a55a7e0d9f348e24cb08926185148834d833e4aa289ba7499b1f933812694195454647484c4254942e921aa7225724941490afa4561577e24d0cd4d4e119dfb7882c329448455fda2f10acb45d4d3680acd2ae114a24059109c8c1e88421a0c650c59e24850fabc16900318c0c2986548906c5e9adc5d303c2b4f0b821d48c15085f3a4d743c232a75f49c02b57a41097a45fd227b6e69d70791225c9f4640cb1664a24e41419439e9753f27c366b0fdc121370f65949f608db8edc679bf608d3aaabfea6fef5acfaecd3c96e0237a5e6068c5a0b6647e49c19bd0a4c5806baba15a336d87353b8c0499ec9710a1e9232d79dab5f1326c11c09c4de1e15854c10166baccbeb38cdf4a5a05b25d0bbb7c39853a9b6df5e5089d6466604ce40ef0b5c7fbb1575ec91d8e7d817b1ae2978fef6cc497dc04927ae6093a4a1a69e634d9bc89aef6f7eb1adb4968e00546bad3ff0c9b5d64c4a4b25d0939a53e4e27eade8fd91ed573bcf045774b347349e06ef7610c378b8f368bf5703573bdafbda6bad2d303007ae76eee7ef6badb5d65a6badb5d60cacb5d65a6badd92acb6c0fa25a6bf50151aeb5d65aeb118565960ec13a0ea8dd11755e9957b28d77daa4723c0f2cdcf09065b75455030e25950c6502c5f840afdd5e665f4582fe8acc326d680426cbbe3f7b67db401c597163e292b57e0e982c5b3b2f67b26c0b067802d53981a2109beda55183abecdcb7dba33cfbf34738f076cb7e7b837ddb0203cfcb2a13680675cb5a6bed75a450b7ecb66d27620365956e59fb9dcba09c22560a6596ab5bf67775af149a2f9a9824b2228b22962d45d93e8a91add11d39ecaa51163d18c561b31c7b3bc401b6883c64dad4cfdbbbfad5b757b82f9a9c410710d8c621441bb20e7c7f500712cd82352fda086cb39836c0770ada04be3ba03f60ad4afb802d0d6619d822415b30443771460c9c9ce1823ec3a7d5a043c2a1050e2e5ab840411a023ee2414b1632982ec795e8a0e1078d1dba7c814392154ed8006aa2056c74a9810d44515e90d728c2a2450b6e504387dcc615357608e2820720206521050e998d2bb8bb4fb171af2c815739629182944397137cc2228a1427c29042d486942957a4e4d03d9012c318d80d27882e8d416e86dc683192c901a58ea8242c980a9b182a4533100000a0008315003020100e874462d1681485ba6c1f14800c76aa467450970ba45110c328ca18648c210000600020c41820a9a26d00847b6b0128020ddb83f41b19e8719d962746b226f59aaa2f1baec8fbaec571efad7439ff382dcec3a0cb93b35207a3d3e90a71ac67fa6383a2037d13055532547de8ba807ae399f943884c38f1e1920e21f60abc26ac6e68422429729f84304cffed49c3260cd244c79d10d55ebf86a49426b6ac0d0b03f6e1d54aa67ec4a33e9dcc67e5116723adf2d2cdae1c6a0779268927d241efb5c250862325efe6bcf7d70aaf454b7d3cf410dc859ad54ad4520e2104bd07e89220157958681459bc4e0ba02b770bd81b911c607d831c707d98e345d92cf6e3387d045123f0fd174a47af91db47fa7d54b74f853d7e83c917e059594494840a6b807cbd5f98f1c0741719359a3d4a9be956e247d82cb060bd97665f14b99cdb851f48404567636ae15b7c790f9e0bfe33dab8868a07e298eb7c1ecfba5f580b32e8aa6e50cc3ef31a70181a916d2144f29c4f4dc4a11f25d1584cd8d25b93c22c677ab42515c482860a1781dc2ff276daa2f6f54d6c2e1c2ebd2fc70b567987cc6ff3c66a9206fe96b9b05bfce592ba28f2cde0729d862a0aaf8275c15b895aef932d38adfb4f1b68d3867c1504cd2b1897640a2844481e4e35ff225c70f6147d599767489bcce61254d7a50751fb9c533369a07790e1a63065c862a2e12251d30600ceaa2a3818b2a27b37c29b986c6cd0d7b50057c81283412283968f8e410b37326819c9390bdf82dcfe7989374a715f3db6f3c086e681a2fef8b8c4357f2999e8a0532d7e1fe40177d91e7db6a418aeb9d4843065fbd3e89706aeedd517a469123b4b7c19de14e4314571ac2ad718c152afe532412c87854a5bde1dcb6eb593bc9685184664541d4e8d2f2b5443ee9265301d852278af1cf129d09313e0f9f8724ca1043eb4dcc86f8e69dea2b014616d9fe47fa782be0c3b2c3cf298472de81e99c92de0b58b86512851b075bb1cd37a590380c56015642bce7f403e35d690e5ebdafc9c4d01eeaa31978b3dd162d56acce273e24d72609951f2acf15aba4117442f67fd71fdecd6c56815bc06367b9be34bc2d3ddb5950354eeeb51fb4e5cd55984035f5dec9f0320080d96652d15e1944277536895b158577b60a98cc11e344de02b3dda58b23e66e4d5e5580fa09f30b8dcefd19e6934a8108b5dcf4506c3101785dcb4e42d662c8ff2ebce2df821d4ea6a8d8b41fa55cefdbea06cad513ae55ebd6a68de5e5cb61c2f7c28e9978c57a5ce838c02cd661df29c8d4f5847e726f06c56db3e3e39a0820208c8176c803ce2ba89f2bf74605989309cdc6ed3e1eca5ce7a9e4dfb3f153426488c65a3cc81cde822dafa58272d97c6979544bb650227855bd71dde2917e11201135567c89481b5a958e16ede08028494c3cc18dea3b4b918ed1ee54eff415409fb197521e2133b6b192be82778f45879ff37878c2f175372a0dd5a94879ad440a4d7c9ada82819f5773d4eb96f7bc10eb757f44f49a8d650261a38107b6cd74a67ee718377f1669f41fa1f1d4605ecdf266a8adca197be84a95d5d83636d81eb4f59496d2a943433bc456d2019877b2efc731c9a7494b74d231d8ee2d3ecdea6d4cd5d18747486d0a7b0408c050723d4a6d6bb2abc63c05faf605cf03eb82068ece8a579d17f6c3d767b159be05eb414b7eb6f3623a84cb13814cde2d79b60b88c9eee893f53bf237521313ae28357f95fb8957c37a2d1a2d5b0efda89ae60ff9e1d68b43a74028784e7172a2ee8b47ef47b39529f94e484ace3dd580456e1f1a567fe207bdb36228fc6e22c9de4c75b00c87bbe0979815942aa8a524ab313e5a015e02f58514a651aa54de4628bb60b4892f6dbfe9059ac5218ff1448109b2a7fc1142370ce66d2389335c3717b0b074b41f24a3ac02e9f0d4e2033430991d81bf1cb3d2c24c18f92d033c2a0b26498b3e1a102b11dab56522a4e04fa6d5122e3e663f20e8323abff23e922cc493d480db50ff1bb7e3f12100c19325e542b8e9f65aab2f859aba2c3d272d7c409f12ac2b4e869e5735d25d635c10f5ca412948fb948b4ee9470228a7f88baae5a3c6b36c5b7a0beb69022ac8650fca09a2a88b92e9b52968d59a8be86eee706afb1834498fb0bfb1032f3ddc7030336f6b3fd1615623b42082730f66e4817c31adc8fe2cd1ce02446a370c5285233184556722ea27535c7a39d102b39d5224616cd3cf2b4c9d6bd732c2535c601f144cdaa7f6625b861f96936270e8e05544b5de440a7d34293d3c1649ee2b94e1da28de9d59a5e1e752f561a91b63e33d734655d93e3e8474de43e9fd21b082c682296c4e33ca9bf4171f5ca5cfd6eebadbc13ab7ed259837710e1aa8167d9d449da57dccdd0b9d184815bd1e66f833113e4d6428d8f552f23864ddb4fd2020461aa8854308ab4d4f17f17c2b2566673112ab813045f75f5a7b53c470dce66b282e06c7057bdead702ca23ad5574727ce718eec94fe8c69dd579a5f6089e5b176880f98a3f50c7171fa66f16de9ab7c3e6ae775d170dded8e62fde3ee89f59d6c7862e76a0f31dd41c385f542975b7d0aba48adcab569330ce0d8e1f94318335489f409bf11a14b69829f46dc54a0371225027dcba72d8c4eeb49f411d533a50007a8fee7ca1ab83eef12d15b0e82eda743b01553b4672144a121164ca48a78d8891b5bd290081aa9d84dcf30364b92592f147800465693408e7b352381d1a9d788166b44641fed08c1420b3e7cdeb36f0cc4aab99d2d94acfd9e4f1151d6730dda7c23ceadc56668736ff21a29e1f9de5222a6fbcb1a24b300360b35428747fcf3970346d9655ce086475947641561120e224e41a4964277fb568465d8bf0ae1c4f82f95cf940c72f7d865fbeea06ca344465ff5265b21ebdf9af22ba7c63dea76e6aa121009e6d7ef06480b818544a7fd578033fc827fb96357da2e49a67b64b20ee6c9c8b9d1bf875e150718de9443b92b52cdc9cfc0bb6868236897e43b3d7e31824ab3fc6d181262201bc85ab6509281376aa9c98f0f6c92440c5170baf135219f39298a341293d7d4989e1a1548f1b7ca67453cc41bdab1c70c9969c679c70b1864ab4e40174a2530d9ed3135417e63a8fe965de1b3e6f3b072c256415a385d22ea731047122694537262855c7b1237f32e19f2b537aae8e4a45402ab270c050d57973bb393258213f9686dc43fc82a08c9891c61fc229bbda8fc2d7bb258911496bde646ae217f2dbaba0707eba7e4f7272440a0506085e45963d212b570e0a9684b157a58c150581b5f458b2dcf445e0c8df41ef22b6bb4141cb95ba2dc8938905323305f2651d0cdeba796b9ea688260a45d0e684ffa525837103e67ddd0a1113422e1f5f7833779ccf91b0660ddd6085d94e138feb329069a0e69070bb2f27f0124c98968c023c5c5f9427d546c6fc19f6545596c2fbde3b2ac485cf9cfb27ea9c99aebe4236a1173bcfbac56ac85dd805a96caf94b81b0c9e0cd5a8de517e88260e1fbbb59f07946dff6d08db31999d182ecf6724141e94ce2ce6559dcf317de38287828bb9c1451af9ebc6019c25e814419a2f0763d5be84468db8584791c61f424e9c52fcca8d967d02b16ec10e29d4ed8d384a8ffa0bfe301205e6455ee798de14a562fe65d615b446bce63d88f06e2ee45ee49e87fdff83c3ccf159630431c31c4e4eff0eb83c6000f2dce07094afacb284a17ef2eaa52df9c0510a728e3907270f507bfe023600f187b8d84a8ab62c95cc143ce8545cab4aff640bc215052eed7b11c78ac144888e27049a740b91d0dd0991da6bba884540c2d44a313d7058d5ed9c8f6b1ff41fd3485b3124b06d00cdf256f620e004292c49bc8581a248f541a73185c8b0432841e97dd5ce6c786328812f40ff7f5f9e07c2a625430e98f4af66e15e3005de84fe1da5928713023c86c042357c83f22f25271f82ab1cc6614f229b23bb803bd4f1d3f24e23fd019b30c570eb73421e0923b7910e15076dd54e08dcf91f56ab7721d1d6c01c84ccccd5bbd58975aeedd5b52d9205b00ce67674e0fdda955e421fbc7065d71132f6ca35ee79262e4a5b5b4185f52bebbad82d555319f6bc7b919d5fe3012c5c7789080ae5d00ddc9f22460456d33a350c837f90a050c471fc1390038daa7e2629e496a511838f7cc4606dde0a1f58fd0251c310e28e003a060902ba1bb4f963319db6621b2164ead83ec4e47c990ffe3020ae255c1cb6b16773421b6f5eb6f7d488e36bd21dcbacb6435b6fefd8e09fbebd10c1a6b54b6ba977875244a9ffa4eea491834651aa2bcadc858da53be622d7da9993ad9e4b984ab887bcf06f2d991f30b9e9a8f11bfd9534e41b507a2d7452e0bcfe94eb3e8e5c50750f44d1df5dd9e754eeedd115392f70368c5c950bd081aea9c6d198b7a0c79503869a1fc149ef740aa97c94de69a28b28f449566c4e23e016721a6b3bd84422f28d36f5881edb61115a6c31ef5f2e4ee2d3135711ce1a164a09683949ca975072e1b1f492f8abaed120779bf375650f4285c5cb78f3821a49b6965c38c27e9d6446f2a7f0447de7342d07d61ace8c79a967a135edd5ead80878c451fafb21b9a84c823bd89d3331b56cc237f4fab401e194e5154b82b686929b08d4236491549f568daa1ccf2b0ea3e8ee73ba5760e34b7093a5867444be94440a9399b6a04200754d6fd44a3db7b8a3d245ae41f5f4fff4d390eb49274bd055b1ad899ec0518bfe492c2048318e08460441cfb9cae45bdb09527bea58e32428287153679a2c9b6df508560d4fbd38750406fe67ee3a1ab97eda2a3f3f059f12dd1d8da2f39a4e6d7e49571190e9aa8a9f093a40f10f35c64b5da72fc1e3808aa6000ee29ecc231d18a006fe8eb203cedde02f66c46977995797ae9615187922d1d6723f16e35ba639017334e9d992e1b3dc68278a6b36cefe0bab837c07af63f18405459c2d210aa2fbb0cd2090167907c27a0c230c9786048d176392acef4ff22a3fff48fb35c2cb324d375bdb2aebab18bf44b7ba52671eb33a0c25e6a1123fd329a40eeb4b7685eea885e9fce1f5a2582e630fe9dd35a5547b2bbd6546a594ac48a594141946b2577e31b1a78860ee89a56fe18c24da6b149c9a436225ebae21395e371c7e728dd9963310158b8927c7da97d75cd5afcf182c6d0034e07e8da5457c3e4f9b8b86acfb4a6323629414f09ec3b2e233a5498f01a543e10017a9c825a2a201098ad361e678c99cc6445c820dac609a05d13dfd9c9fbbd94012b9a239b6cfab35d8a9988bb594516f74ba30b43bd4a20a99f29f5ad561232c3bd4647f25faf0562479d7595ae2921a5a5462a8380dcbaaf7509e51d22a564c44f7621ce70538875f97bdc180949b93ebdf4d42c8cb8ec63c401145e121c690c0d0beffdc3e0fc16022f14e29cfda1ddbd543e02113a273cbe30853ec7de72510b2f9f4520c1233fae1f26625899e9679682b37016b9df3044d28f2d9b3262039b5fdf141d0c262e96dd9c9d513dcf9646935afca88f45e15cfad0ca44b315a804c806212209b50be7a6fc943df6dafddf3d7e2e34d57b290ee0d261fc4f60b7061259f0d8456007ffeaae4402b0dfbea0e0e722c1bc0b5776f9497253dc23ade308c5e93764ea6a57f4f444a3da0989d7c3779dec3cfb3929414a12a4cfad813b760cf8d7e3db2b81e23c3c6c1563a819c0f28cdc74a5d767f6109d52e97612db0ef2bb874678c4569829404e3fe12331cc5863307d37d1e9c064d20537b34a1596d6069d42c8556efe010f2e1d18a6092faeb56739d10f497894e1d02c83a4d74d217879e8a88318f8fdbfa3a764722b96d33fb28246e38b5515d08ba46866e070949de1b977e68f422e7849ba660f124f02dc4c369fa0ac8c3b939b07d9e19e8addd010e68a6add1024e17f88e610b5fa38c7a2876c04a83f1099314ede4fcf7d57127cb120bb433c362d4a6091a67d21fa783df68d00391815ba80e2798b331c6b47939a35cc6d4a2f405d3cbba5c6be75a0cd62b87519b6bc567b4be4b4ebfa588108b6339195a3880f97062b61d3a6994fdec27475f372b16958fae683b91f95b558f240e23a4eccb087d4d52fd3568e63ae22888bd2f40aba91d8b80d86d160c20f5c874310e8b43e9fd07c59aadc2a6084c2f51c657653bc39ec776d4df00877b11d00504b811fa827f5d26b27b03cb8b434500e5c8cc18dbb984613bd20e9d0259a1d4b1f2e4f7c468db50239c30456e5c8870faa60b1ece396cf76cc3cb39f172e66d516d68c33c90ba78c653c3c85383dc8a5b3307ec24e0d4f5a7cb616f4ee30389b82fa8b8ea726b32bdc08bc0016ada7b1b1a300d299d2325ce9d77561829b3211123815dc2ee2713031010591d6417bfd48b745ed8194b24fe1e1b67d26d6469a200ffddfa6ecfde2980256dadeb12fcb830d5d47e0478ce74351eb067e40ac3fb25565f00b373173e6547428b36369a697a944c514af595a4ecaea922f5a20d2857a48af8e28d73193d1eeb554d3a403c01c47e7d0bed9b8e1339a1cfe4b347a653722b3484ed2ab1ba5cf9635cd48c6f65a97a68d40f4b87d200caf4017c69c7b4c1c6128304acd32e4afbcb4eccd213c6940032dd3114e6824ff343dc08b34eb72bfcfb4fb58235227b3f79cd77685562ef7587f29132439d1c30a2c85e590b83f1a83bfd01b32f4e66d735c27027a1c208abe60c1a55a1a65371f00c508d4466ec4e98d479bf272819da0d60989524d3bd211e725d4400f03a146a2f468809cf404b640d2f69dfb021fce442d4839ddf6a75359927384288e4de7aec48675e8a9e8cafac7a8a36cc0ac1a2c9598dae8f77266453f60c1e3520317d105fc1150d1fb70305dbe7c7ad4e79c1d7325fbc1e8484f2a8640088e548063a3959e59692d07ff243642f0ed1641ef08ef68c4b80b5eb37c63ed4b6c4157d1cc74796329fa6928fc1108ff4851c049e79b9a34141375124ea6cd6eac3f6b8d736b3c370c8a78b91641991af87b0ea671b81a8fafe60b1d8dce49c8b79966c42f915d5cdfa375dad10c4029a74b6cf0137e6839b272030455fd571ccb0de1905f739559f7231fc2cf4a0f503ad91815f3bba8aae1ea6846730c8d8c3d737c2096ce9a428e1a0e93a7fdf83877ef6b602250f75aed32311c3ee35734e2fa90248937b47103e8ffeb49a9c19d65cdf54646b02118070f46f03639529e2138bfa207ad7e0a1ffb9b4e4089df58b5f14289635996c07c8771d4d1b071822d424961e4f0cfacc5de9c3a536dee1789bf819e18d2f1932404ba47993f74ccf06fdb327c6aa871e5b208e4dcb127155b6a9f51408fd9b0e617bf2cd706b0b80f9099472d7a039656d2a1e9e495c9a7212475251e23ee98f25c87cebadfce6e8298b71395a54e63836087b10c97a89c8c2b572927f513ec750f2c971b816e36003fb2b8930b34f0808af1323a28eaf67801004f550a495731713246d071f91da9dc2daf9a7b0fe88548aa62a1445aa6b7ffc93a5743879b35b23444da2e6149be041794ad7cdacf33485c7bf80702071f643f5c167dac740512a9d16e2e8c83f8c0151319e7f90a632addbd41e42e0127224f18de94abbcc1527f9084059480cd239d2dc33f0044ca50d2ae65da49bf24f776824f0e6be97e540ef065655c42fe069b1d0f56ccfe606147789be950b60cbf7d79197f327d9e6cbcf1e25e81dadd3372686f9c06ea54cbdec32062b7d29872c2b908b5497e48b545b0dc4c7244ae958dde4c794b072c89c3ab1d2ce73697e15341efba8654bef526cef5b8cdb1f107e346ba990c700c696af75654818d4cbc7506f374d8e88d929770af2a36ad96f42514929eef4beb8686305cf22a22c95759c71d4712af0dc2b8a605985bfceccf3ac638095ed5a9578a70aa796d3d1ad58131eab8eb66fb7b875af97f6167958e89d97447808528862a656572284c33480c6f3738010d06dd250088efbd1dce732ae81fe57f7eec91e5dc7e6dbf643313143e674bcb3c1a5db3e1a7c1f063ad89cb5dba7a43dad9dcb65521138e74373f5622a101ae142ef723d36c4d79f1a49155c394a70e7a726643fb8abbcc2762070b126268b39356b38efad7e2a6bd831a6a1a1a8efec26ea6f9e154049a476eeda6cb3023c5aa10f8d526e2e10c172a1acba591bb2356eb1c026df288afcf5342eab321491a2291974b9b32c7514007caa3cd5313de93840b0ecf032fd170ea93991340c4403ddf00b69deb2e2cc161497e4f2e00da33e53aec6238e355e359548d6e82e548487ee664840d71c1ef5fc70c0fff9f856850aeadaa9ac06a54ba656671de111217deb4cc50f68ba5604a50650f4b3378d00829838fc957ebcb2a2bc42c6e2d60d4c3d18fc511b4345a9d6eb28dd75d462e06f4accc2587f41072aab82a9cb14ad6dfb7d30599d33454c5dcfbc9f21502ce2ea05a459dc5bed2813131b8f5c77988dd72fc79218e1854a6084cb61bddfae63fa2ffa8b52fd145310d253648088459f15fd704c4cb7c4c7e97c31791eff10c27218c5ba25c0ce804c043d464bdd607eb16f2e71fd723ad2542bd790a797d0780ae5d610cbebe8e3d4c00ede13167b5dda3ced6d01a098f3973515c9fdcd1a2a717a5953a1dcdf02a05248afb52a20b931dc979bbc13ddd9ffcb5d1e72efb684a6cf5fd6543c7497b99cb4707f3ff0ce6b9b043119d3ab0a5524d797e40c3e756fde25b70efbd5897d58462938c54d8183611ef97594d6b7d8100c388943ebdd98a147e22ccd2a99e08449f3ab4cc440f52a043fd0a909ecdb939ae114d1a328bd23f230f7ea5e23deeeb9c4bdb92416b09f95d84faa68af474d62dfd1443cedc775964f2620f2ab8c069f8f111b3852a17e9e455e95b10efdeb9effaad8bbe2d0062d4ee9485bcc633f9cb8e2afd1a9dcae45d67c4cd5dc39a6f86a1d8a8f3420c3ddc2f7bba4e825f5a7f7ffeac5096280767ca3ed01ba771984235398aac64a4017751ca0aedf5bd582a636fff5fcafe76ff4c4091240bb1bffb2171eca474b47ef3f7ad87334f3c734810d81d66c04ee54cfef97265e6cee457b7987a631c20036dacd95f6451da9d81418bf4ea4dedef2afd7efcdfee6bfeecdf64379b1e39b6f83eb8d0c8e0bea0400ea560216609513530a59c0d29fdc595b3981653722d8d37940db0bb9774a999b66f6a3682d88e0c5e7287385a3f0ff6d3b6091e1c97be2011de621354974a2d9d7636587d0c5d3990e6f2e4caab1267e6eaa8a4195a53b565dec0d2a7542a64266e85cb1c6700b9cf02aa89284a3c97aecf7f8c8f963db0cd8ede12b4ee1e40cd71b2444315bc654a5d218cce8133a5622632ede0ff3b9bbf3a9b7a67d206fe6c7a5d8f219540455a32fcee5dd42a9915277ce9be5e3ed89df03d00a7f56f6161a9f3d0a1c841cd629ca9b640d99924be2e33dc8b30646fede2b35df13da7fdccd1f1e1d8e3e8218f87bf08719965f682ccfe0d91dba572f5ad720c4865b84d3eab53a1db0b7118af154a4c8c6569ca829b079fa5a627d3bb4dfdf81c0c3a350f8305020b47ecc0e5b2f8647a3901549b24f47fd5cc40ffcf5cb9a91e5584413a848b9612e1aaa836c353ce484e2a4387e7ce34224860b0025a4fcfeb4e3d9c584b30bb6c33174417f9f4ca20f7068f2cfe7df0c985818bb54556e0b36090f7013dc45f827ec6e73b50904821c994a27610c51b64020c75cacfa8da02f69e00adbaca3621a97dd796fd5c931cdff0517e5fb59add9fb8909a987c0ef52f4d470996dd85c3ca2e7d9765149b0e789426acc1a55f82e3abd32cec2f8e484d82f8f984b40ad2f16894693efc5b7c4d6f527562b17e692feb18062159f63fe94e79ea9b694906cc8e11adb3a65b6bf72bd6bb40a1375c0ca0916b745a2bfdf1c72b53cd4e3445f601f31b9f87115845c129941be550b65ebeabdeadbe164104a3a69b6aeaa419f54f1578f8fed84c79f2a45a7d6e32a8ab6ecb0d5dbceaa2af554f3f6149be659818c78d63f16dbaf3393acbf5deca42ad83d293727cb43c4b668ec396024ec4548f924bd16a306b8a695d20aab9bc5033cc32dbfb6a906bee5c59405efc1953c7ecad1cb147e0720a5614b2c26ca147bd704caa378b582ac57476c24f8ababe3a1cb169d39a50d9b1562327a22b9fdecc9841954b5c5c49a10fe1931009f2b5b55350510e33dce6a178814ca86732656ebc7cac4b2ab86459b3268470cde912c898f8a895dec3734a78a469ea8abd78f1d4b676dd7921fc294a1d054f598a241edd13e95ea9839776f85898b2e471a76a978a1765b0544a57e2a8d4473f995ca656a7a8367cf8131631973f46adf94f0066740637d5ca6b080ca3b4f6bc1ea3b2311dac6452bd555b7c9ac3e0292c9f70cac73826aeca9f1d513cc28824abe5d5e2fd63f46958dba25ee1d4c251d3d51db6653edc85a95191958e70454e33ab5bf94afe524768a937a70578bdea9bdac7cc7afb0d5bca13e47e643596d3409e3e03b7972a5379e4296f6438a10fd38b12439148d97f86f9359903c5d658e49ae9705187319194e46d8d32ac3db187939086ae8076773a6d0d24a3ff2577f457f9d5cd7baa8a5555af62fd49345d420dafd48062ac1024dded51173cc5e5d61dc24ae196d25f2034cd285fec6e6aa68a348a0a243dbeca9e3dd0f7c7ac82342a7c8784892023522136a56de70a724430e4ea77214948f0226cd75b110c16cc4fb1727237642a98ff6d024e69928b4d68d263109a020d76339d27333a08c274a1dae534c549757a401201d3443ee03536bd9960586a901cb445a4ceeb9e78806dc5ed2ad24045793ee652712562cade01743edb707df96ff78732551ccb30668b7eaee103fc8cc9bc2ae8e054a4f2ed53481e03727e3f641a609fc016c524604eec0ff810692e291942af70c2111786f69291ac85815f669a2ad5a793bdc280c0e396d9ad195c8db6e9fd186b47ff56662538d0a59c2cd4ab65fb7af24b0812e021a48283f8106c65fc1b9398bdba20e47fa821c07b94221cf9c63faf47a261aaf55af50e8e3978ad261750ed030c4b2332539a825bd7381a903a5d4dc6dbc0ee2729dc164568dce1ae1f3b89a10240b5131a0d2bd69e13f64462fe3a6fdfc17639ea840415a8064d78ee6c34e8490e85aba5e101f7e949b579483026f2a5c586ee5647c0aa0379f54398f2f4e602c3c51cb611e103713aa92c0aacfd955b2280dc1be96585485666f79918236c86854109e2ceac80eb86da3faf9dc1d085a66dffa75e7cf7b1e52af89b0e6a8730b6c1b948b56f25cc6ea6c74732440ed2085e5e31df38146810634bde6da1dfaa094b5a50bab7981f9ee7d0f4823dab2592a09f00de149ec79dcbe7a22fc56c1726e094cd4047e42db1231fa203273f2301512385bb376b65bb5c1857a2a81a96463e7d3c75f12441a0a21b569842ef630a3a54507ff632e16bb3054c34b4e761acdf742fab3b1399928e55de96e021b9510124c200a34fbff1450159c20c1fe3369a8609e2265c99bff444f0a4eb4241846bbacf1e8ded26261106f83ca64c9b50a3a573a660a562d93718b407e2cdda2586f316a2644469910144c8864ca4bf855b0330a8442939575f20db96c09cf3ba782ed2bee546d5098d72e0c3b8020a76a269d30e30416a046320bd5274e19084a6d3a2fbf085ce14d0668c9d44e98eb083481aa4b4dd442a3978d01f35b1e1ca68e9ee30a79ea6959ac953abb921c9608e71fc23c24c3489454ec47867246f8e2e37aa226211507f92d0d40b2ae74714ede18556b48495343aed328aebadf3d2e44a03c8077e5ccfc73913afe41cdb5518a467f178912d4be2f554cadfafee771fe23f669e522d1efecd1f551d220bb48eb1549f5dbd8e6228d5d9ef5cc85c4b5b5091ab111e4b64802f15a0f2f694aaf50b48a658f48404f80f9dedd48246e7cac8d8537dd979e81cad97bd4780c9cd6c3ec9017df4159029ab3f576ed83a57e902b77f7de3276dc1195df7ed1f976848d1e46eef19416b57654ac604080f152a20903a6788ea5ee49cf49cb255aad6809fca16edc561966f0023af5298a068dd5b4758d3118ac82e1b5d015d22a7185094db5c3b9eee6d538ac39976403eb600cb420055a7b7060749193fe222a0f20546daa0273ef00c0164b977102690256414a1ea7ab747150a518e1e05a1c7af569e2b63187acbf812b31113ac78c310fe890268fc1e5a1517aa849e0b5e05cc9a51b0b81088d89001d04e2d4af57dd718a81f575719ae0afe929286a8868fc2ee0ad3a240eaaf52bb9c841c6f509756923562c78f76816ea6b5c655e5b0efb9b7cacd5f0892ed8dcb76f2bff7b50003c3b39f3e3a579fc428679435673e7815efdf59735c0242243234236bf37c4a93aea8472fd7c5bd53252ad0f530ad57f265b3b84f39a591da6fe592db6742b1c942845c85dc7e6a858296a309acecb9dc0ef2164b6b8ca805a2e3e06e217341e9f2c327a627662548401ff895f85b6bded91d630e1f31fa3aa154f96d80af575bece692e33edeb6d912303792a450b4229408d33311de9369d0a53f730ed042ff0d315c1c5b23c0be266060947b3866a4d49e5d233f17dd0f158fbd0769f3603d6eb4c27fb7595ba40de27c4f72c435a67d8de56bb732df7cb2e845f9e396bec51c5f39b197f176fa9426e5bb60f624fdddfbc3cbabd8a283ab082c0eb4f168d8bc2920ea26ee279c3f6c32a18a9eeab19603c379590e3f3124c2350308919b8275fc8852e1a6a387b89f487c04496a69e4afdd0a83a5210c3e9d05c4c5dc6f200a5428acee36455c685f8e347ab4000fa093cf6509c542f33328a4b5d47320aff00a33ed210d55b0139d83c6252b4bb803f8aab83d8c3f157bd8c9c05cdbbcf18fe51f42ab116ac65c52c41011f827de0279563639713813ebed5b269cd09531797439489d0e7719df439327086b88f2d8482f175210df36472bcb23d2fd3bfb6667b9b17ab40847a852e0eef0836a2339a88341757ef3a816b57c891fb2db2e1bc6b258ce1ecf0db8cd71fcaf6c80b73543b0ea45cfed282992e2ee891966d6e8ddc0b69ab784fc80f81a049ff5100cfa617894959a208a380bf570b6fe88c6ee110455309bfda5708165719c10e16df67b2f428235ac88cd4c99529b0974e5f4610870d394edfd713658cec7905e7a0b254cb0e05d6af120028318ceaf6c1fe4cd31fbe60ce1b83e9efa2dc25055a906da73daa003045a1a01abce0d8bd1fd7e1d10094c2df9f316ec70bb460aa9492a58e61f821559276f0347f167e80ebaf73456caa0bc4eb3babe68f97b528c85ebfa135828b7d2803c7f45990c5f0228794aa0376cc6ca2e6e0aa5415fe77773dbe1d736567a1eeb6f1ea2313e8832535ec21b973635f9c85fd9f30256027761947f0d1d98d0ce9a4298bf6763dff263ce6b1ac69a853210847112832b7e25564414a9ddd70e0801d65f4baf855a6b3d4b10ed1f5812caf697c9586828d572e767fa2ceaa7ec64d519f8788a8856053db456f06dbc9265aea8b7fcc7ba564191cd3b0232d156213a687178655b66ea34d69e00e85e80797a7b00fed36a478e643c4f920bbfb259b626028b0c0a05436561f8cb29523b135659809864b48fc9852c1a8fae7af02b1445e65f51d2e18aa87d2015f27420bc8f03c271fc70fcc89fc8d69ae480b4501fdb0e2c34eddfc310f07387f2f35c80f10a296735bc6b70726ade9355cb0d7824ba0e225c8158102462ec466f6ee15aaf4f0826116e56fc8e58ac0d93f62a8209ebaf34427725cc85b7e5c5683a2c7d0541433a7b48f9e90c9e93aeb4717f4bd8079758a5e0f8f67f184c40c27af720640ba79769513fe7f189400d75d69243459e4082a32da3f9138bf22051c80d3535f8565f9c1afb64398dc0bcc72e3499576f6995e4aa8c4c27e6f5de94290f759315efab1f9c17dc60773de757f6899be699f931329ee04a36a776088af0b7ac3f2ed6900ab155bf8f428e786b672bf6bd202383936e8436f8aa0706a86ef32235dc23a7815348fef6079fd06534c9494372e2c818b4546fa4738897749edd3f8cd0178d337191b0346fac14401d47fe095048fbb1c48cb47620965eb57867a60f17d201501e32d6ea563bf080e33424af284d0fee82d546d104971c43865fd88cd3f3a0854181af7a2b390013d139453601a2df6f59926cd2ec03605ae4985c740ad1d16ae1fe741344f112e263d036bb6e2b6cf31c46dcb02ab3cc30b64f2da88e3e3a26c2c050dc3183f5d452cb81147453683ee119214d650389d13077eefa80b8d47612ba9d4183b072a60faf6cb6e0ed105d95de5f707857082e281d607e71002861196317527356c034b4f718d71130040864454f8c3af86fcec3a8bc0116f0341f3781a6158db02c62fc8df97631aba07ead233d06232321a4c8354803af67b60ce699615c2d5d5412d26024711e15129842f7f1113fbdd7df55ba1fa3a90e0d0d577b40aa1352d2c73397ad4fc6073b905254caa144cb89ec4f35c36d7f68526a206b8fe80871baa350b991e0480298a3bce9dcd4405402092770b644946cf941d48609f59d2ae9b141c462607682450df3dad0cc93f10760178c23003e254c4d204d9de88cd20d4862ad2327a6d6631c2507e286806aae6bd109976900b01edc97719c17aac207fa698776064a8940fec2b4d87701f2633831e714b2014c0a077abb4b2d225ffc46415779afbd7bcb68f8d6d88958190d4a7a0808a68a64e140f330c9740ed275cb1291a0d35444b7615a72f1168df1f93a6d9985fc50e1ab66f02d263f88ec3fb5d07e114db656c5a73412d9955629fb1072e34a24cc79741abfc043a70bddcf93b186b99cab3947efc7122115540bae86601ee4b7e8c3b4c16d6568ba349aacccb173b312084ed593cbc46d84e9eabc6ef265dccc94bacdee42518e79556e5ced649727ac21f2e8941fc5494fe5089fe431f6448856094581fe2b8707802123a254aebb5a98467705c1f0f934dc9d5ca8dd1045bb78470925f340da7a83bc39e43dc95d54c7ab14e244f8766902818f1ea346549fc548700d035da23ddc5569fae8957c8eb3d272c907c493c8a1768cf6cf87f525050986eadb6842671c6702bdee12b610387c706b01eda3978928a94d333c4d92073fabeddad9b8dec480b8ed06e26bb157a4d0e887076145b64d866378b8a2e205004885ed2840204297700d516fcd8c4530af887834233cc438fac533434dbc6ca954dc9670345ee2ae8243bdb9ffdc99f2efe1889da5cdf140a6a302a6590a90568f85749de91755158867819af5d1b9d8d656f1c5447f526eef9b684c69a17b2dd86c14bc992011d6a505fb4963e2e4b2097377fc6cb490d5ac0a6befd07087c956ce1437fbdf034b48ae2cb453ac5b0390745a8e60d19810fb95f9edd4ef679736ab7cb7d52df93fb69fb63ddbf9475687b3a3aa0502b279d61205514b10e8e3c22067ca4f53a9a52912281d5b42ed50ee745cac33beafd6cad30b1c55bd755b0f6dc4e2869019f0c5ffa5bfd8309d807a0d7c50dd043717cce9bd53ab23780d90ce96b042cb7f667d0d2149a79e7dab478989246a87a5859abd5d909c36f43e3a641936ce6765abdc4822280330eaf382cd6cbce6af39865bd36e8a1760d51e1fc727d98acb861e161ea6934407f561dfd06a4d8d2b151d3ed9231efa004518715cb92976d2a92a0b7629275ddb2adf99864d15631fad7e034ca8985fa1a6c1abac4be1f0d4c979c58aa99d1616e22d1ff401a9229724e3fc115230356373ebd2c0bc3b3fc352ceb3e8d187b37d650f4e9659d8a876ed8efe52e4f45d78778cbc32044b0be8b77ca107abdb712cc83d03dddbb4e906230e497d52a34ba675e4bead00dfff213eecafb95fe4be48d78f89900ca84b4ceebfb0480d4c19b1d98334d68cc56d8f0c08c0db5c3dea33de9c73107cdd8e0522a3781856eef151186a4ac4ac76bcc16c51e6c20d0298106d97bb3bc957f20524e6ba317e7bc10e9f1877c33d2ff75caf4c3538b008358f7ebfa1f5ca7ba176958ddd92dd7223957a561063448885f2cf25401b8ab8df33d12df0ba55d988ae8be7b5956a839b938586c0335ee66cee64281ee04dda92c260ca6770a31efff1aa842009d6469068b73053225f3da13deb3ced653635fbb26cb077c32611cf320040879f50e02b4e40140f68563a8dddea80bd17f51e3dfc11d56f5b152f457548f1b833b78758b231a09115316cee0efe4edba11482be86b8886d9bda6f079827c6941817a761c801974d5d0dfae50cc8a6a538c9363c624f1426edaf8428fdea0b056b510d358a83d9fbde6ac0bccf84d8bbbe74a4d10def9d3050237a42ad62775a0decc28ed3f57c90b446bc4a8e4bb88d096ec271080484b762516a59178c8908ceb3c5664f166be0e073c3cadc2dfa38521828523ad8915d8416c4a4bbce794844755531faf5cadf449b636085f0f5917bd616bd36b52d38a869691e280035356b909957aa1589b1bc86fa937244bd46d14ad9e92b788c46fa38f954e813d79500ecdb4fee947194367a482f338402e4b3faaae0d6f803c240e08473def478a2cd16029ae0cebc2e5e4e2819aef178f9dd601c8351bcdfcc0d2d077480c8df13d20fbc6ae202805a7e106204c45044bbe481c7f28faded83630e432b5821e83c644583f195ed8f1edab4a1f1a0e183ccd7e832c5e6793dba84e6d0b98410bfc1169079eecf04c7a58a9b9f26929e990b7fbbb46bcd39d90e61853cdd01c9799d2caec85595f5959afcedf140e46da5042a2fb5f2b7946bb51cd5292f95ed13027efaccd753092c5896ee3deaa85b3546b6346dae5d702f286c3888c8369266460638824db4dbb7f62ccf8fad5b1d1d37afd114fa815458f77f68d1b2d8a84df5642655c6860e883992c18f77b22aa1f56e7fdc4e7d4b2195273f825a3cfb8a0c06219015a6eec26983b8bc17ec0a9294f4cd7a79aa16d59464960f4a57bcf2a2cc8cebc9b11be172bf78d8de2e6f7fdc5c059984c8813c103b11b8a12e60a6df07d5d0955f0fd0c0aca270ee3472926f566f07ea4023f1a76a15828f2f7154b7030102ef35d10770ef5f35a523361129e0ee7a225f70b7fef601dbbc72829b48bf0a40f564c02f07c1efc1baeda74b95c0a6f1176a8e5a7e21d61a7ff9bc23b360ab72ec7c70c9864570050f30193de52c63078a351b603181f8efb75648be3cec4f85dadf200b33743b4c5429fb1ab51169bdd521cb762e63c2a30f7aaa77ab7bc15eb3579d0efbb8493e68c954efa966807a4914e6b3f698b0031f07371f47dc21c857633152957846232a5f2bfd9d6c44b441b74d92c310c19469253800c362444093d06b3e5e00b193d806b6cee20903da379eebe446e19de7f846d79b089a893039f084b49f6504d393a091978e12e37a12637c97ecbd992d2d7899345b91f4ac413cde22e51d539a1323546bea32f9755ff9b7581a4ccab34bb649e0446cdfd178abc0803887eefe3ffa71697604c2a9426bf61a94f663bf4bef5883b8bc14dc6eda673de51ac04acdb29d5a5535f9d74a6d2bf86d79f3d1f78feffb9045494126a9717245e2a527ea598ddc217e42f439f9527fa2342384584a4f818c53f4365a2ccfa6c6b32e78d994cae8598fd4e06e917c94c87fe54813b17028eec8341d9e734a2c6b8f378ae1418a8b6e82f841ea6d89b8c5f5b31ba9f7f9c32c74ea845e6279db3cd4b56a7b8eac54de2ae20c2ffcb63c1e75413946490357973d6eb985d1cdd8683c8b230d7d98d99c30eff4d45537b2cb896e9709a94059c1ffc1dfd5d4bb704aa0cfd1c830ad1f196823943f627b5e365f65d6a5de073e50dda934cdfb184ad1c656f35142d320cc7d089550149acc944f0453e4a9bb0e840036d6516288c1461fcbcecde789af83540bf9e7ebf8a20cc51879e9c41b8c59b275b7cde0aaf83974888d6be12063fff5de9ead265adc1d61979a01d076465ad1861b4768144d007ff4d1230b62dac34cc95b538d7c4e2635ad88dce6f4f9dcd02abaaaaf5db453922b2b034d14ac4ed3150f964989d78355826ceef4c39da3b62374f7030ad889c040649df169303adb748dd7c4c418f2a4fbd0e9ddc63fa61799ab86bae0d3dc9fbb2c8983ec31e48bfdd1aa3bb0ccb72899dca2be1c203d25f187590bfa55d58d1168690e7794257096105e7da7e1a8c716199b534807ce001f08f1a5066644965e4959d5f8653c34ee2355f471b828397538b066f0077512bd8faff085d58ab43a14ecaa5c3aefc05d5daac6504e248febbb6cb27832e33dd575fa237478fb44e73fd64f11b3973f15659ad7477a714a4350df49654b3d05f4f9cdbee8af3d55684449798bb97a27b98ff1a1045b89331691de45ae4cbf57bbc07a1752df6d1d4b8daa56dc0384d0a4fa697c2c60fafe44f2c518fd83fac81ddaf2cf8412fecb5bebdb28b6b34085fd42c3aee265f2b4d04bb53a665342914d9081308f00870224142a9c42ecefc873de184243d59dddbdd31f3c5c98dd1a69840c938b6b080ca175f76c63a82b0ae3ca0ca95d4f9456d8d03af776ed5f719bb140a6e761839265711a99d5db64247e8bded60dd2bf3c1f86c1e11a7ed7b0617b1a284afe471973aa0a93102f322c80c82294b174457d2dd28a2fb30b2006ba7355a59b57f3812c2a0c0a6faac7685336181dca29e3b4f71baacb0efc385d101770114511d9f1e731096d65df32756521e9bf7444cc45b160380232846b2ebd7f520fcf7503bc328a4ee165ddcaadb6acb06676621045f0c63eca8d36f3fa0969d324c5c1e1de0b943abf6c9b8aa2213c96e8d4806f17013efff67411d43e1a71179634362ce381320dc17f79fff5750e47d51670efe44339f8004be7a969c2fea2e3c5433d44c9e0a967e4bbad32b852ef20e5b4e6411afed6f5d06369beb935c3bf896c5bd2b0fe479306ee8f693541b6037f230e202078e192fd4a483b03cda8705ec96f56fbf3dfffce36c6a3f8f49d700c4703ab64a069ed610bffd28441c4239620b33e284cf15e6810c09db65c82b5ae26efcff9f332c7b76004e79566fc7b791f20d115d2928dd6c9fbd063bf9fb7b37ab43eb5aba45f6d0685b240a580e8d376f06c381e94c4f84d2a34792dbd1c399c6f8188975ece66c435b090e36837534399c1514b47aa2985b35d554df681267fc18bf3613dfbb99bea0e5586a46f526ba90116ba94000864718859257600e3dee827c9d30fc4446051cef8eaad1371502803c71209741768884193bda7eb9fba46af2ef08c1fc3c997aa8afd7a0ff98089d3ff00b68082d42938f0356bf0877ac91e64f9398b6a56a3e00a6ff07990adb9b784db4ebc90e1541adeb3d563be612e362248fb87e1e1d84949b0b7faa1588dc22d1ea911bc04e1dcc9f99e6ab83086e6badad288d9b97506bfdff4fe48619937f76873694145ca65af2964d38c14c8f3a777db482e4ff703a10a2edac4f74cee042debb1d1c00af464cf18b59e95d4ad26058e8a4cfbfbc5575fde13156b8e56c4d702251c096a95c50bb3dd01bcdea4d18a65a7b003cde36a213c649f9b37037dc08b07d65da1cd5486974867cc5b3a3a668d9a34eeab7f8bb74df75e53c8216414d1bcea2f3ff0c2b16bc0c219e9e146caf6aa06baf33169e1610b7d4e351cfa7bc5af6df1944efcbaaf624926e53b66601dfea26d00b0d15a0a8ef3f24ec63fb4c8bd369070d718d82d0cda09194afa3947b434388c48ba5543f50f3fb270ab83fe7b4d8048db736cb5d0732a0cca13f2360f3933f28441a4796cd8dd6b0eea03e77adb501242fa25e07cdef854b0e7d5651b830b74b1a75e8155794c31bc5d290c19dd44b18d671eb290b387e257c7315f4d8b46a3c0a87339502ab1819dda9aa9132d45ef00e78f0e957e59a7573f898fb94a36f8903556e88cd460a7c5674f2ea434ddc1d3fc519dbb67241e7439c592dda99a11694e1a7f19b8871ef6608c148bb54a878a23928f36fcf910ea0a4cee08349a046737db72591198547fbec06057c175b59c6b76b99c472a2ed52afa6431908fe6c81e51b97830e6e247123605338ec937025c08ff6c313d81037b21e82dbb3156703edc4f2491757db34b47a97c0f5fa78035efc6680bed550715751ca35815b17bc12c50a2fb5c7eb300de453a38eddd50d30ae1da77d1191923525b8ca28a3a2714139a4765f285c831f447460b2b6d3c38aee3567adc0003334ea1fb1ecc80f5f71266319d4bf612e71f4daba8c47edce5c88a33b6a77bc30677a50ba48ade925445dcd09a32b14e5789fe967fc614d8c9d5c7aa84b0090a64c45b553476f45ad37183bf94a395115b010567572975d56ace270007a218351fdd7b85762e6be87523596bebeeb65c7be1293c973c27824e751323c6ab2b382d8a7c54a72ab4ab090482ea133287cb76069014903efcbd55ac220288b6f8b1a08c6a99b329b3bb4edd791a98d3b0e63681fad14132f089fe34ec668044e0803cf06535c044e42f48c8b9b7ba3070f89de8310df3131a98bf9fed457279cd81e4f3852d3838c203e438ae60bba15d5a7e57da7dc42c3afd0e45296cd4b9ad3e110f47957f4e7e1703b8ed00c4350f1ea1094a83fcef3e43e3f4e3b49067d66b0bebc4721d7a61d6e1a0888629110abab2d15810c346dbe4f9a32ddb55791bac674d6572c473554dc8689957d4cd7cbe4f54016560d73415f30bd86cf19e23fe99d1d990c568f99ce25d5f00a33d10e6166afa5520afeea8098b34c86ca9d7b0bad45fb09e606ecf1041940abcba3a50e5c519ab6c9c93ad8759c9113c951c4671d09085a0f04f1dea5770cfefb8bb54c4822a86dd95d10ae02924ac5d2d92dc5a7d2c6b10b5943c71d61a0bb5ec05de2466afa15c02e7740da8c5295713a923608eae3d63202fe4303d3f1a5354efe720673b1a9846f3fbfd4cbd1d2664c4703b57e483f1252547d7a1638501e19a6f233a51e6c4c01dad3825f7d46357d9c3a7b2af04a8ba25c29c57f24fe0426aab8c7062ef2afc1da91111561f3c28840c87494d1441088d8f2b82014837f1bc57b8681f0d69dff76ca2f3a03a63c8472d6fc312c4a96f2d6680913bad1fd834a30bd7205c9e88f87dffe95ac3fdefb2a34d8ef72895f78004f123b595bcc6a482337b2da51d015cd0d9265d27291866cc360b8a213eac4a71f95868f131ead3be6cc45235509485a9f64f8d20323170c7553b6b0f129927267bd719fe265ca93dee3367bb644d9d1dea2c1c4acbe0d62bbb94b4cc2d2d435dba61a2a6465b0855424bc7d4a86da0abcdeadc8094e45d3e9a3767decb53701d085c9393fd20365a242a32ebfea0c01c28595a9abbaa65e3493233ffd599bc15937bffa9c0d2511e9e94b1b912162d02855fd8af9e5356bb80a0ad39a896aa232e99e9126c2f024913d5bb1cd3d363afce34a18396d51586ab9cb2f780578f445ba6f23b40bc1293704c58baed4918660e582599f0dfa1fa61bdd51fc68f4c91fe6f500104781f60cb8eca54265e6428a17aae212690b4e16d44340358a2db15e60dab3950b6b9b76ecaea2226a651d683035269656326c2287b4de5757e6608a2ecc381b6efbee5d65de8ec50526b70f7d82333d13fce525133f03d1d43f830aae047b7952257fed9004f54b8187abebbb544a65671b40c374dafab463c6481a26c11b4269072f3283a8aa6b59062e5127d84a230f3092ca632859eb952917a72951c97e52fb22aad8ba1521ae4f0c1272b1d24c7b44a29ee574d242ff97d869d1e19fe112022614f114be6087c020edf545b2f4dcbfe42fc6de34686b26337ff6971a23d57bc9680a76821f1969229e170122778eb401a2195cf976a15fe4c07319b0afeedaeffd7ed93e70914cc5d321f22fcc0e2c48497b78400dcd398671f34f20cb75b4290e642a0e6820b00a97cda989dd657ce5aab55ada13926e63dc59c0539d8c92e6c43561196113421aa1a5250b303e0f62789be75ef4562cf0c1be326f7f9f27fc7ce6065683ea3d4c7dc88424d83925f6bb4f73bb1ea84f532889e739b4ba67384983feb3405056535f9c59ae4d72db53db8a0ee01ec2cac203560d8712d533e09be917dccafecb2ab568e7b0c919fea1a91ad73b79dafc8c7885c704aaa1e38b7d7617b86bdbc027af569f846e1ec69f567c3a24b921110078265e18da3375b6501b6616186064baf3da052c65eaabd54b3f7766abf3a96463589d3539c0b7abb85cbe7df47069e3329ae202604ddab8081864bc3d30c3b80620f4a79bfaf80aa5d5631368e70121a5063164d7287aa7c3b41e2fdf60fce88eb457fa21fdd8774d641b6451b253e9dad8c4cd374579f52f0222a2b108fc8a92fe3f65b7fe0668fe38b61091947684f136dacaa560ee17b9d84e1519ec4f6cafc19a0770e574438b2758bdeaad5b15ca2d45da420b1c9faaf92b81124e911ccf4793f1a1aeceeaa120bebf70833f50b39cdaf8250c1ceea15fcf4ac31ff38431bfb16fe4ea0b032251cc93c9ffadc25e74c234be8accebabc8913d69a650334723e8ff84a27ad643d678256ff743bdafc6e1968632654b2709514266d1f8ae5738c5b80fcc9ff2760c5e564b212020afc86c21681bf2bc76e773a56b4690ec579c48968e2b6c1237604c02e108022a0b969bf8b322bfa7490b22f683c3e2b12dedfa97758b5592c19ed5118ae954b75531c9ed9490811a967bb3c73098bd9e7245e0c1a8c229827ac5ccec06a73db538312ebb040d0ad6c7cfd17eb3d684b4f6bf1ef46ea160ad029d9e3791b000b003910b8607e8d0cda91072a4e0a430117e2c9bf590d2915f9844d76cd58010decb5ac692ff75dc31e860ce179c1eb667113d7bd835caa63fb631819cdffaf125767cf0d350a5c211d82cc49f54ea268ec1de773f1d533760da191c28aa8a16cb9861d02f8c90baef8e016f1ae30071b5972da8d1b452079b9dc1ed2da6410e30c21dbe0f4e8fc0449e4fd56486dff6d3f9f6a89bff2a4e1a22a9a4e0174df3df3f6e52f8d774a042b98f9f5816fdac0ef6b2e3944cb9e77681582a95bb42086387b001c9c862c2dbab6d08c8b9be63483efaa498f8f9b0be161949c2f1e1a7b13d328c673368a9cf68c49b7698fd26ab5a8292c2582aaf123190d66b1502aac8f9ef3c0809d8730c69fa656b88f001492e53cf7b81744c1b8e63a49cea50123b44371d435e508e8bd80bafc42d1813525a460fcd866e98db6a0ebccc5b285d245edf06a72307c16d320e7bfdbdc2ed44416b9dc49f89cd86fa8a7f72d65e006c1d28b0b77db7642de1dfa1b530ad3cbef62b385cbc1c88e1a3ba71425120dec7d8f2ec2c4930dbb92253e1b9ab0d760f70a313695eb3dabb9d4718d398a37e568d5ed6a3b95a3f0b7f4a66b55c0dc286b3f64776785c859c5c55b1537a8751d371999c895eff104e212dea745d4d7094153c5f09aaa3c235fe9ee49f36f37f2e276fa9516b16b12b23e7155ba057661137144c128c67dd86c8963ba090201fc81661be477cbf3d0892179b3012150ab27c72291ad87dd0601ebb59b934385d29634e07f582ca0fcdad424d0ca091837f22caa2454a84d0e0dcb31192a1405106221cc4704ae197357db9172add3e010cf4dec0df047555a7d6d0901b4f26c9d7dc2d1f7041730bf2ed5a2783279c0b99b6a14ac774fd77a6d2a987c3869bb8ad1fedb24b632ef85d611438a24cea1327106ed851fcbce29481e8210796bb48016afffc43ba00c004ba6b60a3935e6ae5bebfe32180702d1dd633de637fcdad74680e9b6ff3e247c8176155df7ed1e69fd5d8c21925783dec7e3f984281321d8511bff344cca0a3b039a367fb5b0d98946d82d50ea248fa5894807034229ca31aa5ded468c3b273c8d21f4f615c7280096c9c09350f1cec072de3d711ad72c1f8d3e3ffd75ad038b69e2febf86991f6011cf31c827393eb04ef38e3a3e119da0e0c75f7478d07029f339fdb478e280a1859c1ca2cd690a6db35226d63e4718d37fe4219f96c31e32c60b966f51b597737bc555eddf6bf0dac567b533fa1bcbd5aa14d2d276fa7afd0054c047e163766437418b1db874332be201508e89404499fd6b25f3a4a7e9a538641f4c94e998f2a9d96fce744913aa951956eaaafd5920012ac1f800db1246cc5b2f9c83e3dec87844d805f0e2a70f005266357a17435381e88d1e12a620b04a4009a96763e9655aa9e155ceda9b66bb231fbee17a4a64034934caab239cef3a7993aa8d24529ccb9f56c60c3289330e6409109f7fb15ad0c310c851ab8bd156b4ad88bbceaf320df96d94274821ff39e51127a276e856f7fe5a6de92413942f50d99b5ee8cb45c88d52dbb3d428f123b186a74986306e255578609ec739f033efcc962e9894f7484316fa286df560c623d1969a57108e067c8ea1faf48a01981cb07965a46f33a48fc85538cb7150196222737f80bdecadb6c156701ba06456c1ff3347236fdc2cc8f23f1f640e807f010e442c30af01cd45497f206e0837510e5f30b12432843bbb350727e405ebd30f565f7202a4722870a5ac34d02d952176179682783231c093cdf277575a4444632807d5256d36091651c528fae7b07b670c7503cfaffdd4bef14d02410d57112c3cf608e73adccd8f62468110b335ed3ef8fc825fadcaca8e914d4e41b574452d1474ea36c8919012d52d65f3bf074000f830ac3e5b1b62c4c63faf2a2068682d4ff242e100ce1b26379ae1622d806c314091b8f4d5550d2e4665905e841bcec4131a0041857c5a319944b49f5683e08bd4cf6958068de99b6d7d64e2fcb43a11a2d2dafa4daf4db1b84a18fbec67c745b672a046d071f20520a27f80400dd7cbef73d78c871444cb2b28545bb7bfba9c302d1b3532deb0eebeaf670828ced338961255dc126289ed2d5b971c5d5bba1a1965e4a0ab8c702848b72447a4cc4fbcaa3a72f81d0b4bf26e80d558abbc04c5dc9fd1c7afe5674daf8725ec7ca798c4b8eb1ba1daeba4eab327f0aaf1427a9842d93b1b97aef12a9e7c1d4b02c5b43254a296c095b3eccb72c13ce3a63e25908296dc0f218cc2496003c7d3c8464459964c86ac5a07d7a3211a3cf78677dd0fe9f2d1640bbd15b921715bef20495f70ec9c923113b44d371c71c5fb10daea8c43b3569de896df111a79311372df3766924338203a1b296c85a20f12487cba596298f42c5aa966251161ea9752aa726663023751b01688e19fe9890ec615498e5ad8c8ec52936ec5127ceea00ad14be37992dd259bd2ad497e1015a9d8cbaddb97280e5198b7446a1a4ec41ce218d069ad46ad3a4ed82659ebb0cfc903afd3ef0a44e07ad1c5e37d1d1d9e020f2617510ad91fdf9e233c1601c68b25ceb1c205835d63a7ae2b855350f6304b95c5b5797182d9a9bb5b9f7a3d5bbcce0a183f2e15e783051b91f2bf5a2dbd0ab53f6df86d2988586c33deef07d4249d3c06a38c7f8af02e1317c933f1c1ec319293c22f14e497fb4e53361709213f9cbd6bba65254c934822a713c7ca34f34d2bc03a500546e42b28f6209d7800bd4d6f943e1da184a3a1c78c203f3be02bc4f48b49fa04b52846d66f009d6e60793340a4163c13a151f7525843ac4288bc4e8863296f5c667325cbceedeeac4ffb80d030f49ba7c5d4549edb78ac614e45e2129171b0e8f38f4d1cf4d3b57b53edc587bd40a42738f64f559bd158116604fc01428a7f054bcba1cafa12a0e79d648785f168d051787e32fbf22513db92ae15be65bd10cde664bb375307e6edeba12795acbd752da68f758065a7cb938511c47e9d7e028cc3a3f55c820abc95e12950e97eba8b41a3416e6437d0c7c35cd60f52712e788842f4866159596f81b10f89cba085bb7d006bcb71e23306753c0e47fa01f1e561e00a5bd14f82e2b2baf3403df749b8531f61470f4f432825d96c3598670db12828a2d5db695c63a47f420a04a07690ff8a9257687320b6b13ded6b07196a375f7d835b856ac26a7ad3dc71504767db882528838677c07615da721ee9ab45e953f698bf2c52c1d2c479948f9b1591048738d563f6d1593d314a62c36db348eba39007ae91b39ded8c84bd168a2a5d15f7857e9c734fb76dd52e07a8cfd59317bcb2af0c52bf2818a6561d189a04afe1e145ffdc06c6299d89b56cfbec614372d494ef8ab095205c09a7460f17c48495242d18afaa5b0d06e14033fb78594c051378a7d12ec02ca260cbc60cc2b05e4e514c9e8f52f8aef6bf452015ba48eaede0b466b58a0b939105ff58fc325a33a07ee7d0706fdd022b6156c0d58447755632610f33b3319209b65427118fb2b29f96967fce2abe4d0a086a5caf1d113cf4139f74abeec457764413280c66f4e9c60753f6e75ff6c9b15c5023753e73360ff4c3a59898b2109be4e88005089e814a603b0df99cfa47488425592ca5657170834d98cadb8c262e48129aac8fbb4c062564da8f1f34cb86477d756c2ece19c2309e96540b9252f7ec95e6821138d2858816dbf4f922764ff8827dbb9e5d6080b83ab0a09e282557e6db43b0ee9d4b8258dff8e205e720dcf42e848ba4f007b474429ff118aff83d66705287522675ae42e3f1419c47904e168ea4394e906015d582c86ce854f326e4bc0eae4003c5f7f5e54a7fbcbb3a06e080f5a310cd75ccca16eb1512e7335722e217a4b106a986ef60323a757e75c816b4f31ab1a4e2af356b719c0be72c930c9cea52a409b018eedca933f3d85888e71860e0416e910580e72d18e39a26531c4ee03c864b19df1da41f88a6bcb45ca6d82ca3c393a0edc7de9d0000d7ba82f6b6bcea2d930d89eb574bb5a49211597ed75dd297ae5b9dd60df90365b3ac95a21d50631367b603f3d43e661ce70e6b179afec0d9db337e10b5b9dfd2892b1230750f86a651a7113aed7d5ac02e1fe459345c2cc74d4bfafef3322564fe51133862b573f8ac91162ed8806bd79f9eb9557d8db5f41195f522f5ad119b08a809db818506c152eedcb8e0b0867016a9d407f8e44ed80fcb34303ec674743e1672706d567c78694cff382f7105f0b426f8d0954f5a19eaa8fb58c6188eb082ba57f7ca14e089c02a1c8564e40e7d17a0e0de61cbccee634cb87209879e60c69149a981e8aff1d6a133d240592cb34e520b78118a419a21da26c45db52729848457b094dff8c0fc469761fdf6cc1e9033afb6b45600622a098d727bc9f8b049d2bfac2baa5de7e9e1feb25f4dd434c6938b7b10b13fa4e9ddb42ba973ca142e0b0ae9f1799740f376b042764e96856106bbd02c88cf89af086e175dacc3a49cec6c95b1e53d94f2f6314b26dba2ab6baabf6d682086da7ab69001cc7f82f2dcf169e3e8e2b90c28b40f44cdd7b9e9af68d7b4cfdaa08950b51795cd969434eb24a6ba33fa3696da01631214aacf2edc8587174a9d424fac8d012965a16a954f31ada5161449c153a8f127c4ae59fb2b94ead26fef6a66a9122b22f1c863e6296667e34d33c4ef1022ce34e054ca9cd00a423d95911afe57b01848a1287eecdb0766b32e695ef765940ad7ed6358bf7a279beae4e0dd155ad9a31009219dcc56001f677686ca934f518d04a2b7735f69ea13d22eeab33789b17ce940476bb047afacd8e9ca31ad30c4ded917912860cca9eaa8442632fa29e3c7248135d43efa62b3602e0b8be6478e01c9a64536dc19acaaa1b4a19bfd0c3875e2cecd4dcc5b7c7c60e71e11b34c2582ac7f51387d02ebe27751819a2156f48925dd4bd7fc5d7446812cf849a3d6c72df7fd6c3457f4d95ae456d4915b9ed9c787a280df9b1a5aa7d8d72a7665e2ec6d3262dc40976ff9adca0c01c33ee03be17377e8027491f54e4f1a76d1be54771056443e40b2829818267d1189f854375ea4ace01645bbf656a454589bab0c009f7f3e4c6a6f0d30d4e3c32b1eda056564822419fe4613a946840e70c4b323fea4f1a023fccf925207810acf6dddb538e15c7cdf66490b0440c198494fcd2c31aa23f8a889c0190c0b3f233369d720d24a13564803e6778cf010549bbe64c55af8af681e6ad7ebebea7506dd418bc0f5181abeebf08cce0b707d129919993f0d11d26b0a1eebec7edafc4169f9260941c995fb5e4f5c38bc5d48590d5b49507708c34f02f554189647655bc49f53adb3617dc355526a35bf1da04f1a457e8da2e5310d98c20cde6fa03b880a263630f2d3ce5dc57dccc2ab0108815f0b6cae2f4fcad3b062ed18bff3cf0172764e6c784fb707f7e4107f77b40af63cd1eb875ed255bc9e46f2cee1b6c64f33809b1efaa4d7e63b22f01d078a3c2f7f120de7e1564c22962cb0b697392c7bf0e06fc5bbfbaa4bc4d7e693b9a2d34955e9306c1167dcf9aa665338e88103d8385462fb0a6fb4605813a4bac8c09f1a8e0ae02df114a7eeed067c91b98a39dde01e455bee3e555b3a806df3688a79c41c18ee5af6baa0b618413e39049bb187df22e325af4e63a90152c01cb230dfec0a1708ca06a50cdeadbb5975a8a6ad910823d19e8a0f7bfb575a82ebb902b72a6532c4a50c5a2e0029e8cb8874c3601f7dd56d1bf8f3ef10cca1934ea511c962da3d34dfc6694a1aea41d8fad33ec0ebf79c6d63ca422b99d19c0354218fb8395ef27e9e0e140804ffb2ea063440cc4b4b8a85b676118f8f43d938c596b900d850175b16ef88128baa42f73819a42cb9d8e83fe949874a877c42dba057b3a25e7ab8cde89304e406c5048de87422f035cf826398c823cb18ddcaf9dfb85dca5d6396dec66c6408782b779f0a64dc02cc550d5d5d9d026978a9b716c95337486c7f4dea2cc7182841a2dee157026192a00386082eef03abd90c0825c7a7932a9286e8e1678d1b063390a0adfc2dbf4e8f3b4d70d5aadedb63a9a613ee770e66bc4f67f13a934354d2708fc3b8798eee3c4373911c03b285b20512c31f3d419ef7172fba6bd7c768dd8383edd7d3b3dc43e8ccc1bae058306d745eefa2bf69cc2176137af14b5b4d5f061f2c2f62852e8e93769995895165636f2f722ba1f71fe502dab212c8edde39420250c9bdbb5443c3158965e7ebe3cf7580160c00439d9a830a2e1d67f39a6a42b7854d8e84d5dcdc4d279c5929f6ee7544a13ab33ffe6c2ac0d0cd352f2fa86e4037b992d3d58f07692c3c10b4c29035221f07bd7ca6572c05dee1236c781289d2938a912b43f6f6d5be3bec92f6d6a1bcab87ad3565d5fc7e680edc6a82b5cfae1b99b3fe6575bac9f25e8e7866e77cf01d69c4bd77f5c2fd7216165f7653f98c724e414ae426751a98bb48625631835a8301f979661921b69748e8cae68a428150abd40b056003863d094423e15024b899e1928653c7a5546372b5206114affeda26fa77ae2c1e15adcb0c71339ae4687aef44df6451f67a1a0de3c88880ef24888a9c800848c4f8b25130fbab756472cbf479bb65190c5cc25243f0e301a2c860d3edbdd94f0c08ae10e00a8120baaefda936092622e06252112b8c69e953cfd55671ab4b64c2bb2a9de49e391aabf0f39607efa908ccf46ee812794948f1e4412d83a5b73218ab82d21c75a9e1f2c4347ace7e6a1fa0ca8ecea6c8858d5a8f73e3bc2ed93127189f2b791c41d0ddcd6574102d4077bd5030804bf7cd9ae5e4fc8943f980c3f3567d14ed7ca1b64c1282bc378f21610a4644ecefae6014e0680b2fc030c37489e3282ea92e38d678c229d00dc1fb604b0b1e7d66e37b7d120efec03298bd636611b6a537a902a7ede8a476689c886d619eda3d2975b934cb73442791251fa608d688eb7f72d4b38fc2d9129411a20f519c8ff9a31b39b20e42892f2ac7e9c560213745a1d1e430da85490df21661e6a4ecbeda3c8aee19068c4d40b56d5180465cdb6a09372d24ac927d5d5d8e54301c650035e4a1b967e114b63e87d51b107049eb8e39dd53ece45df43b2de07e66a676786fbe61c2038d2fbfd29e3ff7532898200ac2eaec1279e2e5b570aa9fafed8cf1f8884fa1752e06bd90f016c2cfaa0c59f4471e9786758a0192492004e279630c71e747913e1eb1f8878e014fc2bb372b31bb4d57eb2548bd49077a98eeb386eb731d130bd93fc4bc5987369b2ea977c821bcf4a3a842d62c634fac5b972903140f738304504db08c3ae63a3b5f896c125c6e2184f4c6beaf32dd6378370d86950d40fc7dd7ce70c9dac8f020b207299ea000ce96a140be61c30c222b330a08307aee9a8b52be06964b0e8bba7db255b02073809530b3ce794ca81bb5a12f06bcf0a86d703a0f31576982164c6195e3ef7d3877c849d0200c0144167471a961fcd026a0d2f452d658652b278ed075c9328d323580ba8450786f5de46e61553bbf2744639805c0a12956242d6cc6e8193aebbae909c606ce56ae95113d0bad62f91a4d8a3b153a97df6ad45c3651c8c0014cf7680e9e3e32776fe7691ae5cc5891391f087d96f461405b1a00c29ed35d4b4f4f69ab860005dcc30da6a232aebd49650bdfc30a0819daf4f29eaa628183a75531c9ef2d5d04ca40cf523fad41adae707b0cf2d31e1c9dfd5cec2032d13dbabd825847c0ed523f2159a30761bf0a6e6aff37f9e92679e81ef2ed92bc2e98e0acf8bcf854989f2eefdeacde24c3cb7aad51898dd128c5390fbfd18d3e9dc8ba045cfed9a4760334aa7189be034a5f68c8a44676299ab651afb16b82c5722f7dba422779f5ab136451985013426cac99b97c706417b9aa12541a6081ff82da21835fe5b3e36f2c3bcf950140705e4b45b4e27dd7b400d9407d8ea85229cdca8f5a3d62817ff7845c3e2567f1433f775af25fdb61b13ee59cf7a4f91cdab714789f2269357f4a6e05698c40633168fed1e67e04566dce7a8b542652b23844894072c694a8ec8714bdd1c7fcbf87c557cc82bbab75ba539677688c8931e8c3d9b6b28c623fe80f4b2736168fd1c7837e8b188eb190cad146e1a9f31ece216865251a7ee3c5103596ae60062f3263ef2960f83544df2541e1b240a7ce37ef79feabcbbac5b2ef9928a96f5c8728edf091b2916842025956580118f9433234ed8e47c9d7f06f88f577c23a4b57d05bf4d6619d12ecd1ee50842fa3001722c4fd7014620963d33ed2afce9c0037ea6ae2285326a41d36d576d0da686dfedb440f0baa59bee77e68253a89394bb5ceb0fc2c0ce9e6d748f86c68aa2573a2fa0b9a1aed482f91d704c543d2469522671354a5d47454971c9f04317971c521b29e5503af09bcf3e68c4e6894b2d3ea4c695e7536cb18d9ff74ef6139366ecb0fc2e07056ffdf316c112f921419bcb5aeb3907b6ef887614244cb53653911454e83d17a982b5e57a511ebe86810dad389d8cb42c56dc6e098105455d7fcd528d047688f6cc88b0b9d151285b0fd75e274553101c05cc828ce2698944b5d7daa851d0c5c326c4920f90c7ba623ae58fa8bcecd44ad39082c81e8b957596c4df198e277086fc7cd37df8d8530618947b085595e9186fd407024fee4d06b73365e40fd18d46fe76b630241c4c7325b0fceff7fb09fdb90e624c803c0b95b0825e12f172f48e03b81c20becf9b28c07d22cc050f7fcaf377f8a7899dc7c126e4a96311027cec45b5ec9363414a53c71e34e9f09a0c18bd3c93a221afb1a51a993bf804180c04d340dc17c0b97b1ced318d1c88c74cbe4f8a2f610c9b55477da3c945f312a35230acf42f7c245c861302c2e94945f31ee21706c27fb457ba243cf5389dbc338307931b370849ba9a85aadc7d8c5c19038a6b667e5d3012bad21c8a66ec0b81e119bc54f957e3e5351d340db2b7d4d8f32b4cdabba71112624ad4a3db47c2db73a41b227bb7904b10711d1707c78dd7f53e6960661bcc3f8aedfc9a0ca8bb29b0c91acbb569f3a7595a2f2d2dd9524a99920cfb078e07b4073f56cc9ffaeebd7f5f317fbef76f1bcc1ff0fd1b8bf9b37afff6327f6adebf6f307f6cdebf71307f58efdf39983f37ef1e88a550f6e03b2c6980e806543920efbf10e87b0f087ca0d5d78440350f64f3ac108885816e643c0867be43d54d3867ae93d55f59fd21f53499d6a47d52300e58a669665454d49ab4580706cbfcf6a5167b61cef2d6e584410488c203114b04a48c179b37711ecd3b824b2da659719e7bbfe9778b251559fdfe5a960ae4d09e7e0e2a9655ac537c745ff291e94b82abd8b3261fbd9b82b82c56c0a468727142caf8ed09dc7dd9495a3e2236daa13771d80b94827a7682274d64cecb088376964819efad60f812ad99f1fedeb4f325f67cc0a4eb3c095fe2fa3a7fc33d9d9045df849f240921095fc22740e74d106998f13a5f8248c3921e335ee769d879127e925e6a864df8127e4baa91b5186df997309b3f5b7613c45942e84cb405dbf919afc5684f09efdbca134b5c42d8c41de6535c36231c610398457fe785481615817accf81d31688638690b0193dc29ff27a9f3e5ce0c7109fd4992104e724638495a9fbe50d6e2e32467cc101db6610c6beaa7ddce44430438a9c97c74ad498bf9586ab13c448238694b472c3dc6da318139cbcee4a3f370584c14b87458d84e10a122075246d89282dc9270e9b0aec1657f2fa26b40cd1fb267dcf83a60c364091f7ac04111224fa60d88d012648a0fb88089974eea21baa79b282d227ba7a0bb895837e919fe5cd84c4b301f957ccc09fba5e5888b94117ed003e93588c3738b5aac677827f9e84ebad5569a8041764dcac7f42d8d10e6a02dff56c8438b316c010021034280fb4508430861481de184338010b66b08ee17c33054e980fbdf3f46d82ffc04f76b31e7b1a2c3fcbf12e0f7d7669a152da635c1b0f741b84921222489f498c33e08b71f984849223de6ef4dfe0e7326cd85d08dcfa002850a578652252937142e5f727f0fa592e0896fc033ef498159f427b9a2ad26b8518081e0b2edbb0883bbbfe1948a1a4729a594a67e4bcdba0804b86c97ebc79d1d955bf12c2ad19d1ce64e303ad3e84c869a3929b4e419cbf38914af3cc5519e4fa63022e6f9448aa8dcae1e527d7f0b711efa4d8b52b8591367cee3e4b515da43f3ad825289656b3172830497b38b8eed55623bf9d8331ffb35968efbaab7797a8e8fa30fcd1f11cc1fefe9186db517e7f1be595a97a9d3efd9bf67db86f16ad53deb2ef3c7734f524b6e281c2b25b88c0186cc892ea452a50facda365518c30c1326cc1659f55b58d264aa1265a8198b250cd905edb71286bc893e6a8e91d144fcd37954aa52fb944c586231466ca294d8aeb0878860167d8db5fddcc41d1a4876b05872c51256a27a88820208061d00034411251ed081013e36907039b3943eb9e95f25b8a3dc3b0ae61d05eb281ffb5d445ccfccf7b39ec0e50b36721bf1b167c266f2563fa789b0a82f378418992139cadd4ab969d497fbdd2ea216d2433e76ff0bdcd5ef44515fa8f831c19ebba8bf8d8854ce32c29b38a547650084004218c303560d0c17333231a0c7f508d2debe1029448e22e088ffc18dcdea058d0aa7beeeafc8ea717fbb2f44cef746008c00b051332644084308b71de07e9c108310aeb06031fc301c9d70f931429f25f007e10d0fc21c56f04dc88315b6b005db84356104668057210cb4d50f239c010a2e6754ee7f11b68bb65a0aa6e99fe94f2981cb2eea176df5cb849d4405c661c362c266b25ae0b261293005f616a526ca86348b8150e0b26379465bfd5cd8315c70d9336dd3b27bcc161831a4986f89a1c2ddbddf95ba86d31e579aadfe6d23dac2955cc9979c67e629ce63c579e693245d723f916b517299cfdc29776fc9fd953a91f394ee2a729eb2b770f990f3dca63285a8b7f0251f1be64a3ef610465c09ca7184aadf9c60b5aaf9e6b072b9b25f2b3ac8fe32b62889edca0dd91f5b570c341eb27f4c7db95c2e233164f025c9fea9caa54341f60771d0b0f090c8fe9f1697cbe503b744f6f72810ed4a97ecdf45b95cae20ac21d586eccf6971b95c436e8a6843b2ffe603e7830c92ecaf79cce5721119a23341f6bf3097cbf5c3922a4af6b73a44d9b464ff3a2409d08aec4f8b5858382640e0726d89c921fbf7f7c26a88f87de44d142c4ad93fd615cf46cd5e4cb83c6045d3c5df6c4c62e35c5aa4dca0c805419e62308058acca8d8dd2e10aa74f06348ac8175ae4489d1581157171e95cbcfc95022958785fac0a25b12aa63c6dc1dda2a8572ec729580044eb5c0e7392cb514b0d5586549dd951941ab2b045515c4e516a502aa27db024a25a042529881b830204122849453ec8d459510c62332b86e89c60591a692ca96a626394cda390502d2dd06452442193729404a872bda80bca6c051606854a1328b3242c1c8c588d4282c196987a532bfd1bef8931c3d9b1912329f7e7b157141a2fd88b9ed295d2642c72e77edc3e56f19e9a9e92788ac19c519e64f0c4a5a33c61519fb6d080d421532bd2323e74434cd5526f51c0242687c53d26cf2856b6f8778d8957592c5779fecf58cc141c50cad3294f199195ecc55817343f73f838b707bb4dd3340d86acfdc8e0d7f9636aa61d175ae0550b949464444db995a78ce803d9f3fc6b1087ccb758dac8dd6fbbfb2d39a70e938d89a182bbefbd57a5badd54262c5f70114edab24f136e45e89cb95c244b1379748cb6eca7a2c0404a918b4c3df8f63f20989cc0e988082d92d881100980f4e0054989206400454a136d3e0002c750c1f7634296ccc77ce71ab264be3e7e6fe7be37354ff5f6739c677bcf7b954ad5e9f02d42592bb5f7669e0a65cd87e7199116e919dedfa00d53fad1790245b31911d7ce0c70b95add3c0e8bc7f633f770a28dbcc187dc9e682339cefb2decfe06a519066efb0b701f004eac5abc6bb8773b45dade9b9c165c6e194a0898ec4f43c11eee22376fa28ddc7ece1fa4ed4bfadafc09a6309f9be50cb9de7b5df0e1b98adbcff40ddfe6f53a445614955bc60496b3ace89509e0cdc9532bf55cc3bf9c734ea0f6e1f3eba473ce0aead0d1b13c29909d0a7e60f53c20ef0bbd756cdaf785a048815c6bc83a40eac16f21057e9b87e910487a5e0af6b5b2ee08409d735e70051aa67ee1922da767f86f604e4ed7c0195bdf8e368229dec45962dfa3df174ed2ced166c0e6fad910a8c77b5707d7b375df7ee2bd329f0d590700fffb1640f1fb16e68f50038e617ee17e4265215288f4f7cadebe70e8fb495b5d6b073886f925fba07996a0fd56bb30dff247a65f430bee08404f30c58932dcdabedd5b3f2f5ca25d5b29b52ff0bc7089a6bdb7a3766215f10ebac30225a7639b59286f5ed9dd7be190a7fd9c2594f66f47c11484b20571689c66c115689830d90b97749bbb73de57c192f39e5c4d61dbc40e1eb7e47e0d81eedbec3d9a137bb6ac3f97bd05a22531f86417c62c4472efc5d061f210f7372c89c127fba0255cdad94eb2ee98c9da9c6e539bb842ad1a0a4b64f0ac6995fa8f16d2bc1a511a43dfb355878ba5509ef52bb8a3ea787f176cd879feccea3cd87b2f8eb59abd2d7e3dc3b7b7360492c173376705d7cc59c1fe76fb92b3dbbd7f2d0e23a87f4582c91724524094ad6fbe89738e2c04d9aca36edb3b9036450bb240c38eeaaebd8f2d851536eddaa7e00a56ac9b8f5ad3204dbce93c544775b97a8ed68259a1c300ddf7b1e59e3af6db817454a0eb6395ad7feba8323875fb9656cf53c6446976ce0d155a7077aab4dca66c4851f67fbff1a62ad869723191ac25fa08081545903f3a0726a01c216a1ca8d0402c6a072c2f2aa467b17c808ad9bd028a115a484ffb6818e44a4f45e840fef89e000184a4ef3f66ac9054ac2e807e6ffb68e84c440029223d24a10be9713fb860c98bf4100709d2eb3e1a3610319845793650f264f47d349c4e36d04411e921ab09d2033f1afa912aae48223dc46182f4521f0dbb0812a49817f37938697044d230a8ab12841222c81f1d86f40e40bf873f1a4e2b504610457af839417a324970f9a2fa6838a1d860035a480f271727a43743b3e33444d30f6f1af326eda9d4b3833162690828928620900038451123690d83b422124841fe00395067af17f9c346112f4890f56918349bc81f330a59c525ac7ea1dc6e0511f963860ea458726b1834a348d242fed8d980510abc8a2ba820022369f85d417ada57c3a0ae018827f2077591d305507edabdcd4daf8bd31144240d3d2aa4879d7fb850bb179167dd4262da53c95947ead4a97b9dd4e7d439b2b6d2b7d6d2b754dc5cacd7524ac559eb9734557451e545bb76e254bac5f6943e67ffde3b7f7cf3717bca3d0deddbdf7eb3bfd97761b3e13ca58f0f0b61b6e28ae26d85ffb3b6b5a669da9d5387be75c7deb66de5c6820b9bddac77adbd7765e3dacdf1bd9b063077ef739c887dbcdbb64deb3570dbb6d19e95b7aeca0beed5f6ad6e9c67ebc4cb6d9b666f374513152848acc09b0aa8ef53b27f97257fbe3f7f3a71ebbe7bef5d2c71807c34176af43e7deb02a591edec922dc842687fd28dc67c1923d3982f61641af3654ca64f27cf7d8a1f3f7d6d52b1e438ee2d4743eca3a5e23775ece316e0fa9d4b1a997ef9d91bf387befd084860fed4b7aa4ffd7d964adc3166d5abc41c1fc19779fb36debe4cb8f9083e783b46be5fc6c8cd6d3404ea8c43a0cee55733287e9e7b9be7d6b2505d70df3a80adb55fce184ff97dce13d6497bd294bb7bd775e2e6a3a6559aa76dda73c35bf6adca8b2a0a7ff86f9c30c5b266197abaa74aa17cc55483548234a9f56bad150730f9731e190e5e32fdad0031d645ec3c4eddada8a36617bac8ca82c88220c95e4f2a96cb9dbc5d9c430fc7e7ee6bde31fa48c5af829b0c31c4bc87e5cecc3b3672f460c00b330c1521495a8a79f65438b4c4f31dddbb588af93e48e3650ae26c8170ccac3d8ecee027ce39a3dce13b68c8f7739cc75bc17774e2e8635fdf76b4ffb57785512c6f725631c0258ee7886329c3559a0bc05316444876afb5863976565007deb6af200a9c1843e7943075686deaf56f4863ee4c1dfa2a2b70b913c589604c420a21aaa89cf3396250ce08a30838e2cb10ff6588413f6a502922462eb1ffc1cb781962908c160042d0f9181f430c02e17544568f18e1c7f8ee4fcd3bbbc9b375dfef93e77e7b1d02288278b196888102bf306719646102dccf4ae9d7eca55e46cc09593d72fc75831cc4c89c17226584ac1e325ee775c4a0108a2065bc10e9d9c8c41ce1982db87fbecc3bcc79c0aff99af7d935bc4f2cfbc1f7c2ad67d055cd5310057005ae9e867eb4aaf95953c3fa1bfe35db7c8be5a7a4e463ddbaaeb17aea47d993ba46f9fdd6336abe06fcea634df670d49442ae7414d6ad67f4afc2ae67d0ecb1de2664dd848e247423f724e751729e49c37e4f7ce1db31ab7c50e052b322fbfbabf3d635e8b71bf9e8af46e2423fe972e2ca2dfa115512d8c8794a3fa24df1a297398f0bd19a9ce748d798d9bbfd5d87bbfa8bca065e7615d9dfcb1768b28bffe23caaf76f30ce43f3feee729e9987c1f3e2fd7bd655cc566c461916eae35edec5a17a4a5393a5b689433994433994435926876aa71ab067312f1932747440143ea7cfca8c8498d7fc01bfd9e6b465d9b6c862166ab531753a168a0b3ba95f1bd306357f9a784fcc91b7fcb364d9b26565c598d70a0688d4b01b1280747659919d7b7d33cf2361c60ed7428888ba881a0db5ab4bf84cb02f4400ca070c413ece604200be9b9585eac163c6801b10a905564f1d6b59267c1d0d0b65eb37ebc21d4dee75c28d9857cc2ce6c87b3c2fdceb9b71af6fc6bdbe19f7fa66dc8be545bd2e0b44e18adec5a31cea9bcd3e27efe18eb8970adc2b47130d10856a0560ebd664936d532c9485b250166a63e28eb824142cb521804f00200a570096a75b71fe35b45eec170b268518d98a360a2aefd48048e3c8e33d3e34b8c76700dfe6f37147dccb4271afec6fa13ea76ff6cdbc01605701448005cbaaa394d27a350d0b495d881ba8d5aea6615162edaa4a21436badb552eaf7de4a2be782d95aa9922e499e94d05a6bad945aab5d4db3f689d6ef45439f94c028add6d65a6ba5f4d65b5fd495e0c05e4dc3422ba548b7b15015203d3d3d3d3d3dd97a9f2ec5922b45aa97e36a05539fae7691923cd92f97d2aa21fdbd286c9a76933c49c1b2022c9ee4a9933ccd244ffe510f582c1d12dcbf715db8ae4bd7811f7c30eaa13bd2f1d019c1fddd0e345d91171d91aea8d3a11bd2e5d009e982e0fe0e871894c6f8c01e6db4677ea52d6f97c0aa73f2d1a995ecf9e616e96cea7cf1d12998fc25fb6dca9489f6c45090cb9af97446da7692c272a9b9e81724cdd5c1aa70ed395541814b0acb76eb582c16a3949b5514c870b3dd2bc64b3058d47d592fdec30d5d187d5d187d5d187d5d187d5d187d5d187d71ae0b7b71306b446cfbb6afd65a2bc55b752b57c95b494649d99f1a5124de7399eed25d32daa08c6252bc89537eb0175eb29489c2e875516a2497379373a2dc8c7245ce13e38c78cf77c4cd6e8c9bdd1837bb316e7663dc2cfb5bf17b7133da18c6157db31a30f539bfbbbbbb67759a2a5dc8aec5c7220b758d6c17efb1168c97210b46c8509ed788903c2f926b841ad9a8d7ac52d2d72adba89925af0a05d6bd7039669f77bcfec57992e60f18efb943143652d83852d83856f1ba60428a6eb29729905c72b7c8954b5a5494dd6a71114451d105b8ef1590a69706b9acc133cc9e1e6a2175a83615fb8b37714a6e7a1d15827f12e592265d99b7da07fc6df68bf368ef7f93e60f18efe18c78cb3f4b962d5bba74f172633796fd35912bba4cb7c95da249d9bfbc4bd99f265125efb9b21bbbb12a988b21e14d9c92525a8b7c8bf7b883e94287bc74c9e58329ddcb043373915bf4a820fe6edfb31282be3ae0dd7477cfd9b3678ff9d69b4c1fd31eeee7ca3e87b48db445c3c7460a3132153b103081635403de375984172e71bce7c65bbe126295032b4f225a9337dab342c2b40504f7cff7aef642dbbef9238e8f50b869f2ec6ec0fddd0670ffec86707f6703eeef3490faba1a707fe7c2fd5c18dccf6da1e2b4c0fdf3277355300706f77359e07e6e07b89fd341cdc77db1f9b81cb03e0e07b89fbb01ee9f3f3779bee7c1cd7bc582f613e0de107bcbdf6b676a55d3b4726127a0f9bca9a3042e57de4d17cbf5fb67562326539724285916a6d89499152d5ba2606192949692609306d38733379ad58f393b3e4c4d9c8929fb3331d5adce14c0e64f98bde932da973689dbde6631d2383105cf9cb56297a6d824efe9204516d6c4c66c93f3ccac93f34c991121d9df6af11e27fdb94d7b394f69ad3042628f9cc74bd043e0293382246f6f13e6ca3475fce726b3f2f14b8de666f3d1ed3401cb50d6b5e13c3439473dcd81d7cd0e29e81779ca764092fd6a54c9797c05d9dfa394527adb2679cbdf7649d9ffebe9be71f879cb351d1a7625644c90e49a3c6542c0eafd1a3651cfb82c1ee08de374b58a3dbeefc42056fdf1fb205615811030c9a7adbbf2a1adfb42a4f7db23e0fe26066de5cac79293c4f55ba0ad5b4520044c92c77d2172041729743b91d5e363f19079568f263b71c90490b6474afd245955e431d43dc80314839aecde7ba16b5dd6f6c42032e23cb3051ef072bfdc47f95edb9526c1ae12f9520167ad32e2d00c4d729e29638292ef5325e789c1b2de17bac097a99f7ad57b5ce89af96de637911ad1d6fd99ed9bdc84c82f14226bd8233565467c51894bec8321ab87cc832f23d257029ae4be49ee3385813fbf97f904a41e1469003ff532220d4b7a809f12599586d47fdf4f5226ac61047cbcf7372770d9ae54e802ff868362bbbcefbe1722633ed6628feffbf7fe5412ab6120f8df778b3dbe366a22dabaa038690b6c176d5d4dc4f53db1e3aa8bc6dcbd2842fff6b736b2a537684ff7f679506b6753b6960b82bf075ffbedb9f74416ed4416a51f647b782dd0967def8548fff6c22e9cb1a6f72971a42ddb89b6b3ffd40b2765f5f8defb4ff4c48dd543ec4a9f39edea2dcc02e169ef4d55d6bef4dc33e6e47c34dad23891c38175b7ac3d177483b6342edc615d1fd6fdfb9b18b4a4db444c5bda078d9a86a78e7d99a9f3330a03cad9ab558d66e55ebe1965c4a1c1df97cbcf264f199392bcca5346a42966858603ba40e001f367042816ad248a4a08b0a036682f8d944b9f19832b666c06a36f70ad6d2db304a659ddd8a0e1e3014cf3941181d2ef3420f224c772bcb59a37b827d4ce118d43f67f27d97fc3ab1f02df3c65445490cb7116f5d43f372201b9ba108e8f951e510e805aeb737a980c444517ad13de9cb557f7eaaec2d8d34516dcdffa71fed479c4003ccff9d353a77bbc5bf3fbc5e611dbc6a654e52ebbdcf34b1172bb3b9db32cbde3a3fb78cbbffa84377cf4faa54ffde6a9a2d32a96e10d1f1b5b077c401d0cc8f47d6cdc68eae33d4dd2f0d13fc0824b9fec3e369c877ed94f9bbe8b3eb33557322098f8d8a4f9e16d1b77c6189a0a5acd474e7fb8c54ddbb452285b91a5bd50d6f00af0f735f41e0cbb2ad284a07804d3ead35dab623665aecd1372c8844092e994d939411628a6e0198c7918bc674645055104c6542a4b82caf44e77ede70c4f50c147fb79ddd3a736bf19b91ee36306187cc426c0e5967f3a885980b7916e38e54d0c0c3ebc454b9f0f09ab10239e00854171de0ba210011fe97b3954104f78fb7809cb1af042962d3233305663eae9fb9821c8795e3c4de11c2a991918ab91f6b4eb8311ce3c43c7940a583c214b0e1971fcd4e3255ccea85478820a3e4e197e2af3aa9fd9688bbaf8172fc21a4e1f277d06380fcdd31cf3a91c1a2ca39a99212a26a4386627258ee574026badb3897e13d18781fe0cf4a74dc8ea61f34bfc6d5e8864852c1e355f23063559f342a48f19c29ab05db445df266ca222a32cc2e0e3128c3727f07ce12e9c48ed80b5bfef69e30d59f377682b644d31859a574b3a27b0774de0fa134c219ccf52a1a775789c275380e9b96f43886aca6e90657f1eb64e2053b22b413494fd697c4e1d340c985c75d8aabdf46a3b3ed96768086c32a2ce28bc705a68d756da2b26be3bc4003570028bacca0e2da001066040e440041a988204125415fe040a3b45f6ffdc89152b03db8155135988891055a44c4992c3152eb21c9db893237ee4c08503469c804a530894586dafcae41df1c4a3495ac0d9a0b4d1f071177112362c91fdbf95e747ec7849e2a8091d38500325bed8b00445033c9cc045963b3fb0207bf61f64d9bf3c653f94e087a4ee89c9d5ca756f9a58e22bdad087cdf36fb8510e9c524aa9572aa5e99ce2f412cf57d988d9bfa7ebe662e830b6767b7b7b23ddf7dea9513c201c1308c7e3a0d9d66a6bcde95208e97615cb0de38d9b3afd339cd99dba53778e9bfd33776898f9d569adb4d25aedd7adb97c3218402c56e573c6af070f159cd028d90f45b97f4e81752664094204566421d301291404074d52dc100229432090197dc9536614cb25e42933d221c7d4f76e0ded1b674d04f281b346c5ee426ecee8d744af3b18e02a941dc78bcc8026b8c4b9968de78ffd179a58dedfb654f7ee6127964240bde55bbf6e76cb2c1d4eb7f933b7a9d3ee7ac28452a1ae95a987e6cf14b8dce2868286390ea80d95492f817323878ffd5a1461390f18d7a00aae5c643d389163377aa882038c1b394ec841450f52fc0338264f590f2ae881881c685c0084113d1ce92b30ce53d6c30d38c030ace82a300805ade188129e04fef2941d794287602f4fd91126208e28c9e58cad64475e413a9c28e203c1aa3c654786f8103c93050eb8060a17de98702f98260a069904c1a0527de11779ca783892cb15dd01bbc853c6430db9af60304f99112f3976420e15563f7a5c5633af8a50911a58398ab2258a23b2f0a102c5061b84a882042a7685b3974ead7e610b9660594c896aa24357e1c2c20b182194a4c4b6408107ce02cd48135ee72933d224c7e42933a244a679ca8c4ca13e9bd239e79c5303b5a9134ecc39e746bbdaeaa2b53ed5a76aeb537db2b73ed5a7fba46db32a55aa54a952a5bbab501078a5b1b363c3c7c729c5f9cf196d6da7d5ca66cec9d223ae37d7e8ad76ce72ce39e79cbed56b8472d9ab5abed9d36af6380e9c5deeb2e77db4e7be48e33435a09ff7ec6a97674e9c7c819ab456992ed8411c3699da6aada5b5d6f9345fadb5d65a6b9d552c1d90a958997873ce39b9279e9813d76c755561cc7951983f5f68d385463327f744d3984c1678e6669af1c036c33d61ef55799dcce77df562f0c33129106f3729cfa415a5945e23a33c6788c00d724f187dd645d2e6cdc9d18d724e7cf5561817b85decc27e524a29b5afb72e92703f2dc2f5050aabdd1196969b373d9b1a67d9f4cd37c1299641b33c6199fe8c07282ccf67ddd81667e0d4526b2333c5689369a594d2d77ce26a53bbe08e0cd8baadb470a42d1a36b98a3b5c469b7c2dd7e171cc49c2f29a6470db7a7b58615c840b17239aa820054cec10bc6d5ad4a00628b87265d5ddedf692f70a3984337145e94a131925273025272f27a55aab5d72aadf8bc649e986dbed94524a6bad6ee9cb4949ca95a32b448e9c9c9c9c9c9c76a8cdc1c1198213aef015bc0355b7cded923b69573b7a3925d17e8fb49fe2ad3e5e71be9c5e575870e5e5f4727a399980527a658952292895a20445900036022296744a9d926e084aa953274497d42175417422e88eba241d10b585be789e4fa66177da9dd25a6d3ba5b55a5bedbd9ab66d9cb6715cd779ded779df0782a9540c988a89c1584646a59aa1a171e1e2c50b18abba5a51ef958c6a668686c6858b17302a0c18d41b868b235ecfb1feac1fe41903b3f2cac72868bdc93923f6a14163db9c87b5394f8c1acb0176d96a9b3b72ee884be25ed58b72a7b55a5aadbdf5757de3aec781293025a39aa171f1c2c6674d4d5adc8a17c363cee44cffe1ca971c168a20bc504a4ac271d1c5fa91bffc8513027714029794fd4308817b714ddc14aee9331261e32c14f76a920bdd08c98b8a36d88b1c1386200a9f93080208200a9f130e0054dceb4b146d3111f541d4f79a3f5eb264d9b2c50327f2e006447297bb401865ba4041dddcb04268e12d5a2c14cba6d51a41868c9c113a8b959c64a874ac5746412b95a11100000000b315000020100a87c462a13894a6b1347d14000d7896426a54988a644990c3308a8118c6186308308018828c21c628433536006cc2b3e3b141b12a1d4f8797fb6aab617846eecc6d28193c60c203843906d2d1a5b10187d5baf848afbfe5cde06b474f24139841fc203477cdde173d0b3979d1529c6517db8d4e5d0d1eaf49b7d361eec6c14c112a1f9a82b68b4db6be9c4f9fc3a01753e8852965fac68873aa80a9db0cb456f1e63765bd6d02b54f295b2a4e60ddf5ae0bd966db91b7cd853844f1778e73672a1471429fefa8cb74709e20718bd6e9b17fe724bbef9a1f00ea7c9d51ea8306b5564799c261ca6aadc5449631d829e0559db800b333ce3c2e801bfea12f07364f8cc0465d358f719129421d732ae15fc2140486fcec91d89541edf44c9af35d269baddad04d4c705b3870b627de7150f5930c5faa03f4e497d20b5f439909a664c7980c3a70669fa6a746ba0b8b7236975b3beac94316061be741e925c1c6f071d1ad2b19160132a82206b4e463840914d49250b6c18a6e22ea1fb81f5d9804666c422977f48407494b240d9a06273e8052af125aa01919ba6c76a2043ae3501a42539973688127358254e2de9db0439d624448a7c12bf7f029a06787afa6bb1758f893d4652cd2c2464ba5daa6d826b0dca206246f64ba34f85ee25e7e5445e66e705f640c8ec069d9aa692a6df3165ad35282e2986b6ebc78c63400d9f31e4b62e334553e6ad114bbf9f68aa1d700c9c67f8783af506491acb4e1e16d0c7c7ca3dc20c34b67f8071edaf683a1fbef16588a1c664a684abc7e04afe6ab72f2776b20ebca0f34fc3fd19dc02f7e6432a73885e1ddb74233f1cd54465bbc9f73b8dbc4e575df14641ef3e6ba66e558b0873630c519bbee2706d741e0e602a884b3348b380b51c4348079c14bc1b953412c5b1280b6824c44ac5257faf9dc3c3a1dd141acdf25012fa5a8e52013802c08556cb55063ae34c030fc376b1bd52f441c69d837e4c691938110a193f18ab57bba625af702275bb47147ee0f7bbe3f04936dbfdd16073264584b624c3b9efb93434b01f2660d7535918906dc1b4624396684314d943755dcbec549dbef4354323a3afa8dd105d40335e3c6f0d07293f4156aacb2ec8ecfc0560cbd76e46535caa847b593634a968261efdfc514707be2b136cfe0e08a513f3ce0caea52c726ceb989914e3853d12ff591b8812ad1bf9bf1239595a3deae4fbdef870fa2ffe1c4b387a1cf024f5e1084895cccd90e2aa8bd09a36814d568b27a62abc7ccf6df9b23bd5d5d380803a315b335c08aa88894c4260fcffc5355f1d3a8e5f0c5b380d05856457d44d76063b7719f88f399a2c37a15f9ecf54972f5518c5fbb3d96e8238be8d86bf529eab07fa0adf80703e1f30f4a1b02f0c5b0ddff0a6593523c8239879a2a154938ac62f4b7369eb4584f1813dfd86ac3821343919d2c6efd58a1ce0aaada33b4be6e81f0fac74f435b75c6a48625b2fb46917481c339aaad531a21cce00354fedbdf2fbdc5e4f5226dedbc5a577542f325e122fb845f2e3262c635f69b37de81d62b5ccdb472c988a2ca2031ccc139f4aae08a4546e75c345d4e1d14d1389a74f3ab4055784e4779abbfa51126a232e4bfab17870030dc0e8b14f7eef8032b5dd401e1353fb2707c4ce6a9a05f989f739e6c897eec5f1918e1eb81c41827e67d15db105cfb3b2b1ddcce88398b0b96fec4d1fcbcab97c62f321e0acf1b6c1a6140dc670399f166ccb70a61012036187fbb2aba189bebbd2b7412a7342dfec15a92d14e9c33e2b1b6de4f0f153dc288da840f7a9546b04b809f4660a11838c809011dd301ffa1075015b41b17095a053cf13d3c119c30a84cde4aebd37ad3bda694b20d4dd26e71c5b8b104d0d932311a753b9ab37fcce7d4ceb84546d8d493025d0f3c96316852f9070dec75b89ccbc60d0d25f35122818b641ed6dc41f3c0ec12f674344304d94981ae7c67c6af047dc5c316bac577668cec383b9c665148688de5a400d5c6eacdf4b6c4be59feffdb624dd726b4b4b2b8c0fc0844df44c474d244889af7f0da885faa123e54fd46adcbf40099c032d8a7fa7eca4277fa6c313baf761901a49de6157b722be7d256b5c8dfd9b060b960fd6c0025b9521eb9a8f4a3a5142162460d105f841454b638f0c93f0210e9910eb69160d40cb51821b3de3a537e90ba2b659e7cfb72aec57dbb4aded899a34c3a94f0249f20a339e82393883272e2d1d7d81c219604d3d13c4469508bdb0ef6cf0029440acf43b1163be709d7ffe1bce353df6a68350b8b8a8330b8c948bb0d337ac7a37b234c0db58287f21b7568116004a603436c5049365592d50c4ac3d8b5c8779a426809d64a69a188234e4921a6592573566121df3477d5bd48c225f4430925d9a87de15f43894756fb222b50fc51e555e4a1434219bb079b096fd290797b8dea8165a701f76ac821371999c15aa021ec886eb7ea3571b89e0f755ad3aa36df9f5aafb4d217e591965698854967dc0744ce200d44721c752c8f2acfa05a921f4efd3a5538200edb82b7c21d486684ebca71f400a5fd791fe85cd25e6232fd830b9f7224091298befba8c69827aca409a875db606f8b69d0a2c9b142fdcd40f64a5572f2226208c740188abb410fea9edffe845024d20c523ca9665c464dde366b63656bc327bf09c4a66f7c1dc624a5da6bd54938af4f0783ff8e0b432e869599ced5e7c61d4355095631c014e5f13e59e99a319bebc8d3a728513587c73b14a91296734ea3b76f86e64c8506e6971425f5ecb7c4623c67308d769784e42599e8b0608ea131f557afeca6749fc0ab429398805efb437b2dedc183188ba13261f0f78b5c8b06fcc29abcb473d2bda7c5ff6606cd88db5e878352bc5b670580d899aad01e2dde00a547fb7dc4ed0c9de7fb05f55e3e50bc0c65f81a87d615f1090782af231ed8eddfba1a16952edc75e7cd70ee633f906ebec76957459d45ea6dee0933bc83cdc6784f70b580bc56b193bce9d1f6d0009ad3e88ebf42234af9c10102904c15f4f512f61255702f1d4112ed1868540142dc9f5977c130781d55665fff0936a5b92dcfc752fb8dd9c75730b70a0f3f6a40acf0de987da8939aeff56ae8a1feebd70ce2d6f9b726977ec5187f09dde1b104f8c40aa85f7284eaf7f457fb451270ecb0bb9cac5d952f19fe58cb7e452b22ff8d36d6a284328d5330200aa8ffbb994c3a5801f55de1a908af68b407f182bb03cb40350f48c0d2fc8b797c825d0012c6b54194ee6ac6f32036e4024871d7713d1709ac550fb0bcf63a7949ff21865836c71e5dc1847bb3bc614313dfa391e06e47f5752f032c32506ed532f681f5b9d7ba52f39224a6a783b0d1934a6080e2fa069538b09031ccb6b3d4ee1598f5dbf394f649c0c9bd5b0ee67beebdc6bf68205655f5e052dc8cae815d9c5a1b6a469aaca7084a5b4c686c2ecc1939bb0a552cb48b553018ed8750fedf3056197cabde8438d55be98140544e3164b244643aaabdee4207819ace4205db2cab9a4d6ee6fc4a4b8a6ff09332af51832e0ddf11235677e7ed52db00e0f5511f26c5b16307e1fe99c64723e584444c5a12e83fc685e1fb536a677abbbe73d3b3349a3a3934a85864404fad58e33e5c24ee5501b20e66bf1958ffd0ab84511cdf9ff1eb3ba684ad83063d09de22eabfbc5799ca793cec55fa7c910a429a4382e119540dc5a0813a48cbf8059c4801a4e82ed3b012be1cd39a232f11e63fc3af8a3e563e37ac5a5790d3c66a04ede72bd14580eb569f24675bd3c99270605bdb305df92f83283ff78b079afb8a1da4e9a180acb1cfd267501947bf0bd8f6ffcf7c104d2f9f65cb6c2fbe2e07152ef3c15f2535d7a8ac51a539ff3632f2925bc81298813270a87a73abfea574919e030096b8c5fcb57278a31e54d5ccac7f27058bf8c722ef035626315d186d2bc853ff3fd56ccbe805d7a2218049a1b10000fc6161365014c4072272f8682e554f9b88fec03981481c6543f582e363c1f8665496573e118e0ba1c5c6ff4d7de902542d8fce6df6dca45ac9e2110e887dce6fa662741b650467051490fc9e38154363d0dec90e4b949e9b93c446f02ba00cc923f22b900c6523f8ab8c27e14a5c5dd1cd2c489ca24e1ec32b9a520d879783b1d144857059ba45cbbfc6ce361fce721fcccd6d156e0091bae97dd6ac27a23e789be9d43f69070fbb125328fefb562ef8adcc0a11e97c1e87d8b8f255d6f79a30bbdf86a0a2954d46d0014ca5d68b1a5ef2a6cf6715830ff17f4d7cd753ccfb959eda38cb807f90baf886b4af1e970459897bae9af624b4545c7f2204fedfaeaae9ad9e8eeae9bfea3fbfa92236b16023d78ef19167e06097d68d5ebf47b5fcdd29a266001f8d8ac3545829e8ac3a52ecf9a24eabea03897a363cbab38b4fd43d5790a5d85826c3bdaf742563c05d34aade2e2849a50b3673136e9ecb3a2020da62e2d1a8ecb8f80e48acec489cc4408eb3686ee016b90a365166794ca2820592c8e3039b64d23b09b2a2b044ef81acf026b4f455ef29baaad22499d865cdfcbf723608a0a2aa9490c07602501d2d53942e980d96303419f0c8ee962cbc07cc5b74b9ff86fd18849e91a0ce9c6d81f2c5343a3fd241546bcff21f4f85ef343a93f9d8d446bac07a187c66c6c72762d89a5c66132426ecab90ccbfcd9efad456c7967350f26f8922b62865ddfe5def572f5fb1eddd9606975f51ebf7ba606b41550be411f54ef1d9740506b9d8b2fcf2a6d502a56f7fed3a01b942642609a15237b00326ccc5e491505a057e066bd00822b5836af55ae66b4fe5402671ead042bdbd1492ce9a23996ac062d8ec34cecbc0d5e0ef547a75f45f120cf005ff05926c271222d31e83d54688770d40dd0cc63d90c826f6299f0ef957452fb30a2bf74e47719c5adf7af00203dbb407c517c87f3395cb55ae80ae02735f7ebbc44c9bfbfcfc3c4d405e0952f55dc7f42a617b6be0f0d06aa222a03e3628e15dcf9bb54c71a7f12d2174882f8b07d4cda475ba3095e318f0e04da2b1c8bacc3d75be256f0aa6458809c31640655d7ecb1c57928b916d8a1272ef975b15a5d1b1f316a6ab74059131e29c7cfe8bd2431412301dc2486b0b4c27bb8baa579acac162046442fb800515a6ed2817da78ba79e3ced4fc2ceac8759040214bc0ff80b6b860aacfc7e16b6ef267594de1a993c61165cf38159679947fb9931a71957c3821c911a328e282b4b511a1a4e36ce38b4aa16b12acec7eebc69f2ae10907855a0042607ff48791736dc737ec9029d4db864f8533c5258f626601da1953f6fd47549d11cbe23af6440f806f3ae0a94ee7f8d403accfa7874a9d056ff5b331b91501b5966bd3052994412d53de04d9a43b6463cd6cccb38130a4abd3f3f1789d18537fec547540b14605fa35af6e39bb27e8c54141259369d3d589dd06f0d8149baa5fca6550d3162bb2c3d1807c89f39c44bceccab585ee5c660cbad2e9995a7df9f87c8ee2fb38dd3fbb8bbbedb1dab4226d3f21f94790a39e525bc8df89405686c7213d1ef04464e173c99fd8e4f01cf134547df72b21f2af6cb87512d36b291f6601a1c298686c99371407e89fc2d9a1c9bdc8e902292dc26681adbe9961db4a79adcc78c8f761e9e68fa455857a735d57a6d35224f77f0e8bdf48415e48e507c1350bf8fad01ce8b940c9ecc5575a35a002754e57afa82a90cddb07264b43460b0076684c561ae5cfa8c493f56a0c6129aa0e4cfd15dbd7eb56934eae84d6824331058c4be9f876013f888be68cfa678a9aca454920bf37ac176cbcbd6e76efb0a2b0f5fa92abd67dc764e971652ee35f48b3cc1000487dde0e8456a95e31bbf9b04dcd69fe135cea9ecc4e7f2d9de7430f031e91201f30bf02740b5b799c903695ce427c78c01de6546055dad07893cea37626e9ad52e54118dcef605756c27781db723067bf66aaf1c11b5d40999b98be8aaad0b7c480ce845897e724f750fbccfc341c84d26b0c618ce73c1571e4cd8d82d41e7f13acba7e43a1f9d2c3d26f7eac01b7ba27bd961ca3b7d6b1bd651db38659b14b2af889f49ba65b9564c4730d13e991b17d6df50a97f4a378a30b72ce12177441f360eae8df938633833c350a09732c2aa4aedb8fd11f393b2f7073e967ad43f257a15297f4bdafb7343fb0e2694e81b27609d03c9e3b2adeae813bfceea76a438a5594f8e84cf400f479b4512e2c3cd1eb87c883f423e13e31520ca7fe8a323ba5fd76e887129874e2713cda8a0d201b29213bba84e199ce8c0798ad7b4648ccf47f0789f4b23b6a6ab16bc276c19dd0f674328d801ad80e96ac1a5ba1c1d4a86bfbdb623087e320736b359765f423d8b60f3a8e801c63aecc770ee7e196dc2a70d402590d7a99209974d51dd22b4a4c0ac94bac9a3cd67d5f502cf4d6be97a94a23c0839e5f1f74fc2a0c4b150e4f846686f4007e2ca10a7818ce2111c1290ec8672821404a5cd8881eb06cec8629fa8083865eb15ff02382b061c1527f3ff35f85dadcd4004316cc5d5deb92fa567649a8a8b43d7c30523eb86f3c09cd7fcfeaed0e0ff12a0418ee502467ba5c64d9210c3821ef45a1cd73b33689175faf5e14304b88e7b94475c901d5c4c67abc59f524ee8422629411836bb026abcfc7090101a5275caac71aa0bcf64e280a4e9a709c8e61580d3f9e50a81071cea07bcc94c68858910489422b25514b02bc11e68ad1101322e8475bc7dc997340e4f54842be253950d382a8ba04b52ae3f745d11bb84ec06347e5c8ade7e4eab2ced5aac26e34a17b473bae4c72b9f4860d5976479bb2f73b84dfc3115c28ca0799716bdc38718d32f7161ada45db10ad6f529da7f5695b8acfe847c8022eeae972282255f55920d4f120774b558c25111a0d9fbd21f4933365afb793f6c062a4bbe6337288dc51c51916b031212f35c78ee40287563388bb91126ef66a2dc1a99e0bd7bd2df3d5ed87e905489bd6fa58868ca6a8d935222f9b63a09e34ba6976a18d9789b17757def25061eb9447f47d27d7bf029e2ad51488ff085e4b81d4a5a4a3ae5da36ed5d6b988980eaeee1c5a9abd6609e6a9422c84850eda96d948b8430634b0c2b774221c8ba1dc9be00b874f6dcf5a89e44a9f84cd438005800437e4418531bc8a92c60178bf3ddf1df1bf83ae1497db29f7c246474b6196ecc1b7bb640f1b5e5cfc3d489dfcdd5506770559d96e7c362caee2dec38bf52a4848ad3f7b5535d1ee466a4d0075f57ff79cd27d8d1602843a6b4e2cacdeb84b842607687e8bb5537d5a6a935b59c2b54f4adb14d49ca82a2d814d3860384fbeca6f70542725c0995365dc000060a8097c2262dca47f547a590171da85e72394267b2c4acf93f9647e323273bb59553159c88c9cf8c1e2f0e0278464da19a264365b9f4b7e62c96a73767ff52b9cacfe060ca61f338253292db2799f6b80e2554023d198cb0a7a48d686f4db5db7e764c1bd5de0218a3f700b83dbc82ca0a9fc23f68ec12fd118f0c1e9f897cda8c9bbe05d1b3bed2f4d24f850be8b3f2b0539535f3ee100ae85dbc395dd38093066499fb6c189c30078d48efa7014231968ab57e086a02b39edc470aa7a656ff6609152dda3ad023ab5737939353b4afd4503312601a4a89b33ad53d18d154a4e5f1d73f37e5db89f5860f2f9aec82f5d0dbe08e4c3f572fe26ce4ba98580b0a74cc36d3c114e111ccb05f473af307722522c7d2fa70e362c18e8b10b71b12374b949f17f4bfa05672081a8f1e4b8b7a2c2b6274dcf82bc7504f2fff1bfeddf2658cf3fe27e1c95d82affbcf75191ff538d4c822304a005ca3a27f247d5b0bf21f96bbf1a6511123289a0a712c143dd28a6f17871eac30bc1f27324251d48bce56e4d4a99651eb06b8d08f717eb0ed193853590538121036d2f942adf71217bf0f4929547c6b15e18a513ca171cab3399773ec3ca7dcba9d019032f9f6c76922b073337395619e0b34bf590cc08f887829e0fd5ab90e365e9ca1a43607f3d0090d5a134d7e6c81f828994e37997da468449202821c5592583cc8f939a18763d772898ff0767b3fa880019569d9fc82d044716d6db8221be3e9f63fed67d7e5c5b90e7582b0f6cb6e98f20ed8a6a115f0b1504b69afc2ca900cc7315c892d4b59197b2836585de290caf052d62e7f56d4c56ef97b6c083613e2a68d3efb8077169b4c554822e8b998cc77c01fe1eb8d30bf45809118305a6002d414cf36944200721330243e52eda4a0206ad54da16010c00b66222ff17facda7c819b5030a7d79059b14b91968062e6e66e184c0998337448d861747f10074988838f94b4e7d298f8688c7c177be7a0c7398bc25250c9a1f7f7157a96e08197ed372b406dc47bd3694fc3664dae4828bfc5589c6f44fffc23fd3198314bbf04221f75a0b026a9881219d1bb4a612c2d6d090a6619ec20a339207e35b2217291404af136cc1f64e15411fcec319d831b5a3003743506abddfecd8458134461a4ed6b55e06ed05e978627447cc8e674560fe785e0f55d9be77ea110df2b68817b31447ea5978135bbfd676ae6677d956e05864406b425ca66d1a2e4a9ff12518d1d6673fa9bc16445021bb0cea2e94c84c482f325419ab2157ee78378ce659128bb5c49c5ad6e4617c7ea4e0c81eb1f8092af6a5114e63e894b45aab9f0afbc27d1297c48dea0536de5eef03171b93b9e7e165d46416ac35642ec6ff8154468f154fc0ed7a0a408fc3132bea6e4ea78c1ae36c57fe990be2c6b6046ea30ee758ed536c2a69d3eb166419b8e9ca06d2eebd7aa31c9de2b2f17fbf4ef17f2b73c54ec97a5bc011218f8b3c4891a0a86946aba4a0d8ccfc1fa177955697137e07b9e88a9bb8b9f963e63d82e3d8c5334ac76f66047b2451d848faae97170a3f38e27b674194b84e28f7af59f6656219675632ade868a9e9fa83c47f220018461bcf929dfb237e309a4d2a6b8f2814336dffe5ba13e9eba2944d91d356442c686a064f8a5f34ab39aa2268cfa1329e7c0c0bfd97beff217c543d02a3d84ec3df1cc42d027fb00275fb6e4f4e79a1c2776c738b3ee74321f0448d2554551391e3e5b3938e8ab1f6817339ae786f221e73ec3bdc5bae87a22474281d880b181905a64a639367e250febbe4b0c5a4245be1f2a75b93316103cdfd2639ea4aaa8047c4bc417aefa80c1207d718aa1165a4bdf11e9579efe1c5dae31ad801281a60c53991fd0640b3a8b7f657cb0383b3686413e7c7a7d898ce1cda5f1c93a0ab5fe581f83d196895133ec340e79b1b6b1af60fc4ca55ce27bc07c5f2e45a4dc18d171ed3d6516ae5cc200bbf6540a465130e199168c8148f0578a1598ff07828220b336138c168d5e0fd14d6fd49e0be71c3860ad6770dd7fa5310f845114f0f465f482939dcecc745c92aa776e1b2f8d3de5a98670c1514da3901cb37dee01ac9d653855dcf1b9cbe5c2087b7e468573c792cb1a8a8f0bcbd05823f5547ed94dc7eeca6402358d6414399af5ce3841950048d6e35c82559e570d5ca14030f25a2d8e1d6d0ad63345fb7673433d350d9ffd079370c1941f5cb39364ce396b603cdb65248d7eccbf22b153fad7a709345ead35f730b0da8f7f86724ea4218c703c106e306cff5e284a44c66a999f2360aca70a42c8dc168ab89118a2d06b6ca438a8f7e0cf7d802048eb6c2b2e496c8cfde4ac1bd91395788648036474a2613788ad5b3a380646e6443a460d0b312079303e8092a4cc435e1264fdf13b1f9fcdc9c9f94bc3e98b1eae3e1779f83b9ca1b3b08054fa0ad13ffa683cdf22bdb92d959230ea630d5e2632905609daac486d7b8a311bab00d34bbe55d7c49e0faf8e72fd3a867738ce0b57f69580c2a20fd43e06682843660ea2019b29385935dd1e5e6f9866b7751e147c37b5b36f0509cf3e9e88ad987e34d9f487efb7469428a474f23d3275a82df4f74b1ab19e27c0a1696cdf04f8c7c87eab9b7d1fbe94a8015a3a6d447ad10e907d90c7943360272a90a3f643f1b11a927b860d03fa7c67e010b1d8467e232d0dea847235ae04a9fc654b0e4a0fbfc10c22a390e70bfd00bfc7081c818a67d28f639932260850fbf321c11157306c867c0027bfd35056aae44093088c0eb55f7f0b1f7a6f0f003984d0e4753f2280607fc3ea45225e03625aa9358420a8743c0cbb1539ec907b98af00f255581de5d5931d9a5771dc2969abb08223a03a6688404bc5f7bb7228adde046e017812d53d70ebe8058aba3bfc6cec3c108c278be98108055dea2f7adeed5d83548fbfeb8c1b8050baa36f2727448a85c3185fde0df72ec19393be390059039d2e2e4630b1363bdf392700e738c07223a1b9a18fcca631798056b9227653a6fa1b267ce5678fe15b649ecaaeafa866995ea7760a3a8d5e89bfafa149ae541cd399fd765d1471bfbd0453d9b195a40f919703fdd976ee6e1d39f17c1754ceaca44fccfab44e9468fb7ad282ec0016fcb6b91290c3d31cf7a680381d16c65242451c44a429b8d889f3381f12152d14aa2ce191ccb5e2a20605367d450f6ff0e700dc789a4b9ea5a185b79e309db748536c1559339ce8de800a10a040cfd16c726b3c45b9823252254e35118d9dd0f083275f13476df3ffa9d7143aa80483fe50dae0c371b931ae12dfc3e397d7cf89c3a461bfb9a97911da8121e8d0377b79e0a88d4889c54df89063fca91a6ec30b83a9e8f4b5b9d78fb4450b86f81d129687ce0c083dcc05b083641bb2177fd4bec2f04d1ff0640b28fe0d0d62917649c992a56d55a97755616697407cdf11877c494416f70484cd196b32befbb06ac4bfaaf4a1d05245663d5619b0592de753bd88e9d2158d89c3f1bcbd61796a42186603fcf88c9e3b038a9000162a47486c1f35ba0052bc455542dfcc12f86692fd29a4b7371b432899812be838e63dacd2ab8b051de00cf4c408af924cf7b7414fddf07da81509e2b6cb4d6f79611f066b0947a79f50bf483274c3c2d6fd591584dba213c1e73be786459d2f35a22380fa1c0902e9d5c4534445248aa93f142b98805dacf41bf4ed097d008b89c991b6b7929a5d64532d0b9ff715638807ceca328d66c5ca7d13cc9b0cff79d69f10c57407ef326434ee18e5bbbbd013789d6c4900a3bf7e8b0cc03d7cdc6b3c28c2c65bca5cb472f768f8280852a0c5bd5d1f17184f3a6687b9053868fef547e845152f0d6b34ddef37dbc5b62ef0de2e5fd6473dc6eeb8916d61b6afad46581b6fed7d24b06f802bb03921a69d66169238ef966f1d27f1dce5bcea0ae6747183a20d48724a4ee16a9f3c8b04abeee883123570cd81b80ba79f955cea0461dfc149b8b255ee1a88632d41e3661e80aaea5f04a3b000839b72dfc6dd804511edb10b7c956e75b7ad811201e6903073c92b81695032dc76f348be54062a05e8a0f3b2a18ec35484fe41931e654350a7dba8752dd7903434cc3dc10447a6976b010c146a4fd3e1c1b11edf78aaa41c5d6c19a865c5d8e71ece8832f1664010be4905b8c5e316fd094ac9ab455490e8de5b43ed2147e00e9114c66b8c60a6b39ac58881883a77f15d694244cf24fa2b652efb546ad42afc38878bff7df5ba3b21dcaf4f8ba7821674f82697017a9dd6c6949ef7a12297955027f0fbce127ff00b54d9c5d4b29d426c98f120504d46cf482f6e96cc5a397237f688e6780f8d1a6cbf102ba5d2d96769ca3d9b229f94d363b2670a1b5069c469f8141114ce986288217fb2751259b2c45898d9e5bfb8c429be4545abf7510ccf2f5eea2d46da9693f0c54b8990aca4890f3f5ee41c570cba29199dac505d0265142e0f09845249547a1c8c648a09092945d0d7be3d80393c0b3c1d1b887253462bdfe688d0fee253012ef90d5f90e032774f8d1a2c8c9615331dd26af58b319630bb2da780405bae992b54816e4841a96e0e20cb863bd5931ee396e44e248027188b5c7e4f0ec6bfc7fe23c267762eb776eb022e2d54b5bd52ee146d4aa4d6e85edd15dcc60aaedd2ba79578d8e180eb6f23e8d4d91238081e5e021bdfe347ca7861ad91c7ac3011ab6c385854a75817f5d9eed393df17a9c60b698a96a753fd646748771bdef013e2683e280cac400aec9701291f5d4887ea647b66f0f4d4f48350dc661663e74fd26832356dc0cf25a1503de505724d2d854a9249b19153c883900a9924ff8bc33e263f3aa80cee8041ad10c8cb484aba1703ee3862dbd8487d1286fb130924c48dbfd45b21fd2d35f8468762a8459e9d95255f2411871d7d1bf883983f59cdbf74f6c60d1c2e95f9884a95d400ee5b3c4906a18b82fe34bf3a061136d136a8fa1a849feef6e8fc6bcd769dd50c0a298f5e10c188a493318ea0b6bd902f6984f0b1f9f531e55db2ef4283be2c4db97773dca09b22cda063c831f629a3466a46d2fc5306e1cd5c8587b953bd3d06eb69b5771c10bf07f611617da11760602654205ae02df1a31a601d1cdcc567f0e6cb0ad55543bcb9f0a040ada43df559b2b91664ffc6f8a2703f33ed33b4fd4ee7d3e72ef90189e5ae34ad9be44d12ac1cc0c26352e45f7f243d64c8262a237813a7e4f59e09299d9f717634a91e1a94a1e5c94f589234229c1e7d50c325851f1025fe3272d46fec667d5e5c241c88ac7e6d97403e4d30664953511202029d99487281a947b1bf9d38a3110a87a1f78d0b126691788dabd0d84c446cdbdf94558269c50dbed53842ba6612999b845587eb03a2280f784c386fb8a4d6d0624b11cda9eb04caa2ff0059fecf266986c89fccb760804833783d0539ed62e0df7aa40dec0d9207a78d2c091c07df06e845283736c05aaf9facb58622ade3a5323a2275354825be7d11bfcbab7baebcb3602189f15b07392874e231f3331cd2bc10e1ce4593c06598eafa8f0f15069f649f357a1ad588559f5945a5096f57bc035727e8e03f6c6c554a46ed5768072378cdd2db2b295f952a68c769f1281e2e32e638c5dff966f6aad7e7703259cb96f95185ed2f902f2408abfdf88f075c460bd216096861c8562f04f1c15b20e69dd66192d2261d5192ea5570277e2ff34f6ab8f1a676ef59d3d94b30b0095b4b6f350ec09078edd5e61e009cd15aa574b6aab77f004fe19a28baf191475b4f0b307a56b44555fc975e9e5eec1d2550da68cdef5236774b9e84035d4bcf5b6530bf7181654649aaa96fcab654c15826ccedb35611689dbe48f87f43383cf030c35a93356aebd0acec106d5d50fdb0073176f5dae9d30a667f6749a3458a7758e12a34186aac1109abca0a0ad685157819373d17626aa5c62edfa9cc330d4357af625b7e41c0313be2070d25293f618b034d459d99771c417c2e04824dd83bfba0c0cd1865055a1e89bedefae7901da2dcbbe5c1ec2676214be1005e9c55bd42d65f82fde5acd1eb959ef7905bc576660f8548a4e7c2f6453a524b9966190a3754b31f9fed7164210b2c92b69ff9daa0202e706f9115ab49b1442422161da6001b1f92f33fb85affeaf41598d25e5f6053dd47f8d7e5ffa15be2c319423f1030bc1bec0064909d95735eb116424a6c77044e56e9a6c1f783e7468b8a9612258b6ff6a5a4c02ebac808844aa1c7b086249cfcc0815f4892fcdb806df84f23559fb7d6d7341af0bfeedd25d161231365fd5963593d8e49f00a8a4d1e3c3641f5ee5d19b8c1f3bcd69301b0f9f2168ca0654a248e9f5ea8e7618e7dc69942129e16a0e1bd2eb5c8db31de92c7fd3c83662fa5107274bfe823b2893306402e6a71f77d28cbd3a2622d73526657c755e79e69862fb4c753a337a130fca5759e7f28e0b7db1ce9493efa7af401f5dc70ed29125c4aee35225aa396b304035687578ed98142b01c2bbce3e9485bb521f17c630a97cf302ee8ade1b525041a87259b4505b6a2e8c78ef79db5a5c7ec53533fc2e3fbeb054e98480e27f5ac87f72e4e24a2c638fb912318db7fd6140e8f400542f4c4340747a177e73d899fe43ccf44ef738857f9d1e2746b39f0245d526162abae1b7fc9c9e70d6e61cca3de89f174602e9847410044c8f80d8fe5217bf5492000509831f3e69a43044163dec479518999e19fdafe0871f88c21f7c052d8adafe6c19ee67d63457d3c4c4e4437f9d396e51931d85558a942d69f348cce2e70149b4a124ea380414c7363199fa4b475fdc2e3c55075004cb538d34e291f629fce7a5d5d10634131cc57816b490da900048f489b9198624246556e42a858d415a1c79c1dfec37697772c1ca2f19af2e1ac2f228ef9f78138669fb9cf05c7baa1780cbccc64cc9fa14e04312a25a764eca76ef3d7d8ee8cd9b2f80a6b73ac890fe71a4afa9d95d2b6a1707d3a405b65a4ba38cd81211847192e9baa21385eda1acd13d293ab0498c3e8e8e856d74f64d1d4a50577532490147ad1f742d744d87834acdbd6c78f9faf2e402faef625e37a4448cfdcdfa1504c818e68d231832c1237dde651a78865a571d4a50cfd070fd024ccdd93b5fe20ae1e4e41a89974488866c4928037c52bd3bd83a2d8ad676f7ad507fb18852f23bcea5dcf092c3f4a7ab8e59b4859c67826776668f208c112d6832f70474155ef5ee80b6c69af29c54bf9071596df1eaf53463367a34130799430c9ad3f3665f3eda858be0b9a5e6935d01275708141434b6f2c16e725e2cb9a100d47d09a2841982c8d851369a8279dc9c41d00a5c5fa70dadc64773daa8a3831347d50466401d688f9a4ab8c557666503b492386e9c08a27dbecc44fe2018a0aeb9d7f345c6870bec8429c09cad2d3b0d382f87ebf0efe9fe35c20777aad3fe5988e3be161e53df688e3e4156c1057e5af888996e9d3926884da021e851c1459510f89734a15244ffd9b3a265bf6c8dcf9f0f7e702504c296910b13d1774de0b3e51a693fd582e6f8d110ab7f302140015c208587bddc2007345b6436ff5d23db0ec2639f0c69aaab3b515d71a9f73b0db2f791d1b421e4940a23fbe7473c3a66a3ea87a0d95213ee40061116d0603f0e6dd734e05868dfaaf678ec0ce29cb690b33d885b3324b29b58ddfb93b97f30e379beb8c5da9c2d7367cae4ffeb9724d9f74c6c45a26cd189aa171389840a8ce73a1987a9255f0c6808b16f33d48c5557e07825ec04e3b053308b743c889c1058ff36e62a0cb9f6330e9bc2cf81fcc59368b373e6119b872e74ac1d92944d139177fc8e2aebba40db30cdd41c55b666bf40158b67b48a08822e3f6e2a0c4ae77cc11c1be29dea65003ae09185db3647d5a3a70d71f0f40dd5f237538ece20a110a62cf6a2b907a0d8b90f9a7cf4f669ab175b3dd04f31ad83e8fd60f4023d78f503b9d24614fdfe5c223a72f24cbe5f223dc7737d3aa05210894d78b1dd92f3d6cc1a8030b3aef13a63d4cc9e2d1ffba6d06397b562cf9a34a453b88859f10c2847831c83b10cc126c3a4bc151d68807e05eeb071e21cf408921a80c1f5ee10b26a75cdf90adeaa67410e0a54948efbc35628ebd9cfa24eb0a4c5b3456ff597fe1dfeef069b37f5ba96858b1a8c5a29fc7bbb72f302ed98b00a6cd5a7ae860625e2f0806a8ae75578e80086f17104da75c84a7181577edd6e29989dcb35a5f87202d24516b29a31903b16cb20e5f15a8d4414150ef52079471359a28fffb033b3d4edb036b08593f3204ae3c7a5d712ebcd573d6d948952e7d4ccd43a5aa885ff7f1025b519555d08120d7f2184d5372d6170d906d48000a72946cbc854d67d67a1d6885b1be507ac92a23343d4cb998e23790029f65ccb584254cc1d0605097d231855a3ea72cdfed19f7b01573263f26990eb9b7f2c94576ca0797f2fc95dd4c8ba954525856272192ff70c9a90b4936f8db86165a81e0cd1678e9f2bcc1597e62e8b2f34cd39b3dcd248626d7a98944fb96d5c2ddc779a8529e230fd96f09c2deea76b1af3e7c77f081b126a7b55868414220e935e6a63d7a291a8aafb75213de360d946571a95f062699730d9a5ef51669e23af014edc613426a26ed182980b7d94a61fd2104c1cc34b0a4b92b55455661e07afb5f5b51f99ecdec56c444bad73eb4592f8534ad3bd44f98352c2ad411aa228056000a2c687d4c8d3053d06f4017195efb4c987f8b88e0690e077f588f549d97468a506728b7e85c3a382600e6064627aead5c503d7f4a03667b9971874099a1a369a556643959e2ec799ff7dc7e5385830ad4756fe8a24ae075d8762bf5dc13bf076c96a73c4266390f07eb2039c21df9171eb0649b0449e88cfe426b12301fb0a7021d83f9c3fdbe42f67bb7c664613e9450d0a5caff4f5eadcf8ac641f9760b37ee609b32ecd92a8dbab4180ed25991b9eb849dfbaf638a8eee0e30e5de337482294c2e095dbb0cb1b6bfc43a991c7bbc226cd695508f89ba73296526cb34cfee1e98fc7f60d4bfb87e2d8f00a6c049e22c458c12e08c705158bd6e078cf1f8e6282ddadac0bc79f2a8340f4310004411204320702e68667d7a0bf32f86601fb14916c261c1d4b439a91108afe5c2206b0e2028228305426e8f4120aeaa0b8e2e02ea707386d6ac03bb2cf292037e4aa8844c355183db89ca0b2fde1f4a34ec7e0f1d78405fb82482b6b5c264ebf0c704381019a7cb336325b0ecdbbd4b75eeded28a2bd1393b634a010997807056f1b30ebc368b411b7cfd3c0eb039f8523e0cdcd14620ddc15248dc2b7f3d4750b0944adf3f3800ec442c8ed6690f4ae274e616de5ecca3a908d99f6613d1cd3e89c54e1d9aaadf388ef31c26987fad6ae855d4f3f513fe89bb858aa08581737ba96307fabf75e95705a30986c8df4ba6b4400085a8838451866af91580f960e45f516a3c2e9f4a077a0ba5d8e82282f99c9068917b17e6dbe7d78cf24d53394fc56320a8a29e67549c6f31f71dc1210c3f69017fcb06bb835d95a7fefded8f2268fc18bf13047bb01990b5ec560ab4a1a28423288dc43495542ba9d5676622e4ef7f836b0d5d15b97916838ca94e4c000387c870edbe8ba9459a960e49589178fdb806d1b15ff9087a5aed37621d4fab69bc5d8a32d020ab131c7464974c04d606a7950d1329bcd600fec317a13c6a9f04ccd3de5f3178f5ef24e1c68cd1d659a8b0b53d57fb71c7c793d7ec5eb1d799b6d2533723efb3d7a8aa91f310960c257d070a8465b65e6c267491a94dc55967ae6074f5a361f609ec91c077ab0571b6c14c434ce6623dfb00fa8879bf2143ad52aad5afd3be189ccd9dd507736a8b5e7565bf620477dc96979f9cdffbd6c265a5ab3f33db5676ee2a1eef60de5464f8ae9d61fc258d62e22f98e9d07c485f6834d2a8e1ede6a52710252aac887fb0530450e28057470e50a274b8dea05fe8cb0ebfbfe915231c9360111149d056ed1e52d1fcd27872c04be447bb3d846863657dea9cbd72aa285ec73459b254bda9590a58903a6496c10bda4fff88ab4828fcdc368872bfe7779b9debe48faad77428a5b2df9d042b4322e162664c9269d232cf738fd2145e0b605fe7bd07f5e9f0d6ba69f001059e550b79096ce116e07fe9966f80f3278ee439228666cb657ee5a72795b3ce972e216e1c15f5010c773b7ebfe220303a53084dee460c94fb796701268057e4bb5326a9084f30e3b026dc8e8445f20e9421a16737d6a524e4090fb91cfd14e8bc82a18eb84572302c153a6fe0027d6662dc296c3814c54cf98ad7c80687248821035bfdaef3df6ee6865cd72bd8ed28a8ace9b98d9874c66c9dd2d57195abf9121697ff91bf41edca4066ad58d02ae8acbe475a37dc850e7dc09173fe465f2fd6c0f5a04181191d7c483477447686ced22d0d05ea0ab69fecabf863cf4243b607b8b0bb38b96dbac9fc2d0b8e998d1851455e5f295fc5922f8e9ea80733391c8f75689aafee0bfb18df9c14671063e7ad2cc57093ba1b87ef04ff8554e355701e78bbe7352e553d240de10093f990d2b386f1aabe205dd64916c75d1155934a768d5a419df275e274ee208264bc51e64a1b2ebdecb4eeb444db5de490bd7bb52bb6ee3f64cb143fd64849664059bd1006b8bee221941de8f333990c1df5aed0f738c66424feb76a8d98153375c4e28c9d7620d67d7e650d39bd1ceeb2b98cc68edff8c6becfd4dd116db00ef8d473c5a45955505036805632f2f6c78e97c0534516db299b1a7de81e5fb6a12435a897ae20e0417004416d9811a173aaf145c766e1a2985fc06e26894b586a26060927db1f58f43c613cb4c4df91658a2d75c6cc36c5a329bfca2eb3b125841ceabd83ccde598911658dae9956a51e3c70ed8217f73e501e04e25282a5c59f78df0881d72bf153f9cfbb7ba70a12cc01105097e488573923b18733fe6cdf719c4af9cdfc3b86df2caf56ea17c632f2def79aa82210141db3ed2923308f2d8242e3f482a63637bdc6ce1e5c0153f951e27bb4bc077b0e3a8455a043a88a1c2d55c26f98dda7241dab9237923198cff1c6d079951b2033c4eae8bfdf3ef4ee7d20605790008540f3c4366bf098a88d33af0fe2c4872d39e4cc2b9beaef8efaa05f131a79059ec05e8919999a96cf5596e54297e9b1309971e0ccf79c32585a25cf1d5bdb54052bdebd2603247cdb65ee2fbb5cb354b87bbff3fd8ae2e7e8b559aa887d31ecb28d7f7729f4f9005e5d30aa2ffa3178d283c1426048b1905ff39018529d645106de0fc17b4a4b625170c50daea23deee0de8b7f6050f086139158c747cd7d648a5da9ab05b0c7ef26ba95942b33fdd74e7ca808e1921df58218410d295c497901d830d0e2799e04a38dd21be5ca212db177c5d34229cf6e2da59ab07213c2df89ca9095abd0f52dfb950d52cd19f03e2c6f8cc0b53c68e069528169382325df36016c3e2535bc0869d360ab37c40f80e195c1013b4f912e657af5b8dbec3025f0c80a2079073b786cad4d5124ce8fb63c9d8be59d9d2e1f1d3cfbd0fc7b704803b486701114be09bf19ba48a16d47af3c25498c8d7ca702653bfb31aacfc196fed116c598c9b195c6f37b6d644f07d0beeb0e36f7fde0926a9627f5ccb881ccab8d84e0d183c2833d6200764b3dd624cc55325e018ba61b56658afbd7c814072ac08ba88b4bd13d394b0dff569b4b68be80bb166a38d6944905d579f24734938a704fb27bc3955942402f082adbcfeb59e1401cf2b5ab5d31933eb1b20f97aa360dcf8e43841608d22dbf8165e5710523740c973f55d43cb759abbb279fdab78de709a5c71b2d87c6f13e7182e56ed6c8b748461f4e275c956f1f73ac4d7995b1754baddf538f0b23214815a0b1514af2c1f0c6bf015b65dca0a220f8f0356dcc8249487be7541ab3bb1667b44e01bec553ceed133fa29a8202a20d2f0dac8679ba00a00dfcf836216b75b4c6dd1f6abc718ef382947f939022aa70c436a451098f3268b31147e24e294b207d813845282eebd31968ce3c8be43a15461c9c7773e3421913abba79e96d14b992e0452f0d1f1595dc15b2785a2856028a7d2f43f84216a48e5167656a3635ab4bc46b1321a1218358a79c436b4f6cf97b5b6aa4c8d015dc76a650fa774f20a56f5b0abaf590182cf03642b0c2e512c7077f2a046b28537090b688688a00a5cccba355d18b969d6becf20c787d09cb908f5a492f3e46d61249899745b740a0a92131b654950cac71f5820b698400fe85b59c8c3150d4f3f9e875e758ea08b55c287a177a0e08f3f4a4fbdfb0a5a8b3480d0eefb16eb582b0af2a14a83a73887abc54b2273529d388bc8e1de1160fc42ad74edab7b0ab40a1fa8e6f67538d15eac7a385393102fba0aebeb689d311e43809aa7c1dad8739811b675d156173819ffe24d873efd4352fe7d48bdc9486a8df48c09c792643c6d530cfd76a0585d1db5921a6873c507d689e4d3a649f29fa99f1e8c7b7abbf17d05d1a0bdaccd4e49c544fef73715f008bcbb8f3fd20180348999466353d745342167828c7c042898aba0436d08b2c61e4a1d3f5894005b6af420ff13368b05a478a5c29821f1699a6f6dfe12972ed50ba9b15460c4db42546246eeb00d29930fd7dbc7fc5a40d9c27ce6dbfa477f1b62c4656be9b9b75321a65e3a27bfd81dc0a59be4f4fa3a21cb9cd246c9b7a41523781d15f206035ef87e71b4d8e15f501552f7cfe775c6e89494606d25c5967a3c1150805a6c29d272fb97a89db2ea47a3265b80566176b919381c16739cddceab3d177eeb90d8bbcb0461aee024c000a40ae444f173d9bf046921924e44dfe80216e75c00522f2109a686942afb3c86335d21fbc11e97a801772963255239ac132fdec5c8e7bc76287e007ff056bb9402ce1cd3cacb0acd866c3a26c6f3357e14be0aa38342dedf09ff25bfb0406daa077651960a00077b93479f176e49952aa2e579d2dbf807167a793e2263fbe9c3f14b03008baf20f48aa32e0072f4953b17c357cc5e34f4c0cd2bc19e00bfe318d8fe2255ff3336f48710da006114b102f48489e60c74ea502604043eb4f8c0239bd01fba9da2352479308d88df3afa48b3588dc61322368b83c0ba9f574f64c5cb18144cc4cc75c90f41ac1cb7ef532ef44044763f84c04f20a07e246ff2033655b52d33184a043558fd8f0a6d55b08f1b294f0ab868c81a3ea71758f129c25739a9b03270b412bd312b0262d1209ec3bc3ac8c9feccd4a247216ee2e6157a41f5057dac2115806b869a19a4094201a74baeb8b51904e034fffec37db30eeefcefc762e350af764e50afff0ec8ccf531c9219c26174020f751890679b25f86a53b47c2b5094da7c932914af50bb08e2f65253c5f4e35b47b574b16d5aa586413a7a7cf721fa5f08c16fca4210559ebb694a19d20842fbbe08ee3e49ee1b8792850cf824099fe531d382780fecd6dc54e441a6fadb23c3eb4b132fa3d045ab306d0e25255dc5803a1a3616ad835a155983dd55c062babdc9f35d3a6975b398df7e252b4291665dc3a77e112c8c64de32ddf5eaefe8ec77f4a688da6124de7738f32e62c73cad1e0275a7747d4b8fad380bb6112ccc1c98284055dabe58d8ba246b047215559f40020057e0f3562b3b537b095288470437faddf034e7c7090bbf2ef0e00778a19a56fc869a485c93ac03e60da46117270faf7d9092d10486fc8b6c316365121d887118d7e2c229a14076eda3a2ff1784ef5af1fde5f289a229a87fa4b18126db9e6c303bde7ad1b5c6a5c558755c310861993f02c631ba3858b82074a1e6209afda7908b4dd8a3f82f5d8dfc0022986aaae46d21a7d20b60e4f4976063c5dc0d0387aa79dd74879c4d8913de26ca2b31c9bee3e257be18cd1962ede3a2e4021a7d7596ab852d6865ad9c75a05ca28ab7e591fa6ec180cd1ceefc03e3619a49af0efdf3bb841953bba28aa774ff4b45de330dc5023f25219aec8462be6c15f46278795a7a612e3bf555addd197fe4dd81a014a7f2ffbc307de24f0748bb9368f09c1146c903f7cd3bbcefd321d0d3aff996ac0e74b904d31f0e57646c6cc2d084f320bf0b8cb0223797c82d984921188aa19822a38ebf41bcb0acad54d6c8a42a75895418b607c821bfff7e0ad978d7db16ebb6c6728a80d25bc893f14743d25dbdeacd50fe7e89032cd095c9af2d3d516c7ff7037d05959f289a5fafa803f7ac8f2ed7e7236f351749150a8e1761c63cbd4e822c1723fbd17a421810bd90b8b852d19e242ecc726a0d8100d649b376ef881bae0d008e0ba0def21296ed6fe5bc340514fb2116935c0350dbc450413dc3983d595c9c366b132f55951c7ad934aa7d8f457785e29abf8f9ae245247cdf5ddca10dd59098eecdee9a0deb6267577cf687c136c492fc9a880a333e62ce93f4dff249bc69a634e6bf8eb9fa7bdf4c69fbccf4c106a866b4fabdbd26fc5b3b030c3eda01bf432dc228f853ee57b86233e651b7ed50c3a46af16e5bfc0118533cbb1d73762071f5e332d31e23a51f6ee7ea27340e1168ab2018584f74168fca27c9b6b75cb96424fed60c53b7d0b6b6e5c9d3ede313004a05aad1fb06dff0c016e759cd7e8e97653290fa18cd9dfcc88d2fedbf80bdcbd1529521f1f622ccf1fbc51712071d42daab8255d2cef9cc1a4cd97ba6c0c93b1ca108bd2f2ca6deda97c9d6fe5f7228e12fedff33ea0bf2a30f4170bca7f5d8d93ff3c63fd338f519499c7ac5016ba9fb7610f07eb8d4339c201ca91f3de4d97787df367c7d8848f03effb989cb86dddd2e3f7f0e4f8e8e8e874681ce02c0d57b8df8e8103c21667f1f4f0f070f47ce27ce8747676344e1cf856b06feb076d37128b0776f3c251013bb8fb09d13565630803d5492ddbca8a010467a74cff46b88cd7d30f4fd992f3292088681506217de5d3f2ce98b3b62312667e2d7e51423effb73461ea329c2a9093a96eb7a42aa5893a60d00c155bcb78830d88006da07d97d18a7372708c179747d0214b40ab14dd74b352aff8deaabfe0893a21f8a33d649fd01e18508241621a94c4f434de37b7d4209dbc951b766443409cb3eaa1715c4c3ab827ef522bf4a42a104a70150ae8da96016229de5985997e9f6372bc93f8b83193643ce80a2d6e6b7260c8ef542a33146fff3117dcd46a16b09dea14132c9b3fcedb8fa45c7f18b65aa73df27d1f081dffc59836909fe55da6ebff9ac830bae9d3702dee48ba551a34c2165008704219b8b423c9bc8b18ae5388f185e49e87f25590ee0a94d489fa4a586561b838d54e1d8cbd80b2c1f8c0555a9aa4003278ea5b9a4c9f48e142f7a2e4f5b5ba172e377a0234206f5714df481eff8b0312f3fa3b2f911aec1752c640f02fcb3dbbce9442ab47df9cdf9a63eb23a3a5ab934e768c6216f54a4bb1e22ee7ef5f64d2bce5a6337077d8b8e9e31c1d0b9f267bfcb4420af61f77158c7c5ccfb6cb897067270ed54ce5eef40877149ad49a92a8118de6843f752f0782f767970de630e11b0d731a6bd793cb4cbc98a535c1fd520128b59c67081efbdaeb8a41313027c92ce1c6d55829ee896bb7b500676832c4d06b8390c87911ddd08e13b089682c4f791a1a66f1f45cb78ad997720dbc27d22cf9e3ba79ebded890abb199bdd286ef23ec2af0d4a76ad8d5480a5fe72dcb8d8ca56b15cf42ca0ef373155dd488276cec980d74587d372ede4e53883a544b8649d1849bd348e5a265583cc18f36095791af22891889460fc8ecf7a74309adead520f680589f3e4efd27a778e1931a7ccdea6d05a37497695a84206d115499dd629d16e44590f4d608321b6f313040ba07e7d363fdd04a608fdb0b8d26904fcf5b1222d5e0dd5e199173b1f6caf692b88c6ad29cb5cca81888e22296951f6f41e25e983f89d0fc3a98c4229573b47bd0674de31fae8cd9a912c969bf2d50f40f736f7c4e8b42203402c03d5ac11311fa4c4460f70f02785446b8e275018ad082b74828f3f71e8bc4a2d4204c5a0f717763fb00cf50888b9c191e0365985500893bc28d0dd93fbc805236cb517db2838876f4565cac7e2b761fa6314d10aa048b15dcb389982126fd511b7c11609961ff287239a844f1ab4e695056112636f68f2289771f308b340648ec205c940bfb3dd3afb5b6250a22c56d05a0e360611adcb8fbed316463822c95141360e85597cd9d717f20f5aaaf0ec100179e10752fa2471e1b0d18f2a4abdb7bfb4af72b2b8c6e40d718de1f0d3307a1bba5f6996d12c7baee2288a55fbe69cb21867e1a187cfd0fb58a471f554a48e997c5815402745191bfd1894855def027cd18c44decad90cbad09e43f2d173067592a10ce12255b205e580541ac580a2050feb05c40ce625778e2c7a6edfe92a56adc10675750d1e389a3d86443f2f37d96158a6505e42591a78669d2bc4cd78ebb9e177fb4a0d65c6c4b903f5af88c760887893b94baa949bbb19d0646c0fc349e03fa20c9673f5c7fd56b566c72e9e848cdc9167c1cfc8b83644f31da12042f488374afbb157281e39504ba8de2b8d1a583bdaf6355a806bf79861ef7cd853601fee296bb258b23b45c0170f75d390f8e9a31b7f566b4f1e68be6bd7ae55229f6d808196ed22320fc1e6c9d91c78a4d43887823e4144da617110ab8863e69618da374512a3d71eaae931a66eba757da03b6d5eb4e8a3b775838f0d30a252d9cc4828d02ffa096667e21d0984f4b44bb8daf4bb3497c2281e25e6a107bc081f7f890385af90ff059a30910693f77c09f94bd1972553ad3280e13984ffbb483e513fbaa8d203f806e42f05ba268ace9b2f7f46657bfb1abe6d6fa823d9ee116520c5c3813c68c464d9e923f1a0ef3e094dc38188e537e5c869a2c2033ec8bda9eb2d908fea3263350b6a0b448a29d02ecb15a8262b584082e66c71ce51681b9262b003539eb6e111eb377039ac8c16b82f83ff11ebe0b2103d4bc033acbe2925a2090329b0ea5089256debb18600017deff55c1888e5196e41dcac7d878d58bd68b2e348cc3a9341360a1cb2dfecbc243285049079773b2aa2487165250a1afec1dff8059221c33f5dc8703f5db979915b1ed6e7b4b29654a5206e008380926094b4fb4408d21a4196b9cc1c40b3658d04316361c914349d485a289d5cabbb1810aecd97082171b6ee058d8bbe1e18887252f57504a29754a29a592868ebd825d482b6432a3245c7c5029916195040b4ee2858c5225b97d5d949577a3a4058f2533e27ec0430c2f6ac4e890440ada04050d5d2c8993df0f461116cbfdcf3939438715c49882861b5451e44314143664b045962b3a50b981cb978406e344450627a921471228b8f3e9010ad29165cd8916170b5b2c065606dd0d77b9a7ee46124128a1f1029311153a300551012b9ece60c2a40627e8524555c3fd44772dd2e203ee723bacdc3527463cc93259d69cd4c082ee1304f16468808a8d29431a4390f9de94734e0e63168b2ec993e65da0c6994d14092152820a3b24e529bbe439ffda2a6bad95aabaf973ce39e79c33d69cb3f0b6ed02343a0a8e73c3167d23b36bc3167d39d1954911e2befb2129f785baf7c2a18e35c4855323d7b16cd8aaaffa51bc12b8dfbd9015ba5cd8a22190109914e8ed34608009fe5c78bb3a81f37caf95254b46a50696f38912fa8bcc9e5d4408f7add690fa5c8882bf841c29725f8a507dee85ea73d26bfd1b0e71a16847aee2fe98b08744bc2378fa18f21920656882bf0d67189cfdd60780b8bff786a34f50e67b825b6686d1249798a8b4d84f03be3f4e2ab97f04975ec47160be8b8c5eded697739c446188bff04531f708d306e550a3983f5bee32692ac7913e8284921fccef4099ed6a84279f0341662b3b28f499330e8bd3681215cdcc256107108df1451ea516364c417e05a114619186410ec4dddddd33151bd556b574ad52de1aba4be9524ae95d0f35ef08cbf760545660f99ef4f979864b59ba3765f9632d5a891f764a6b9dd5bdbbbb5d2b105c7486a32bff7c8bd2dd35d3a2abc57be7b546542778da6aebca08bb5ac2f34f209f8894f547978cc9ac0547569ef6fe075900f7fbc93fba4608d2d2b73294524a29ad952e84322c1cf02893655c322c9a2be89252887d1eb9cb3dcdc91da43c810b03bfa4f204994fc6be4b9998b103b9c6c4642c29476b2bb7808c35d33147a6e10932cec59333de0d9e0c404d428b52551c7198f592d603e31c73d8c6d98a60eee3b80f737822994547fc294729a5b488e3709c35c2fd46964bd995e6cb5f4ef0257b49780e2171a4ac37999380ec3f95640ecd3ea1984bcc23b283347bfddd7b9bca94edb64f705269d1fd69c045a61de56d75dfaf4ad5fd546a9c39c4d3524dd69a1ccda6713265afb41d94c8e374da41298f334b7618b7cd5bf65775d39babf932bfa76b3722454868d17d52366c1337ef4d26a60c2c7fca55bb5c3f58866bcc20a63ba5328fc3fbeed6181d9fe3f18e5007285bcc11ca80b2451c614c88c371d26042d9e24b18865c287e17f7396992a73cbb5944601a347d5aec69713ecdbca5f0973c679409a5451af0c8cd1987318bf55d9e83c12cecf45d4656cd40fe6a1aca7cd405380753193a32366b4f54904516590c993a4f787832430c93f797c97c502293d950a760b27b5f76c19efba3ec7ebdf6de7bc3b147b62393edf4dcdab5ca48a8f5fb0044f6a6444c6badb5d65a6bada5feededeedddedd3259d743cd0727b2b7cd8a57450ea699a58ca1d168b4a6997c0abe9d754e7777ffffda1330fee9912736b04e18e3f125d3b712c7ca179d3e2626a28c27110693c1645206bb81c16e6430d98c155c1957c993bf607e37ac5fed3077ffe9dedee1685fd6b01b99c36433304a61b0ae3d8982c1d2689bbdfa4fd9fc51467b66d397f5c87ac29b169d46e62f8382b2994a9d7efaeed46b3e0c21b3893167682ccd0d8dbd696be50d0d8cc6ded0dc882f69ba768546be9ae6e546439f34c160b5c8713ac7b91da3df212c5729c56fb17e37d3a264ad90b6781a7eadb625d812ec56451adbb2b62e355d8192aa3d45d96e5b727d3a9d3aa5b4fe4c7705c2051d6b913271420bd551aefd795722c7e99ea34d32a7bfd221e81079c44a79ac4660eeb073c251b9af1ae55a8d1a074fd5a3a55a8b922b945c95d6a092c7ca946bfdb13ae5b15ec9b5eb73d7ca27d488ca76ce1e51c85875b4832711e0b5695d32c7573f7552598bd6c3bed9b9a9d2b5edfbcbc29e1681de07e8e5778f048164937c79a59417a8c7a7c5f6f7e9019299f6008d361469770927d4dc5df4016a7f8e73eff6eef67eba3580f39c60b528d322d79ab37f504aa9ad284b1ebf16944129a5f467bbebe9cfb4e04aa62e7716fd19b25aa473be8c0c225b9cdf9986d239a369913e16dc851fa5c9942aedec744cbce9d9f1d991d2a7070604dbd9d9d1626767ba4ba6c5c744e0fe5186c3371de4fdfe39b99f99e35eda0abba1ac47fe2893bf1393b21e59d7b9cbf797f54829eb9137e2d3cc1f699ca66787c68746ca645226b381cb7626ab09fcd157894131d0f2551f0b70bf10912c231011229285088bc56211111a21cb084244848808f1d9011a01ed08922115b2c870c93b79d2b814e1c245852c2ccacac2a259bec8da408b1d590f8e2c6b4b466d5419f509a24142578408d92021fb3e8530c6582848c81521414233480868e7a667073c7e57829a84b608691a61cb9613aee0c6b236c58cdc4a70b0bbe353af4f50ad55a020ce27a81664837c806a403e4134bb4f500d7b38190932197d4a29a595da5ab3ac4d1943d62c17594f0f900f500f101050934f0f50a53d403bb6224d2474ac8413bc49daa8a43d4d4db52939c834944d9788a93ac256e07e4ff6146f76b89fdce47e9a30bfc7e7de9dbb93fdfa748c86eeeed3b333bfc787ce6eeef84c2e94dd9066a6caa481fb4758dee958145054943fb7b3b393eb9586edf874bf4f8341fd4041d3278806758cba7b904f8340b2d61f44bb7d82bae7c6bb84a99a0a2318ea199e40428b1e4081472a6b520a48884b91e0236bb2d68213d01f28cdcdb47f637bbeb5efb6ad6dbb7323bb997f236bebd5bb61373d1d9545a86f6e565cdc502b6eeb4dbffc527a9ffe7873df04fab29d9b09eecc9d8e71efceed8037f46615c4834c5f76b3e393bbe91d7a43223051a8c59b9b3064635418d93f0353a7df1f005cd0d16be3cddf38f51b96ac4d7122d370c43772aaa6619fde4fc187b7648df390a2d7fb1ead4f2b0f59e3efab054cca92356eebd75cfd5953060cdc55346d4a9bd2a63af22b05c3e9c369f7171efd68a8b20277efd1af7eab6945341aad05d70bd961376b74d96b50a4b2e3f4ccdf53555ac7c6e97d257b4b91fde78dbb8979058397474155e425145ba4451c87a65158855ea80adf3e0c78c42afda082dc81a3e8df170cb9f0a38eb1972985ca3c1207463ef10298d07f42a9619449253b4de388266620f560850653b3afe86bcee6c91160fa2e6b556859564b01955c93658d072cf928298fb0dad1d1dcc9352c6b29b065580aa072ff8d6ca73d9810fc019486ad07c819ed00533389040c49d4a085162b667d80a9999cd1afe1fbabc5dcfe82c2925c8a908a010a22a32448b3970c4d5e2841b2822b3998f5c3fa65fd474e59d68e96b20759d67850ca3004c81c8be4c29c49f1f7a8d0945198ab07fc593ec14485d2c0e2a4ac22055bfd3f9b60ab652d7a908faa0bee9b54a866e061a774d2a9c5f3a49c53ce091a991305afdd9d52a74e4731cbb9c59333a3bc626a093c6777af7ef07bee3f2fefd1283f20d04c6b5dbd67ed0ff7debd2c2c6ba6ea3d8e9b764a2359d37545aaeffb91df8fd784bd979717181898d5cfea076318fcb2c2313118638c5f66f63e8f7bf960561ef094b0b59155903ff3cb2a082b4ba72c5d29cbf724c7e99bef68bd7c37729c1e2fdf8f1c87871abe24cbf72432d6f2088917e1d07a4be338cd5fad7af90d15157b79f97d3b22a5d291261f91d23d0c3fd381539ffcd58e5fb2febb9ff7719eb4b693397478ab0f06945e7da12c5696543489d0e4928aa6dae1f8f09579e529d1fdcb0a040af33978c32b42926fb52a2eea251c5b4a6a1586aaf047930f4dd61cc963a5529364cdfc4e29cfaf51561044072e7c63e5604c3e00940dd4cbe900502fa7dcefe1f87270154472d9788cfc75e4afe6a1f110497dc114953b7081b22db29b0a0b3cea4ce94c71d1e9d231bbba3f6a512e25bb87f7a369a6e982af26591315f585634b4979e1d85bb6a8420f94aa9d69ca3d7aa0f43a563f3b92c00ec2e41e60ece6afb625b5188b12538a51892d71b12f624c2aef4737f21fbd686563b3b1f9eb36d562db70b15943672a05dd11a298528c8a8dcdc616360f6de4a1f9111eda6863cb4f3d8e2a3efa58ab9fef59ffe33db7e37bda2a15c1a98eb083ab0e44eac0d501541e13609400a222d94d36d585d545d6d47e38fdb8f2e3698d34b270c9ad33e5ae33b563945ba78beb4cf96b87b643b48364670917fe68ba5cd562f3540e7e2a3006153b8a418925c5a2c4a272c7b4c892dbc66663b3b9b5d8365b6cb85c1e5a0fd0872611d01ce8e5289b54114fd28e22a3265038b1083c4a289a685034cdccac7e54efa0ec3a0f069c597584471e5a770f3077a1f92b4f2d3135d59c5ad4e17906574637ca8279683c477890d8d83a76a53a76ebd8d38c2673b8efcf593a2a4aea25b4b1d9d8624a1e1126926d91dd2af776be47c4d5017c0358fd549da90e446a395dc902d562d41749f1d078888a5aec254d9076589a479335fd3a5c1a6747c7ec0e4bcb0e7a0722b59e05f2d076b4902cf1207f210f11016080c76a6b817887cd716a92bfe6377559caf3c73a95ab52b57505f81c6cd9671d9c52823377d3e76ae61770660cce0ce3a0cd15446a7d0722ed780c4e59335b2c50f607e36756cde7a0b491ea57bf8d4d4b55cadddbda5fbd037c0eb6b2e7e373b047ae2012eb3b56a803c4b0cf411eb982483b9e8608f81cdc91bd7f0f3cf060f56323d562775d17dadc6c00b0fad199c282471e1a4f51c7ec775667cad6eee67350267b1f7c0ee2c81544eae03b10c9f53dc059d1ccc85fddc1eb00897ee69a1d31913423ca4f394b86ca51d976673164a91f7f0d169725b6d40e401e1a8f114f131e281eac1cd0b31dcf439339ddf7e72e1db38ee3fafebc46e3c86eceba49268e60c90412d6926fd23728093062228ace148f91e388e0e4af9808502db68c89c085149b8705da9c215ffd2ed0460cf9ea17810b19b301438a0dd5311b5b8b67c89c1cdf6f6386ccc1f1fd3665c81c99efb7d922736e7cbf8d0c644eccf7db90217360bedf660c9983bfdfe666238693e38860b30943e6bc7cbf4d0c648e8d940d18365a6cbe9039aaefb7b1c91cce692a80e8b9ec10c166ac1f6d6e90fb6da6fa07ebfbbd0eacdc07a3acf590fb45b0394e526e25ca24f7631d723fcc0eb93fa649eebfe124f7cbf090fb71a420f7e738cafd7e83ace95f813e38f8e400d68c3ab03307fa2451813e4a401f1b644dff07fa2c91351d38730e50ca1a2422d8acc7e300918864b31e7f23a6c7d310e010b0720d917a8452da8cb2f643ee870136931201a3ac21e57e9f1ee407fd5eb52ff7b30bf43102f30d7d8a6437c78951e9573fd3ad76bb42cb42148b8a49e5fe310146363600c49498e09a8dad2e497f29d58a1c7cc91544723d758522d8fc558023b86f797c590b4c000dfc3105fee872731cd9edf6e306fe50fa41e5c712f883490df9634beeff3186749ae3fca8fd90fa285616fce34aee6e16a833a5d3e5c97174d638a263b50056bee18f261089e8673b7e003ed8d854dff7f320e17141e65c11456e41ea88e0347968224835ce8eef17c1b603d4e1d23f5ca8338505d699cafd3c349e233c441debbe5f6749e7a6c3d438390b0f4d76e3a1c96e3c34d98d8726bbf1d07868b7dc9f63b5801c7995c3a887116b05a455f53e8773182555b01a5d2879fea76ae2c46407a71cab1fee73ac40a0d995237b61168bc023e6a1e5289235fd9e8c056feeeaf7e08a72579a8dad16c99af99533ca75499e2f826dea24c9f3fb6dc8535e6173b04bc0e720e7e558f0dbf9e4eaf30c30138010ac74878e1def09934306c78d9897f93a403993574cc974095a7852cab7aaae7bd2e943ce316804bcd68e4d1c550e02827c81dc202cd84c7b7612327b3052f6a4b9e4f7e012a3d4698cf32aa814bffc752abab2ab504af1fb86545d48c9c05294a1d47b7ed3cbc0369cd5bb2fa53f0da51455217d0f544d1ffd3694dc163c43f028192c6941a41de5fc76a5942ecdaebbae8ecdb71dbd54aac0cf05e08dd5023adb104f1ffd3dc6c0b35dc0eade5eae01feb4abd5ebbaf7e7ee77e0f8dd776f95e5cf550837c80ad50209b242a6340c4f4a1d973fa60ff93d70c0f3e54e4eebf4944d1f370dabdff4bb5290c65d6c513e0dc39bedb4dacb75df8fe9ad6037b2a9a37af9393b53c79f0503e2ee5cb91e62e039237d0c4002d943e9a3fe5d01e9973eeadb15900e29d0d5159096a28b044ebeea7ba0b34a008267774d6b60c30f324a9e3e2229255cd00213962d567ed8804ad3549515b4918612307028b9414c14320c24162005e20a79662a6b7a3af72a9082dc03f9c89cfefb3f12a788bfeedfa6c8f7e58846bedfe03c226bee17b97f9ba07143bef7deff90f0bd61ff91a372bb49c01c87318bf53f8af7efcb2eadc57befabeebd5ed414b8e7644d81670addabc0e5fa3d9376711cec2f1725b53d2d3ea68229c8813b2db6867cbffa55c88214eebf10af4296bf5cccb415849ad00a926dc80199e70a48976dd80a624d6805b9f46f38634351059c6d8f8facf1e7c02021fd81ff057fe413f536059e593e0d9fcafc390e636fc29f7b5af49d9b2619e67fcd53c6eadf6bdd8e2ce40b845b7449c1415ed4f2e78445ccea21aa1f01fb6b7e6765c6859cbf561290516829729a714e933cd577efa940efdcf577fedd4f2445987bac1a721fe6afee67917984c8a72d20a1e026b9e3baee811aa7ebba19e42e0d0c85d3752f657d415ad1cc25753f89565fd71a72df7b2f64c1fbee2d2073ec773f8dbebbc0c4e1e4ab7b4c86a441ee5e4e1ce4ee2d089335dd5f905b8172f5803a5b85a2bf3a30f0d7a79fbd2267bad0843a55050499ef4b0ee62f0bd4e2bcadf9aef74c02c7f57b9112941a05535152ce2c37da3ed76e34dd6bb04759d65400254ffb4548a8214129f5377eed6e75c03dde7bcf5720dcf8af45ee73c24dce712fef5ccc120f1815fe9a78803d1e078eb9c48463464da82cf3890ad704e3b9c80dc78b3f1dbd78f8e1b7dce3781bf35173c9718a4cd09fc78c9a503138c0f9047a2ee2a424559e4bb03cbe70261d4928a1162d0fd89b2b106e3c91162deb8610a1c699f9c62f77a0b800cf1e7e8b560261abdf48ee709cb9c7355dae1a8a5c530552dddd1c08faac7e5a415ccfbd2b046ad1ba5ce1545af55fb0052434922d949723442fe1a47153c995d46211d6cf09de0960cb0333bbde487685e39ceefee272852dcfaed003b38ddc31dde2e1fa29c5834767cbe468a966edcf2cf62754c76e64fb33cafebc354ecfecf370d99f50665253b63fa3d86ed7632bd8f59e0b9c59c682941e0f86b221e0871f864346666008f397f52800be41cf5e95b32b7de1f19e79000094b9489116ed8feb79b86e3cfe171eb10ede3e8fb71fd4b177bd557900a503703e6569d13e0f7042d1eccbe3971df3fec6cbdc72ad56ae702685f30800a077c3b5c7f378155ab4cffd8e67bdab036bbf83702abdeb31112efb2d7012b5d80394e11162263c4a5b088221e72fac2446135d666028fdc502592ddadf01ba5a3ca1c5221deb97d7118e5cfe728423cedf8d970947569eb4699568ddb372f737c291158343989770e4f287846752388f6e98fb790486435813fcb9120ac087e110dda1ca2c0021e7ad0578165bb4efd9fa9d48bca99402cde38fd4c3a11f27889a9a85a15c35800b7b7c5ab42f37e0d1952dabdb4e250eb3fef377ccb3ed98ccd696d0a27d6b59d98601780fc0cbd510ec2fff3000e1908c428b191872e087e1d0e4d28515a219d8b1d934011471749b746c5e28d9ff897bd5fdee87bc1121efbba7341c1a323202a7114ae802057473ba4928a1ee5531df3d0d8586605ed525fb77608b767fd8cf428bca565dcc170eadc28eeb68d8724007f3aa6721e6bb1fc202ccab5ece46990456ffb5688b862a707e07e2bff146662f730907914c3834938c9692888c6e4cfca2227af9711ae5480a5b35147244c78e9733fce35c9a313f24a57ba7ec42307f231c9a377ff9c3c08443134a150edda6d39c509d5307a59a30fe18bc4960dfef1ff22d1b1751b8dce088469bbdfc8d972284a50879f58788b2bf9724e4fd8d70a8bdb0938cbc1f9bc8fbb18d929ce8d6c5896edd8505ee00af0ed076379513c97c43f9cbff87a408798f7f488a108ef77e6829fb13f1cc6e08bdbc3c0e5fc22199b09da0867a098639bbd14e312f67313ff6524cd8aa6f647695b23b4cd8aa466637a9cdf07ecebc7f79988781f9981782f998252118237f49a249fef2efc02437eabaa4ec2ca8c296d0eafb2e6c0d59fdd712d2854ed97f88ed82830c9c3871a2d166ee44d433d597a0fb2f6cd1d197b2ff2b0d2c6750504e4c321041051552aa90851274210d0825a244374ca32179a1dffcf5a34365ff3f821570a4294b29f24893a851f6a7469448a87befbb9b94fde56ca446ad2173a6fa3953bd77f1dbd7a2a1906b74e4ff31718db2ffa55d223b65bba87eb4b6dca221b5d9db5476ea94fd39902e81ef029633d56ce6912ee527da3b9a5845d1d44052d4c6155aa416505ea853a68e80a2a5861d98cc28a594d6262e274d2a426829e2861b6a30c56c64c9868a95c1694007275d6268620d25b6c899b125a22e8759b0f624acd90518aa18b54dcc982d576831831867dc3084bfe0491405c4683af24593194a58d080478c7ba0b07b1217c4061304e11484910aa4989d4515decb0f5996b47c6134c415ca7937133306366e70e249176870a183ec1734164f987278c08723564491c2052631c8995d8349239e7820820a23aafcd0b4e2d2031a388882140519947a962b9ea8407606961948614697267228810e554e70f3828c1f6c68dc2309ee6ac68c7ac203a594a2e1aa82f6cd93196262545ea085259858c152832c8aacc8018c0c3dd07040861033407aa21a65fade0d256c85c076e61b8e17c8e30a4fb429539713afa2c527ba8872a246132c5255dc80638244050c3960c122860d36c0422b7086143348b1c4195856209fb2a80590724617215e8032430c334a29a535a4b9f16c13cc2d9c88a12f7af71530640142882d32e032a5b1483086e8c209195ba2a88822c48cbea8048f323255065349ea1086961a4cc0061a33d8d25400712f184b7cb8a2c68464ca091e59b93db3648d91cc71d517f44676d1434729a55445abcaaaaeaae3e40d47ce8623ae3399c699341491393353265a5841152ac058524416d47b0a1d6e3612030c9ad8486a811456b4604629a5b40b27bdfb69d222429226d57c50c2d11769f712d6d2fa92da90c326c810cfc020e381163cca78a592d6ce72e62e3adad5ea5eb91a7ad005a597d65ec3cba9b53ecdf62f956fa5b554d65c5b2badadc609793ec9cc607a28ebac734a39d7e456c173665993c713e45396491465153a6349a50c1e69f6e73eea5efd29d741f660fa18c2d391e54f00645b6bf794c958e51eaabad166f9501ed731ea738a9efdd246ec9c31d802e32c6b3da031440f3148ea01ea4972b887a43cb2680f383e98bb0326e3d3c3512bc121d32c6b47502e8577a9e0f9922543d17bd2ee6e0864ba64c50a049bbb4cc3510459aaacc023cd6ea594e142d2bf321c0783c964ac2a9870dc0b18b358ffa24c96853890bf3c2ab5885a6badb5d67e9f8c9c9919a513104602d335eebdf7de7b67ecf784826f109915f2056ba625c817ecec150c95eda94555967ff1a62748266bf24942a99a9e9c3a36aabcc8355593ea4995434e61ae8ac0a36a29fb2f75ac86324cf7baca0644944fcea1ec8121161633957d52a42f5f142603922f6444e1cbd6dad003f74a2ad65a6badb5de77b9ce0b816296c0e34c06b114ebcb9c90e9a3803b9053c1b9ef3be3de7befbd37e85624f84ae5fbdebd773a1da275057aef9d5d027b912c9152a41c67836d6ba79d6dadb5ed817b635082ed4822456eb6041496b8fbeca8c982ec576494b5d65eee41ce5feecf42c2a3acf9dc00ddbf0f93ff4ad4092b1c3e40f6a7993efce50706f58ba2816d10cf8221b0610af7460e13748c99be7db74fed0d5983630399be8db9d1852307327d97914760c03d727d96b4a94f73df7fc67b72219e89e94006552056a9ae19b6ad9d76b6b5d6722f3b152800f9a23fd6c4643b236be813198732e57298aeec7fefbdf7de0bd42f7f595580ef8f33b3d219c20da714eb0a35049aef7dbf610a77e68e539ce9580d91b877592f28679c6d6b6dbbb5d6ce3a9003a5acd49d8894fa68f7e86ccdd9eeeeeeeeeeeeb3a9bfbbf7cf15a594ca10e9babf5f0abef033650da53f44de44c2f3633c7f1f94d5e28e9412c79b92284d8928ac4d093294a882e5f49d9b98d372b7a0ae81b3ac29b194c71d777724cbf21c78b4d6a75f80d9b1ce93334d2447a68f650ecdf44790395fa62f57344907fc79c4466a68f2440d0a0545507164365f741c1e183891318314254b40cde60bd69842a4650a1b5a6618005314288c28220a32c498c1e67b2190bf62ca32e4648dd7ab103a8f2b64ee8736a594ce96ddb4db5f8cf44c6166f72a08c3cfa4483a5b3e97a76bf694e9906210cb1c9f3c78e532e76ce69e5f573f5e5741463a1ab6808cd443d6095f962d1ac9465640da41cfdd861439e2ec5fe6642f2f704e39b9448eb1c111187e56dfbe9c197105bf6a032c75d480c79ff41b29082f1986d26e90f6a57235658da44c5985ce9e427697e168fe57ab5294e77320885966c053617ef5d084509a309f8626ac1a6082875f8bb706782a999ab2d98e689a4a70932c3f4a96a1e8044b28624014035a9eff29c15d965048a191e78772024a0f68ea9f0fc4ca8d006330c1128aa9a9ac9425145347f96609c51493cc6509c55418f921e0c9bfc1c6c465b45bb1a9bca02a2c2a6d924314d60abd3908c15969b24265c90a94a31c7ce858dc8783ca637284779cf15d255668c02b1a25898503961737b272843271e170680206479635261b66e2626693a31b1dd3e7048e2ecb1a1313c5a186cca7f4e12c6b4c471c531113110f2d39bad000ebc8b2864454d3e4b6d0a1246b4b8ca0515ec6053b90c8b2864411b659d6904041ce013482479a5559d690a0e12a53b71260593b22cb5a155be672c0ab283c74e0d0a3f54970b6807b4c1a96b52a4f72fe484399203c39f3d643213cb4c05124d1f22897f4286b525443eeef9f35c89c99fbef0fad50c55312a799fd0b0e9120074ab3eb843393981242a40415646be46e69db32d585ca76fa7b8872df21b5052cb32b040bcc589ad9ef69fb309ce309d3278fe37c565186e5f36bffacb09b16e5abc8c023b56e6df5e06816c164abd7cf831ab07c99bb852c6b4520c9348f34e37723caa791ca52d6c1511ba1d4d3cb520a004d33d0a47497f8c9c7f2658ad892251879fcba02c1dd7d4e2b93fded4b4f9461b9fdd91e98b962a96fbd002ee0d148a674f543a9c704b66da891b96f09036f9ce6c382b950464546387efe9eccf190ca1aebd6561b952c597e361a2a621ec5a8b6d567be3c5bcb37e7ec615b2a9ade94d2d456adada39b9ea0113a266b4648551a952d79946549c4924cc4960ea454965fbdfb65f00ff8f38ec4b928b8ddd0a57644152a33f93e12e79ff002ca852a5b2445cde4946b8626490697272172f004c40c6b787f91299567bc60065150aab480893472709fa25b4120e10213313859624412417c914653104250a1c1d65e4cc941a7ba49652175ab8571b484098824b2143106922442425a2c6a33e416336a6dd100420553b088e281872e6ea6688173a2b4c0640b173a38f961ead0177a3e4d410286292ba033e0a323538a5c58b01e7b1c96e1f0d7a2103670b3244a2a18f744868ba45f7249938e05840c99e338ee599ccd1cc7715c0d4cfd9235ee4abf640d59fa25fbd35032c3540d6098d190044651d1d1163114416581618684b602286450b2a45f32734a9af44be691c33e5388f0c771b521bc88212222c90af2086bc25d96b52447472e2c6cf0c69abbeccd4fd2b428ff956b720b48677f9b3b7b734e98ac45297ee720954daeaa1374d97c80cf60ad2033cf5419a84b7186524a296d77984c75a3474f77da7dd1e4eeee3d612dca27eaee1e1add17f80b8ebadc599352b74fd23d07ce53d1f608d0cb09c151039eef7f1b50bf9bee7d35046f8ba56bce564b5f528bc553554adbb097738ef321da7476aef59dbe676add86b27299edf4be4bd51c95a2b5be02e24dbb045fc7b26c4b82e9f9ad25a0b467dfa64ba2ec39ce23215ee06e68fa6568ecc8272212052b72c32073dd42427071032d56da30326256060da0dae09246134ab371d25ce3d7e35e5701f23893efcb36f2bdcf61c9f73e4b698c7cff8748caf7ebeae732c1aecc8932c7131eb93cad9c21dba7f68590ca96054bd9b2b89f4ab370e5712673f4f1925c8b4246a65296c8f49dc854a4345a76ef798de827187c944e144c5083c28b5b1b5c6081640a065048a0c48821ca1022849862835a932e8e90b62646c020858818b02c79141753c6a83d7c90f985ec5fbb16c413fa7d363300c3e33e9f3e80e092c320aa42c905509214311b613f9ed490840f2ec020098728679860871fa2f8e18b2c9aa64d6f71c49729a6f23019104bd8e4e6b82a3c39737ffab997b7611159df8625f8ebbe91d988bb49739c27721c51d6e2bddef5c2499b9836a9802a2ff00b388dbcf842d6b1ee3b598bf7650da22cf9409b5590ee5065a63a037b4fbfee5feede2bceb7a1f88ed31a626466c3f7d77d39bb8f9b70771fbcd96b39bbe94bbfe75685de0d1b9919998dd236d6dc9fcd28384efdfb45eefd2941bafa7eae54298430c283e0ef3dcd357b21acc57185ac0aa5c42d64e9ab9f36a105a4fb169059f37c23b97b2399ae80cc50caa290a8c46c18753d0a15d508000001054315003020100807c482c158288c3361f70114800c76a04c6c58990ac44990e3304c21630c2180000000010364668666db004c017a926d11c4130752b15a602131317c6e6a4bdd6fedbdd5d5e16cb797238b705e4ec4bf2adcdc0e0eae7e5e7490ca1e4c3dc2fda0b0a28590e934039af11f15557dab4adc8b9b003345e28d8e3af03ee2d02dde013db3a84b0ec17709c022b6e773912f663de7ccd62ecf8a48e21c907ee84d69d7f3263bf103d40285a56643ce28ea2b488998947048e7732ea6a833c311084b4ee013ebbac7a78e23838c13952dea58611784430c8aa0834c51a9f7fddd673d9a64cff4319bbca0022503f0f72e7c75ac58e032a7897f8c3f98e51519c54cc83f9de7ff6c55fb8badb0329ea7820032f9407be11de6d0c92af4868ff8273a2321aa14c5aed3630fae9421f1d729d7675c21500fead410d52de529413584a3ec0bef92257cfa60d8dd07cc3d0f48bddd7cb5e47599d650d364f6177669d8d7639fb59de51bdb6cfcf47a5f3fa5daba38e9627ae8c75138f24f3d4cdabde6e8eb7b1f26802aa06224f90113b5faef365f48b2a1fddf47ad771bf959cf960c909f8a4c1a6afb0e267ea2893ae4df3ad5b43a0a2d3171b5e71576dbc23e791ee7ae884c7ab35bf2ee467cd9ed31a2212ad5aa6b57636bab883d53eac9d91dcf306907d3d6cd678c22549617c50af3be4b66a5c29cf15328250ad7037d3613a78a83f4de9796dd4b36b353302dbc1500c040e77ad9565601c31d0a071a449edc868e57293a8e8dd58ecf66706ac10c6394d424cada709f7582bd228b2f43e2264fa399b43c7d4f4aadd21e3f22ac07f53a923dd0e303ba9cea8b6817e7e73a14ca4a26c6a875850386e9c840969d532704dd7b0a91b57f7db8e458cb8917a983a4ba1a9090df24b5dee710432ffd46b8f5676148313e05710998a075840e4cdc84ab881ee440a11f1bf8f8dba67046c517f0c2d9a6d005e24c58ab6ba5e9ee505e00bf930079c159bd33a293e57e9ef2203be3a7a970ce0008565cb9ed2597a5b215fb090b898aad0020af86bb4252117072469bb2ea4c19867126264c4787b7192f5ef6f100b71f451d3d08a2f43dca4acbd29b2bd614d1319ebb84879c855d46050e2c1219af6f0a60ee564769d75a910dc0e19c343600091a02913df1994fc869c58af395ed4231381366d87717f9b5d94b6ea8667e3bbd64d2ee654e35be1746c384f638c1bf66b152007b68c2df56078912faac660bb42b38c45e0f2d93053b3453cf38c54b41577fad46014c2f2f3057256068158a832359c26d65d04231a166360ee69685a434657240cd7f0b8d7f0ad286c3aebc1ec117092b44e93104f087293944a306d0c0f7421a4674d503754b02dcfd4f087ebf71bb2088a23358655741758743d972f39223fff673f510d516a1835877b2b61992d6af8b6fb7ca2bd55655ab098d19cca6b154826e89791a7ed8e274fe48b72ccc05a397e22a4f812fee25252d323fc3ed277932ec1cca62c2c1a4459498495217297183712ef00474981891374f0815fa8121afa132c745352e9952bd50495d334fed7a63745e2fb0337c4742146594cd34a77cb18603aee20502a81521fbb294d2f959881695ade4b3f414f99620e2c9473ec8da7bde60177c80aacf30699188ad9538d01aeb277e58eaa68ad0444257803313284b861bc6445c5cca2fe8553c85edd080677c6cc114af3011736bec038dfdfddac6bf5d6fb9132473818a6e29aa5749a8cd9d5932614ee8df262b091c226c7413d1cac9dd047499af9a478e6595522c8b060051bbc47f83d7adee0297f9a0de60e0b1de2b9d514eef9439bba12ebb5e704674ffabedbf20b14e6362755e693e586a2ca23a7f575c44ecacf5cd223e172536de5929f1206d38824743f5ffc1c3d5c776600c436d9ac9554de13d3be8e5d76b250616fc39bc71ab038503cfe5cf2890a72f1657717b04f41a390f6b9d204174762b546bf76a86c22b180deccc53e9a06bab72b474738b97685559b0ba0f2ef220f7a62ad65899a15fb0088cf0b8700674d40fe9b90298a0f07280a5f4aa2197b2c8ea1d33cfad4b1d3149f04740a9700aecb4298f5cb9fd80909fa2d78651d76bc083f97034d553d160c483f4b764b91500be3ce82b55265aeb202964cc3d6c6db02665c8d7164a2e78359a86dabcfce052448001b226979e0f19cd0c0eba44a73dce23ad60dff14ca36595dc08be939d67e90447beda2bd67098c4cd67e79a0e3c7080016800f14d38282d43e0c52587ebdc49cf86c3418efa90828df29b5be027de6949b63e3e7861465281c913539106a84b4d1ad2ab1168620a61693b38728dd6d8e0ca658a503b07054b1505f80ef73233528db049b149b8144336f2d8ff7a4c1b4739cdaef3eb0e4fa0005373620e21c209a49666f8bd516aa59f99f1369d8afe861212420ee38976b7c02af828851c3b07f15bb958a2ea513b0363785950fec0f4d2fa11de5726875cd9667b462dca1259f9938b18a081001852a1bab7266eeb1dcafe876220cdb089597606e299e28b2207151a2a46103f26727379f8c3e04ee65e4c03fda202d1432f0433ac62bba56b43c8c204bcb59cf38d94bd5d06bea452472cce743b002415c7e307453c671d5abca31f16b5f49c7b2276718bb969d5c8ea3d9652097fc53a48e56515ddca49ca0859e6de18fa96d5809896d7801f276336ccceca9406e949a83881a0522a6553b670982b629fe092ed4a78020bba267f3d1976d8332a6a34a711c618e9150d8e2503ff4793104245c6d83a694b7fa8cdd3677eb3f875bd93af00071c25e5d199c1d063a0c959a802b07eeca10ea1b9ade305f6662729faca631c883054a90cd28d88ede198bee83f7b094213015848894f395a8d77245faab9a6bb64b2944f92e5e711647adebbcc3188324480918b0a894f5fea43ee3cdbbd2edff521edb4a76c1c5ed2134c2e9d0891eb8e130d4a26729c2de5cf78c6bf9e3ebd8dd7b9bde8d333e772c264fd67a1ea8c044a80e021b2935af19f187b1a742b2ede3a46cd291e637fb75afc134c29e601b46feee37d71805d1c1f114a185ecc516ce52c15a6092294938354562558024350e93974693353788d82b114c9a40ffc49c54bd8d9f3be76f88fd22d86d3620f2468bdc4c1acfdecf0c5d7cd55358850d763c71b5f69e6f1041b1f93719e51e63b377fb80d6903491c0cb1c15e533578c39c8308a4e563c4ce89083fcac71ebeb16f6425f7dcc13d46a6aa425aaf0166eb0cb7ceabb482003ab5f5c7fdddf2cc2245b8882250ef40b554969da5eef77b35d06a72d7dc3d7bbe30fe0d21413979bfb24d6ab82eb578823c5cd35dcd6089fbfd20c71572d08b7e18f25b7fce1799ed72719e100e6c7efeff3a84edfbaa8782cfb2e7323d723aff626c518a1b57e08d2a06a72ac6c023be3473bcbd352a39e5329403ab710e917f84f2a6902530e002fac490be22e9c306873bc1a27d836d3685c8e6aab6acb39278789aae14c8cfc55232b00637c97c1b7be935af4eea83c318e7c24ffd5d0c5aad86943d393728fbe8c950320609110298e5e824bb697d49a8ecd67f2514f0644a9c83e619a8b0be15e01f0d2225386aafcaa6107bc8bd18a4c50248d1d93fd9803ee4ff6d83d8301be4b075e06c147dfc0397494e036e578be8f87e2560063978edc0bd0d10d4c45706e5d23388d3e34509b34bca40b3fa5b46402be816b8f51e0b08c94b3a903c6c8e6003e84cc41f43013f4cf1ee8cdf1d0fbc02d4035e3c23b207a4c05e1e384a719cf86328acf0a20f62cd001d94ca07ac1347884f6d969b0a033b3a54dc6f34f75871764f0066385ce2f876fab885800cf7cb5322ea5600341c142ba9080319bc4e5f6b29f789ebc4ce8b5b430a90e13c94c8c6a1b3ed14057bf9089475e539cb2b3aa925b7b8c341140a4c5b0ed350335a51db5d1262d59f9e928a8be51edafb581bc3e19a9ccb3f9ef0ed1cc78f2f5a6b4f2b385e0de044b106d1168e37190e2f6fddf75ed2cf8df1ad069195e9fdd41b7bbb40075185e892bc5a9f8e184a0275a14700de0acadf243116d8bdd5939a6855ed12f4ac4bfffdc71846e14159ff336a882f1e0ce1eb09135c2286191ab442e72f1350cca2d46b25df49d1c0f0d89759378cef2d2c99fba722b93c91a1f668a875de987fdfc2b6c0191091d30627281f3ab6c5d4def14eb50d49bd9e7ef7c5a45166810f3f166557195326008ce61d20bdafd271149cdd6d57ccb60cd6d7d533904c31e77d093f5ef31775fccb9945cebcce8b30dda364bdbe53c8befa3890365ced336991e817f8cc0d126a8aa869b936325f674313b7d4d1be411e13587dbcd3a54c23f09db4a6aac38fc5c9f022e67e7a6b49854a5f9c8bee1d178f6a9b2343d4edec70f245b98fbd30492c6d73054b119ae38ce26cf797806331f9c66ae6535117457e795ffba70ba4d78453bd7ea1bf9e7c02edd7fe6d170f94f77fcaee72d58c6ca1cdbba3e1938f745a402aee7c3be888ac871d91d90a324e9ff02087f53a34306065f8268792141b40ea7ff6c704080c8d444ba7ea4e00a1d908477902220e53980b2b5f1cb91849e63de2040e98f9c0f575146f0c5831c0fc5810c58d1c72034e2f975fb3c2f38ad01354c451cc46349e2157f80b1556533f441b2bb4777a00f5a8996924786f983d9d4b86a55c31a759080523907512a08071c645543093a21c1620d7fb0f0b2a1dd32db76e030cda55df62f92d40435890c7d95b4580baea0a73fd271d29bc9fe1e2c202fa0bbfdb29a3d643075108e5a7ca8fbd83968d7381b71e81aefc06852d3eb0dc777649974b6cce1fcdf1c87596f07f53f1cfa059ad22244b50594373331c4e16edb347d216f91212ea80a85213b5453adfde0b3c7c558e397416900e1e34954a69c1457db9fd841bf9b423f90f51c535d09eefb488938220897b6ef09b53b24ac6371a90d6666a9bf554ca7b104a354a6d92d40cf78175ef369df4f59b55711ad8da75cf388bf3a18332070d06f13009d016748f0f10de5aa10cb5bf3a28b897712995d9d24c4bcf8f8e1e8b79843aba9e5b35856194ccbf5bb1c2e1df20642b26b10f86daa5042493564ba741ed55d2910f58014cd33f7e39536c6f30f53c991503eb4e6e6656c05d25bd63dbcc112fc01e37db561b2d48136bf69ce350888513588dd10bc66e1f350f05082ad1b9bfccb57ea44fe0abb73932533d10b12e868e1353895114e25a5589c9d21ffa4547d62aa41053cce8b520af91188c1f86c11ddd952c6b4950d3d4366301177d2874a7be89032363151670d5e32be5d7f0c216dcd4b945793d579db606315aa73e8a2b40e888407677930f5cbaf20620f6db8bd23dbae14b5395922be99cd78d3c165772fa97dd79132b12fe97fd3c122b13be94edbc186a25543871cc3dc04d326168ae1eabe77dd6bfd5aeb429c189fb7267e0963a8876ad3967c42a99d850f4012a13a9b3767fcd8cff02bafa02ac5fbebcd17fde948abd72714d14d417271103577f5e17a92919ed54d847697fa429cbf75bf362746054cc11bdb12c99e0e30c9d642c165e1c4c7cd50fabe53349a76cd801d4b47a7b4e880b4135fde32db5a2af80f9275b688828d31218924a1130899d3df1d1a019cc617be01f138384e3f53077f9b2dd349236550228e196bb32f09fa2bb62971c86108a8f03d88e6218a32045de85c295d2eca570ba5889c24e58e0069f61fe7c71df9cb84f20cfe4490f55c23f7b9b5be86b14bb4e9fead0d7fd6aa5913f299bd0aff7d1162232222100156d4bef93eb971fce8da9c86e85403018ca543470ce1070c0f1903a4b4f81e3a4832eec2ca35e24d0af5ebe2c44445e67c9fb3376e57be0b019bbf932c7d1f807a98cccc7ea40799157291ad3adf5614fb3241fcbf774df85266827242395e5c6c7db16e43fe3ed1f0c8f45c4c9638a05dac9fc592f75b0b6616967b08e7ae212f5ed86e30eb165fe46106da8e89ca9b6735e87c0b56d0ddf3472360e6979f4efdad4c825a83e42b51cc102af56ae669461bbbe8b8ce62b7025120a5cb89ec00968da1ee3b33795bfd3b62331675de40d647969f70c20be0cb8ef85a6e395b46da489e2925a0048a90931c944425fba9f5ba5b0553cdae47c347cb6ff9f70c84a139a250b20dd13896fa3ab0acfa4a63620dce2038ef53b7588789e437af9334ce62318f71bdb3e5320cf1fdaeb1b4409209a94f5e845e6e2466e787a43653a45e699da00b24270d41c9443053a7ece2c445e806b734a508a9ef9830773401f87466925e23d4c8f8a426206b12b79e9d168a9feb96ca9eb2008cd67151eb7829a300a35eca2e457ebe5310f0099df39f5af407a1c728e5de5fb5d8aa1e39e1017225f1fb354f3283539a7637bb33f1b86242f26ba14f466dc3e958bc5eba056b83862d7320ea8b8f8275d3ffda1c2f393e63f51cab4403248b429984f3ce9242fb063ba9abe9a537481762ad615d85a916a7424bcf2144050bbec91a74010a490a0efc936508ecd3879409fa895e1c9a74ac04f92c5880622282594d5dbe3785adcb9d5aae6ccd484b05968b09be03f194270b6ec1ad91383150c3b32012d671f45eeee6cf5159cdd75b31566988ea1dcf71ff5899a463e18a491101d0583d9e0c8cf25ccba4a870c3986e40f3c5a6a9db7a4e0bdb606afe3b54278040bf64eff4df3bcffddb87c8e96913529a90928db9500f2078ef239c0784d8b098a4c107e512755aad461fa556f9479f6858ec1e5c3b543fb2ed84e7d3166f267897585f49a82d1ceee6a0098e1b641bd41696ec4769d54b20ec66946e3422b4cc84164ed17d80c2b1eff88c2e6c9119c5e21c79bf44d10a10c41f087b334b1cd184b98803b46118046dd78e73249215983105474b3dc4808ae4664ea041ccefea314ba107e256605c3251cf006943dbf3cd83d74ab670d73f682f3d06d29258d1191f8e27c904689c3e03598c205d2cf4e629c6833cb235d38b69c6638e43a5b23369ddbc179d99257127c096e2d0e40befd408fcc9e3ef4f59b1d0d8d304c91bd646c83645cb80638cfb133dbcd30457ca4a20794e0e760f0a90742324bd972d91d3d010920d4ed481f89fa033cee09f2cca7b121794e9683662c25910e517ce90488731969ce3039a41d5b3da47e89b8c3fbb675e263befda9874caf3e889128cedfa97f869f6520c36c533cb88928084452ecb5c9d6d96ea5a19539757ab7b6e4d6a2625a7fb33eeccee8ef73352984b58df8de3097082b3b3d6c17ad3a880928b12d579e9dd84b6ca7a3698784d2b97bcac69df9af3f10d9c0313658530f734f944befc9c36270f3118dac9d5c58345120bef2f4555e63ccee7cc2649b5009a4545197a357ae0d676b5866a17cb9deb94ddafa9da32ffc806d85a23478a39744bdf654d5d1f22bbc89e39cb1782ad4b7228d34dc3ea823f2f0c8348f7e69d1498071936121ef6b5c8fa5c65d36aa31800cb83cbdb90f361bff8f2c2f77723d5da47eadb10c94e495277f6b1ba6e7543a89b1eb92cce5cf205e16cab4d2ca73a2ca06b9f57d3f01ba3148373f2ac061d7436e536fbdd67760f8543c511a5a20c87a920e491205c80f51b9828bcc11b404b12f3a1c2ab6dfb7bdcb12e2afd9f7fc7bc34c1b4c6a4e6a2a0f0c214921e296273ab2bc0fab0c1f2a927b543599d9fc09f2d5eb966df51d3de3daf8db64c652e7323d8256e801f42b835347751c98bf84c0b5081d06d49756c5243a5a0f70c9b78d7e987a5e4953646c66198d82a77b5c056ab3fc5c8bfe0f36560fc09415c87ec2aaa6367d44bb15e0d1729a0eef1849e498a34d633a48ca79d0aad828ced8dc1272a4a26bb595166bee70787aa1683a8596f947d6ce811719c964f5a1d7d3d501879e606c64de0027af56ed5b280422ce1b7c3caba3606ff7da694858a767c166d41a090d808c6c4403ca4e684269decf29fd835f4ef1a2b3fb68f7392c9e34463d458b26ae4a499a5305ae680245dd638d9463b440f84cf8027d0d21642ceeb8a5ea662c406e2a1abd725f9fd7d666270b266b2f52babd7f71502a331f4541d7f146f5ecb63132261e912fc5d8a6c81054d8d1871ffe0fe9e42c0c749adbc8ecd0c852d749731bfdd2d454508bf17f54eeb41491e70320ba5c5ecc46270f469e39c1e6aef61eaa31ad082e570d9cc926c154bca27e101c8ed568ef07901fec56adb450252acbd1e42b81131e17698e88ae4f917b490f70326df19f170ea0381f4784b939961a67f7f7e88eb995b6651912d08857d964ea12f3c2ef5be033ccb2c4bf219225f7ee86ba128891ed51608996a512e45f6e8ed51d05294d5cb6e4b425620e3a76a90e550a086d762f8bd2f625682e777843c857b7f0328f800d320a24b7d3cd3f5cb24e0be57398484e445ab736c8e77433f5a6708226e4571903d1577139fb30ae5be3c717a1803a97f0455f1c0560eda7586e64fbf1522e15b4914ccb7fa9a8292894a9dba89fc72cbd88e19c0e39e425773d523f9062f9299ac7ab0f8ad6fe80805ceeebf15fd98a724f856ff0e7c0df547dd6b1c254f08adea0770665237d623af3a4bcacb08ff41756cca398cf7099cd512a7911db71788c3bcd1065bab756215bf19b16cf6d12d1de55a041a82d85b41afbd71f984f6cde1251b3683df9abc3a0f8bb925e6779b1190779c0568578c7f42cf1ecd889137369df11693abb9f8479c98645a7156db65b8594ed4d5aacbaf5a7ce113b97818e89e3b07dc2e3b89a25406eac687c7ac6766b9fca2bb191bd8e94887d72f0f2401b0834d01439d535828ea8562f98158e8ab14d8ec7e8c46f149d311c8077ccb7ecfbb994f797bf6158c6aa6dcb89e79b15bc0f102b18ab8424f56517615047594fcdb0740d50e18c398091a71f0cfab3a82d2e927554d75cc6e8e1c659543cca5d97908c08f517da2ea209497db7ec357e4ce51fd4c5896bcb1a1e3b6c4e1c053033aad76f8839541d9dc63cf2c4488c59f519f74745e5c7ac9b4452bbda09d5d8feb2d9fdb47461e5418086dc782e249d6f2a0678ebc05760d85dda602299e861afaf85063503a1447ffaa7d95be2ab3ccdc4510be89694ec662826f9cbc0740824d01c172188cface96c3d3539ff1f68e23145e00d53419f28fe041d15f76439bd0189f905b74b13179eceaa38cd88ae9af053d3619408677580e76bbc1bdf3bc7f50d64b7986bbbb1693b06ed7ca912b26d7767ef29e7e6640eb4aea4dc52576b6ac35da3601e7d91a0802428c1dff964cfd7ec4dea86bb76246c68e4ebe88cb621bc276c222034f47ea94c9f034abda214e223f2b14761d360b9bfc2d601ba2b79afc2b8a4a5bc4a38ca3b43a7f2bd65c5acec466491d7a6e48cd4bc968c118933aef80cf91a494df6a63c18f9391b182795c1e63486699943d26208898cbcfa3319b3839dad941d74e65b486f6ca87e46340b8068a994a6eafc66ff4038eff76c455523790438fc9cd904dc2a98d4423c375ee3ca35f0cdad3061af257fad6e753822e574ff35d70e315d9c9c1907dedcb1a582afb03d7c047b610f286a53972e5491904c096534645375343a0389d1c269e581dd1b9e62e2f4b36ef6c11d2be23b2262687252e0a02cb82ced1b483e3f729de7a6945b82a4db702bd8c865bf32c79f62cb40f67b2ec79e56904c02a7701320dda59794f164560b9a88dd8cebb55ec930e83b918d0886450c2d713ca464aba4495feeca9fa12b06967512dfabaa03549e0d42acfa4b36e5e12a888552a0bdad5de48feafe3790dc898745b67e88239983892881b711d5a0ae2a35c3b7748087d670e187c0c3b4de8691d82560a11d3ea96a4512352fafccf99e4df9885efd888719b8dfcd3111cc41dad3328eac01e1d9510457e6e1c8354e57c70f68024b30e4201be2aae72c3a7cc5f589bf80f269e32555db36e2d5170e10559f33a4779b7e67ea4f3dcb5a5b743921878d6118324ea090295b22d151d9ea4215dc55eeb0855186b7667c8b9326c842b6986a88d868f89052d84666386810829456e3a4b2e54e79c17ac5e1e3a46eef7748c97bcd44a224f6b2ff5cc9734ebb59f18f03ed87eb7942dfdc78570f9c6d030033c194e35ca2360614d624348999e252882db7744d8e89a98243838249d8fe00f31359cb2abf863c9eae258629744c1ee4ecf991ac82f8525d702ecb8d848558dc87f9f1bb85e2250d72f7fd72cfe5d6da74ba9aac906eb921b2c539158db0a0fa25805421cf4d99bdca1f4908f694dfe0253a76e94b0ebbea1a6bc5e44e2afb5e13c6566e19781d91ac399bc8ad63d2dd7798e6103a13c8742660698206e5547eebabc9b4dce8abd711be7b70f1b84611f984de9532aa0a9a6c4c1946f47c03da52ab633ceefcf07647f5afd6302b58bc5868aa3dfde13029b5dbcec2afdf06c29331da27032b7fdeaa106ae2887c70bd1b4290118e03f3efcc413e1453d5df5c1b84107b4d72038089e5794b5221f621b578b0b8e7f01601ac6ca28f9b5a0fee3c6e1304a0433bccb8ef1efe16609cbf93d8bd40a488e47defdc8eaba21a35ee0bc5a899d9d912a8345d27277b418b6dcf8a1741bac48643295c6391598ad564c59119a4b1f80c3d467b2613cb7e86d784999fc0da153ffbb4831f17ef4162baa108c144d5a01b2aabc67aec461e5b5cfdc56fec1b99f43ba332aa8fbf8fafb4eb0e3898d675409863dceac1d5f33bc1a83be68e6c192d634095c99e8606c643c620e391d7c196e1761b6be9ccdb4e47215ba8239254f65d298bce19d43306fa3d272f185bb6e364cabb81ed3be7b64fef67ef2a0ea9758e234c4e81ef7aea7c6fee2a30f6f1816b097c715f0db730c56bdf15f97caad7982c78190c2552137613b9432f38507993cf7d3a5bc0a9c41219222beaf63dd5f7da41cf6f0bc73b4757273e8b211972df4aa4c5203632b7e69b695d2faf7982d7f6f8a5845741c1c6ca70785f894c6e8a949897b1b1a762513881b50c2678fcf15e0beb343c3495627adffd1eba117babe4c7d63825510684f9d79c635c336ac42f76e936ba6263f32283fc2fbf0f504544d92d7b1b6a427d19f519478bf2c401a874bb7961b07c75f928d5aaf75476404d5da4165c3cd0c9be231399b44cd98f88a7d2ab508a4666df9a0a53ec189603a7f03da9b142194317ffeebca9e906aa393c2d60c1cdab03e964d5eace908905a7401d42ecc7c45ff3b2679e852226a5d7b6ee28b194f1a14c2cb893a4afdf44b500aaea1ddfffe18be797da81152306a74d94653428393cb9ce5934e492c7c75ea67435c358005d3ca93bface5466aff3c644504912da5c0772d03699ec4b557f1e0ad508caa74a6b83c940fb7af867d6a5ec86b7a4a86c0f4a22a389b931d704374dd6097cb4019ef28c40b10f2bca6067ab4def0450392794d6a8009dd75dc430ddf88e73720cf200d45f94a16faa6fbf9cdaec792111d09e85a65ed648eccf6592c33b421117e975764cd777704c37ee3caab3059ed1832bbd74d809d100c7e34eba8435831203b5c67373c19c60e33d05cb31942aa3aa69fff807a0d84c628a8c563f5a8d063ea688b896e71e6d2167244f37f2f90242b73833a227499a2d6d48bbc24d422474e4ce59711b708f66ac7248a793ed7a6a8d0e066f2be894d3155bb842108789ce7c6f4de5804dda8636c8ee73e9dddadea52a638403fa188f602b8b49a4020c442822548ec40d1f24dce0084013843132483245c8ea1b8e1abea3acfdb4f596a230e0ba9bd61b106282c007c4121c1433d5c599540d7043a437dc23807ce743a6a10e53e2416a1d49dc3c12b46e78c0356a84925f2f0a1f31a67bbb8cbfe6383c24472c0a95ca959ff3452f400792d954fd963ef994a8e5edf3a19e6c725cc5671ed411462befc9df16d61360a847791b60b0f9c5fa631fa14e83145d048aa3651ea9fdd463480204837ba53afc8bb628eb5bfa084021a12e6272087560d860f68c2ba3cc560644a407f25ee5cec10f7a4b96110e5a6d9b5d209995113a6a207f74b71ae442e413b8553372aeb9bc2d2212d2bd430b6cd61fcdb6f6af1086e3c5d9740524d216f0e772dd8eec979c1908b60d8d89319436b3871bf4741e231972ebe415ec1b0c06a916f8a1ac5c12169013bbc211afb833c18d72da16e8024880f96814252323439fcf10c749c0bd8f0f6cddfc8c95c554ff5889e33d480a54348f342c9f3bd646af3b94fb4c6a940be80a6b6ed8e53c11c3fe47cfa266b4d94e4a593614224936cea2b44dd5c08fd856db953e76a160392063b3dd7f53ddc9a92dcf4cd524bbb76ebc33a1b49c915532e630f949779d6b9c64c2f24e3c4f391d144f0f862c6e019e1bd72c843913631d022c3017f24c3dd9590ce7b3f7bc80ce1a9542efa4177493aeca3dd4baaa715c93f9db44ca5485c0b4945f461610d05d71ed998cde88ec42c4acb29529a90147a94d29450cd13ac8118db6038cf787bd1f40f50930d0268b0b6e7b48eb64719c9f6e426e2c5181891a6dc9fee4f2695a5a1813d17b713f32844b881355a24cc6793b018c5af6761540c175cbf0d514645283c6084de7055297fde1d3c0714b945f310b5d807e8b4ad3c901b4c19aa611438653a13b213152311129cbbae62b5e475f6856411b1a25cd9d20490bcc4c3da902e7fb163c0888a03d20eef58729c1d83091d2fc474ffcb8cdc32a85e32c22b20f7cd4496f109957b86d90aa6e3f5c104542223d17c24ece85ba36737dfdcf174342c1c857f5d2b69049abc20e1ca2f1a0529b119e7c5dab39fb55af2fdc41d1cc675707bb11870554051fd91b6119519988da4974a9b937109f0282ce2ecb8b8d12e8f90035bd4a428f511a85a3328baccc04a4dd78d13f27ac271f333786dbb83c4a2e480a5ae31d2141ca34905f7693eafbd601055642fbdbf3f8cf69895760db1ddf6e200571e38b0b5e8dce929eef322787033fa7b599a7fcf40c174d33c06042b141198406b88252188916cda6998573daad66dea074f9fc3443c659cad55d1f06323220462a1cc493b214a59cefdabb40e4bb7bbafa53636b82e6323d5956463f5d0c780dd19c86b1753435bf5deac40857f457ba0d713701596919aa32b5273bff40aaa89a72a9f192f588c1ae36e7f801ac3328bfaacd29f7c398a6eb9bef6a2b90dc6df9d51ed25b64d2cce305966a5027f1408c50538c6eab5329f0ee810a2ca86364ae694f01d1e950b4a340c33deda96b9d655c8c2ea8104a2a80c49d464a0d4c77231d0bdc4f875da6a64b3d6b1e92ce5de23d7247e55cbc18cfd73d0ce830d06b0cf8a851bb7dc4cc1a2124b79dcf9fa261c03fc41990de3964b96fad16452c29e3c86b29e8459f3acb1b4c0e4441f588e5470fada387439860661c977fa964ba9373ec8173f98f0eaa34e86f40d90574a009320caf809218de809f810232bd73de46e9b17b8670527629a49deaf5a70859ab525c7a99fa53880f45d5e0be5c8011cb001d6012e0de61c110d3462cb1955c0c906517f40c94cefa5518b4ee9b0c39dfb0ba9217f0b3882611644dbb1fb668fb5cbe7b1a97243da5c471f05ef44d1f17bc00c821391caa382f8ba839d3adb1042c69226425300eaa06236d29a2ffa5b314a995a747839279a2508f22a085fa6de4c9fe55e10f4a2e0af2b84ad6a39aa3d9e18bd4891c1ad123135b07a568ec84171f366875cfca3e2a76a48dc5c4953837bfb583eba42984cbe7108ca4c615701d6b8686732a2ed93188b4c78ae5e52af89c517a0ca58f2dad9551169917c4ecc6ba1237ec62065f1a11be2bf16963046f7bc7721f0ac1c6a3bf95c7e33cc7a3ed8c9a91fc54c957cf29333336e9bc5541f3fa4ecab2806ae5a9f2411d7a1f29acce32b80382606bc7b83aa9f2e114d162fa62b997cc150c938453b027872da5824d66c5d399c86b0576b2d2634740a8c83a48255e6307e2ee049d6621f98f809a5bbd3c5897106fa89236ad9b0909a07fc27592fdac3d437ba141d7694c60524ff51469d5b30ed45331dcc791a49cc8fb48590e3e64c88ac1d008586df68bba7eb5bfb23d4428ace187ffc9096b2ad89358e2d051cfbac4a04f9c1d31088dd4004d816601a0de651f85bd6c04d5947229d147707eefc0a6a5d7464497425696929a7aa509b0098884d45f6032c25cec2c8f69469f9cfc1d1206e39caa91d6409fa82a66cdec0de0745c83560a8db3b14c81ed05be2532b965b5b39a9ed917da9682b5563a79261f199425fdf392954c00bae73dea455576ceb5f0ea0ff9ee38e6617a11333e20617111bbc4b428d5373681362f5c7195a241a5f100147544ca3c5ea5e3bb0477e52a82c708f9cfc6d7ff8cff1c634254091b935c8617a80e28e686dfdaa7c0563aec8e8b1ba9c2c43820ef303372c745a19203fe44dbde40de7caf7fb598a332da1604dd35e9d75e7dbe9994f2d5296f6e3ed1505b5f21a79c6ded74461dfcd8a14c7076932d2aacac939436395a6f70627eef555c2fc87ed38135fea8beb35670a203e6a187354a7fe69fdc7f9a96bf4c49628fa0e15a9a1b0b0310f90a49b9faf3022b9c5d9c1dbdf88954a2161fbbb1238c51f765ddb0eba0d8cc56ae8ba26689f17a28f301acde996de70161bfd4ccc64a1f8b63adf66add88d6108822dcdab373eed0eccbe4d0082eb8d2e9cd9ba9d7a9fbfd56b69795257dc018965d1ab6ab03071dec5e1bbfb55500529ae3f87fe237e9dd2831c98aa4c595460437db5165066d6523e3375d8fca4ab9159e1eb003b665e6808ef863223cb168f706209c85ef362bef9000388bba851d48eaf6fb2bf5d7b2591214df8f7a0a10158c7925fb783df4a598d5ee7d146ffe9bd284aa433177776e0b759f005bc92a7b63771955ef5ab91363af29efbb7cbf3c642c12937b464e0898c1a64971d60aa17e714bd048094047c8d6ff4d939502ccfa4c51e875cc59ec35096d944d4233d3721b8318f96f14a72ff0612faa2d0c16e310b38e9abaffdb8fcdb17e75f28280f58ff92ea14e521e2f9d4e960a8617e38bd075a2c2899f3f088b255942b7a6190f602fa39333eedc702bb2403f930b21bcadd9b4f113248dddb63989634091df8852b2af73674c018819d333602617a34c33dcae5a28127e8881856f2606cc1fc3931e5cd83ca29b023226876736a5e065dda5ed12f7e7fc0cb2384414000c8699ff65f20781c65c44425318999c9a5a51662182e9bd74685e0fb28465059e0a1a8edf90c94f7bc42a1296a765bb0a4ec7e003ca59fc65a7f564615f920090e8aea3ed76cfca75994ab71505ad9b8e2891fbba6728c5c7618165941936f85ef0ca2989c5c632ff2d6154b4d142c3dc5241e7ebcf7fbe9567e008a8c0cd2bc99d1460d3985e853d31524c178df6faf452f7df013d87fc63b62f268af988c5db1e887141a081c5c66227c683d324acbc1809f221dc33aff29c8ccf94b6a20012378cc5e640260c4ad49ee6e8a0c5e152715a8148f790d8c5a10006eb8927257aa6c08d0b550524e0fd530a59cff0c37ee8054611cf6330a6381ac3d67a30943376e6c1eebf69b783d5636713bb02ce3975a63c253ee26669e139e9b76ef6765ebdebf1c84b32bbe6fd990f0318804993057d2a4ff62ba1f80ea0e1a4754b7182116f636d137b6de62378cbcece344f4442a2de3bb008229a9759c4ae789495a168df810d45ce598eae31d4012070779e9ad4707d3e283eb7678aa2b0e6d65500dfe197bb38bce87dd6e31c02d20e8952dfc92be73eb296b9dc6e5187ee617c337702660719f1fb7ecd693fba16271e854f8c216963baed9f395bea82ba2d47bf7b2c1cef3a8723a17569f79069f2dd9dcad80c436acdbcb8151238bdd5e1fa5274fb8c544ac14235c3d92447bc3937b81ca2943bef413eb152c08271646f3aeb82063e8edc3b3adf486af3edb670b0dfe8586d78a31c5d096a622adb483d6fb08f4d9233e8eab296d1048873ab60ba29368c82a9c461263132e260c1d99c6dcd95093dfe41f04bdd6966351dd7cb90c1d603bbc31a222d1de79bdd9012d2c64cb2d4625a565b4e42bc2f998890fda1cb60de84a774bf1b0644900e995fb96502c72f45d1a03cd732bbb3bb5722db6473168c30e4890d6c33e2a6895f5c07f9a1ead521b321f120518015c9da8962afff4b15cd4181e9af542997ac2609cdf1792b76ee2454b1abeb4941b409726a64535f828a450b221794aff72c5c18f593d5edad918c23c8717fcdd71704eee6f7e4cb47c7b5960af504258b0251ccec28a28895c4f974578cf713e288fcc3b9a8b004f38d5eabb16e11525218b784fe7ba96697896e1ef05a37b932b7105bda4016f18b43ff9bfa53893d37121ad7e4636a573cd1b8298e18dc8c50ed464f1358b9131fc0ab44edd2bcbece56435bbdb05f364375f03dc4109219ce78070babfc15e78a01f2d362235946868969f64dc5d0dd98a3c4694761ab86dbe0bf268fc23e520c8aa4a089f283387eabca356549b78d0ec89b0265bd8571adc27ca910e13d0bd2fcb465dc863e3ee892de4429e35bd6cebfcc25a8c0bf965b0af9bfa88d1d14b208990cc563ecdc1ad977dde2101ccaacb5767718171fe671a5692b848e0d0b5f459347301e4807d467606387f63b301715d18d959bc0132b0c580603daf1099e06f93a4bdeade87e5261e3345487b8d08765dcc7740ebd3880c377fc512552c930b5bb26015c7b3e59aa357385cde37120171ee7f7d427600139951114933222f29254d59ab03252e6e441a0133afe8c2416e705dcc59280f5470e22d72c695f803f52d789327867df1172e90509ad4a49095b3764a6f9f22051c32691cb0c4f9949df8f934bb67b63dac128f1cc1a098c376f1546aef74f30f66a7f1cc315acab3c2dcc74567f9362079f1ba2a4f3873a32b79e38abdc598a8cb2c3b83b01c73040ae125201205ccd972ce49421c6d97d73f13b0b2663c9c2b49660a5babbc2c786f36feaf8353b6d4a772ca1d2edc16a390be220f979b6503e3eb97fdbf58f231cb9003937ee18d67def3c8516b6b236a9b2f3f73756cb3c9eca592c064faea9369f27a5f6f37ca7393dc426caf85978cce3f4e240e160c77919573297a43230c206993f1632d4902490b16232ed840deef7a7b244fa6f8c1d20be77430cad060876a40d0b512c7d6c4f872d0398699504af026c5630d9da5e4b465c51aa42d27127e9a372259822948a1f8ba000ef0f414d83ecf287d6b6080bb4023cc53c83af0873239f25c16d66c61cc0d57a40f03897a00cf664434a3af9f9b686afb162907704438b591046bc8b58fdd0baea396cb7a67641cb41381f9687a3d2b26352e2df11fd7f156271fe34ecd6e28375064d8dd22ff8a49c9baf976df35e1be92eb7e8da67809b0f08713dfbfe0fc005189c00361a595659b768e40dc0729d29a5600be2dac5d1c5696c612d684e900c2228dc8f118ffec61fb389e0e7384cad7e6fb18ae059185bd66f9b550f931a03e136541c0e6fd00c26c7d355bf88b3e002ff5f37bbad73eb6fa078850f1c0bf3838651eca9e29818ce84d071df2f2e373fdc5249cc6a61b0b2203cb2503018bf584e8e95c3dd907f585de072dfe00bc1e62d053c68d60fb2ad97a42fc723105ce3a2c59a9e52b183edc2e18fe83a6ec1fb282f97b9ab3179ea730d3d618015b7930fc18638c2f0a3c4ec329486414d161bf055090eb28360f1ffcac4a20d20f11c74b35fd782e1a08bb07223a3d7a474360f5e7fb629873c2e08f95014a4f666937cf23d7a6dd24599b3b05c05f6b771ca16a4ac1d0e4726a0f4703e2a6dd7eaff350d078bdba3f616adec3dc111df654fcc9716873b3fab8990ff646617572eb93dfc67c742814138335bbc8c71e8e26b34dec2dc649a7a83ade8fe3fdca30d387b67964cd81d99f24842d660f6eebf6ac26716b3bb757f0d18e3245fa79d2bac8a5d17d6ba17d032ef9a3e605f5c0acb488187e1ca3726de24f657d90244a809fea7482b8e8c4398cb522c198140f6f0616fe335bfd19fac099f39fed9177b3360bfdef33891e374c078c246e0f899af60de0a9d9ab07225385f056b09a982953542fe9bd05d979c7e4ebc5d8da859b2eaf71262ac0e4f9239afd81ced68be0e52b35284fadb13f90d353b9383969dd34a211a8b1f22cc793084373206821c4073287fcebc3facac8cfec999641f8f810469105a310a73ce90b2535a4a0f7a5793f14d54004ed3de266dbb58c3c29cd7eb0447d7d01a742275332217227f40ef14636661851272e92c240247f67b61749a299722340e103442bdc42be055c08ce98b796afbc5a82e1150bfeba379d75c44ac7d9e176951c82fae8a482b5f3836c2047d9008ecab0695301e4ce20ccd15921f4e452b15eb53e5e25455c0081369ef0c15562b225424caa7d18c2c0bfcb28ca245fd5c86ff061965579ac1a01a888df2a425d7359bbab1e52b52905b17b1c699bef900a3306bd06b368ca15e7c5b9d0abf5c1e4ccf6a0b178366a5de706a723b9ac43f94a6bdb9ad40a30f5baf23f32b9ca64d827a88c3097d132cf3c7e7046f3567958e9ae462c5d0c2d3767f4528f8cb610acb28b2195315d887356297b0d13a982f5d6613426f2de094ce698f7b6c9ba0321cd813e8be095e800fe9afded06e162bd4177dad0466baaa9c18332a70b81ac2e69f61557a5c631e4e9c38fd2c7a82455116b21664170a9cea8806c6e8d5638a62e6c287fe1dcd97c113b58524f812bb65b34414b1ceeb1a33694cd781a6fa67855e60d53e230f74907e6db9978382123fc69aee6cb6630b527e53c1573a4b128dc3b718962acb148378bae6ba1185c952024203ee57cbcd3f962b61fe4573d05a33fc870ffd31e63a1e7e8e04ec2bda3634bc21de85460fb32474e6cd8e90c4e25c5beaa3eb4fd0d09f71cd13fd1b402cd92d1a6018f02fbf04542302e17607a36904849109773753aed2409e144ee991c09a15518446b0ee78dc4b0703a9077bf8f77e959baf07be9c58e4cf4b3518b27bdcc54facdfe787c3fb33ac5ce3b600a168c861708377180f8ffdecd4e025ca730c3eaa903869ff8a0e061aaadba996a481a6170ee6d86129d118959ebcc8971a3548d9c07a4c5163383993e173be7aa1d4b44f284e2ba73958df8fd22fad0be5e81f1080ba9f55785e789472484ddb05943dd95792acb6b6c55981fd5f87e3a4dfbfb1a87cd009d6d66d416b36988a9f9467f899366caf3c08dda1bf20ee79dd6456a22eb454a3970708e058203725ff901e5213e0b10dd2c75bc2fed86ffb33bb2f10a33de85bcefa819f12ec14c1ee8668c36d88052d150ae40b9c0e362dee63f26cde7dcb340e5e5f98637de3e0f9422300e1fca2b77cc38c073c0abb003e124b5ac4af0160d582658de0ecdb4375461923a279d59893c1b53fb08e725aa0cce559e441e9f6dcef0804d44ba81ca288691d11b5a1b9f39e66054e2b0da9032e7022376f4e8c5eb9aa3e849d4627cbb714af782181d0e281300fd2c80da4d57a9e7591e1046620971187b527f61b2a1ea54d4ee9c934b41803ff9f84b4b23fb8167e6afdc1b279bfd0266c0cef78acb5fee1ce13f62c5b600ee7c509e761eb635f25dfc0de14a3008596675a14fb7a2bd26bf8fa3c50a8252ef691077ccd4d10adc48f957a2ce70ceaab18828cf6e11b746b136f62bf7f1cc06f5d0f682035c4dec12fe20f5ee0820709dda6a4c6f1f0af3e333638b172be569b6fc2115891176c0c851bb10008bf0aeff12c20e3c2221c8a1a9efb9cd9a7fbad5bbdb718000222f47e5d913292fa83917d7401d1aa8689281711605b1e3b7cb38fb91c676a171a4ad42c02dc084a9a20ff81cc566e58e6f71b5a431db4a5c78860fba439b1d25ecca735db17e85a239e22be1405ad6120bb916bf9d7236e1a56235854fe1eb089f1675fc02f0963a4e5ec40997f5006d58178796d8fd2b4b833ea15485be3627be6c30bd0fa61e22c5abe2e2004da61c0b613ed135031d39924afbfafededf92b3516f28f86532c8e136e98a294279d344b27d0a9283a444e3e66d8e04d1714a49f593a439522cdbd4b430988dc05580110aec7b5fac42760e8dd2ff6292899c7a41de08fd8365666b2e33abfcc2a0004ca2bc10f861690a0563c60dc0c4159af5e1932b2672a84f7d3ee3feeca9f3ca8296ed04b515fb4e2c82b49989c4df38aff092422b96ef4237ccb2bf0957c3b5e93ff4b5f2847296594b23fbb87fd8f681472d3c346f313d03814963fcc237d7aea37eddfcbbe9efa0bf41465949e304c4a27fc26a693ea7ef2565e4a3d7a62209a514917dfa5d9c9ca08ce84f4af7264bd2b076e73e70afc13353c6245a5cdfb912e9d2884d8496c7f6787b2125f631b4b90090419ebdf746988c9612c598749b9d9ed52fe01acfe92051fe60048080b82d6748d0c6608c424563cd14a98d1c809559a476c5145a32aecd9937234716b42be075a706002db8dd75fea29a552e893689ebde4c01a2a12c2e9bedcfc8b6694d9c10dbcef35b9eda1d9d97d75f4a71386f08154f0e6dac171bab1f5e30e63cffb2f0424fd604d9cf676c980a54d881b8cf2a9068870e83c880ee5a00675266a7d547bdb1e8a11417306d08907c25e02a724dcca5850832a773202e5ac041e732d6ab01eafb4b7329782f5b5f68cf5607a6dfe32e64cf4f7bf119041174ee0c6fdc44a0cfd1430dbe97da11f439a6f584d15e34722faa7fa6e87dddbd08a279c32babc6c292e96c744df05d6300571727e9d664d2a9bb4502bbe6481074dd79259a018374a8225b3ade4b1c35d3f15d59167564fdb2506202088f6b1962cd12998bb82e6461396b8369520862000720b62b75835251a6241818efae61bed0c2c987df772022288816efe862628e5956213d816043dff88f4712da67437548599d8ec3ceb3dc1ba26d03cd31d71b9562f59c9a7e7d8d209103384d658206d983f1661ed213814ef5a9502d1a7b4f696fb764962b859d89e82a216c96b94088a73963c97a0102add0c5ce5f9ab3ab5c03ccb19c01ba28c31158bfbf4f7f90fc8f76c8da3795f03cd4a2ddb49e6738e6e65f4eeaf19bd3731e34c7a68c24e5a48c47daa135bc250b496cc8795ad494e614b15c06d1bb48905e70fdaacdf066e61c95b972188481aa943e45af90a89d34e0c8c4d2ab039159440a40924f087ec159061b663d2eeaa800d69c93b72f2a5cd4cb23a5ce403c24f8963e7cc2378240ac7cbc8183d56f52d63de183b80e5daaf7055edb14fb6e9ebebf29cc3c39ab3fa33188a254f4beb876893644cb9e11b28c49cd6159c91618f9dfd1b432f6d2d057bca22f731c04499b8c86ecf8936e09c4162144b82f2df57270ecdd577cb0a735317f6dd0413b68173f4bb7db773d1d9ecbb42c1e0d04a20a2fa8ee98e554709c1c5ad78f4b5795ad7d360b36b70897ee5ab4681d275393ef9c8cbc8b5d1f157280885ff00183fb286bb78df7b9ef551e25aaa50e423f94f507718792995e55100c0241580d62131ed0cc019a083cb40ff8508def866b560335a41891ba1a647cc500d1937afd17d51f357c421ccd6f23b21f94cb51572421dd6e959a77842d81d62ec3e401f66d36eb01ee2c2c16b95e2c96b1edfe93584a4ea03deb49b6a6e08a940f3b0b603e93a74106f25e8b7dc2f0690f1c7903f204e8098bd629d19893820769800280b8e58b8a21c9da7bd941bae8a173cd3226f511fc58b4f6b6a1014b262e10a90135df80ff981c4ce678b50ee6039be1b81b4b1c35b6dcf64b7a7f8649a0208a4e9c0d41673746469d5b5db3939e84d1601f554a02d487687dd364312c8f98a153e0b25c849d02631a4ef245adbc26f7ee225a824d9ba93d0330a32c9eec9c73417cc5a07e27e8bda06d6e4c830505fe6e67acf4aeb7bd5e3efb8f31d51a5c39c5671cb581204df0ac3570cdbfb5a119754bdfc62a8225f2c7798db5dd31d5d6a8e3032a34da3d1e5716ae9d059c35faa381852db7a683c068409c8edf9b984668fac2f079ff117a5b853bcf1c9b36ce52599ed84c8a3e8b888ef23b11584a83d707bb173703008a72f260ebb1bae69f8540873fb92eaeef55faf0b1cbb9209ed0a8d4f0e7d075bf7d4f57a886210e401182028ccf8bc3599800fdb56a94c47f40d75ef2216bc1848e83684a4735d70f980cdd7d496babec59fe381f53c24a942f36169a20212bdf883ec9b8a7b5beb95c6b20117f900c67d2d8437f62ca9482a68a9a1ea8ec880bfb3aed37afb573ad3c9b259354574f1a4fd654745e21e28c0c9fc26f9d9f0a38b8dbfd079f517a4815351efd96537be1a68cf0add5d638596ebdae729ba323a4b34aa59d11b0794a35980f5cc158838304e4a45603fb415bb0f2e9b0b7abb526d1e694c7ab10398d332e3e2c490f87ff9b4cf33365872f43f10d9e903f327b7065745562b1105e8931ecf2131923f1b857dc1b92a0c733d696430269cbe5c487a4219426e9516edc05abc96573144b51b6073a9e3345bf9e5b4acdd54b3e3d73804a2795234671fb8de12bb25cd40079ecc2a9d0b2505dc5536a0736e8d17392816eb090705d8c24cd47e0c154029533325e5e271b4959ea4b48b93a9e6133e0e85a36ab73046f8e2c7cdd8ab3018a9b47ababb269237e2633927f6403c422db9e9a67990294d24cb1ed8c9ec711e3f15cfa8caf14c8be59302c6b1497f4656ad76c04b431279927b9ca2c960b80cb038252cd70c115cc5564320312715c50b03da6dfb8a0cc49d3a5f88f4e95c652f3b399feaa56470b637598d9370c4bca8abed37712dc2e8ad4a215dffb3cceb47586d94bf6c14cf3358005d5fb0e0ad875e06809ae7aa02a8c385762200a640e823064e55ad39bdcb13c88a3a249c274013b2b62fa963da656bb2455316d8d8ed1e89068689a230bc6b9a507bc4e40b54e7a13dad93042cc31fcea3a2e584e1c9ccdd26cb4c18ba8fc7c4e1a3d07aaedce9956f0c740b21805ccaca5cf6dcaf57de3a0bb3a7f049d34b623b9c5210f69f0b2df56a559d4546898d01f1f70db35bfbb5eb6d3b20f32a3d48672f259fb92a9c00b699989190307021992f2c816edf2fd0053f30f01ae439caa9c90bba64b05772635ef2c172dd75c4ed823b3b53b27d63cf35895cd41b1b6d6dce54c566a78c52ab3400839548144b0496bcb6bf943f89d4a87fd47a0b60b08c90a10af9e1f880d43fda5d4c31515ba4792291171ff6a9f88706e0cc4be2402c50e0c2ac67ffff1445cf49990e392705175bd7e0a6fb62712b0ee49abb8b1b644c17e58950c360aa982b04cd3ac20c8acf68bd8d25d13d76785a28568d5258310a4f2115510bdae15ee32c55f13af6b17c76db8e47a579ba6f1ed274b430d94b663db941fd0aac1130be8452a0b3556ab4c0feb30ecfc2cc565fbb67e4d512670b73929ec4f576aa68b8a513e4ed71fd0d0a1c26fb46dc9199769d4955878ff217198f0af234878b249717a46260662e0998380a5b4696e9844ba879973d9f821b63330e1f97ef03074c127bd2d01a65fc3e3b2538c57ac2f80eba6e8661307076189d6ba6f885b734f71b37c8186ba96e02e71e9a3a122670eea685e77396b1df32390299d4b755a8470e3c32f83db440061e4650c12c3487f059cf7c47fcbbaeff5e34f5095d850057f6c6071c69b4f2307b9419d8dea05fa7005d8a14ee2bbf5072994fae433a0040eb23d9c182e4a9ae6af16d8b0aa297a6eea6d771e99954dea94560df7b8c7b68ff2a244b5b1f209830cd954957defae69c46bb6b3b5a0033c347d2a2223601630afabc1fbf95b41f3e6a8c84adf38ba0e0b33795de35229e241ec102909e7fb4562b31b247c166ad80deb2ee2cbcc3c766f9bd9685a5ee6c9e87a29d1715bb1359d2371656f658069b7b2d58502260033cb1cddef31ba979a75f794d1d03cfd0a44f8fb5f10e8267dfa297a12968d1d881656e2c8b6f1a9df2fefd06ada7a4b571f57c55c472266cc4c02d1d3a9e3ef95efd661563efb98338dfe4aba7b3bc6b586ecf9095797866d43a94dfb8f9638ad230b29e751968ed7319003ae232308fe1a4c94a74b24127cab70ee015b8195f45ca77aa0756649184125baf94d1a31cadf7049c2cb661403f42cd1df7344846571ce87435143e69a41f659a54bc8bbb44d0b12fac3c54695ad357ba3c0cc0ca878b09b8c27864add75e145120be84aa49f477da3dcc125fa9180cfa40816ecb69fba7c9a1c9769a3c885234c0dd48032f1dffdb25493fd91f979170a7df93d0d7cad3ceac1bf363e75a1d935fe1040ce51dcea587ed17c2c3dd9ab0a0e2125b7ae948f4da4b70093f0250b1320c54b63eabc9ad5bac0da9d99cd07fc6661a0780c8b7b71e8b24387741b1983bc1134c8c69ad60623089a9f29300a12158799aa2bec571fef9b14d4d472e16feed8d2f08286af04718afc0309bf00c4d560a3024e352944fd5caa484f9dc3c7c75521cce5426c0567d0c378f0510b30421529b3bd55541aa371a3b14af59825c0099edac915ec8a360d048bca05a16cf1d41e28c0ccc31340325243a0dd0633fe1744a28859323150e29a200127b0e346c01a230cff88d1f0827601b7afdf5391e19c8b60637c839601d0f30cd6b0655b38f8249fb493de113b1ad1f0802474c6440e2ac3d1a2e0aa8356e9a5b6970d7c7d3f56519d57023d33b3082a5f786dfb01dddcd0c3a97d0e3eb1298c3c4a03ba4e5a0bdb5c5689f9002692f34ba23a6dbf46c263400ccf38616af6b73ba5ca63562a68e92fed5783aa142fab02a96941bdaa1ac91e1527a79c6b2b9f87d47cd58c0d2023a8dc6fada70c39b6e23ca4fc41056ed84335996e2c46cdab5c7fa7f61ee1f5ea9d67275ca2e9041a7ada11ecc6870f54132e562e10c1d1547f96e2fd75a6f940db3cb1627c2b13381c6f603897b3b3fc6dc098cdaf9bc561a63b8eb0f71df4d12fee0bc8167359e780f4301e6134fbf8013ca9c825510bc65b57be27b440de09fd00dec2ee0d4f6048dd4e96df5de997aec7b7730cdb41f7a3a48c2421c0b2c41293dd2f89d77b27cd73f4c451d13bc67ea8e6d405cdce68f683c54fe6bd71e014515892510134c94465c1c1783d7ec8e243976d9e711e852c37c486cabdebd9c24826aa1103ee5b48dd4823f416158b04dea13b687bc4fe41ee9a783529c692c420bb7a8f6fb438b653007fe0f33c9995ae59dcf3eb9a274eece7e457bea49b628f3c43517c05c2027047260593d24926884ef2aa2de480a50ce5ab383ea3a8dfa8e1f70bc60d92e54bde8f37e8b089462d7a55d33aa8838d76d7a925ccefec1e09ed74fa9c6768da299a1c9382e368b3e99a22a72d606c084a1779eff2fa451027ea61727c391c3a78c7f23b697ba410325d02eadad416c4ab3eb4bce0c5819aad3df174bbe4cd313b64f266b20c2385440d1a0f853aa25bac320a6972d5d22864e39d0e108fec0593d60375bfe10747e99800c5af641a3c726d00e7c46b099b789885c82dd4beefff0fc9f4ad1f81026cfed37e864d721b7bc81f054f448263f06ec24f3d800dfa4d7c982356ab7504dea1fe1d539bf8426a5b553ee98fd59277640e87a607fe1483b005bb0ae68c9165f316fb8aae0f17f9a0036f39086f78894cb151f10171799f1cf5813b96327722e9827d3e8d2b928761ef93207a181507b9c17333fd35d37e737c5e99efcccc3c10d4497e081dde48f1d46530883b5f791ec12e3690b75eb3f622bf1cef93e0f7bed99561601a82e142b0e41afc58532c094eaaa8b494cb39cf61ee212439e829a64b06bf626ce274b45dcdc03dbb086c117f1a6ae4fb0110577182d685bc214891c106cc00ac5e8388e1bf3a5afd7515424556da1f863200f8e6be8bb8e992346d756fc14e15c19375dc759bfe8a8eb6228710e7453e1df33d2968c02574fd175fa5f2939b73a6a96e157f3fe8bbf853afa7ffc5899f33ea9f1b93479a5bc25b0dd4cf3aee321702273b3dd61d7a39202039b4ebc1fe4d0560866cc9b70a4a3c2f252456326f0a5baf350b5c0250c5ec8d5bc80411f4796c61a278dbfc747a29b29911e6dc6268d3517e9d0a6b92f2b21cc4c7d1b477f253a936c637437219ad023164662e26b4ef84ab0c2bc8d2f8283fa746556808d158b0736719098f7daa763be080ad411f29369da5a860afa9dea58ba1444e4a619f0702db57f091cdaafec18f3b6b5f7299b051027c467cf8524d8bf5c884d2957b45d1dd1368afc8f37b814c8835c8e620e72a9720f94c529a6dabf940dab0bb13f58a11ea739970f82309cc5bd7194e4ad71aa4678b8d59099ff0098e0f07bdc7e849c31553a433f08b40a74f3428a4780897d098101927865a0dd06245e49b0fc5ab966355694a4456ccd10ee094ebafecf4d3926c3bb91339bba1c560328f4ab72f0f044c964f0cef4de3f20294f6d4231700098feca547c70134a08e619933053e7da790e57b1372e97e30f93fd0692759693d6eaf26dd50949a2f46dd6e2781454643897614482c626cf7488a978648d792760eebfbae1d695525420278f2a0788e3260ee812ff32e49510308c06f984a9cf2f119646eddc07e601d561b4718135c457e11a84ef3b0745af88db8f7f678f0f8538ec21c940c9bbd0089578d4e1a7a2c4e9482187b492873dbb2207e6aa60cdb679205e41c4704eeea4180122742587e8c42da9169476d1b95ac1ec618cfe0b1f97d52594b3524eceb0511edb4fe8bea1c93945459998eecdffc6dfba4967b0118e37a778d84c20cf9d80c24e0579ce3ab94c51b58effa322cb81f612314c6f2dfbd4e903040cc55fb034a83c2533dec39b6ce264adcf06542120230d530732d7ca19bfb4e4f6b0a8ce0783534abe743b83d585851e33d1df82c6f87bfe8a0b26c10e24c13ba7822c3d7116c337cc28713e44b6c6e73bc09d2b71629a6e10b53aedeea644e14b9c5abcf5ea9ad0ba058e7176a306f9bb152df4e752f36aa4187c1271508b9818138ec0c593481434f402a10831bf731b6f2a4cae5e117cd2b85e97fcb018c23c9fa5b2366f457e5b07bef03b334a54dd7d22ff8c4b0fe5d2bdd5b99549424ebe81f33b40691e12aede8012060d99794f5e3bec7c479092dc1fd1d59cc085b4cbb9cdb3c36a4427846718855ed0c18f845c7fea6eb57d342f4e6cc6d2d23cf799c2fc9e849177ce8d009070e80c02ff9da22c995d1f17780bfaf4d12cd6d559b6ba5437dbc93f524805548ea5753b16c05287c464e8dc49d50046266d12afb04b27c4cc070b9f425b7c30a27759ea633a46664f2843ca657c61e436b1fd31a81ba815b75feac002d125dd925774c919b313c372efc5e5b4d9ed5a9856c1837dac1c419d29ba0454980197ea02258e0e58da293a321ff5d04d494e979de2782f373f6c5aaf2376ae7f989740894ca301f2e39fe750e3005c27dee1f8aaa8a7d6c6921807f9141b4849ca0f207663217768568524cc53c8fed87b00a0174bb5193d73f2560944f0e67bef8227c40c71c0097aa7ea4ab9dc46ac62a7fc09e117c884a360d9dac2b9723844c9081a8a616dfb15f9cfdf3996b18a727a5bedfda4ed02303e53a84cbdbd0d8a5c4b2ad7eea39ed1cc18da2d3f769b8928e858e5007231b6ff2c922b70afa50fb37eb5e692643105f470ff0686f2aa7d343602527a81358862aa8489cdf6f8b4fc5c2bd1d143410a273699e21f6f62705c5758403f5a29d945dcd8f1ea8a3cc4ec22be0e105bd6fa67d26d823b0df7a3a20ee3c13c9a4762ab644c1640c9551d6d6844119b2d868ae90535235fe85675a5947f0b156b90208f2cdd907867ce65102b722e1c400ef0e77614c00314eaeabe6c350b16158e2a593d4d9584f98e243076051d2e43c1ff569b8e8045ec7bf5791cb5bb348c9d36ebef82b85341a2179d0ba3f29c635912d053a1443dec2a0a5a203e0f04dc2a4f6195112686314930aec2fa397a11f1f2d6d2d5870dd25edcedaffe7549bbb6d902138606c24899d79e231f72edda06fc0069af96f8c374c7be33f13314d47ca89a8e1199d74b88b93bd6d26711c3dcfc658f6293b9cec3f6f18a53753e176b35b349d56ee12cd8cc7503772962a4ecb422def050e803a9c04fec2e7089989d168a4ce165ee08bc85977f09794713756c99c78f148cbd1990699faefca5f0afa2ae4d2625c34494e55cec97b830e7d5b619a935b35f7ad68dc07013c68c8779bc8c4e74bb05f011391ab38b348290a16b58de7675b41f50e7ae3629aea480d323028348c35d184a5349020335105f3449e453e3895f92316d5d231506125ae66412f49e5eb070117d052ae284d770d947a8cd24462093a2792040d95822c8293d7715a281f746026b2a5727faf1f2f7848129098e41016e62adeba0b233bf391f3e20c91e545df7c996f7ad2406788582ccb5381f119ca18bcc74dd5390e7e00af763216af81913ccfcebced47dc6bbfc2c16a8e912f0d079cf783ca335532aa9d32b740fa083a1efd70ef776dd3e519c48c033b4a83796141d806dcf6c7863d7abfe7be01535c8ae8ee6a894faa162536a99922ba7803ec5ae1edb7f93759cb71c4204fa85e98dfde1b0f6991be53ccbf4ea5e4e6ab38cc981599dad3b6e685b9aee28f4ddc8c8130f0f808416fa22d0354570c3c012ba96a3a1b242e3938c667f9c8f03a61aa6ffd4c45c500293997c14d162a5c41e05276462aef2e7ce4fbf962750ff5c1b02c0ae2a4d9a9c2a1c6102d1c79d8ef88096dc29d93af66634eb471aae05052947f373d46faa5bbdc72d5a86a2dbd4f367997b265ab1a5730c24c0e6a7e65754f624301c15f573968107795d1d20b90059abd4f675c10000f7bc5052f104c227215c04ea9d01dfa046155be8e0880435843b38c51574db3550e005d6cd30e0ab86ccf78a9cacd202665eac3946dcb6b59483ca4d033557a5b55fa3165968ad14f208978feb4d69fd53b3075bb0d9f082eda1b0b476d1fde2b35a14a495c1a69e2a6cc7e67506bc5b0ef1f4b3a2368b2a8643a6b9e3c782a1a1fdb9cc8a2689deccfa3dd3a493187b54f6bc5b029e55d99ff2118ce80b72a328085895b136e9b8e3f62cd84435ac3d79be475cf3383ab9649280f90e7b5c5c5431c795f94f5b1236c9c145aadc0652fb788e3a7f331b75e969988bd12ff12a0027859698865cabf0d9d6ece4cdfaf5ac1193da8a8e77da4679542100f31e3ca2284c5aaf873c4e83d7211211267cd3de4d6c46cd9f5e2b52bcb28bf87aa08e5a9dc82845b2074231a6b6c7c044e32212be1f68b05f240a673e154f5412e27bbc73ff12508532dee3336a0d62ad7fd996d0e2a8f8933126cc7702a643fea59090a79fbe994aeea5bf40aa1635fc593a2154662e2ffa60f59602e35acd4628324d123ea8106afb1f127e495d710931f7e537c910111759da9e11d3575242a06abb629d047105b3f1ee41f83bf2414281ea8c097b2e9ccfb8de57f1d09560cc499b50de20129aa1476597bdb3dbc9988acba8bfabd53238f75853a24b0ae275fc54603619350068f04e304740df164ba34e46db94288cbfe5e05d7196fb1e8d22d968a090662dec38d32aa711b7b2c33f5b86cf9b1c3985b72b810dda67c3b2a17e24a9542bd32be179096849ccd353aafc276cbd4a81fce2dea4b795e73457bb88217cf7ba621cc1045c6d98639277cead96eb2b9a67a11c9e499d7ad83fc36b5bb6905d9ea7ed611f46e80614bc02668eec66da14e4f9a154e03bf43639b51dd5790ffb4957e34b837bd8b7446140d6d70c2cdc050e23d41aae83434ec361e240f8aa78783fff790e5c41e6a7fd3045eec4a3087cd3b8dd266d0f6da9c991b836c2bd6506275ca336492bc09393dc77c5e14259a59fb73bf51a6f6782e7a93d9609e3a62877e6a1988d4f0a03304c05041a7193ab58309855693a7f79f6efd1ddeb6534a8f1dabbea165f5291e3ba7a8942646ebeab69cd1c6eb3b2686365f0fbb57a32636e8e832fd050b8e181a6dd6cb2f6cedbc5607e6f62741b03b258cb5f5b6bb6971a2d355ad2f6de72ef2d0a620ad90af851ca086d16bd7bccf8d7b38ee67ebbdf445f68933b9b8c455df7d5907e7d3f48bfdf8f949adb7d353793eee904c5c47472626262a299689a764ea471269ad689b4eb2a695fa954e2388ee3382b7497b9eb6c321e6d5e6cf062edf8d5455dd775dd8cccdd3de78537739fda29c8e8f834a48bbe286570c72779a267d8a3211d7fe4cd1cd3cce0df7b8dc8dc6566e775e66866dede9d8274e74e63a50ceda24f3b771ad18ce8a31a0d37c3e1ef36a85da66383da6baecd85c13fb88eaf2bacc956d63318f661d50b83c8d8175a8fd3ba6ebd161bbc66b2dbb026d75b3c95a042923b866b2fd3b19bf214ed2837d9b89332ce131d7b1d8de8ddd7bd351ea4731508491963181f3fc3bcee23cce3b8474d47e9d88761177921f7781eb48f380fc38e4f37d2312facc9d82bed07fc0e63cf38af7b26b51ca3731ee9ab4026bdfb31fa88a0890dea287df498bbd2171bacc9dd47a490c3b493bc9084518d8776ecfba17df4fdd88e9df36a48197be785a4af8694b50f6f8f3f99a47c473131e9ba7b7f7299beddc548c71cd69d747cb1ee240ebfc32613e699f03dc6183fa35a0e9c1d3b15469779f4eefb717f7deb2edf7d2196ef8f3baa1acdfdc5792129739924c217e18c317e777282bfd0e4a48b44dab9789257dd6474ed25af0899471fbda74633faf5b5c6e31d65da9277f46ce471a32f947944bac82bbdf3b2a9d1885e7ad466f04997e9934623af7336b799ee98d4e0f6d668f0b73d7e3feee5372fd4be1a52bedff588730d8933014ba6cf2c5278b3653dbebe0a91ad57cf2ccbaa18b6f5d7a3dd1285882c42d4b01c610a28bf34d3537e4fdbf14be7bceeba4cde95debdd278e06f3c4617852c99bb381c3e73dfa9f4d18cb677e7ae9b78e1f678d3459b77992ed3f8e2b010dc3b6bb76d3b8d8ebff0c443f4ed310b711a7d34a2ee9b10193f662172b7998e4b9fe9d7f7c374d1f783f4ab86255faf61c9a62fac6139dd4bfb9e72ef49f693eca47bd665272727ddf67af2abcb4e4e7e6d27ddb90ee5e4434141e9baaeebba29e0cb8ccf7138c3a32f1492471779214b167df34221f2f612f785cf5c77c235d885a47c72137715d317e2cc3568f2953c959bbcfb42d255bcd82d9ce83253e4c56f5e759217d6b064fcfb11c61863a9f1c0f8db394ff4ce0b5972f7a9d170177db1c1ae7387b98fa5c11a96f823440d4b2e42a2f4c6861ad290f2b0a837adaf7ed1a643235a26818bebe49808e528f7a68f484fc1c78eb157fae671187612f785af341ed831fee6c5463dbbf665df96bde485dae3ef3bec65217e864bc78ebdf0888cb9eed8179e7868cfb0735f78ea3e1a8d8bf988cc5d7b95dd635e88bdf4e5300463dfb3efc77df7fd20dda643fcd974de488f4f19d1903ed1eb68c47122918813d98be16cce8c4516e38e33ec1c767232359ace27c7bc136c3bc7611c87bd9ebbc5380ce362fbeee5b55d7edbaeabaf26a49bbbae19eda46f1ef64223327e6c54e926dd4b369dc30a4cd147dfdee17b2db43949944523d15784ccf5ba3c4d6a3c34ed9bd71d7b53a3d9de7db1417c99893dab358e66fb688357cbbeeb11db23d4906da4496a56f8dce401e4e8430550166315431fb956d565f85c738cd863fcb26abfa9f120248732398cb7a93ce44321b93f65d0c51638cb2454f44c31862c801c7da6d8a9599685369f7e3af93dca473fae73bfbe6d1e9e620a9d7c3d650a1c237c91714e11684ac75f48c47311295974fc4ae3c1fdbabe79e1f3b66d1be9e3414816e15f57d83d9e8793937e2d40e693cbf4f5edf407d1b95f5ee8235fafb41fb6e3eea1edbe130f4272774c3a3e57012199f4596025779f8f8c1ffac8dcb987ddab1d329f9cf342eea22f872198fb789cfcfa7e9c9cf4fd48f96553f375ec85dc6753f3c9171b3cd59cf2f89117d28cf2a9f52069523edae0e9fbfd628328f807fc85329b6ef2a8fd60ba89c90b37904df0b7679b37b389c9a5f643c87d7b6c30f491bb39b3d47e08f1b96fdfcca62fd44036797dd57ee86cf2eb077c0e48eebeb0de66669387b4c1ed7833f9b2579abebcecdbb72fccaab7dd666ec73c1b99af4b2dc76643f3f519ec6e814f3dc8cc5d66eef8d3de1a4d768b2f8fbf10cbd98fec16e3214f054f76c9d1878a213993da0f99f532ce93b7465092ed33d147f2c267d23b2ff491bbd24ade8e5fc25fb81223060c182a2aa7534a0a0a8ac974726262522a9148a39148d4751873dcb669dabd598661d77572f285366f2f95bed0666ce5ed27fc18634e6e3a7d6195b7a33cc58bf105e50bab8c6f824d5f4833bec94fbc185f4cbe90e6ed256f7b8ca8d2b7d13b107fe13de93293e4c5775ef59117dad4ccfd5ee415213377aad174e62eb51e2477fb85d9b97bdbb3a8cd488d072151a6b92cded67470dbb1d77de2775ff88c2f3339af33f6c27beb7d6e47cc3974003f6b0f9f351a19decfa6e6ecb38f9799328d79385f5ecce17dd41b22ac36b4a10d43d986d294b244912429b2d842e28178fc8eb8c1fc8090afdf114708a922038239e1e8073153a7291f3f0dc4cb78f99da69c1107bd2cc0b753c0218cb422c39e6d7588a625374e920683be807b26b98490fcdc799d90736f496f14cdf72ee18c7c6fbea67c59f205f37d6cd4bd9f5717b9bf93035edf7921799a6087caceaefbd375a5621220ecb248a3a0a019bbf4e9f1c958fc0249c68072288d64aceae9b902d6832463d88132f6abafc7c3136a40859d838c4d0edc7b3f43f3bd37423eb1dd7a277b21d9621d7cef8bb4914e6dbfd769f026d12056023f81731cdbfb9d44becfecb59ef5ccebcb9b6eb9af5a8efe8eb8e794e0fb3ebd9752449969a796434a91effb0431e6fa7da340dab0bfa7debddd259032ee97c3101cc990b15f5f9320be60e7c6801bc37e44a3eab1cb9b46d9639749481b316343701a959dc8f5b26bda9d57bb0d4a9ce6d17630b10ea6f6e25a65a53919d6c11d5a938aec1c86b4c4029b2072571c8122478d867322cb32ecf15a9665599665693d08817df3d78b11c4eec146dd2f3c22dbec636970f668706a1ad6d61637982ce09c2718032d43d501b6584016900564015940225555811508e30256555565d9b7a37a78895955252358e7bb2766fdd555619875495aa725e42cb1eaaa9295ecaaaa2a53ae22487f79d56aa55ce31440f40cb3abeff1e59f4225d3872a21e966ca92a2b1855251a351b1aaaaaaaaaaaac68d4e694fedd03c986e71e9a23a808d1b3b5c0850c055550788d181d53800f68533997eee98f33576647a93695e43987096d56854b46daf3001d698759b491c9977619dc561ad1c955e97090bb187758448d1d01517492c6fe6a6dd565b94524abdce72c6b9d1276cb533c7805a6badb5d666963773d6171b03b62f625619d0784c0b0399d2541e34dbca7e41ec6d6c9ef1e57a4f0dd0387b93f1a576e70dcc9634d20dc3688e912378d6b86159965503c605ac615996455f63a6ec075a94247008e669029313388c3f8f9692b39ce52c67398b17966559966559d3a5b4061cbae41b2535e030feb8dc60b13e7f23c6442d7ace39658c2f74ca1c481b8df12077481933c99c69b017ca73d0298c146e20576aa22c885690197c40828a0445b2653d1a792deb05a1a1f659e54d4a675f57b441185f98dd64fbe9edb836794ccb91dd2fc88cccd937447cb19f71c94f74df314d268ca93d0d281ab497e96b034c83e7a3b1d3a07d1891c0fd90c64eb6df21c660b7a8abefa4b5de4af321fb2e69edf723faf4c8c0c96265a7124a5c9315f490f2881aeb4e8c09414ced88406616764c2fc8344a267ee409327d0f7189c90a780b2d6eb5d5bd341faea5f1202457af327b6dfdd9f8d2971e95af69d4a93f9971008c2df4568299123018926c54e869006c805b7e70189700b131e288fe66621ed2281c2232a7514934aaba8e13456662a63bfdfe6e14b8c1202dab1bac0b593c92e5ab283294e56733738e8f04c850a4c0e1338a10b08c48c8c93503655a9fd1940654b3bc0f3c492650153f2ea8420e6b64f9e38223f207a8aa20c8f2f1d59327dbc5cccd36be5429636f34968d2ff130350e12b9e2c8b469c0e10d93ec39e7677f2a0d52531555745185162dd8b942476ad87e49849cc8550811c9b18a2dd45023c72aa0f045111c737d18b07593111714139bde05458342f2851d23c2ca184685225900395a31a44496da7c26611a25af4faa7c26b051ad6117e098abcbcc50f264923e41de8aa02b7072f4f9f9a24b90a38f154a7216b51c1806d88a9f1c7dac38924369822c1fabc8d1a78a25796a39f012b8afd81dc95dfce48d890e0ee9b4175bd3335dcc6df8bb0d529936657c0e7b3153dc7d73d20625e761cd33a99ca54150d6b8d1a0bc0cb0ccf4d4d603744a4a29c53068016602476c4a28ea6b8c3418a1f000eeafca2ca7c822de01d601a6591659326b13ba2ca17487f96d55e025a3d4100f7c07c1717c390cc1a3779f8fa3d1e8f3a2d798e6d743cdf3f333a241d16983a2cbb48fa125434be2c518c894dba6e5b0dfb41cd794390c99cf80e4bd982d2d87f79d9ecd7bce9339866763c4110da40c587ee57149ae31ce71df5e63cabfd572fc3b715f0f3573e73e231adc5ed276c41ce33b71e7e4ad955fd274cd3b39e6995c4f2e195a52dd7b29e568c66519a5f277c35986bf28656ca79ecc283da687a1e508429ff2ccae78b1418e5b59998f9af66d5e4e895d57c29887f1acde4fd38172fcaacda43ce59f96e3744c03d260cd24902889482f8c4b548e9d6a33303e73c0c8a4e8d21b7dc5ebb8cb8b7199696378d7a567cf61120c4fa5c17a15efe4812e1e8c37a34683f5289e4c83f5266f4783f5279e0f5e0f201aac277942345847de13df45df7d344a76ff1ec62cc3f53033a4fc9c77ce4b7935a9cd89b3cf6f5996655aa6e50832df7dde10db3430775c4fda5e334dd3b26cc39cfca6699a967997f64cbbb41cf3510bd2ddaacd6833b3dea5d372809acc0e441269943cc633eed0a0f6794d45c6dee6bda1dad7f3c2e8e3a3512ac0f4f1b296892b43f551186dda22c34630bd8856d143c980e7e9fc10ebb22ccbb2ece5e117e0beb53670352abcaecbfe621660ecea00cf12384ae7ecee9e945a1fa594dee6da1ff5013b81e729125514a9b5ced994523a6badb576adb5d65a6badf5b5d65a6bade7c880e92bfd583a874c9fc6208b98c76eb73cd18772f0153f4892a31a72bcc20744b24ccb217aa6e5d8a4ace2264e61bbb1519b683ecb32a9e5b0465a8ed177b2b279b74f2d87e8bda3f27a683b8801cf5f3e9a7d1f7b8d295bc7b41cd677eaaf879afbfd19d120f6aaed88f9470e1da83eb7ecb2c7bc7b79ebfde899eb071156be1e3311d695deb4d8f532fb4529c35e7a995096f3f2b0cb4c2c4b8de60641b992fbf4f0314fb3d66566837747a786900e82e3207d37c097a712e3cb6cbb7487cdc7273cc9d798b2fc7aa8595e7e4634a89ddad3537aecd906b1632a8dbaa7526eb237905bbee65e4c1efba6278f754b59a53623b5998c52179621e030fa600f5d7ce8d1a8ce340ac9139228bd1830a543b8b7351c013f81e569830ec8e223cb121979c66fe3bc80fb72cb3759d75430269549c406f23c11324f8984c643e14aae92cadb603d07064c7f53a89683cac60dd658e9596a1399262b6765c94b9768abe99204eed316f201cad1c7a727d3c3e4e8e393d3b2e7fc42fb85d6a541fa1529984c594a974e4999c91cbae497d8424f632220d3e9125fe8392fe0f9becbfc58e823900b324bb26f2f9c9fa941fbeb046cbdfac528c05f6cb03379e7e31547a098b7596411e700d3064f4850a2278a1c91a084911cafe588042596c8588e48508248961f036ed55424ecb6afaf8a551035a42f3918aeeca68fb4a75cd7b65d2b62653bc75ddc7148eab28bbaadbb4eb7cc914e0a6bf2f68db45df4d5907297bdfb7e64177d3f34925743cadb53469b86b27da16934baf7de7b5d2727272760209570de8ef1a9f4530dc9922c69b3597b4822e5ecb338926a48d7a6b89565d9e4ebb2d7b240ec16bb3d36440ee331d946f8c275611856c40a662d867535d75a1b9b9a5b73350cc35fb8aeebbaaeebbabaebbaae11d7087b536f41b8296b593cac7bb45b6c6c6a6e6db9a40bd78569d8e8984985851b615e78b1119661231bccc6c6c66654736b6ecdc5beb0e66a9aa6699a76ac8471241289d485ebbaaeebbaae2b73a3ebbad7647361ae18684bfb557a442525122e8c7e45379dc4a5705f4804cd45c0c8a58e0721b9f469d79e7dbbe665262251c783909c3556012159fb2cb092b30f137522518a8894322291eee8777447f7de3bbaf75e2e685e64d765814ccb62f55505d234d0c28874c25ef6cbe3ee35a9b07019e6aeb0db4e176d27fc0ddf63cc6da2df2bfa68baed3103396ddbf7e374d1f703e597e67bba97442a916e8944225dd22d9148a4eb1a91bed16874efbdf76ac15a6badb5d6c64ec1b888eb0ee35e6b71beddbdb8c1a3f43543c5691491f8acd6ca23ac39578afdc20c2cb1bc4aa4c15aab6a81a11cc6d7d41c4bb60a6a4e162e11e9a3939fa4dce425d351b073bfd7c3a6791be99db7915eedf80b8f390edfed5aca33cedb522ed3d876b563dc2bed877b7cce3b65dd372cfb68bacd880c2cc9f861b7a5685bcab7ef47cab3ef87e9584dcdc958cafd4c8f4729994e4826a51289442261f7dc8691b0bb61984824d39827c218638cb3705dd7755dd77571d7ebbc1c8660ed9c17d6d49cedbaba7befedeec5c9984ec6ed646049cdc945c89a739980abea1986d16a1ef364aee8e9fa0f7beb1710ea83f6cf1548bf4a1f996e3ab909ca53ba8bdee1ae3b8a498565c3b98853ce44ef2eced7f59deec783909c75f8ddafee9b17dec773d5edbcae13fd12bdf32aed87ebdd3de68e2faa8090cc7d1658c9f73b65ffc1fd3ee37ecf71bf1f908c0f248b2e7a783b91178abe75dabbef8776eefb81f2ee327d3d1b2afa6c68d6be0be5f1292634281f6dd0f4fdc4c4a4f451e9a3d2a8341a8d44efee48f4ae341a89eee8ba48a38f44225d41749945582402b2e1ad3b7932b3b3a1572412894422d117ca3ceabcc9fd07fe3d877f3faeebdc894ea2fff872e8003e755aa42c4096649b69ea8d0896b481bd1e93366ed43adbf7764a5febb36fde4cfdaa99ea0b7b9bd73c79753569ec1099de0252bdea715a989441ed2b2b65d0571ecd35735534d5ad5b6fa6ba65d964fabde65e499b80b142e997c935d24d3f3975bfce3dbbbcec9c8747adf1e87e554066d1af7bbf93e83b05d92eba6ea50c7cd1afe373cf441ecdbde89b37733fd1471bc434a219d1afe81a79a1a849bf7d9d3b35a9b0dca4c29267f6ce068b4ef7ddbde8f8c7fd4e4146ef4e13a58cf0881caf01324483f646d13d3570d05290b41c179206edbb2e2c20cbeb9f5a3b494f83d606d50b77e4eb196ed034056e1ffbce8bb3a5933d3bb267a8417b5a515aafea45b64aa2c87612c9761ac9a4a4b51a62a8a651fd816c73b5af1e0f3600ea699f46590f9b8a6cdf468836ea17c4063f8696a3ea9d78d3a0eda06e24f1c5bef2faa7b18832ec6b2f21dbb79049fbaa779206add00770d5415f0b35d86389d06080c34e92adbdf5216cc5d864fa41d007241dd4491a55fd415cb6142dc589e4e99f4662c91e19825c5d521153f8f61227c6a8e4caca31258b44ec354fb7643994320631257baaecc93939db91ab0645158f34787db5791ab4ef23378dba620c914e451c493891ed3412eab8f20c000e70d83b48ac2c12c261f34891ed0360036cbbdb4f9c9d4675b66f28e8f5aaaaaac739bd27b0b533c77eead8cf1bfbce6b2fbac5beb69221a6b51857b6b21fd85e341d438e41d91e8818736fef43a3b4dbf7c8606c5b8c6d5bd9b66f9bb76ddfb6ddb06d2cdba6ddcba33056e63dbd5e756fd07c60b99e61f5fabc7ecae64da7e4cf12fb899344a38a348a66fb09054fb633ac1294e490c5da1c4e9e6c718413bb7aa48fbdfc914032480e35ca5abf32090972288588e49065047686bdaecbe6d8a631824b1677007f5da677f41063fa0d88a948136da84819210b8cd2f5ddc503a9276d782c2730acd20df125c69c744e5ad360eb880d76ec79191b8cf1459b6169b09f837490cee16764a6f1e24bcfcbf437bf97a2b0a35bfad69a7e1fe24b8c894dc8fdfe8e27fcf064eb57b6cfae0912b89a01aec2fa45b5f30aa851d7b15baf82628cbdf5caaa8e64eb3d1a75e5281a75a4513a33b543eb64eb15ce4cd5e82f66aa2a992d96f5aa87061195f174054544653cf8c9d63bcf663c88a81e3c8db2aa85043e1121db90b997b2498e3355de2eeb5a1318b43035ea073668edc8da2f2fac91af679915817ab0b94783339f66e6bef0023d808831dcad99b787336337d7afdaf12a28e28bf59422e0b0c6fde68535635e58b35685bc3aa464a65c5c94684be0ac0e356855a1066d8e597eb50b7a352670666badb5564a4538c015cc97cb75baae6aa753d2a788f58ae7a74ac2182290902c82e40839bc35078985c4480e59720594ad2a875550b62a1c613594ad5fb247a34297207c0cd1280b04c2ba118daa0e24821cc62e4290c3e8054e0e59b28584658204c66436410263b3d6cfd05cab50a3eaadd7a11803447cb16ebd5221a21a1041ebd6337b4d90c058fd7a046008b8da99d6e3dc81e6071f628cac9a58424c42b6be6362975a4b4915e3f91a0888368ab0b9de7a8e362a1d291363e46be42274c8d66fc498ea01e105115faccb1e0d5aaf74a40d084419d6adc718633dac9ac8964a9bc2a018b31363e4ad8c275bf5e386e28b75508b8c6702c517ab5a9f9715812a507cb1ea4d7cb12ed32e50d8afda69d0ba919d6c619e524f261f59ec049237b204b3942859ce9087b962aac76ca9d5e5f7012c6ff8c4968a311086895f686d097ce5f9d5288263661b155a8f41d93af6b02606651660ebf29fad9138b9faf5b0267a360757efd37b8bb68cb4c100c800cf67a01338a7ca9c06eb4117e0500ec93527d71410dd525f7b0080073f3b7cb02ea5f4513f447d8ffa20eaf14c593bab95571359bc8696c0b26b15e1205a24b0285f38310675248726964ec536bd29500a1238344d528ca99fd5e79593c518341423672d6f39362aa3935a9b7699e632482a03aeaadc03882084a83e440d904665af5e71628c0172759b4ed5982d1557857248ad6c86df2dd56bcc9410b18b5c9dfbaa6f5f187f7205c403c2eb010eefc55d597d8bde3a08d328976c5931d7ab57d817adf7aabaf5f568b08a40433d516257c0f2406431e3e433d9a22ae02b6f8394ca1c2b2b65e7b495652f2cbbd6d5341fdefd1ab9a3c1069bf626bf533f664941da5d6bad550ec9b43b368893e9110dd26b4b602ce2e96d8c8831d6e9b3231ad52a907289231a158102c004b636c4b4ad5e4ef3a19332561eb533b54302400b6cbf4a9be972b4a2ecad8ab227ad95555d91c5925cad48a81bca6eb0e8509ed798c01226cf7a14142f94a02c892f284a660a4508c5a2088138c0610c254279dea0135f26f71399c0ade9f0f2e80bfa2532ea694ae0be75daa08d2fb1e27eace69090c4230591801ae47ea40d1214a28c49da02092a2613adb81fee67f40509e80428beccb354eb3b090508e586041423c692186088365084640c2531bc689485220531e4e983fdc497f989f508491bd81551c6fcc49220854b6d0c2537e8c498eaf337288931f41345499eb4fa62e8c4978929d17ae2cbac00980287580ff5b89ef832b725f165723f791eb132f6562fab99eb07c69799690c2f1a9c31967c319434388f04960f6328b9a10c19783125e5e82967dd4e34d503724b6d4625ab008736ce2d361e6d898d0777632670fcb42570a4026b53684c90729045c9066d092be8bc56ea00f3fca403c8d9a4937ab2c2b5be3cc125c71c72bc48a825c72a63b59d68aa07e4f9fd88d639fd8c4b11824c11c2ec3929a5b44e9da993e5ab2fbe884139450895137470294fc0a1d531a3ec496b65d9ad1f3f822cfaf464cb04b64ce0302ed1e1e5185fc25a24db6b4ce0b07ed1d79dc0615ca2cd74beae6f881b21d6d198c061a90765497cf1327dc471793277da12385c4992ed331e1d80a7ebddab27ea45efcbc698edd7af18a3fdf2702882c3ce6c11004e00b20070228ece8b38324d0538bbb6022cea66aaf6cc54f53353bd6511633400647b1c8a340dfbcb0b71f80287dc3bd9bec28127dbe3f0457f38e85801873800657b9d6c4b4338a4b103948a93c64ea364b65a13f8ba032a07d48b3e1a3b9d478367b6d897aa80c395a10c0adc1fcaa10e3d3974e8315981431625216651c2b224c66cb76701438cd16ecff2058b121c705894e49695242b425c96e12cebb24c9465a32c23655929cb4cb2cce680b3accb3251968db28c9465a52c33c9b2932c630287f8c84fa332248da24031e616c05a55a5b3ca96ccd96757ac10533af4e8f0c305d18854323931a11060442989d212a526949e506aa21485d2144a1f631a8a465d33d538b0ce2c922d8d1d3c7580aa1360bb836174608ecc008a312cd95ed3c121d681d1a1dce98ad00a172b4956821ac5ad4cc15be9a24125f1c59eae0cad6861850bb75a3b75e8d1a1a7ce4f014b568674e8f98648d5fcf0ca10661962c939a22d81431d7a3425666c7cd1e18a6803071da9434fa3b8dbebe0d3287c7b1d7e624c16ea90042f05899702145fec3be5a7417b1c74a48d942ca20c7b9ba245b60f7168225b9569e22697f203e327be608f45d37165ee7b83f6293f5ff9f9c208e4185fc417fb87291fca92f8627fbdbc6d21db7321dbfac5116b31c63a37544a2b4a2d4a2da517a518a519a597d2ecda9d39007c84c6ce457f7d65e8f268ec783478b880690e69ec3881431a3b3476421a51644be348b68f31e6393cc010876118c33a0c1361d808c3481856c230130cfbf09106ed714f7cb1bf3c2c4583161f3992edb3ec765ed45480b525707823dbd3d8a10184985a198a2df676250b3dd97ec50a31857156b880b3accb3251968db28c9465a52c33c9b293eb6a4be0b0d4a3e3caa59e06eded0e0d2968eccc54df9e060f8d28681c39c0508c69c9f6190aa529949e2855a11406a531285da1d4bad77c109229ed69d495ed330cbb36798c3353256a9f699aa604be2e5ff269d0bef4135fba977a66aafb6c56ea71010f101463e8ed637696b032946d8c4c3f969cf8620f6a81c395a1ed26bed89e46957c1ab5ddbef41363b2db6fde8c062dfd600030050eb39bccc337f1c58611c81c4f7cb18f5ac8360b4898e06407450b2d30e1312da18952cec9111590864c78f081914cd04fc9c230e10922228bedc55a2c215926b0a0130a1a31410429c05b88d8408413bae9c620822d8b1e9c851496d0b4d8e1b2c0e204d7093b5b16452841c6059096451498147a64a4f073710d44703d4149c6028b659143022b0a45ae2c3a50822ac98f5dc3072a148e5857d0a15ce8545aa060022999d5022501a72db617372168b644db33022620916182c5403dc89179820e9ec2117cadcf144a108020a0410a6da02fc0f80b3406f8248852815772f4910210e41af073f4910213bd041c230dcd0446a94217b8cb6222812d24482db8e04163017339fa706164ee70c1858e501634471f212c7aea10b2134d3f3edad08c9dc2fe4e34a1ccddcdcf2924cb79fde8f4e0bc02fa552eff889f33623b39be4883734696de41901610e105536822470760a0800bc24004212f6e962074cd13549d0e25a856d0a1bfea0a11501a370ae540149d206484dca69b5272f41152c274c12003001638b4b9a38c803dd1c4cb1cbf93cc33cbef442385e4acbdb033d91d813c3bce209d6b22508e5960f007584e2c64d92806b6bb7b04032b519df2052c3fbbbbbbbbdb830196dddd4db120359d9a1318acb1aa39b3a5abaa33535891d9d2395f8ed7d5440289b1c9a443c6e8058d159929ce62455632c7633790657ca9bd015a4bd07989dc938e82acab3181ad5f2d6dd89d1cc13983d8d8dcf1856a20d7f842bb9250c8fd5150c8ede47e761921f7c32b771cd2e1e5f955517a5952ac48ee9ef8d21f15c13d493cd81ab218634c2943d8dddd317224c04670cdd1472827d3243097a38f1007280ab095a3cf1668c026bcc517688084206cd14506d2c25a6c61c4905dc10b5c94e4f6b2c50f725fd37274b6451b323dfdb5b08802153e3dd0c10868b006277041031c5280051a58a0031b542106316707d3a71891517022003d40c3134f709103356011d3d0c4089ab8820d2b50411270d069822f68914bdd1970789cb238a250dfd0413eb9a1901b0a2cc80d8533e436a18185522194e96d900b32bdc55f3ca103991a21d35bd60c4eb0e246a6af6684e10c9bbd7509b451d60c4d7001ae827c904aa657484972932428532700654aa98d5e78810657da4f0b1ce47ec4556829f1a34ccf48ea94cc79acd1ddb485ba25c77e4074cbbcf5c974512401d6557a58196092fdecb68ef5d5d86ca95c725fc614c97e00f78c49252581802290a90a1cc69e9094863cbf03d34ff2f838a124db384dd3250bd9c9217d4d0ccadd56cab2685f627837554969d73eb06a8f920b31a57d4d440cb9de0ca3d7b4f36658889223ce6ca98d135fea2d1fe050fefcc89f0f3153d6f617626caa200803e61a43c4978aa3a489f4555ae5884a0df0d7e7c91d094583f5ed499e068fe8967a15151616179719213844b7543b2d1ee0502ac94a1aac97b55bbe82b3e2799ab3595024099d5c2bd04ed56a9d5249aeaff435c42e55a5239da73625070fe09af968598065b6aca5f1a0d2a82b574d89beac3c42477c306f9b4440c0f2b35bd20d4b15647d51cea64a9629a9c58d1ab27c54c912cc72c6ec4832c918639cd2caf6e4153218f9f9782376b19423e9246f1fcc3c8d98001c8b437b3dcc8c78433b0270401c9af6d16ea98f8d9aaf27754abbbcdbb31bcc6f1e088e437bd61701eaa747679687441c1147cb38b1cf8c7de105228ee95d59f3220e79b3c4b84149b51cd2cbb06753cb711df3ae2981594e9aa9774b85a9f531e654ca265576997480f1a5de145feaab96bd6af7569b3965d84ff79b3a6ebeea5962ccf59a2d1d37631fcc8cf8529f5204981e43a4fc0c6bae624c95e3cdb1071341167fb16555abfec69ad15bd953ac76b69ca2c9de9eb45696bd6a13596449e10096578932466ad263c50a92486215d151430e4d39bc61858e14a6392335cd9826956752e0f0c60477883137a6f7eac68d4e95727618623ece396769ceaad2094e7995374abe5a219b50a4c0b56b95a5215ab72005b580b6a0248771880b3f55f60555e8239da9b843ee108900cff7a58622044c1f3358293d1ddd504a6ba66b3892291aae5882062fa0218a52554318195a020fd4c8b47a7d9819a4fb306431e3aaa9a231c6b2d7d65b16a9c1aa62ab0885fb3052016bc10486c733801c904b88a9d1eb838831a327e42aa7c03d9459f842f7509ac1fa421a51d6ab9107ce967a1b45301b4a0211ac0f63cc7579939d29ed967519513e2c1c1f8d6a9d964044f50a22585f3fcd83e915e8f4174466d75d02a4c1fa2dc7cd93a066599b657196852dabb32c91658d2c8b04447cb1e64f6ca929ed75368e8ca9c6892df5d348b7f408e24f2612c2d348ef541c82b982f999a938edf5c3640d0a1b6020d289181373fd119d8a386a12b91e8c31d5eb7b00d1291fb325d6df1a82b91e20d768841004125feaab7a1f73debab262fa82c8ae1a27b79136d2465a27b7915cdff5ed44a79a48e334184a9d5c0f001ee0ae8d335b6c22aa9f884444541b011263eceba58e11b573727d7d8c31d66b3fd1386da473acb599b5d75acddacd5ace5a6c6df7f85512c63b4b9596f422bd9138408c20d9895d60628c7d556daf921029901951f2a7c16a651280cc54bdfc99afb37a55c6ac0b665627287043e08c1e6c08eb021bc294ccb0aa926c49296beda253d850b75807bbc5ba17d9c2943468cd39b1671886615876cdb8aaad41d6d6a04e4922f4d4212f1a1587600105911a5497609124872cd97a58e1541c619593ad5b70460f36c49255b5d68a0d615d6057c086ac1a54836472f8b0232a210947c8d677983e20a1345e6b671c40e646ec9961235baf11a720e11a8471b0206ca80661433528071b52319940974e55a11ad4a0f51a94adb370435889ba24ab31f2d5b61c69466f0fe1a37a1887aa0f6dc41133c6d0c87d1f7248a766c4a11b4472ef70818943497c4ce094e55b88181344ad2c7b6199a5f180bd58e24416fb5a8c9c753633da54463aa9b5c973399bd7091c56255589b42173f765e5911ebe6910071369d47c4dd23a4ee022f8061be95495c2fa40919b7424c6cc4092bb02f1d4281a3cd260e31ba1dcc73743a4bc9d5876116384861a454daf9567a64e3d240e2b0737393385a20332bc200b4252bca00338fa5867a684c8600ba0280089808a35cc00471fdff4314e3f6a561e8271f08d1630cd21bec90d13638262cca5f5c5524e966373b2d596c0fdc7ea5953aacd5c197b164540b8d565babeeb420aca936dcec93657575b025baf9a0e59e4a456af5a8eeb99091298ceabaabe79c3836f555595a3de04097cc22ef3494795b16f0ec9a2aa2ad5dfcc166b24c660328836b2cf06f18988bad77e3d6c2237d37ef220a6e417427b93ad10b2956da022db9f9e37f1c50738ec219985d8627f3d698528a91065d8639e1c8a2fb6a75becad953dd8a7e5006b2fc0610f2599569216d29ac0149b4332c58931b127c66040d39b3dd3a7c12993746a26d1d2083135397063c60c17171616959e79135f6cfd668eb5031cca9e21111470d83f758a46a492c9890965d60a49b7354102a39800dbc7ac11c9d167094e64691b89cf129264297d3ad543b3c5f6c8245ddf43d3ce2fc4d57ba27be585710cd906a179ca38e756ed5853744bba1dddde3a1263bc1cb248de883c23668bfd08c86cb1b73c308bbc385baaef4433ab2f0c22d70f650a2c7a288bdc74fdbced2c4b645923cb225956c9b24c2cebc4b24c9625ba27dacc95ed3322d735895cf3660e69548d31d94c02c81035291c77e238158e83c17131386e85e3ce711ec76d5a0fcd942c3265912ce5a40223c6cabd9b618cf16da5e3cad5b499e9467952811163e5de7752811163e5de67724d664e1299488373c8c49937277767472269d04a2498cf4f8cb9b1d5e78d44229364fb21a6b54aae8aa6c1d0b4189ab6a269d7344fd33e4dbb41d36ea60223c6cabdcfba37683e6096e9565e1891d8346803a427a8040c586a8b5a324524100000007315002028140c078422b17038cf024dd4011480108da44e6046950aa324865114e50c228c1062800c8008008c90066910008fed8ca9d50a679e83796a94c3b9986ab4bdbc3a5c50238467cd5ca33de5d5f1821a23392fa4f102e5f564811b217c136d8d0bd4af070bdc88c0ac987fc444b3994b0ad187d42b484aca4421a40bfe88b9127c45a8b5c81a6814696e31f20608ac22bf88a406095c317a29b28d504c45d5f2c81aaf4045e9cb486a4ca215cf47a051c11cc8fd88e4a288ce821b505fe37f27414777934dc27aa78d895776eeb210e9860856316b39d20d2b60c5be26b206695411b78874631456a1d667bce0cb0d7635b455da506a96262bf175ca9984671c6f793d37e5e513b31a1a2ef9c1c1871490434fcb78dc6ce41bc94623a35902b72db52b829a356c94e2b9d9ead719a14c8050c3867627b29dbf717664e63ef8bdff76fe9614668361b9efca8fbef1dc165b0e22fd5ef90661747e8410ec9ba50a03bad9497c163d3a9cb7379c75ae0387b450f438049e3dc80ca6c90684fa16d82fd183b535d195eb25524b86ef48dd2d92b095f57f5af4153c6348ddaf49685e1b3335eeba05f262a805f968b2693f2479d7e88a5b2e2778c1956a6317b402a9b2ab19171a54c54333d5b553369ffd92a5d2a8649c0acc4a7617b76683158240ce8ecbc9ea5ad12975cecd077dad2271153b2b5f677a33188b25dc7e7c89752f83b3e1973968b00ae5828f23d2e8a103d15bc6601ba9e42fd6439da32ea17d52ccc9cf751716e1571c0866c709dc98e716b02f83f2fffdbb6c759f5ad40cd70fcc9386a2154d78e5ebb1f080187c3c544f629c9c6e0bed321446eb4626454130b39cb1228353a01048f55c9f7db97c96cff9d222a23e4f3098389083644cde1f889a333f0b0a4cde2a3d39155b9ae6bf59b1559ac4a3fb6272e513902edaf2ef68471372f958bd91bc98306e1d24fef1ab9a9d03c6dc3b4df4e46bc3b0eb542254a67f19e3f2098a43aed14cbbff88ce2af0fdd82283d88d0b0e7e97bb0858f052a8ae70821cc89cda4e243d504da8fc49c5dc5af9bebd7f54606f933d4653ca31989521b320714b0599f36161ebbaceb930c4931cb8d901768d1f4b078eb262640bb28dd25159f307107c03906750dcfa31ab3ff801a7cae0a47ec9d9ae03cbd95e27b3a2b2923042606a0fdda58c3fcdff68e5b6fe38614ac77c9a0e2a56e98825c04dcde69c30b9115dec0163d3dcf2d7551fa9d14be88f09d7a8e00fc1b128bea50bb8d277c261066a0ee31346ccb422a438ba997d8ba8c40cd92e4828717c504af366cb6c5467fb7028a9764b55961bc1248672c901174722c4d63b910a96cd691209e22fa105daee335c1e5f2e8ce886020fe5f12cbb552ea3b75fe1fef21921f36482fd1a0a52a1dbc0e18853baf936394cca357694f979b9f9b5465895e5d614e9236f87c0052106783e5b61a466154a1605049b3bbc6e16476a702202136b02f6e017fae84c5241a4edc21bed1ce7d1cdb1bb55c7f4297c321280323edf8f5ccb999594cd56a633614fa052ddfaa4f79095cdb0a9689080e35bc44889cab1f1cb94d702f76087a1afbf0bc390fdc032538aa8a9ec3bb2b4952d696bd930632eed5d5817a16fc82da426ce6421a35b956bda70aa3ece222d6844b4860971b0df965d58d20708f3d848a7dc19c7fde931617db535732cd6eaa4136983e7b87129225cdf59dcf40b732862afc06f60e28016f4218e9b11904a8d103b04e41990566384592cbe57ebc51ac46d327abf41d88078159313e423f2008464128d71d9103b51782032c05f5eff44808241c18eee3bae4bc66ff003e6beab3852a856ba26c4b7f96e2ff1643fd22b2bd26dca08cbf95ff4e76fd2f9bd6c8672df64c3d4d9d9d44d3a1f12a6404abba8086d3180e29248b6bffb7c95f1a283fd2e27717690d2867a3b35a036bcde3db900f632b9634145d24bb53239d050af59f30a5bd630cf854c1aacc58e35e46e13af5aad2177629b4ed6c7c0a5c4c034599fbd149e6c4e50a7b96c7f1785695904c3658e5b6dd029f952e124ec067693287b8693c4032aff61ed927bcf313a29f17bb4e201e177d404f2b6c45d7e15380dba894eb4144a1267c826b28eaaff8061badb1f0942fe5b04716d5873d997192be15d6efe5ede9d5f41aa2a0d96803a3955cf657c8a6bc3d611b83960267dcf0295446618a45c795c3557b195c171a7749d8ed3650e0f25d0eec7e6e849d64849f33659671041ccddc68444e25d432032fb883c13d14f4b7e06fbbe0ac762d14069ee318be154359a57009105729b31abaaa48bffc74862bf5c20734e609d204a4f754cbf26b1a7818ca692c7945dbd492e72b9c0142e5daa57476c2695db1f3ebb81f44b046a1cdb93fbcdb06f1f48e991aee32c48618152c2fa815c874e157d9f664274f20e18f212cca0b48b325adb5e5773690c2bf80e620d366ba6a95a5602f490feb9883a214d9639ecc9222b0b2477ec4ff72555040de756e32c4dd891f79da1ba92fa55609119890b4c7b8ddcf29ae230fa75157d3ddb298eca15318268e6d077d6b4d434518d5ccc41c377838959023c1a6be0d4334862fc38f669174db6468f4fc38c9f2571316bc0b9569add6f6cb2e7a6b816a5bb06ec922047b34f3a1fe46c72b65cebec721c1d8f2034fdef89a88dac8f9bb561ddab2ba915390f6ed3df6c505a7239c9975e91d15aef868a56dd6480ec029f0e12af3b5c37862674fb4de0fa00446c2f701dd4ef006c42ef02132b11a80ad2c39b527463a097cb5f14b745efc7821e000a1dd1a8a0c2cab67b54705119776ded9c797267a193dc6f6507163b09db5589b0e5365ae996e8dce3dea933fbf1e4aec53cf3c7e3628ae9c1220606047a91ee8c3e8bff3383a72003ec2c309a08c2c32526d6e4bfada3206fa13e9b80e7dc4a206463ab0236abb60e8787c0e64355b53b8fb6514024c9c0d9ef4197e8762c40a82a567c5fb462836653933e369a7144a03f38b6fdda30b1be872d3021c6c6971e4e6973fcae4069ce2cd8ba7424472c5137ed588bec4be2f0ad49704191e2193079e8011350a1d260966f23d8fb7e57f6982fa7eb948cf2ddf40473eeb72b8b4d674f9311ec84a33673210034c285d37cffbfa3798020b339eb64b29147c04c282a7527b170d456eb0dae89beeaab4939f6a511bd608490e13d2f8d3c61315bc8761b93cce4a50605066f08ccc8c2c6f21943dce5fbcf547a522edd648cac02fdfa59182099040297a415a2de9961eac45d7454643cd36ff01353f62e215255113253be8f518624fe9a4c81750f55d7a95f6fd7646ec838d28f39d7136ba6417a878f1f7e940d8dc21d375d9901f400155bb9763f9555cd10ae929b81fdaff0a28c519032b7e4c6042657b8ab46e2c004deff0d3cdcc4af06dce1eccad45317f63e2ef991735a323aceda6858eddf0ad69c37cf976990dfc10f015bdeaf5504cba96aadae325912bc4a84f1609c97b412495ddcc8b65c6217c810cacc147cf41cb8900992f972fe709e25571dde0e4cf26f177c75429d334ffc79e2dae21154e1761537e5311014316687b133649ac94da484a1f8f3a023846d3ed185fef8736f4fc4d418d23c0d52e4327813618506e19ac254d52839cca9e02f915a54e4299552c70135e4971350a0b1f5d3fe140d3cc5d209922f94d418b880d7cf2a6172576fd47aa569304df353ebbf848b920a8f0cf8a2023917027817c491131e6b283acb9e7f5cd02da18935ab5e8a8a37bef98e3987f053f5a9f3c134c00c6d660d04072e97be4a3872e1d038abbfc11ac1c3e74e0230aefa39deb827de710d0d1fbbb01c007c72efdfc59a5b300716ae4d7e50d1198d6c7fbce737ea4c85e1c553a9285d351cdb8d2875c3076d25d0acf814f27b0ddd2ab4b39e997615db5861ffba9faf4b6b8af83c4c5b1d9c4e8a31a2c826239a53c9a3a165707dbeb60096e931c1cbf8998ef36f1c8f6288d7dfec300462e283cfe7f3cba51bd0bac7abd07d19a06c9b452f7a8f2c3039d73581721717385f35398465c3506e65d832cfb9cbca9723b534c8cf4efa5796908c97adbcfa33951a92d7a9acffa090eaedc6b8e677cf91830f7afa67f966d77b18c084521d70f57eda50754d5ddda3cb30133e8b8c4c04af284b84d92e81532198760abdc925e55ad2ca535d121481c30c22f0aed61acc14e825e7ea378c0ce45a078d6210299a7d23e71e0db0cc35e298d06e9e75c28d6771b84e7f76254593af4935c3ace9742ea5a7ac7dcc2e5d21840c07703e8dd4a8817ff857bba7d6a4857c202b458f814dbb6a43cf629c11b7503f3e43b12c6f1193d81424e6d4d44a66b84a34e59f94b92d75eedbcf811053b4bab3b0c0f6d7880cb19e1476d4bf17009b7a0b9c7c83b7cd529b8df31d9bebc36617542da4610a5eab5d2a2548d9b79ec7099a6eb07b549300ef3aaf25d57300d896d4f2975bba6f8b5babca5bedbdd42becd0bb66bd64f41d8b292f2bbbed96715cff011e15c1e0d5fdcc2982d23272e3c50de3a1d83efef20867b820edcf5a7d4a1522d0d806bbe5a32421d8692cbfd6f8552abe41d8f9a0039c45cbc7540121c4529808c9497f6ad983386b3d79bf9486f08584744f092dc2919f386463a1f61b328a09de843adf8638818922d4e5aa0ea3a1eb34903d3524ce10fb8286df383a8d8c38e86eb793f0cc7e759a6b0acf1cd9a92ba95a518db6f64aa91a12fb0da213d178cae6b278f8d51b58083c35f5c488b9edb80e8592065c4477ab9002524b33412e60546a9d9bf1014e41ac3804dd2546edc691bd5aa2cb7d1d39d5fd85fd903194cd9bfb0d9b9171f51c899b0cc62056bee48f8dab276d642befe158da23c9ab00b1890b6e719addd82476a1b2afae70e3b940a72b15a27e8985d3cad648e4ea7b9705ec6cd84bf60a2d28a1c751e1f454d17e702fecb3f6740ca019f7449cf91dc6ccbc6b98e2bcd662b60df8083e66991dea34a31161fcb408dafb8357dce44b423d15679f210dce1cd4fde3e1aeed1676a93bb53a16a8b6a4dd4a9b632a000e10a6083b2973c3120ec9c2d55d9f8d4095b2f3727356d9bffb40e46a93285f23ea21c81428774d656b53281bbebfcbb4df987ddee9428a902905c18543f597aa14c492e6828fcab0f8ae7e8d1e122e7a8ce81d8d92c38df04f066339a68080e3f2f95e590e496e61275db59f56ff1e4b01418b375b102274fd795aef11ed5ba0584c1284b60890701b97453adf565c0b8865cc39f81406e222e12c0dae7a855957fb247be9f3faad6c78a69d3d75d5174547eab16f8f68850e48fc52bee0106b65d61d85bba93085d71f63dbd3d6eeec2e9ca4fedbb8628366924afe965e83813853b03945f0398394b8a503331524471c1811c12045cbd28122ddfcce14ac3aaca07f43b3cf806721361edd6d244d179a8dd7483a4b08e6343bd2673b409e0116815e143d5bf85af8d243b4303d9fc13794bb6645ac5184ffeaede1741c885f525ab70eac22c404dc64bb5dd1c3a7b4a62822bf44a2d192c62826f44d85bd593e8fdc097ec83f6740543d4c157ccd0d160e1208769deed6c5494ae3fbd067317c5148564164435226538e6c0357277cef3e8883ea8a196c30b1646831df7d787a5eb9c67512e41991acbbe6984a46784f6b6b54b4195b541f430473412345beb46f9dae3c789a42dee904115cff6af229a9e488a973e7d54d210c0297232cb0be9e46cb4afd38009e1a79b513a7b406a97679a5acdd18a18b6e2e2ef55607fdaff55c7c7499fe4a381c7008343e486e4f0cf32573277ac0c40e8a1ffac36c6df073c2380c5b128857edf573842face340ddfbb04e25311f017e4c73aabb5e9c8ba46ed19f6bc763f3a9bb7d65402235161ecada045cb44bee807510838d922c3ad6431f6e13953bb92e7ad4215cb16dfa846ec798989e293f7054cb10c7af77f941b3761e145074e4b088bc674ba6236a3727b2dd7182b8abfa4d6c50a53fb28ac9e27aaf3af103c2fc9b7bbf776748177accbf0e5032f90b5124e8b7fab58fd28c2a9403ca2e19390c85300bdaf46d24921109b6a8421bba3aa77c1ffdb2c491478025c07e70ece75465a70049431928a3418e4f361abb15085b1d4f8d5a5f4cd0684fd1bed7e040035fd81db83e7343af293fd474b8b2e0f5a0a4a5928ac0d5af0207d79844b771e6366e404e6f63dc624afa7ac2d400d5382a63bb12f84d0d7909ea2c059d9c129cc239c70ef28aa9e20085d40835a9de816fa0f28ea7444eaf8a36c1601818c2cce707be211aa4577a1128435d764f55bcec9b74cf15cbb3c59546932ef9b9125b08966d652c996ee2a8f30ff715e9d262936f347d574c979ebcbf61e9e2d201bfa09472ab45cc3d82ccb6e1f8c9b182c3678bb43dacba773c002fb47cc2411a3af2b3bf0e8cb53a25e036ba8c655c9ebebd172499b4a381c0f21815440c3ee25fb4105b3e998cf88857ba682e4e10c97f69d85ca025c264e94c9d8b40e32c8c0bef80b872c26c473a2061ac3bcc3d5c34420b5312a6f6730bf95cfad68f56d3d8f6f251376def2ae14104152d7d5d0b1cc823e29e2135f552b7775bb03a6d79f5d77bf59f51cfd503e1d4303a129eac5b4865d6ce8c05c276612d199a098c29db91eb84db9e03b78252e3973bbb587575dd07904e8834b5b6c34eb6cb2ced8a78e73640d132595e799632c83c77e620add0bbb1f22763f1d31fb9f213b1e1426138ce29acb07a7f64619280bcfcd03559273e1e978ab6a33b75f0ab3e74f735962aed6e81721d8299f5f568b035f41140411fba17be167dc9fd6f41b510fbfe81866e00d094b08caaf74061a9e28095ba7e6a71b6abea43a4f5bac8b5eaeb1cc6e6f3c46f2d935b7692c35abd13d028234a7512a4eefc4df5d5da72f2e68c2747a93ebed2277008ea468966f069bd90ae4f87efdc5a94c6b4a2f44ef52c71b5c8eac348c57bab350a69b96297ec0e1ee8f2a16b2e0278716fae288edb51111a1f7c1c2e54bd62de726b422adda025f251ebc3702b5d6a9cfa6000cd4a82ed0b9ce11b5c775d2b317efd129241edcaad6308ea4a2672d4e4723962afe8c6221ab01afd4bc4625674f1a5a137ca7217dcff5bc90e218ca04d0a58c77819e01c74634151d433d959acf7964cac83481bbc8f96c1c2eaa0bc0f5a98b1d1e5e35a139bae6920f6dc577f3287a9cca7b688818f5ec304543f99331cc876a0cb389072640b8f52809e9245ff4b30cd6750171ed8234cb5989c4e5925755825e02f0153e0e34a9423cd79fdcf339856896cc5319c1da0d9245e317df878959a8375151a019d7d9753b5b83771dade7c7a42e1f6ac1a4eca00dce6e4f73c6fba1e4671591af67b68c454a1741a114e2ee568d5b70b6b3f48acc18f40120c0043f5b00134a8c29019dce6cd614d83d20b7bdb6a46b628ff8bfdb6f93a794404cc21e53df3107e1d131b6e20ae72191f7cf9d22d660c77ed8a386fc2ec4e90e5bf9308e40433e3e8058b14d50d9bba6b9ae796db96180fcd05612583eb34432a50858171e403cad1ee96fc9595c6e27474145102b06cadf1dc09cbf066372e2697bf127b922b8f06d6634dd7cdd5ba31af1c2ec3e2faf8600faec10eedbbd65810e28c1d13774160ef4679a4ecedc346c13d118a45edca5ea0ccb73efd0a6e4443337b95c12988cc1e5a3fd6d3752865105db1ee28f72361d7eacaf9b5ae861a180c741320b2d13d9ad8a86b52e34bc07ff73741cde633b3aea0906ea02473e0f47a06d7d84dd2646cf3f5e376a59b9379de1d4d4e7e1475beed24f2a663414db6148cd468da5a622b0b2f9866b69d9fd868e8940611b4c0a2558a4598250e8a8ad52453df728ffa23cb7bc3a492951fd6f4cf3e1df479b5354a94e44ce12030607b50487289df787ee229a00c222cc00dff3add2405b3de149c313b7101df2db846b48f90a6405fc90fad9220c2ec0411457b83e2d017cbf4f75a14a1fbd3952164d7f100c613a29b6252f4517f18514e1bdc6ac21458e75d49b3aadb924a48c6f1708864d0e308029561f92c04c2a78d4f74c9f3583e727bedb5c9302071e795b9d9d2d9b212e2c3ac9eba1c488428e1a3980fb46cf326cc39f200ca5d84da48503bf438b30159536d34ebf6459c79071de5f9db066b925e42c0b373a1273b6217805907e442898c98630656c35dda2a01fa0088d158caa092a7aa287cf5eb051b8acd7d0ac9e829469221a4b35a0ee7b6c482c9b57005dd54d2b5a5999d94a317189adea37fec8b5bd8a5c9d164d3a8aa22e8adab1a862ea245709c8bcab4ed1c2cf41b61834a288165d7a1cc72661b2d53f09ae0eb2a6dedfdff40632a7bd7d37246457f098023d5c5497616b5bd91fd597047bc3b7bf94ba3cad2ee12b0297a2aa88e6c31e4fc0be89548eb25a12d88bf4d087a7e9f61a57459f1515ee30e621d678b19563e1114e2503e6a707bcb284f2304ef688fdc828f4f2d91ee827701b28454e8afc24197677795f387c8f73c3a56f28e41ea9781ba6f02a332e1a276c33c0b58451412679bffe45a83a76634dfbc5796081985ed9c8eb63514f79b6019954f1e1742ead43b0a790284a8625cb3c6db21a9a348bdcaff61292e22bd6a84ac2f9b0be9eda276fdbda632c7abb489517ca12f31b4261fcf62234493a39807a88eea678f494f98bcba455635eab6ad19c272bc76ee5754701c6107ae2b1279a3cae55d5985e48655f6f43ca1a2b95434932217767024b5099a8abe34bc321056a22171fc79d1bfeebd01931b29490e557ded2c5d361960743b3c8531688468f3a01bbf70382d70b2e693d0ea9ecb62bdde77326351a7273cbb9731699e7e3f4fc3474fe7a6a76fb0ea2eaa914a7dca8e9b8fb7b31d817bfc12dce865e0a416941ee72812f5dd3eb7702d28a5ff40553b604515fd46f84fab546f966abd233b8bf5de9d31cac052ed77b26295757cf63b983a2e02a3369a1bc948e2ed80d7722fc8dd5829e9ce74af6101a3f1feac167e5d37920e02305c1ab435b0322a700784aedc27131a353621392891dc4912e820d1b4eb8ac690dbcd239adeeddc96677ef161892809da479294302aca12256e361ff9eef3f858ab3af147fc7f09a67d0d01815d241b392987563f3a6c2a2d156fb71c59d5e878ef824c2cd47e53369610f4fdb04c1edfe2ccdc0c1f1827ff5793a3f8f679820e569d4f2fa42e87c625b5f4aa6d1a4426ea8115e42036fa121531d2f1c43461ffac93e715d4876592a59ae3ed60571f52af5568f53f2ac4da90f31e42aeaab4839f9a8260597b37ec3c88b915b772419200b786e689f5ae9e9914aa77f226622ae2b289995f3d173a15ddc599ada13b6b32a72fcc416a826e32616c24201e70ee82bb0766382328ebaaed82545d07f7a8771edc9049a082d55024196c65bb8d4e6e5c6811bee260cbe931d95c5682203f20ecdb5b9223b86c6aa28bcaf06551475ea685967ff508c46997b885a0cf70361c486e92bc786e591476d1969b37966f03e53127c16fce13749e224ba8dc4dca90f16d0143efd4a6077d1cec8737abcc9cf3cca6bea45c9f52ea65164198cf77bc872763b58a646a09e8989a672db90e5c168f8c6cd204d999b36208b84ea4d695655190c0a3e295e33a805e774012e512dffcce3838d1f5471c24f0ce92571c8cc6e57f02d628466aec0ee3a31b74a7026153b7d95cd23f00433a0f178e214af978b80eea06da5a6a47449a32e2e126be2bc51deb406756cae9dd9becf078a0e9118ef611d0efed777fed694f6b74656fb169e76915ee032263363784b0692266c8be4d6b486dd95d6d2040ef8050d98626624d4be797aff0804eee9a67ffc22794f4de542d8d6616a06e6a2f1d6599876a6d951c8c574527d4ddcfe30af32edaa16816c1ff1942166729da2c02e358b8bde5cf0739332c89a12b9f8a455b34866ff5ad2d0674b43903a342ba3967362e2a18134d348b2618d8e9778fb04e39b1d214a6a2a0070855439f14330410c88880b501a9db7b995ca4606528b99b63c5f174e5da3ca28663361cee38d19df0b0e128981abd21f59e138c2c8bf922abd9de58f2f11630ddc819e81561eab4389e88480adf36259f3f812d3fae7a2934f25f9a933fdea5d96a9238aae2b0f8fd4c39e5ae6ca32d97f199a0b32eac2d038aae54cde3f14dc8ea8f8ab24ad65fe4bdb8b50ee928a04146b7c3531883468836a3360ed2bdd4f0ccfe46f9747b511a4093c770d0f83afcf42b2e0b7d67c01394358b9730602c152417b382633c5695e7e5708ee223f678f444625b53fbcc52271863d4461e4324bf5bff6f23c407a1cacd5d162e729c314b53a1f7f3e4040a6c5d87ccd479440983b089f2b9c87c3f1a62764f8800b4038bfb774183019ffb11fed17881a2988b117efc074c134f850f634450cc6b757d592c5dbb0d6631273e842ab8c40641589d418399cad9918eba94e12db13a1d140830186ac298b02e82d9ed76222b4a3c2c5f460b1cde70049d53df015eb6173cf6e2c8f370916fe7ed9be1ae5c9b236cefa3fd0a54e8419b83081508de00de0591bd5b1f5af4d9b156cb53d40ad7e6da22d939e9e7521e552b04b1b4d53bc158d49ea1725e70a08d5686ab41485efbc3a11bb953499dec42c27106fede58dfab855ab950a6d1b036459b85768d2cf8522d19e37d14581e7eae212b6b7bdb234cb81ead1e517410094f5cba5bc1749ed10e1e69c6bcc79b8f3c68c64765e3b024a39debd4b7af003a92598103b8448d39367699b3f1df6ecdcd0c32966622beb8ba60b92d3212967736a255e50d0eede9fdd9425d9986a36f830be9f9393678882b7f93fd871e546b2a2f509e7bf856781baf0b8346bd9a8cb7d5791b3fdd1d394e48a1312b00d783498cd6f15b4ab5181479102aa9ec3262198603356d0162afba85817186d66b9fa4783d2e726df5213c2aa8f20884dd5a8cf17086c99f9a0f04c87eeafa7c53cf33606d5e45ede3a549f3a454d75799e3fff071fda76c09c4b7662e1a6433a533c1ca800122f6fd1bc494721cd1adc042dbfb9c43f17e3b69fee1da17cb22d684463bb8971db144c37560a1bc8cf6f8de35122bac384d08c21b343f806fd9c0cdb32936f491cbc17ea1bbfa489430f1798c5c521aa76b2002af136e2428206ed8a34539cc916f537c57760de15580d1d985c730a78968200559612bf00a3b42acfce3749196aaf7d1da48fd506eb3ba7d15bb442ce45738ee0aecc61ca5b0e52dfb684df95f20d0c3c1440a81df393c5c9a87b03a4bb99194ff8d060b30b1cf82aa5bf793ac2a1f0c5cd81463e64d2983e45560fa4b448fc25a9a3420aca48545e71b493ec0711bafca2faaf23546ed148c25468e928cc9d372798e97a2989545f3b6fcecbd58f7f9196d23c8de420ef715f0fa65075bd7c2f2a65d3911331d55918da2bc68d308e456952248d0d43f2f97a3ef716f3c5b9ab0e3ee463b0cff157a3a1bb3967ac887fa5a94723be3570c3e63f675966c0282d5185a3e6376c2e80c07ffe017823f47a347420112c07da3fc0983aa4b5bf46b324399959f00cda400433de55265c7d08b2728f2e8e5ce5030f35dc18f8bf596b260e05f1292805e9429495feae50cc30d43f08251191b8aa0adb0cb04b516b52451aab02889260a42479af1e582bd105e833867490740e3f3ff814a1176837da9fff19f80dea8f48624b119559086b8ff1251b110de3c05c5bf2658dcc857997a6fa7512893ca9f9e38e765ab1139ad22410fa90ec82d178d6da5af32a744c93998c9ba132d6e2c3b5c45e33513e9ad9f9f1c173893a1a7f50b3e654b7c39092078e78f869ef7bfaf3941f683da74ce97a83af5ea20704a9cad0f786b35cc109239727372ddcd19ce87b1fe8b83352ae066bbe99b6d708cdd43ca8f8884bd97b10391e3dc66a07dffbd5a0e4c9c5570a78af7a0b85c91cebe4c880e9f735c5e140242cafd7176ebf69fc5ea10b8abf60ca6a317dc82374c9105ba69227fea497739572f6649deb7bc5b5a1c57d8dec4d360cba77cec528c1033030eb351c4a29b69e5e73045af06ecd8cef80669d405e524d4065cd35f59b143773fcaa23a4af2f8f92b1e5fa299781376121d2e9433225fe3379659577d707b246b5c1be4a055cf39a6a8131539368390f0613ba167c5fef1186005c133d14dcaa074cdd472008e1c6116aa8b3f35c16e2da19ed17ea71ec5a290ccbfdbc864bf3cc8a86d6cb733b707c27f16574c5a1750f6a0872dc7192199b49f60ab030feef6c8bf00302bb32d773d7fd09a9d27647ebb77e17e23b41fc427726ca0bcb3b4ee7600582b9faf65d649e9e64e1e8d52e95230b9e8bcd269ab321e9bcabf26f297d1856abb5ba90637d64fe6bed32a0bf32c43d091e8868134af56ca64e4573923ab321361ee11ebd3687206a85e2a93585744b1634ae7aefaab55ca37a1f3f866ae03136aa8bf39eb4c1b27f9f0d68149468a5b6d6145eece24bdcf5861f0b73b739447c1ea4148179a4158f70ed837682e660f49697c657d527d59c1a52a5c364226a283f86d118a6923b002b9f4db9ec9f7ea817044478a1bae33873c5da93e8eeb85a0c86bcbfce11026772788cac7077502836bbc2a77a3d3517334436de0ece702f382650ee228bb68ae8c50fcf385b3b968eccfd447dd16aa98161716b2db7a099d8c9ce37a9b7b22e78c80d6d773b734a81915a7e286a8f9a31b3882381756a630c0c72c3b09caa7c8f9d1bc020192b09527560318de4a059c2d9dda9e9e51ec1eec1320eab1c1c95f738f3dd2f03d50f74807bda0e88256d44084e9bc7d7561d4759729467fc95739c4688b098fe1fc42158cc6df2e2a3c23cbe2ae8dcf10aedb6aa131d4f8fe495eaa4a1e40ffe03fec6da27b347a464bdf42ff30dce7ea15004a8dffa5b636d0d21f4e34802a9bb435df3080096bf0d55b8a39e97699f16257d2a6a77496fab24c891c61d2de8be773b7551c0a1e8964b3a012d2bb30ae4e38ed9406248c9d19e521813fc91753d94b2b511ddd44b841b204496c4fe0002eb06895cadffffedaaa9ccb02e92b834c4be4b2b97f37548bcfe99b46269fb913bbf33630c57a35daeaa6a785b92b93740731d3cdbd7c33e8fe8b68c39ef5deb3bb1789a2f1bd2fc0be4595e19f5b9e203a98b3a676e99847325d861d1608538c201a621a6c03b54889da9111e0d41280281f90b76460b9d67b328a3421199ddea7f92b2a3722e82d66810c45449f6c9257e4b98e6a4a12521e011b3282298110dc5b82d2cd65db6219e24ea3f78d5f57b5a41b8e17680e43f703dc441a0d8765fb0fcd8623e745d03ffd495f724fb6b356b8b6e05060446fc80eaf810c0ee2e0657c18886dbd9f43a62fc35a9f212ac33983be187dddb34fd3464b4163e7be5ee277fc63914956767c249ec6fa3ae0100853937c34af14a39531de329302a9de6eb3ae2860ddc237586c6d8c9cc129de98b1c3bc9c1edd5b4429600319e0c1c7e5604f6c847cdc3d9f939e63b33165d5241813f10493850c644e976125fa81d5fa7524039e8d64e6c8be392957b8da8b8b4410013653fb287a96c1d59b42a0a4e55eef14a8fe808c6fe9e10337f013b35df41a46afc76cd5bf4fca7ba91ec643e1cffeea4bb23e1347d55d30e5e78eb959cf6c639a789ca8769a9aa905ecad6e9e2f204b1dc002b9ff5882ac3e01838640b9baafa140025b9e44ecda825bbf65136769e191477d15a163288bf49f1146e613bf36036b716ff49bffcd13d53b84ea1032c8009918193ef17707668e4fd62d660cb71336ffbe195f61ebae640345ff2771117b44dd0b93d733a14de613426781db2bc42c17ccc4f169cd72d9f4ae2e59a64020c1630c780186518a2fff721d1f4370bf1ba459c307ddc31eb34415fe88c431b1360c3221f4f729680ff7de6d393ec53bfe77290f0f0215e2a5e8eb9f7d5a1ca85e2bffdded0e87670e7d5131874488351f1858589bd8ff8b877815d396095e28f2ec5b6b93ad3e6f916f0d3c3946f9496d9290ef300038522cf5bccdbfab03a49d68053a75a0b5be70fbfc8e36c1f06c7786765abc0a341385eb3e35b1404170d36b6791cd73d2cda9f7b229a34c6ca092bf95faf2574a0044820d75ba0a65f21580e1bc803ceecddf99d013c85791f1e3c34fe0bd65a2b3210c9456385543f61635f7a9b22a90bda4d91720eec302ba738051e252dafe21569fe296880ac36730f728345ded9c44ab39b5eacdddc5a7f19d123055c4ad8351bfb54bafb34b56cf85128cfa2b1872a06bdb4e911fbb5fbaa7f6feb4a4570cdcb748187dd28d8dc579a38ac2af4d2678cbfcc9140a9c2a20f5b8cc95a1ee7017c5999a0b7ef9a4bde833f57134750eb7b160de70a11121a91bc2ec4beaf78312763a39edabe01685f6144f02b30f2ef4d5a8be67e4a2bb024e9910db4173875912af09569dbb563a79644831fb20b8a72f1afd57cabe1df49825f7aa730abf157e2e7fc8bcaefdd6e04800a22d0d776e4c89237605edee335233e9c51cdb42182551f9e8a81d5312d84710d031c77d61780e76429509cf1a55eaff100c47b9a4805c7faf48b7cc938f94600aa874d89f2c0ed0c98a6f69cada3f2629604459a6d32e5bc121522dbefdafedc36a3e155e01eb1890bbd19a9896af8475a97cb0a2f3482619d74c983f8c42500eac8c2ca43f9bec860cb7c11db41cb8b2f133c55b76ac54cbaaf07905ab94d61a417f6d1d9377fe2528068a3cdce41925fda5962c719a3f010f65b2171ecc925924e94c07cb0e28e0a557085155612ab12f2e5c530d8eba0a8442e40f2cc316428be4b3cf6496ca649436daf38d51438a2d7bf53b0dd87b2e57e3e4e994dcde854576ddf86da31e15ce71c35813ef16781fd9b3c2b1c4a72a043aa359fb565fd0b874d2cc61e3a892a29b3f636d0e981f54c3ca736650d42782e1a53c533ac0b9d3f11d3a8b0de30156e9dc8b25c44e4fa0cf67b042f364ab09579325a67fda7b6c88a54264b00ea7b97237ad2476a066e55212686ca3d4491cc4d991bbb6ca4df1b176ce0bc59cc2922d27d6372414db9ce8e1b1bf6360d1da8223a1b07c0d0e95895fb39d61c340d6f247f3b62c9169ce4c09c40df642c94258b8cc55ba144328887e233614ffffd5345ff249d0378ffcdac85801a2e84ff089c42d8ec540f5f0be7d5fdc6afc7b1085321f288e390cfc644347188702b05de34f54f5a5668f607951c05b599b53393fee986184da900f950ae8c7b3101d825c0a28cc667dafca45b7c68aca1a9094b30d54831ee043d879faa77b43dff664b0d7b390faa1f6dff028e9e490b5eb61a84f38c3d3f7d3ad6158e5d5ff5a0c7236296a6c38d80a33601e35338fc6ed5e62ab13d31246b54db228735e945ace98529e1942e240e827baea9603b2e61ec7e3ee9a87d3e2069cc6ceb8004d1906d7a96e6fecb60b0143a2637c4387babceb1f82aa0ae86cedb60f8a5aa009fde67e1c63c7d1829e9f9cfe6d2c03d4a2d5f064b0baf66d32b2461d9fece934ac737dd5e657e3b0da5bff699889ac44dcd87264154cb019ca94bc45eb8cf7ef419cc23c64702ece11205f236f7b64848814a23b2b2c599b8f0c1f35bf97d34fd10e49540a110828d682327c4e7dcff05048368b9ea798d091da14f364074a3e1a7d0b21e09ecab66eca2dcbf95fcc66438557925904980b257287123669bdeab3a2871d1c928300aeac5a3fe86809bfca082942e65748c285b30ba7cc7911f82a2c54e2602398ef9b9e61a31728fe6b2a06c056b72294001f620dbf7ecdd6a8e0a59640a173c8ad0b0dadd77f75fdb055605198acae855f96dfefbcc0c790e46f70ea52de05e4298224a0403cd7ac6f48cba0ecfbe4da2ef75b81d1302c22a0b7b93c90bfc0205b385551c09f197a7c1d3cf742e4230ec9c12f4e7b94c152ac0c0b1b5a2eb67a0a35c458fcd55840fb4efdd47b973c6d2ec254ef4576704ed9ba2841c6c56caf3908ae9051184ef35c28ee756da06b2b1c129d5d832ea4b1012ebd9aed83ec344d24ea8bb93001c457c9ca21b352e92470eda963135349434bc7cf509bf037ac28fb337de3688de8be84b3189fb27b61ff6c62d921e751d539335688a5e93882a8908abc3668724b06fbf8be8dbfb71fa2419010d47bda395a263d68eb75392a63e88d8c807c4aa094faf3c3ade347c10d7ff0cec4ddfb7069c6f107c04f3011e94558eddfc11167e9027b1bd38cbcdadc14db6830ad1d5fd986468949cfcfcd95cf9a896141234b2740d809a207746a95eac13598c2093bd8b7ac3a61ab7915d2851cd5203d3da924f676bac75576622dd73826645ee81a9ad25170c06f1bf5370f8b29b3575bcdb2b9369e906df4df57168f3f3c26f4a9870b7cf9fc762b66f9042e18f57e6f27217ad81c97a7dbb67517b8a32ddc59ebaece2deb97c3fb9bfcb40961ef4371336cd7ae804ba1a789137dabff42bf346363aff9f3653d3d67d3a3e76911811d26a0122c388825fd557710bca64681b82e35d65bbe20634d72f6e27d7291b289355e95806f4a2c2b10c105ad7fbf1001fc480fdc98aa9597f56eb4eaaaf964c7d3054b54dc47aeb04e1562e3b5a9ab8dfa666a2d09214ac5de56317f958eeb8737e1f2881baf478d456593f454f5b06d61bcf16a27d1eeeacba9d9d25714dc1db55febc1111bfe69a9a9b8c40c62ed533f37964ed041412af810a03113be8e56d269527832be87a0c2cd1c4d4d8d336b82317cf39821d5831f86a9dd13f70b261fb55574d3b391fd2078993a0c82eb872284ed243486b04284e324fb6ff1aa0a0cd4c0017e6ab08b3b6701b462582c30c01d73c406c2b2817bdf9c1e658026f4557dd175f1bb84dda06258ff75bb86e3bb6a4a74c7e03e201de1cc15312155273885589925a3de8c1304a03294daa6d74656695db74ea3217d15dee8447aee6fcc3ab58779788ae75ddda28a44f5b7b235cf955be69ad53d86a6f5c46d259de38ecb6f4b5a840c5d0760114bc2701d0d50fc7d3bc532c58480adb92889be1b841d51e84533b499d4314a2265566e4e21ab3afaa447c1422ad73ce3c6524acb9bc510c5446431aa14c90a6538698994c2b8611ffa79f5f1826e18fbbb7cd95c249bf614e448993d9dc090e0a54ff27cb0b3b015a1033f72794d0ca48b997df4fd820ced9ab40b0589b982a39665352a7434d85f7906b134cb7bcf950c651197c7b23cb86de5cfa043428fbe79ea943385a69726f0b8a05928c0573fc7837106d5e6ae4fe377848e999594996d6e180d75d07934dd1c1d54de185cd14e3f6a29d25f599e91ca1c99d8830510c63200f7dc544f74e127ab998c4a911a23a7f8e56bbe6bf3b1edc5f76da256d9934f04687613ded20d13d9d89f1d81309509f0faa4498c3220b03e610bac639fe89869101c44fbb9249263beee46c11c3072d29406c4cee85e7d37b3dde1e507898cbb8e7f02653b2c450b79c8569d59bcd08ec00e87eac97b19f588c7f22ab04afe199e5f98f78b91652f451391015c684aab76eac641b11dd43ac44b179643901f04e9ec0d00e92e2993dcecf3926e9e5939a44aa8ef65c2a05601ef319e2f24820340469783f37d6be5ccfbdf7857b90673e71ade173287eb06048e2634c4928ae44c0865198011c1bd4e34dccb06817fc9c8d129c6079465870f96d08759bdf19842a8db6df4cff03f7e60adae5f9a58b6a0735c3e8d5b498cffe0538f0ac0cdef52ba90152012b096611c1003c2281bbd1c7c4656a042601f30ca4d2998607148b419754a1d3ed87f32dfa93c9c77b4e81a02e6f75579bf12ef608e7a2a38e97013aa14b5778e2cdb31af0ed00fd627e94560ec96f31bcc1832d9428fd4aca0e8fd7b796707bf543a2360532a27d0cc9e5b74b49d14bd8922ddc26f13f217e7e30b907c8352c856cdde59d8ba89fc3ce080698d1f487ac8dbc6356f8ede8a9b4dcd4bd8c49299444442cd840110aa080328693d3eacb42d9c159556759d26e63251287bfe4425285859ed629cfe6100731eba757a4404a1c0b1f3b66bc7460e094aab19c7f212a1d95e65940323a36e2d259507e0bce9e65fca8888131cc60ae8420f0e5ada4fcfaf713f22c2237b1678abda70690ed229cffab97244b0b153b39932fc24c32227d2acbec2226f0d4d681c89386cb0c63a4a6f49cfbc68923faa36accf67026e6f29bb052ab9387522e1792b8d0ac0d0e86a95c74a800316606179354b2794fb0d5998a8269097775e42071a82268285c2792642c9f57f91609d0eed3b6e5015d1f47c72f24ff83d1c37785f9253d00763e58ec0bab029c75e0da54b03cbfca1cb073b48de788391e5c5988adb22d7244d5d8f11f988be3ab26d8ee25524d5aa854478367d62a62314300a518f51e2cea30a5c3a1c483cb203b6dd62ad0fd5a166469ce680cc2494086c9c95eb1f95a1edd4be2add42b0b0a18e0d520afbbc7a046b45811a4d94f02b1eef095788e33d7f071062160c894cbbe93f386a2507964abe5f51cdd1990a529c8b83a1a6d0e203d34e6aa8822abae4de4c7afaa0f01bec97ad046e3bc97c5da2c717831cd04e551f61dd9955dc124cff00a4808fff00366ce92aeb65849c37b1ca368c5126934a31c647244f7e060314c52b7090e1cb5b01772ccf43c37ab13c167f52a0d1da700a55be453d189fb3e83ad405c81641a0263ec6bf5d54c9535c60b2b15513d9af90fa031602e623c26b32db6384a5c1078a00b3cf011389a361da7f54b6d13234dd3b7ac28a7d381cb125d22c7d8ea60a235c75f18f05211897e71f8ff328fb0d69b601e56dd5b8c8280189f541f771e0707e796327aa07bfc9a5a0f5a965df21f1a9413ca1f199b7db3194ca7f7b59e61c1d369c7e984da0010920ac521b6b10fda717b4942350119561c4219052607837fc22ad95a2d96c1ff369aa2b84e9900995a17ba829b4d3ba670a50944abe163e6ddbc809869dd3b9018373e8ddd53145c49184a38924d969560ffb30c431eb40a842e1c5b82e938f257aa7af5d601da02ed7d5e97dc13426c79c0a683a47f34258e0c61094d1a7078bde53c72c61c3acdd244a2873a726edb1cfbac1537a1401b1358ea10d6eff36cf929c40ec645e2eabb224826ea2f840b40e1393787fa5f8c39c80130377ac13bc71012e59eea884172082cfc9011859fbfe7794f8262ca9764f11e13910944b78c15cc490bac568c92ba1afa15d27a051e8910b0809850df23522e829099e84d6b4520486d09a615f0525b57a5d027fae4e5fd331b839457cef61cb6c7fd278775e5b88478b346c6a338ae604f2feb39997a882878453dd24caf4ebb512063f1a98e1bb9d1135d1997c5b736bb8c45285af52eaeb84724160304d02e9c4b02ec48f20db866afad4b144e855847f90fb5190ae54056156aae76dd773167646d0e39a225b88d66819528dc44f042c0dfba6b61d891055f0002b4a7d077500a96de93bf726a8294ea0a4b8de8602148ae9152ed6f8783e3397972e67bab869ac6fa9a841b9b226f6be8f9f445fa94f0650100986c9bac59209303430c999971c068433facc8a1bf68c0a4904719dd2fdfc4bcb71b1b8388ca4897bb60cb064d7572c415684282bad3d601b4f45a32847a2282ff4af2e5fc4f11fff58c880ff976d5f7d7a3375f81c9af8494a7be5b6cd830b2383e6a4415a6883d77821a816f52fdf41f7a1bc3e909dfeb7aa15c048208661dd0c927523d1141e9eabab73cedf1d0ded359d1953b6c2fd69cf565549b51ef040d48687194431321abfad3f702fc7b10b074044d22f3a0002e3bca7a63623869680b0ced9eaee392f2281644d82f29b36f3aa88f5da09886e9006e2466b74c0c7e638bb016fee1298f8193096cec2d7cf4e24bfad15a91146bb4aa8266f6181f543a48f2e8a62d1d7794f2bda23fafa87cfadf18ba48c002a876997068f40686fef806b6c59220abdf315c4ab2264c0c13f824d4874006e5d82da59780c338b6b18392ef7fa1a8119073e5f7be5f09ec10153ca827642c441ddf0dcdcda50443bb1380a0a6532c71406e07fb82bb1f8a8e247e428fad8e46f2d1b404847f6b07820e820fec74e83c89fa3b068c5884ce859da3ac63922ea15d68a2c3ff9c239ab446e520f35fb102c6c09ea3857aaabf02dc5714d984e8768e22f9d2644b07fc5a78f68db27fa492fe57f572c43a38320c6ebfffe3576ff3a263d3c2b7cc6ba29929060ec9a21d9b3730c5cb34798380cfb639c96786e0c5597e008ed9ac973903e1956d8f3088713e0170e6da4afb4b8a27ce62d5e74d140263c817204dbe0c0f1259aeead629a679d43bdaddd45363aa91508584f8ae93a4339e84620eb71b1b3d65dc5637e0dc84590c6d8e51e18d6c4ccf86926cd6a8f780092d53fe130767174a82e369cc2b4ed60998d8fb637fb0187e38303df88fe046ff60fc2abdf5230aa1aadc02f2872b9cf546ff64f5c4b20ea275d867bfa0cc80077d2c896b0f460345ae82d3a34fbddeff422c8faf31285663f3e1d75861ce7d7dd1463aa490a776727086872694bb469b90395694a291a459efedeeef9d188e100ebc669319f0a9b944c425bcde767ea7d0a9688e348bdf63530fbf1df3ce810cdb3f2f90348f0b4e0018c1e6edd1a10e1c69b957223d732c8dece0a05349802484be2f3c59b9602a4bf84581e4cfc18069422cf67838940a11fc6983b778c4b4ba4f1cdd9b5eaf7ae11913c922293c19265ff3198c07d022b8c6f3f34a294a1bbec7dce08d260e8be47b5cbad7b0fb047374cd4a45a6fd4ec3bd093fb1b57fbe5cc78ba3fecf38b17820046788298dc76eedca49365cb01ecd13601236660b7c70d2b703095ad0eb5c5715755e88b1f48ec03bf85379ac20efb1d5f9301288b8f927e670a3ab13451d9349e68300c22077f3d9fe196a16c040bbe0821e1b500ef3b674f929ef9175b263219519e91a7238d4e56fd46704f004b1ff75b9b23d90f8cfc85e415cd3a589fa1349cb76de92b733d020bbed4881de7323a2737270b5450cb19d1b32b8680c6d1129cd00077c0e4ad83dcf0d72d27386ec85e8a2e72bda4e199610fc1fd8d5cb744cf279d4823cb8d3c836dc460c441a0004b1e5bfa629ad7a4b86e39891b019587fedb932590f4cea45221cdd7a5ba49ca12151aec22625567a2be43e5345b0ce2b46ae81431bbd165295cccc0d6ca26400e8f660a3ef24559a43b1dd497cae0558bb1d4293a1dcd4e9b0a41238999c5d2fc7a1c3bb641b5fc72f726dae53cc423c70a0dc8e663f40c347259d09fd0a513ecc56d24e29ad275d56354ce306194b33a775ac19d11eed8e9531cc1f0f598e30cec9cb5c6a145e44d7585a6bc509d71a5d5a0a40bad937a4f513f1b9012bf6993354d76cc93b5fcd4c16a1b1fd25f7cc96b763358cf7ed09c55885b101232b0fc0ec13fa4eabc2deac08a05d8d0cadd0dd255125d1323d30bb96b9d0c086ad2ec7df5e7e699f13e7b46e391e9353b1056239a4acc180a0b88c7317f53951992815da416601d115d56bb2a7c884b27059333708599d528f3214281a570c46a7c3980786f556c486f344ae292b6dedb06047c29f4b8e785263eef636122aa0f8ad39f8ed637f5fa036afb8058990ebc9172a66a5f1d02fe8674033b50b6ea567cd18e2b36f9cce5cb2e80b0c60365fc00ef539e9247f96549e3f6672098a2d5698c1f5627244c81b3ead39243085c97237c182b2c35e07cc47294b5a91286cdd499ee2d66c11d2bc65ce1c7fd3ff4e6d0e925e1f85f68d80cb45767c10da812f230a1acc2edfe5805b86d9ef9d6ad09e73355009a021f13ae0e58a1a36e710f7703caf8ce08ca6ab60cf553bc0af96e880ec41b27bc59a09c4ec5ac453606d9cb9b343132138526b6b9a2dbdec9f45640ff313b2f1e08e9159970f3e27efff38b1729e6bb12a4138fdbac4c1e773b6602f9447cf7f9eb45835ff501b3d252aea4b4573eedf78d5f62d1339be22b4133b18cdb62164422a946fa97003f1b725521eee5b6c60f1edea33da4e4f2cf4bfce4b83511457e5ec81412bcb8802f1bc2fe35f82750c4e4736f5911d4c574440c73fd2fc00bdf353798c98002af52de6f620c259e5a116e79cfffa00541771583056aa3c976eaa5a4d7545614505d7bcc35cda8250b2a165c30fdd2ef08faa7f381ce807db095ede804e0f0ed94ab1ad39bd5003f6de11d26f5d7e4bae01e6bab8b1d58ed420325c2414beb5d63ff64f2a594cb19d56b9ed9f664208885442c6eb5e7ef5874e3b9d0deb1e7ac110392204f9b1dc22d6b8ae83992893ab7dbe6906d7977f1906b1aad3f3d606db70e344b69bf241f9d3858d7423cb9bf3e2fda2d8d5e4ef70c8b6260dc3ac6ecebbe19cb4f2120983cfff56cbf1ec21dd1e1a7a0b7a9dc47e24e33e1c994fa0bc947689baeaaa0afd7337e12fd5cb703f1efeb0293a826ad2b3db157c6841535695b95f00293bad7f81de10eb0e6ebdbb33062fa8c3132adfab40601859131a7ca1de54f905d6b45e395fafa1ed2c4d3bea6b88fb3f506397389792d898c1bb47dc97c4036339608e1ebbfd76b745d989d2acd10244bd7d52fe0169a70b332f4c9131a34bb54210de226891224f01ffc77843ca6cd571f1ae73b8dc6c137ae7ef058164a00fd22e035e3dab27a711a094809cea435847601af055e3e4bdf2a3b14784f8137464e634802a890042cfa904222d937130f07f12695cf0d991aaec7e5b30704e2464f07defdceb36338e0b113351400f8b3b487cb7ef337d3d3de87dcf7bcd6bd952987ba22c373f400da3adf1b59b39c376a3b0f50b66e8f742aaf7d323d7d8464a439b94bfb724908289fc473bfe297784d4a043f23768d159e1ca72c31fe106f145966ce07c7c82be46ea55a83463c010db70a3397d238ceb2ccedef9b1810a0404441d7725002f0a2807a7521d7e7642f49faaede38b7d53ad27930d858196c25dec0112d999fbf799a4b8241d0fc049cf4a6fd2a1af826fb81c30fd6666500a28e442dcb93e6e765440f29c05fa7121eb635c8115d41b5e41f3f4a71fbc24b9f10c83f5391653067b20f58fae793e554851698d45ef3eb0a7fc45a7e03b660fe5beb355570df45060cae1665635d74d9bdb0b43fcc9b6ca0d933c27bc30add670f01c5086946bb5d7db1001d6605a22a0583fe99fe4939c3013bf2e76f0cc5d424fb63ce16b9db783f7a5e1625a6048275a77266be7a1ec2dc6eb41f4114255d77e2e0747cdfbda28942a2ec9e4cc2ba426c4ab60dd56793be5ce434b1937a37faca5ece715ae3fab7f78853b2b37519672ea825be4eec02553dda6bddcb23814ef91bd1e35b694588b310a70a32ccc896b0f875a4655aa8c17b667314fa1bdeeb3a984554151a0f990394eca6d03c444d4aaceff7f59b9552c3c28fc5bce83e25f9fd18a0557decc98ae4c1658d8f996e57391850eb21559053175753f71e8278068cab0873cd958d257dba2d4ef04620f050c258344529adba879a96bd5e09300737f5f104b3123c091c4242ebcfb5b463b4852e98aab1e6e717f02424043b13600c1b48816f7e33387e5de0aae4cdb99b9c136d45166d9500782fb35dc58efd5528be31489ae920af72bdf715848714a72acbaee2348d69621ae121deea958b9522e4f8f62f5c053af38819b718eb5461dc9811dba1333eaacc5469864db7eb8f12aba04fe52f96b71681be6ccb775e846b7d056fc47b90f21f809d8da9a3ea251bb56e511e8a31659c57b04c4fd3d6acd1cf4c382185a5c87a528393c1906001ca8e4dfa791a330bcbb62556412bf6188088d5bad3d62475605fc1cc99742b050522ce3603920a9609a537d750d4068071efa29aac42f55e1d526593f28cd09c48468428d02a6175a372cffbdff7ef4b63578c173d8d72bc44592e6739931c04c32089ae16bbacc0f5a7f7ee5ca45845a95cc848acff2314bf2ba3198b2c5b0e89fa8a87514c33e88d2c9705b2795e61fb7c31b949bc04f71a8a47cb95ddf98ca503be706dbe5c0f794692370edad0dd7c71dbc2a3872429ad0cff7f26a671e6e38910dc341c0f93cbfe05b6181a4469616737474b5946d90f673ad0d00ba0c820d554879ca55089477b54826dea5ceb0a932153eda384b5104b9f9af2ab1b3e7ea2ae8106d24f1e5a96720ddc47928aed969537985c21427d074a430fb403b16243d56511f3fd2fbfc1c522f8076de72d02e892b9f615e4864e5f421fec63fc70b2ac8a9d8600e4bf05405626d97b812fedbab0dd2fa955384d24656662541bd005805f78c2a4290cafa73efd2e062f1ebc9dd1cf4e737fc829901b20212221447cb2530125c979c64af15107b9a8813b89c4bff5b560a97817055899003337952f03d7cf6387f03cf34b065339938c5f29dc45d2456d5aae464f5d8db9a2204d1803ec5929f73659842b8476ab9df8226f9eba7635f9ba5f61a3ad391456434f179d6195567adbfe5de49f8df3c041c745b10025491f4ffee7b92841b491679018a04474aa0511c375e03760d1790b7ce0e8a80c5bf1b5394ff928f0d5d41d27dc8974690bab435860b6936d8d0d336eb5dd47510218c9bdc0a78ed5cd02b65a258741d5b57c7118366db4feb34294768dec493c54b0553d52632ad247f78fd521a04689360a86fbfbe53211be6830a4b6bca248301e9cb2d4ef0e0007857668dcfc2473f6adadf16ac0a1754b332f2ce66d35227ea3b5a1d0a312da7299dc3f4e23c452965d3af390c7bca517c0c3c64c9cb6cbd7f220f8cfe3d350563112f01b5ab0e0512ead5052e04dfd8d05c954bc03e972723b3af31bcd096dcf372612b7c53f7c9cc60055a0b4b96788a5471ec6ba6799efec167476cfe5f77efe09b74b1e8035a5c5109762b26fc400cf088683e8709c3e640c4a89557d181eeabf095d73c8663cf63ee855cb017f26c57d22f29ad30504a15b544549636c69b397d2efca6d2d224a273c06a543860e6a3bd3262a93f7a05fe6108bf844964b156a8af04939344c31a9eec40b2903358eb443ad9871565b253c7f463336cbb63986e743514a93e52344da2bbac2131a6ca0de3e04ca5c2b7c3457c0fe7e619d82942f8d6997b33287a51af251b52d5a7675679961bb5bd83fd97d6bccfd1fc74064a8fe28ca68562819aad17c3ca9b621d3cc1743b017ac8bae3e2793b0a7b8f1cfabfe32267c2a1bd7f3d330923e2ee67a09aa3087803bca29f285bf724970d0828705823e1ed96ae165462de5d387606e34dc79c5da04be66083c82378d2bd620e3a0214b335ef7215ddcaa690d0bedc35848a6d68953d8481cf919f4feee1916d2c074c6a153d848660639207973a1018560630e2a4fc38c1b63b9b043c86c1a20c13273fb450a061c3d33cba4b8109a929a394f9346b6faf25738fc384684d9e8519115f0f6b223e24164244841b894faad611c674b446b1aba283265f01fa0056158bb7fe6495ad671a780df9f0676c3a06f029adffeb8a86fe81169e623966fb88095803c97e1528d18b89819c7716499d051b8d89d9757e47b2e161b7071b9247ce39139382be39afaceddad118721677d83055ca55a6a8721d79490930b6ff2724f5533e5ede331417097f109537666e4ad0bd3a5c9ef6b49b48a4f34fdfe87d4f0a10214ce2d07702879dfc9ba6a4b622831978e7cf164a0a44a4b39a6b61ada882656268e6229844b22d6f88e7e0bc3c7b8e250c657a3d5eb2286cdfa4c95299c590e07d6f5564e5cf24df3be56c44bce82ae26e759f84b54f5ca7348cb97ac68d366d9f860161eb1baa15008002e3301422f947f09c1c4e4a6dfb7693586651a66172469103e4031936d6572725eb481c205122125ff110887feb0f9e005b956a122442d93bea341cd3dc8c080602e1b615dc8045e1294c06765fb1d3ab67cb2e3ee5f2e65bf40853432a4d64a41ad810a880caff40b5d45813f45deb8b03932ecdc09ea8286db4ee88c4dba89c70feac485ec6b0a16f8d538dff9bb32cb1c194f0c3a3be6862f2d5f6ba4943f9048675710a88d8d188f270e80dd68a2f8f8056ee0d82a3aeef6aa57725c0168face139a13e02ac3d6275c3a8949edd52e80d93b10927872461fbb7b1717484635030148ba80b419985a80ddf36bff2a2780ab6821a6dd83a2c5253f772f21418fa67e222971443f04c2b22cbe43aa82efe34f5a14a0d8772493542a913d9cc0693a0c30d8029b71a0ed287205251238d4ab3e9807f1f92f300ab110fd7abd72ba03da690ff2e0eec5fcaf8257ea77de842352894a7c7c4340d1414a26fd706f64c0111e2fc3a7ada6d2d5d6a9f3ce455839d09b292069fa0b7c73c37ac3f1e65a8986c38642e0f00da783ed0df59eb7fee2dfb011767f92683007edf33347c1837af7e94bbeefa3cf81df015b982b21265becf7046ef637c1128209685346d11470a3ea2e3268479cdba49b552d9e3a5978fc369b814f74ff697506c1f9f3cfd92e450ea9e129bae94789607e4c642bc4846aebea64a0198a2f252b00dea9c5382f0827fbe8e9c82024c883ff8a9306cba01f671288369241f3cc3b7b73dd267300863e779230d85d7e4ea613edaf424a0d580c9db58f4a7ace4ba0d82e02ece6dd1915bfe9e8ba39cc1400ce65620f336b40f3280c13b395492cd91096098706145d8b06b7cf5836eaff09234220e8f61485a85d5b5902e6443e211146c62a570fa34c29bfaf14b981b254974e0c43533200eb3d342086d1348e48046a1a2cc86e07dd3fb7a17421a1f8b58956c33cb041e175a6ec813ec3dfc0453d8f8082fb686263cc4013047c190472925fa7a1f0b30445543087594020741f296d7d50038990501271e3954a40a9cdf841fc7aaa84fd1c014f9e7e9fc5e0000ff61b9fb337497d7ce183517dfc70924f3fe9e7ad03103fb967f91ea54c2c0b4beea23d0b71fa20fd3b09e1022ec0e4fb345920ce5928017eddf16a7b5763cffc81445f24eb5f357c39a111384971f85081153414886695e2285913edb8adea217fb6093c92cbf0a97596b114da1a8f7fd29c94c71a32ba36f2f9d7834c5b834fa49b3ecd68ec1ba4b408ac8086c2aaf43142e70ac195e2f307dc7dbfce1efa47b61de9493c4fde43ab33ea086b04370a86b907fc09b3bbb45da028e1a83edfcb190a4cc6b81e18eb8f6d6bbbb2e9b187807a00cd6305bf626c59a8e0d86cce34a7a46be8539ef3af60a5713baa3d396807451584f6dd24c6088a8032c4ac5fb8e6d2db85bae79bb64508859e3624e52792d5011590b5517ee1c3b864b9815a8e1d566783e5b6406c687ae71198330d5fa1c350d2a242ebf998628a8c2acaa771edf83c5e58998caf4948bd06b752ffe0d54f868bdbc2356d10de56aeab98c756fbb511086c725d5b577ec659af960d79d9c325c4eb499d7d91d60d3413b5d60a9876333d863c1a9a6af844242df9dd1c21418b2a9be6f86f56bba8fd6914ff0bcfa5061f381226407b401e510a803cd42d381c141a01afb54e06234ed7ea0e107b4c6c82710ac5ff897409eef31cdea591fcc50199af3bae3e47464704c8bfe810916cda54e2e3029041e9781e4e959680430d4345dc5541e637cdff7a1d35fdc134cd39822d89f78b2216f58bea1efb49faa9506909cff0d633a12f2aa4bf98c3c5711bb08d0c81affbeb0251a189f84b5cc60d67537d0d2e130af96c8037e7597036be3914c6a138a7c53858cc4931ce0b715484e3628e15e5bc0887823914c5a13887853858c881228e8b715488f3624e153d52e80c272aff87634531e7c94467ae9c0d11aa9848db07889aa184fba64e4e59f2c481a67808260d078b06ef52bf5b43d24d3377842cf709058438a369b981e38aabac7467baa047fc721f7d918114191c4872c3f8a63943473c8a1f4e4fc2ca01afda14128a3df505bba6130400d3fa5dffe436459aae65c69451e96fc4af44e3e0abe6ba4853349748455f561ea2ceb49a69d5011704e6ba070706aac52de55007e64d9c1fafb6f19c49920e5f4ca851c0a292d2a25c9c968049371cf1aaa2419cbe4f742d6e729d58e5763a3df11cc313efa07c04c5a4e4b322b3176ca090c542ce797f9466e756b19eea2b4ae2c19aae0a4fe714528b450f1e46157b46b163bb58e4ca2854e48c00825c440d13cba403ae219b00723b4454e2224adb3f50afa4eb452017901548102eae101bdc10dc81359d588c7c6aa3374c7c53cd1be49b9c0206704470a667c89e0a6986c2874e7cfe3d2c153439a895db2a6f1d0d6099e21e21360d0bd96c4b0a5b83550a6d1c9967970bea42a2fa47f9f10b474600668308e7ac906c5835dd5eefe41797e304858a1a33caa0ebeda7800368cec02507a9ba346027aa9db2af9b413fa248b99c6a9bf429a83c0bd1e6b8ce1d5f58594da80139118bf24f9454f53b39126dfa3a74a8d063fa22016ece2de1d1315ca4d82116caab0043b8f00d74d09622029154c10c556d7a9bc3849715b8fa53a57139259e7490504d53af5032e64c74230bceeae163309e2f0bcf508f629231601f7c2983e4412d7c4b59705c0af43f6321fb261bf0b5b4475a0235dac2697d2052b157c6c297bd8b1fc7cbe090485cade0361d13452ecd18f3aedd64f4ac1a3a2c803d354d20abc8fb225d41f7347aaca1dc85415256b540b382cdddd08e298986a259ee56dce18c2792105e7a6f3a9689bc43c88c7e3853c39625652fd17f1705f07beceacb6807e51ceb2ab834d6189decbfda8018a9e9f66e9cc306d08d71df7db9f7c5a8f96847bd8b20b9cb705da0fd1ef2edfbb7d3012f486964d1d84e399c6f3e1ce2c369f71135ca7a75db6c62e3521e5f92228eb4b6e6c682e1bcd7f291bcdbbb614e2d1fb1db1db0981975c6a05623e035542afe0704fd014b5b0194d122fb2877c61422850dfdd40fdfc9a06e84a0764019c0cb26db00013ba169c0c9863b675db0eb98c6793163a640db70877a15cac8f6c3abb39228aa151daa9fd9823c6ec4a51bbb33fb0c6fb367da100d2f4ae0ac2674102105609551034a69034f298009f898c89296f7b9e0420415187def311a965920a479e1f7c3d80db9cfb3736ea0972e106e263352551401b2106e6cf1349bb9d632de87106f9076efb958d91badae7718d5ae5e92a0b1f171c7d1c06d2aa324d742b7f7567721aba62ea8e52bc6ce2948a598e9c195a93ae4a7898493d56cf4fed8a388245a1faa371441590b7f0e74304e72711160ec3d2ab486646be20e6c43bff08a8d1e3101ef8cd9387a33ad733306b50471fdd270976c45eba61842843e6ef9ba4044e1a28de07497975524d53f95035274d4958b8ebdb05785a25ee8606f6fb8888904c4a14f78380877bbc5ec815d41c3b4e145324ac399c8161d44835d1a5e4c938548225311290e54b3c874880bdb4cadb9c9612803b9ba7a692070e97023504ea4bf45101919e6729bff759c4af58bfd17093b6cc4a43d7ec251c6616e496141e93a3bc47633ad547609f7925697de50eab756d847cf47ab9e39f826bd1a374a69ab4ba4c9d4e8ba2ef3369aac7375a3a6f7279eb4822ab252a0317bc9a372c0dfe1f7579475da22f1e18926dbd209a6d22ca6497ab6a1b9acdeed17db5d98ec410f0d46a325833ae09528d1059b351af9c4e99f3c6fe0a28bd13949c0f65620152d28160d4854542dabc3c20ce9a3e1da27292c2796208e219af525e91d8d04b1a010e619c9411c8a48d309fd090f3c71c9909af74a9f0771ff9640cf1869a149654783285428261fc4fb9d8726279000120930744d39ef8291ab427c4d9f7c4efbbc99312e3ed1879646369933f111f83801e8a7ef1f078f23166660d93810ba43dc5cebd5ea3c90fcf4d2498880fcae35d9d5e27007968fe67c8c8943103373980f547d675ac5eca7da0be53002e5ce948f635056a139d30ba0cd01c75d4ecbde045a2dde8154d2eb1324371b91849c1c5a1ccc43a89b3b37261a8e96422f21809a7c63604025eb24d1a2dbafdcb0ca2eb2e8583f37bfb996f5aa85f0d29545403139f9569e98ca93a6d088d1760b6a8b013729cd6f9e8bf7e41283626c4d4ccff5ac0ec79ffeebc9e21b4fd444d33f79dec8041fbb73fca000c0df8bb7ef020756eb0d859ca399bbbf0d8eecaaecf88791e10cb98e2e8d1d17830f68a154fbca502fda34f7b8dc56c9de6ce1c70f386d457c40b741f736dfab9677f2321c27cba5d16888a9ce156a481662d871415dc9d109bbe6cdec09efd82ffa2be3bca4ce8cf0467e86012a2fb7004cd21b8e4d484b625a054176d2d03b57e7f426a57a8d148cf039fb41a014e837a542c149c1efa662a6678d7746255e1b43e7815ef942e88cb6ecdbc8fe9dd9e124744d6e87dbc613e61ae993ee0ffddf0d7dacba34ee821b3845bf0c54f15a5cd14f20c7956037b3b29ed59a0ef70803fe3e7a5251acf291632517e47903975d149d9d014cf61bf4ac1b24f8c2ca1d67065989ebc7ca5bc4f83b15c6eb53132858868707e2cfeaa4e9a9c870bbb103d047c3540fa73dca97352c5dd76cd1af9ae14f1aec8d855644e421fe159ab6fdfb48dd8a56c8d577a5a68d9451bc7f7202175b0cad2ecfa252284b9fc7b5d20ba50a62b3e3ffcbd62f5d0b4f08be6129da5ddd02f940ab7da0f51995b478bf4a68d326c6f516033f7fb3f9effc3915a9bfa744233be262c8c06b312a96cd016913c88dc13f9d69e09a56ded614b4d8c3fada88cd3c06a7a3fb1767c7d00f49b3a0cdb1a648df22f80848b56366e86569cf0ad05c663a845da23e500afc43e3434c890178075a2f9b1125ad1d82cc4fd40a071b4da561ff4b4b10049605009068aea55d4e5ed5239d5ee722ea5e99d943ac39d7f10f6e884c6aea37e15bb80f9c4d8296965a7390397fd90a7be6c8c09c030c469a4c6905ccf485635369959c040420bbb5c9cac40d027401bc0f042a0fd79e5a2092b29a0e1669870fa1f9131b2cdbc7e2fbc749ca3795058990cf755e3bf4a75fe6b5e17d35a61fbaa90a6d6006bb39183b01102b807a2c09d6915194b5898beac644eeeefe6b682fedc101e36c9090d6f6cab6e5de52ca2453020a8709040aa7ff71f37dfbf704fe9019c8a9fb1f3f75178efe3f3c28fb584323124ca6333c328b660c047d23df053c439638cc39270b9d23a75138895c947f61c06310d10e17fb6bb8e7119ee2d6b88136adeeeeee3ebbbbbb9bae5c7477751e2592cc03192f45abdce6eb4506937f652f6f61e4adc4d70a7b5e8d2f672c999114c6c401beb9af38a1c56ce2c415453811c51727b0d4f85205a594524a29ab05984a2453ca0ce690d5024c9b29b35c505d52960b585eb0fc49a7cfc97201964f5dce1964c4724133cd9e7353c19c93b35dddb62bea159488ee54ab132a4e73ce4b27a5f4631d55af5627547892884db60ea55fad4ea840d139bd7b22297dd1af1b37a7dd38ce8acd8a4967b76d4768e9a6b4d287c5023c5fde15963edc3704f5b6ed082d1fa5b408e92ffa2e7dea5fcf8382e97f16149f678756faa12a4dab45a54fea2b45a17e2c2a983e7da566ee5f612c7d3e19a2c0d459e9d35c580bc818f75ce8c361f2c7e6410cd8b32aafa5cfd67d24d0ba2f17777fff5cdcb44bc3a30d8521042d8c343a31b4c8d9144e866da8d68551173490c16b938b26b8232eb6f89210e34a1eb11403892cf34dc584d1a21e1152a680ce4850dec8bef1b7f8c3e00b700f1e2efec823fb69b66a5d18f00ca5b888b4b0fd085ea8bf85ae077023d89e0babb8ac6cabed15bd885b33a6872f702d8d29377564bd09b78a5459abbb8cbe002367600cc92149248d5a13f01bfa5d972144c0135ca47fe3460a1ebb690bf7f48d1cf1a725b4487f5c057191d217822191a5e460207d64967248ac659467c68acc200e1b5242c31cd0f41d5064c65a43e4d32e5729ffe2ec2e93dd41974bd0e5a106a47c971a9052035e7655f655760f4fd95d7a31f265a79e05816cd9c3ebb97fee28f7943b768f7157b9cbb873a1dcb6e0ce9d33d03c902e00818c232e1661d2d474a4086e2ae2b119a5232dc826692ca1f428c686dbaf51da2edb7e6207a56cc119ead1af3cde52fa6248e98b2979ec2d4c4d5d7349ad377770ea55f1bf78e8887c7d2805f94e8f28cb0cc1e0440d5b723bc1a486eca04b8606e81cfa3a1996ef06e687253e45297b98c4b3013ac7415519f9769e835e17f99e3c075554e47b3d075749e4d32743074f46a01a85ead139f4bf2cc176e28620f2dd3c07c5dc1f8fd501b65f80ce99e9c9f46db0f344a63fde64aa44a63f823c9d437f260c5ef158503a8f8bf45535f0f0fcf0f078ccc6d18f90135208c216ca6df55bf2f1eae485aac683253c28fa19504c441c0eba991734a62f50d48003ee024e8ab88841450d4b5021fb91c40b36b85294822586fa35762d6f7fa9c7ddef5fb5eefd6fd8189429d0056976f0f497369bcda2c04edf79d7dd8b73756fbff3890367ee0f08c9a97b6e296f1d38c482ede2146c2405dbafad898b447e129bb77795d0cfbde7e94cba1aca262eee3491422e0eb978a47e92fa2decdcb716c9e9bb97e0099c373cf3a63eae3b3b4c5e15af2c924d76726d228daa955b06cb088b1bc1404a89570ebb593e8ddc62694e1f3f3de4db99947b5bfaac0e93db07a4ea6c7751de8ecc8f3c1c942f03768bee1e52171b1004e5c885329c3051850a2c64ed37a777f00b476f4e07c71632fe091af1728ccbac02c51df503c261b057a96df1fbfe3e09a51f0ba8cffb4e3be88a8a3b5e5e308d8b14cbcd07af7dc9788811a0e88202df2a1521f71531cec85eee2b5d76984a1065cfae23f7153170d0a5062a9aa35ac270118394175a902445d7a04a0e5b58c0830f67445162346713ee26f795da0f5a04c1a35571c41526a60e596221c5114d6481831b907a90c92e5984d1c1164814c1250999fc96bfd0df17904a587e33c18124a05479c286232e31c846dc3904e96004175ef86003d2144c64fd8d815ab7fb444d8b252d984268b14c805d24d05c9fe6fa4133b062031296142031a1856c3ecf8cf9c0e10530b0818a920a6c90cdfff9e2fc8d0a1e3f53a5eef9ba71b63b7d422ea555fe7bcc5730ab59d0e08962c9d431e7ac72968066fb1e60f9f26945e29be7efd995ed6cb2c0a73f6d7ddbf324e8795055425d30b5983af812b28c0c444f91afed4ea8958bfd33fba594e279d3ee53062541efe61b233b97e7624b918e35db64812535c2936538919c643a7491204723ad641304168bb23c3ce5176e8f08d2c67574f7bcf238e79c93d6d47003b9b7393a1ca7102e8de7fa6ea066522d6c23a646b78ab2e69459ad6458aa1a3136702b3583baf1b93c9a1bc2094797c33e076e61ada1afa9c36da4085e77778b60a3e35513829f03470834ae1b332d11b5c2a26dc8d9cdd3acb9a232b5a52283569adc31ddddddd8e258672d27f343ea7362ce39674b4435fd2e0de803cfca6be1ad72d5d66a77e47e8e47eedf68be13caebeeeeee061973ce392db6cdc56caad68d5865bace913d96b686b0fcb696b396cb2a34b6b9c69cf3959bb66ea0e0e865d9366ab4502bc830d945422ba7f20c470a641d1de6fb3be8e2a9ce1ed29a3794d2097a764afbaf77879422d9e6d75a2b923a678882a210cb770f479991d46c24e987a19ca4a53cdd95d2b5b74f3ee79c74ce395759b09c734e6a2d47b71b638c1c078349e79421c2f2e9ec1c366911968f3debc9f480e5dbae9e77c5ff3ae54ed7b90e85677078351ee5c16373431c32d30a61466c89734a996384938d1aa18d116ad4e01419a2d4a4d434e409256ec56d32362b1c191c9bc36500f4cc9973db1a0094ea5049e9d5410ac05c7d4074c70a2b76bce039770460aa00201300954e1500ad127f4035e472c0320094bebc02c002487d4078f080e5a35662e03907e0cd7034b99452ca517a9de254ab85237c893738393b940031ef48536b11227e4144b079e9a8f980688ce35e350028c0c947f8fd808f2347081f101540cf175a889c2074a48949e80852ad47081f0f8d6be6468ff5f1e9b12203d3560fafb7cc83863bf9460fb07c03381929024c98bf3d4de59ee0035004745d0ef0afcac0d4e7677ab665835563f501d14f093c3f7b74723b60f932df8a0c5c5f7e8c2a532aa361e0fa1f50fd5664604a65db964249231b5cae5409f1a982c01e8ed4674c172cb538e54ef77b82ebdfeb1477f7aba15ad5a0a1f9d68035228823783b740460c3c3f3f2c843c7ab060c9fc7cdb27ba4c4819dc0cf41812a8e4af301cd989765077ef1f01b8fd9f70f8bf868c322f3060a71db685c3768eb03aa3331cbd34f8fbae716408695c84601a8c3bcc5fa5b8fb7f97874528f2da9523f8697d90777884704a03e7d1b1fd0b6440fda5d613d236ea38813a0c96380598325b352f9789f1298fe013ceab0a9fa8068c839c1f2e9d75a3f86568c3a0002eaea0bae151f55314330d7b012cd2a84801c432bcc343ca584fb5fb37addb3cd6daba0672bdd9edaef47e7d9e70fd07e3f36d98ee2b63052c070017f4c33076c9798e042abc225089f01172726e022349d28430a3c73058d82574cbc90c510416056ee2b59f4f0c5861464311303dbf04205185b0106563541578065ac30c114650201dbdc57988aa612f8cb7d85e986255804a18685195a6051c3a289c6cd60b1b5d8358513a256ed861839555eef43a5f0274445371a97442eda2bb0e7ef513f36962024d4981e1bcb4c18fc7a922b11b9be0c2246fe90eb8f5de7d44759dc0222e619ea00d39f4520918344ab3c4a2249b4034c5fe29881c1d414c60c87520faf5add451255a3ee91dd3992a84a49e4b18d56911c76c5617d050845b556cb6d34ff7225b5b7e4ba81f269fee5d5c7b54aa61a615cffeb677cbf83593e2c68871974910694211db4ccc0801554696a9a9da1644683cb030f9e1ed20c27b2bfbd620610663429f2ea465cebb0ee97dbf614cf9b793363fe35c438353d8892c0dd9d500a8447e7ec70de06d26af3165acb81a311cf35d2ecd861eeeefe2e4aa734f4a7d6fe58eb16aa50dfdafb8ac1f3ec6feff6b91fc3d62b06bc6deee5197e107746aa677577ffce91364ba794ca1b2c1955c6b76ff8008f74a4bf6d937683b26bfd6ddb727b0deedcba72e17452b9a90eafb7bb9d78d670fa9c435c191cea9792927ae1ececbe75bc72c7d921ce862cb06abe3a6c3c3bf315c1b360cb6e4491026d4a5bcdd327ad2dbcd912d88db3dde97a1f2a85635432abda37f5eb409e24d8ccfd65d5b0d19ab9e1a20901478e07c39a970e1b116e44982e5b145134a49d53bf8a60b690e7cbff8d085f625f89d7df9ab1d3775076982842be9c4dbe56c72bff6c40cb5a37d4e47bc37c3d30dfeff345e5c83785235f1c42be3134f9aa5cf9cadcc87735932fab956f0d1bf9daa8916fcba3202b5b50c991d94ca64231b3caf7864cbe2e55be3431f98680f3c591ca37c77ff9825ebee1cdb7e694efabcb5787cdd786cb57842d5fb1e67b43f31d61e68be3f9eef03ab0651494f98a39228ace1f415bdd9c8be1b6bac7398b57adeef9beed4d0072ff4ccf566bc4050002b63aa78e3318c873d562d7dd2a7c6dda298ab41d9e966d51630bd922c19d332d278a1e6b19edf4084264496b8b48cb52834ab72347d3b21c2dbab305a63a67ba28dde13195929013ccf882a67774b7962d54e2d7d3609aa472abde0f8aea8c06590efda08b1f509181cdd70b0dfdbf8e3c76c2f41396ccc041b05c81b9da1734e491df4c6ba9482a92ca0706cb666581e7778c85d9c74211161318252944a590c39848211666ece5f3e5b5c7ef37f3fb3b673e2b077894429f135ca56fe6bfc0ca20cf9994e78fad97c78acc1d920a0b3356a469260c0631d039f325158f5569258bc36a9e7de50c2cd3073f482a7972331f60c9a3bce20326524b9eb34b9e5fa9ecee22cf9f34e4e9248fde94603b0652dde33f57576e0f65eacf211561e7b496b353dc799bc591769f931fa7f9716b6d4b395255ee3bab4d440e2b721812d427b1d9c861f453b469a6a06315cbad92e97d41a6e34522d33f81d58bc7766864f2867e4523537b9b56b150e15388e523028f7776ffe4b0cdfb0fbcb3dfbe75061eefec87fcce767693b643236d85b699c396386ceb4ed7fb50a94f080af461c12040ad43dfab81821901dac703b600edd343f2740f37fa646a7fe478748f0fef217d48681dfa148a4c7f3c40a6de4c1d75cf4c0a199e8e3a87be38c5369bb4cea1aba6555ae7505aeb1c0abb61bb487dfcb8486d8ec042ddb3cd96e4fc9ec24fe774deb8cc6dd982357720cd270bce7c3f219ebd4f4827efa943c59654e17e490c2f136555ead3a7919cb5f6467171d63d4a863cb6cdee128709398cc975a17d76ae51a697e8da20c31f219d439f0383803e5ca43af4b7d98cf50ef7dd4ea634dbdfc2f0464122f10c62431ff632c9f4af50a61fc4457a8732fd219d435f7e40ae0f17696d1a1009e4ba903b87da3b0b7f5857d04f40f70cf118f6dc3eb275e4d3f7e130fbf48308f9e99eeeff3d954d689ffaf4a9fcaf752476d5e873930b256d865209289853cd4ea7d3b66ddeb5e5615bbbda6a247d6afda17b6c4dfab80bdeab091e25ed49c36aada145fade7b8dcef9a7d96412758f7ddad43d34e945c3e69316e97fe1b7523fe20fc71d3bb24d61ff39a342e31cb292267d6ce835a944f7ccd0c9e81c0ac473eda4c035e943c6a59ed766acbbc82813dcd2096b834cadc85426012425cd05b84952ba75387e20a3d039f46793293487261317e977e05c32672e52afcd9b1a8a327d3a9fd4866c38893a873e102ac013efcc585c301752a39d19fb9e625a8d664cd2e60d7d8a6d38628e69ded0a7292bd8bfe665ceb9855e733032c0a3d732fd49df6b1ea334afcdd914f29a83899959afbbd65a6bed1e8dac2648e70970c863d53ff2c85695036c82dbff91815d16b796c0fd9220b81d0d70ffa5d15a72a42e229b9d3792035db2bf18d78fbe42c312d7035ae67ac0e9bbefc2116c635f99c13f7fa9c20c5d24a8b2bf2afb2751c1037d858625599527d8576640221f51e5fe13e87a80777aef0123e0fe3be13e17ba8870dd735b8874c2c90bfd68e3ee8fbb927c5f92ef34c7529d9a71fb355aa3ec7f2f9eddd0d5a3cea94454da0df588ec2fb34d025330f3c61f8ca560e6ac0ad5a119f3889eb40f8743eb383704a5639c0e7de3bfb383835353e372c9fce8508047ee6b2d73b419eb03f4bc1939a4ecdf7142274ceb1e54f69013626981478ec6c2028f558aec53c908f5db51f6af65748c13aa758f1ca37d94ba4ad13df5bdca9ca243ab06bc29c91e0a9d91bdd5d45d183a143c4e97f5078405061ea752769f634dfacc502a491d32ba4786f2069dc305e1421bd2e484664c4ed137fedea2e5c06a817b909d13ca5ec614ae0a035ce6853e03a552e7d8a075fc3ba319d2d2b6843463a2f8df6a2d711b12fe0d691a1de5f1338bcbf860b2cb5a93f0149a3317fdbb60af088f76559b3f33e6bd8b6f3175064c9917be008fd687ec60b2fc94152cdf1a61234e2f739db32c5f4a774a29a5748e465635dc99f33fcf3ce71022f0e85f7c41e4be17ba8878a80f92852e22f253a063993792d6968677b895011e77c61da0cbdffb20d407c96a44ee7b610bdfdf9f2011ef51610b37f8c26b334618f5813f037c29d0082f609c5db399a062961d0d170d108327d96b5e1c0cf8859705ff90137e82581ae09d490b1264669a4f7fb2bf7ab970faeef4364fcee75770ce8e51d9ece427a15a93f52c66c145d9751cf733b953c8828bb295cab0520695e798788c0256d0c489294d32178e3b3b79b447799c445ea644f16ac07d850c2f799c44998c89659c4259be1ce750962fa514b42c7f16cd2859fe14f258ff4b078c2409cefe83ce91ef5f5a47be972e59cebc6c912b20ed62d7016d9be4381fe105dc7dbb68ed07a45becfed2ee3f20fd2ac2361cfddd5970f1f4a7772f0ef350cee690c34e217631e923037b6f97c097e3565df86fcf811b9060f29d23098452d9bd8c81e5f75269def8f5efb08061c0947da1c52d0e7c0fe4012671b16b5f8ef2d860b2945fa6642927d1e5c051660e4cf60ec8dc8548023bf288038e3646d9479b59eec8c0234b4989cbf15ccdd7e4005d44727ccdd7e4a8a9c901d68035df1f90f9e5cbb6e5000493284261e01c3f62224c7487728037c0cc9b3b64a3e395e3549b311b1da7daeb54cb71aa7da1cf529ab1568b8586c3e8ff2bb1d070d1cdc0544eefd2e4a28d8ed7cf1c363a5e3964eee2a287bfe4a26f9140f8357f3f09808f237411c1d15e944086e3836435a08b48cde7f81c610bf287a62c8864351f24bba71a9e3fd68c33a443b39102539ca11bac1a0eb0653560be61d48d817f69c65e5ff3a3cdf14bbff40a5935bff1afb139c2f61b560d47c86a26dd23b3ffe907b8f3c8aad22b48bf26046727596b76920d657f96147864d5f2833c7e43f30c775cf496e1005b1602d8328f06f8f3c8aa65af31f3af21e4cfaab1c0ec9c825c0ed4446b0825b7c606272fa0758145103d80528b01931631180306318c517df09dc0b71a3cd97c5e3c3b4459647f2b933b89a806ad13b47620c311a00a8e238014d60a8e005eee242225b664995c0e51e8c00a306870610a2d50083305144b54968ccc60c10f9f122c18c204494431e092887ac8a7dc49444343780fd846ee2b5c1c710105072e9448d9420c69832daed859e256da728e41748a7b57cb7594db4e73ab2450eedbe4b422044ee54e2272e135c3d85a4609a060d162080a181ea8280114a2c79eb516b7c0dc57c210c20b914709191e525661833cd2c0f2f8da61872e793a89419e3c3011615c53a69ea43b3b1da54b4db20880f71660fc80ba52a9090e79fec9f35a0093021d68f872c511404823490b19484bd400c34c5604c6d195b4d846df36cc7a493a64c9d35ff8a109c56d528728629e5fade71991c6174a4ce1658c2ace40400d8cba6c41ab52431599bfe8125b28d99fc757d9dddd678705de4165ee737a21d3fc45675a2c8f832b37105521c6d012383cc1418cec4939b820ef3c81473ad2b4153179ec51432dfb12494c5c70830d5e647fb1042cb841862a53575c9f6520337b379dd24a96ef56dae5448d4150e0510a49a1d93fda4dbe5bfc5cd88af5e704f3b4c4ee9959d272b4ab63e26cf14a99f651ac423211a5153f026346539119934c849afa0a2c3db766bb952379442342094b9fe046ac2cb0146adbadce91f3a8d229eeec9022930e3df48866e81bf9724af6500ae54012d137f28fb04964279878acf5c9a3ce99b1564bcad03972ca238fb990b7c82e594a59434af9b35d862c25cddbee91010246609ac4228f24d2ac066d7b69bd2878e4b27f8f5266f946acf7168e80f6b6d16ac4cb93e376785eec1ef9605c9afc6267fa48e35ce6a4b9d1aae1f65a9b72ab7337c1edb93cafb5cc7c0c499a6149f6eed2a3b1b496993cf69247a7c7850457fdcfdbe30d0a1e77f0bcd1fa82470fd504cb12ece3aeebbc7eef81f47b1f942938d2162e78faa0532800a9c33db599be942f7ce1560cb61d3f41767866d74f51dc7ed5efbf37d481d29cb0b1995c257cf7f563a0f590ebdf931455dfe021344b710d51853f6fea8f0003bed9993775270f99ffe31854fd758fe9eca9b3b6d3c1cc9e3a1966a0eafb034a81312a10bf12d8be14a197c9fcfd4b4f9e3d79dee9099a674f351cd5d3693b79f6e479a727a098a1a18b674f637fc125d7bfdce9747a20329f3e134eeffa4133eabd7094d97b99bf7a4412b94ebf93bdf7aae02f6c261452f0c021415630ab7fa43e0bf5bbfb23a27aacfafe96c8410f4bb2989722f346640d683534d1130d693b2a0268888bf54fa7571d814fff334fa0e79d1eec8cffc79708bd0c7b61cec85ec8c205a5e0f0c8bca95df3ee7b374452f3bd611864fb31f3293cc2031e9b0985143c362991d4c7842d3818216ab2d4e3ef1d28c970e431775a3113c242e51542441ed3bdcbca281d885d8c750e6a2cd4974baa54c55c56df9eba20f585d41f220353ae4fa4feddbaaeeb4e2af06e4344c163d7b2a3ea03e803269198c7610b1e12b298971f11d5a7c2160c50c483914ca502531f03621a747a1f0e3bfd4cae269f96038826a0a0916b7237018586ec34b3725d6012ba0f55e8504972f772a3639723c1d1fe26c1d1eb4690a5089074e7c8976397edcba7d9c3d1cb5d7778e5c730cb38b99360d092ef8cf9f9a5baa7d2c7fbee37e983bffb2e10987e09aabfbf721173c1f2a9f717ec2c1fff0a338ceaa21e0587390f8e668e2451a1eef57c1f88e73b9bcd76e8fdce1ee8427d7b8ca7c29e4ae57971a4c21e0c42d99f87e7799e1cc5ec2e1e719867e7624694fd59b85429fbf39852be5e2ebaf7de5b87c5bcf79ec354ef85238d07becec0de8f34f9c39709a91f28140a15feb8e8df02f07b31322ed6ea93c880d845172bfce19915eb2d8684a090827f11234758f0d894f9b35632e28e122fd99f07cf92a1ecdfc3656442171099653c55e8427dab76c01d28505459cf7e40312f3f12f0ab5e0674a15eba50dfd98bf1a1025da820e18f8bf633618519e6fbc6e08e1d17c3ac703dfcd16201a8f072ff92132504a61f683ba77b0fec3aa77b0952a9d3fd0537a9d3d9af019e36af098f4da33f34fe2f17a5496809080813264ce638570dc53cc11d32c0434ef809b2f21a49dc7ecdd89451bae3453db6e34ab1aa34918af8785ca4b4698f067928f1f28be6e537f377288e25f8c7771c267db83863413cfc8162d5034cc7d7df00f14229f5ebd7004c63b96ee1df31d24ec142dd8380ec452c0d478c672b4fa42226a5530a2121d1041762e46e820b30b9cb5b1e3defaa004fa5fb2ea9a4d47441c9f47d15229ebc44ee7fd753ba378906a42c80dc49342ca9d5db3ea0130de92b0268684aeebd7e25d81fb73722ebd71566983097aac0fd49be44a2512997a4d2d33f6981eb266916ee24b3b878a5032516eea53cdaa6b8e858a494ced9a4cf283b15a8d491445cf4211b28f3690c3cb69292142bf933a1869bd4417251ca50d2945c4472d125924f6b1993e4517efddb1f90514a69c4f380bc3794579c0b3d4ba429699c077ce8828a29d278d2032c64feb2491eb9e82d955cc4f3955ca6072c54694869c88552ee4bb9e109577a6d2fb52e6858115a927d0e252941729f3efdb77a25e9855af6242547524a8963c90ff048b3cba58d8935c3adddeebe49f711c4c52aa50f1779a60f1e58005aac5f3bcb4ee7d41d4678e4e1f1af5e7f05a67a48a97e8a83000345971698608623a4908d387b18337c1003252960e85286ccfdc91854589b3caef284e539935c9821cfef29f26cad56414a909098224c1542c84045900c688083232f6088428829b229676bce4994a7184879ce39e78c89028fafd78e2d55a481945d47764f4307d9c31c917d3694dd5b45e1ad6870e4bec2451350ec00f7cbbfdf0ef85df47e758fa42121a594a98bdd9d43bfbbbbbb694fd0768ef47e1a8fa594be4710262b40830947a3c83f7777ffd9d27398ffcabda919b76db750f577a84176e8f6939fbe76ee5abb3616e930f9b6c8288ac3bc3ff2a4cced34457e537ff4505b97af7fe08c0c054a267e530930ca26b3be4ba2eda7d4fa2258358c8515cca38d7ef2b7592d52e5ec45d030a9a4c5aaa461ddb30ab6ec9326e89c1a255759d40120f5768081545cb00c533826a59a73cee92a99182c23232323239f26cb7015c6ed086c290f942dbfa1ab32b0a4db733fb9962e86ef331851c97d650c2bd92677920f48e49bda7e024c49e8e3d504ba482db5dde94f70051264ff215dc44599c30bfca92b58cad0a5908ba2d852c252a86513228769c9144422733f53bed2a3b418bec8136c9a0c58727fb2ee80e67a29dddeceadd65aebb60209469a6c6717f69f402246e0cc852d247191fe90131cf6029648c8590d8174ee9ebabaef8c5da45d6749248bac78ac65425cacdb06244828c4ae90caf6691c46f323add40374ebd0bab8d1b4d21014889c3081148a849ecd429278e67e7b1f65e0ce3e3c46654180369ac473ad78d5a2e192c85cffb32ed688013f7d893b78d82db42bc0a395b4d30c22d05208dc4927d892f1bf7f40b7e96c5a8e09479af1db1f7e662c8595ecc2fad1c82aabbe3f8555385aeef153a098e7fec72d0af0d8349997d907c7fdbde0e713f899f5a3c53f62d57faf7aff805496158e16e370c4f98b09c756febe3bf6d337dc7ff7bfc8f2537f5b0268e4d57b961320b17ddb49f503f5aa14eb391c8e46325681e32aab5e7e4056906132cb7ffb16b00abdb30a832aa84223ab9cfa2f06ec9c7a16a8ea9c027fa0deff03398ee3b8d4cb802af8a7de03477faf3f13fc532f637fc0282370cb385538934e4025b3feb584b957c19ff5a3ffeae7ab9efb152bc4e0676b6362629e7e40312af033f72d607b950a447956f5ad025f4c58f553e595e09ffaf9511709f8f6b70ac7a0bc7a1538caac7a0c8eacf047778eeabb73621effcf8c01bd5f81322a9004d5a35e158e4656f97bfb9d7f660a6cf00476e006567934928dacb2ece752f2fbe1c6d856e7d0ced6ea5bba18230833c0d0ea393843c8729c0482e90c1870d1a176a08b883580114b18c96c68595c3a1068fb7bbb48dea411700ea1f485ac85ee4920a794014656657e90cc821d4877401bba6c0776a18b48d73fd3dace5c338dadc9e282eb8ff6b7d0482b4f09663b37ff986ebf466c84ad749f73ce20597f403a0e0c9251a3548ac5c245b80817cd29f3e8c934cab2b692130d711cec3bcd25ba447de33fca196a7222b18dd34a960ee8d836345b094ac7b6a15a93464e6b2a1b36308b353313d36a6d2e1791211b0fd97f9443db50dff86f3a748c1b2515d92889a45194eea9590a512d952e6fa96e71d163ba6039243cc155862c482667c0021d886436dc88e68d7f906c1b9a3741320e0c927553b024f29a8b3e5d736e431eeb6a1b51148775f6df8e3624b6a2ecbe59c9be21d1362cd9a9bc440e1b6badc8e9b792c3c656a24388780da3a3239165a337c9f268369bcd64a317652a47b7227d5c882cdf87ba2726cb6fda317082321f909c447969de30e1f0b08b88150191cc8676dedcf04edff6f754b75a7dfcd45ae775215ec32058e6df60065a08dee9937f4f92c7ce4e0f1e9e954c0eafeb5eff3b44514655e359d0752022099a8c0343a822f328948a94643b3668324500545869927160cbae0ecffbb6bfde26e746d36ad56089e0dd4ffebd7569c66c58fd6fede230b90d9d68dd33e4525ca24bb4a5b0b41251ede2a25777eab52ec990da2849500419e0711bda7c6e431b158107119c3cc123cd336c0cdec8bef150635096406041a526e340d71432a31e4c2e75d8a43c627827c8175af6f7b12361588afe8eea50b951d9537de328540b70101751d9c70d580533098acf6ff9d4ba30e59c7352ff5182a067297fe5208d09327b08be80e56f3fd2d06f39e79cfe94524a151044d35cfaf89b00896cdff39dff63b339f2fc3184dcad1ab951b9c78d762f20e097f4d97ebe756765cf913bc79f0365ebf85370b68e8723d7ad63bf5b67f4afaf823fb5e10e17a787481e0079850e9346dede412ef707640c33b7d9cd8612f4ed9b96b7b03ba7faf65e7db928c39d5434cbf447eec64d18cc8563d046430c05db3c6b4cca362d8c8668910f8adf9642a4bcf9f2fb65519659e6241fa8e46a420d2d0dbb2501dc493e30c99d3b5fe9ed289758809039e0546e2c615cf9a33cd2e4242846342d59f41cc0526b9247afb1d4867896e0913678432ac19d94c46482492a109de4da8871058c51ee57cf394315e89fb20add33ee04f58fb49b862309e8f78fd3af60093a552411666c214b23dd259320d74e7a822527919953c148d76028d370032f7fb4a7fcfd2da06b30943bdcd9e4ec26960062e6d986d19ff3b7bf144c7ab284080d22db73df1f03b6e7282ee2c73f88ff8e3f8fff9c4e67e03c2f7a33b6b276c6e4b7226287e7456772fb353917c76d398c28a534d3a4274899524ab58ccdd4e50b6eab222d4292c920c82078cbee19b83f22b4084936df415a8424eb8f888b31439599ccf18ccd198451761c4f543652f303b281c3514e507584270b625ee69870b40056bd7f24f416b9bbe00f7ad862c6aa49c1a3cb484acdbb8c66ac267497116d56ed86d18d5af7c4cc7ceb97a60e219c21000c758e1b5d571487c9bcbf6b4af7c4787667a8735c87d6397e9467c09112d162d54250cba3ea8dd4a19494101ef489a205348f8b542845f5ac9ac3464c14028863718654500122207440c51344948005773301cb0b18161a355ff352fe53ffb782f43128f36d026ba6e01acd37a6740f4ff6bf189c790bd30f09d0253c89063d28a51c86552c1d3236b3d6f78cd9ccfeaa409d8c6f2a959a01719ae010a57086c054d6519bb1cfe237fe595cf49f015fe906f85a6c667349cac6666623346336ef6f43e4308a33b4b47a0ee748479767ea9ea52d0e4be1942afc2cafa5737474d1d16483831c780001072c3356f336886c5e3cc9f203195c9052384d885221ced04fd9028f9f45caeb3fcb2b394cf5feafa57b5231dfed8333933afe317f55e06f79269c59377a06578e71cafb1a8e532a9cfa2933a623acc1d8e6a74cc9d6626c06de7e64d5b691e2ceab11038e5d1e3fcb885334e21c657fd668f37c0c7adec262527291a5c5c5d4745697eccfdae2a2bb8e12760a96614461628a0c0e11ce945963e3c80a0e920e96ee69a97ebc19e749fba87a3c80718e689f1493aca3f6f706e8fa1990e65ba04eb651f32ad00336bbfecac8c8d080364b401b2110956d66a9acc211c299b908ae1e83ac9f608d1910bf0c383f05229979995781a96f8139b906a4b216ce921970e5038c2314e2cc585ce01167c8652403dad8d03afe36409b590dd06689cd0ab461d239a8d7515b621dcd988ef76721b1bc66d451cb6e63c4bd008fac283844dd3384d3c461f8fd53aa97f9db9da6e751effb84608ffb14f0ac28ac299e4ad57c4ac7a75e9f4a81384b7084409c195ac773bc94149bc799cd984df84bf3c6ff975aa98712d064393e48860344e389d7e30ce9d0ba67e8fec966d6231c758e3885cdac66a97370660ec3598223d43df8fd637cba8ea5ce711d429d63a3844797d12fb984e68dbf8e17e89a81ae21175d4636378c3831186f1e716636b39112513406a45ca8246d7655512d11d50800000000e314000028100c078422a140249ce9b2ac0714800d839c40724c170a84490ec3280a4206196308008400008c3184c086b602722f905f137be5a7470e736967ea9711edda4f1ff7498eb1ae9a57449fc9cfbe3886807955925537a29cb78eb8fe54914ab60b88752af6955eb0dd38e6709abcbb9ecd67e24015b2e91bf1c6a1476d60444d8e971a1b9e6ac03911fbe549b3fe9ddbe3394b23a44a32e9336e4ca5af622193885f578e5879b4cc87882dfa9faa00e889c1a627fcb878deb74bdcf884acf769681f9c300b4c99345871bd8ed270d38fb3846eee4b12dcf2b8c3ee6ae0502c3e58dc79e79a5c7e24d0c4630e8266b2509f6f2113cd082f46dd7324c1fa0ea3f9302cacfcc6f0af2e6f9f45080e1035b5480d74986014d0bb8453be0a2ddb9949b1d37d4af98525af429313472b326a03d0a0266a0589c50892b435d2121f1f1ec8866c9d0fd5be8c14e928569dcf06be18db13ace3a1c0960e4bfbb8589956d2363d920dc99e796e0b87826985c2d4fe3b94d30db07ed52f9169215b7924b670ac576c357a511e11f97044640edd64af70089a748243f3753122a6722b4fbe33ae72f41e2cb7fc2791ecef5dd09abd80dae3a458a697558c4c9ce36d2cfc301d2522041e93ebdb76f629cb9dfc6e13891e84b3353250cb97fde514104c1ad7b86ad56c59ad85efd4724527487cf16621cd0ce9145cd0826f4554e0732a96b69f2ad0fb4ffa1048e946b4aa4096702b5d28e6e57334cca72c2f22bb4330b9250c10373597b16ba42026ccba9f248e3c66ef01c47c01b384728249d6d26761ccbf2b6c52c4d37bce62a5384ef8b1e3da751288805b3e2fbf4de3e892450853a0806d1e386eef69d39f001c795b029cef5bc29bc6e3141b683a9fb658502ad6f5827e8f4e9cb447a30b0418e3ee4763fa37f8d9813296a6d1a61fa1ba19cacf00b86825dc550ddad46b7907525a96dc7fba1c6dc4e2fa1d49945575498e447e71db73ade13b3c30ee562f3f7843df1adb82c741c80bce996ac33d3e2d21e5cbbacde446ebbfa23faa7820840adf6c097f842bbb3251d7475de715542c1cd96d980be1cf25985b8b2e9802468be58de71b624239a3a4a3ccdc1533e589b6175e0031c054fe61166cc92baffd15d57cd9432bbc51449090ba5b04001ce4f20b833de56042224e0e145be7daf84b46c6d1506f522a0e90dacbfd0927a76fb8a4e9b1dccb82379486bb0605f744c9aee69947bc9554d288e2cb38fee432ea106e399538c9aa0584ca5a3bc953c972b019b9525c72e79a6d4588d5cfbf33fda19e03006ebd1ca0e8a37de01966a0f2156c78fe09934215c1459d88f7667cd37f6d9d30164b78d89f2269a87810cc979fb19aa859dfed2eaa092d885446c78aa8b31b9293918c90888a3fd84738c8b535259ae375e79405e70aa1287aa2ec19b55abf696ed512299b3b1ee8973c069684df9141952a129264989dc54df7cef54f4cda4894e6a14ff817bb5702729e248a89fcd66fac019a66fc8a159536c17d5051eecb0fcd9b96d03fe438c182d008e6af5d78219f628e0e3f9ee9c72f56a5658d0d8b48ca8b084b31143059b9486b9033704b291204d9072679c783482242e44aab0b118d8c2a3d6f03197886fd429de824161a30e7c0d29ba8e986a89634625cb7752002ae45dc52ef80adc5276f3f241391ec9506d4ae6a30b7cc2a6a2ac633d69b8a09074a178b301fb06bcbaa993f9e9c7e1d057b192d4e157e76da3cdb744b56490dc6eb4f4adb5efb2c12cb1eee705e70e131855bf461b67ca8f4b80dd03857abc75a20a8437c805810e0809ac575717501324b23edd4c50950622069605a22813816d9e9a81bc65109b395e44024883e5ddd3c844159204396dde181ba210110d24b6c6ec9d6f974d6537e6fd4081995dcaaa044c334f5ea78107de9f8145f89e4ab7f63c413fed1a2df7c239af964448d72500c501000aa1e78e3c4884c96d1abf14ec8257f9f9c06078c487d9996b9feaef631426801565bd423ab942ad2ac5efb35aa4f117c59e675aca388dfc83775246c0645ccd164a909897d9fb80338fce430ee19d9313bb21360b9d49e3c454d50780801480f014e3f09191211c5a2a06d811d0911d4a842f9ebbb2061c387825005461dc844d3f482b6d4d03409dcc5d5f4a35d8a4c6399d2a74ca6c5b58ea00a7b867651f16bdf66e6f08f10991a910ec3c6298c3ee0e466fb8bb36a6b2a92561ae819268977e1b7276eb1a96b87eb27f15ae87f3396676482ec9b1b2dea91b2b307f562c46f5c15e8a8260d9474c6263e0f297d8a7d2089ddde27d640bc69958de74efab8e14a6c2fcb694f30c62d7348019e5b9cb4c935ac0b4c02b6dd53a91f7cab87b562306b8fbef173b6434d3f8830baf78727c54eb4b10918992a2b1157835431902a9d4e9f75b60a6f3cae252eee8c66d7c256a839dbf045b91b491ccc3ac91b97b78b8da9941ba5b89ea729d9f7e4ca31df6dd25798cec1259dc4633aced19b3757b195010210db8b985978a68512e83c20fe9580cfeb6ae8a04c243ec404a2234af1ea46215d22dbce5a55fcb1ec636dbbbc8118d24d9127f1cf4b5967160d11c2946a19455ab38452f5edf182794040b21854105ace0e4223b3950ced401f11f90a9f0e3226dfb71947a02d7672eb4bd0c6e2f6bf68bae1b1913309056e81b01fbc55dec02692977b0e7c9fa9d522142cb88289270b7ad74aad7b890e28e17db6a434f24120f83f299cad2115e62e7777ef652c3caaee4506acdbe8d412b09c617b06ead72840de019b83d44d89ea5ede38583cda42831c393ce99b8e739e03a2ee05050be466f49fcc3a08f9f058913a03d016dd0b83d8332eb70300d8902aba176419af32e7fdf40337c6320f8c7be328ca2dad08b2b888e6ebc0e6da9e58eff4036f6e29a1ae93b269d03f5152a40f7b3631b8937d49faa31a05266d55772726382a692e7d4e100a7ca238736f688fb752d6d6ce7dae6dee118dd5f35ff824c1be089e799c5f4344ffcd96902df5680a2b2662915378c39660355c44d5df24e8e44f7176fff91b71d4deb3912ec939491cf05b768ef979bdcbb58db7e1636f7be8c931f67ee9861aa53e34c2e1fd99542ff791fa73b31fdcfed08d1ba8c4b21b760ab86f4e1e96fee29cc95b8a61a684a3c02b1b0c3b044c3a9af8f0382562fc73c4ab1008f889fc98df2b4efc23ceefdf32010e7186d2278ae257c3bcab35b86bbbb0d885ebd64c4cc80d379ac178553a1e35cbfd17ba5baa9aba83ef5a7681c1edf2e269cd775795c0d3145bfb70476c42812ac6d34fbd7610f0eabc921d2b3bc65e5bc3043abda685a18751010edf394ff0a02953db571599101a63cd09391f0d40af4c385e2741e0ea9d19062beaa96bac6d18f49e2bd1edda16766e6cc173f884699f682b72d0995098d0ed9e628dbe147eae9b99e6d20e41cf122557522d5bbf61be49b0cbb2ca50cd6b9c8bd46892c14e082b4eb3ac18550704a7fe94511281dd62e9cf73b9e523a0c9fec6083927bf5f35d570207934079894113cfde37703f702ed24dffc845015eed19e01d3547ce3e970e7539536d81f304d70bfc49eb52a7ef068aef7287f018c9c37afdf4ff9fbaf69544d574ba9cd80f8a0f152ce75d114fbe111b41df44c44db6c335eee0f37b956b67ec0cb5953a45720624237bd5e3392273b4350d0230b94fe96682c3016093895dd8ebfff25381d1722c02cbda80f10f93b00008ddbbfa90dd6d9989bd07ef52d8977d424062a41998bbe4172ad440ed3c8dde77d746f442d78d97d4891684b6e8672511d843e8cda0c6dbc659d123ed53cbc2f4ac375c107cd0311b4cb39adca322db1a89f42c296b7970638a3cd88e0db425b270baf645b2c5fe02198643bb371eba8e5c761331e6c1bb92eb76f312e406b41a47f187c694e0af7fc2acbc23d737bafecaa4a4c365c755b78dc62157a23bdd99b3d333dff7c6fa402efa8d2d03bc09ee9be0a1a9ab0c0826ab449b7bb80e8834fc25f8a7e95287efa2fc9c92e8a7e557caede99451e7ba07e8006396e4a950795f29e395903a7736dfe10e9029de557e933e5740818b860437f13d3ee4f8ddae8c712a65a934cc9bbf004b8a695e1a31d2269f0a9cfcbb63f6f840e470bcc02738864eff62ba58ebca13bfe1042370734f4c9ceb9bc0533bbd12c863cc9aeae7fdc1a7be5bb6635657eea14b29f4c6768baaf9a19dcea6f0f703ebff97e6b3935426e404fff442e4a5592d76dd09848953da1f6d6335fa7587ce91e75b67f8a2ed39092b1e5a763e701ec82ecdb3d00f0c30322f069cb6b07401943aec782b47ac9eaee009f76ace58020e245c0d26e413268a823354b6f40fe3e433c09138446747980cca80271baa726076aa80b67b0efef9fd6fdd472372eec55b8516b569162196378dc9d3655ae1855224b0061e648f7369a31a6179cc7344aa17e913517d1ad49cebe93295b7e9520549c7896ec098dd535ef4c5ee36305ebaf1b964f8b66d8321211964eb46ab6d271077b19562625acb1a6efc17a44f76f5356d68abe56fa8d6c646bb6d2f38dda42b610e975f0920aab86793100ae6e5475e4c879ab7bb69e0a40034d9c5318012059320012de20bc71c6549f229e308ce170c8c4268443763468528870c424022d64035fd6e6e85277eaa195063fc371548e57358c4d5a4ce539470771b5a4b7b173a7a5df11e771c8b1966619feee80a02b57fd46bf0b14f8a16fba8af8362df6857a96585883888be27df52ce4d3c30b0c8633969742038c4c336733cfb028eca631898caf1fbb0c216eb740db0078e1063bef6582f3db739f15921da9846c4c4c238a80c5598b23f0d1d261c9f9156c8fcf5c4a20eb4a06cc25b5ee803604969b4a00bb39d510a4307c28111556e222c023c7f3642789cd0edcf17a1de0912b028567bb426151352de3a04edec2447abbc9a4f2118d2bcb809a0ee92b004e593833a6ee379365114878790d805a3f4dfcce0d38c796b78f022df1d8e3bdc6ec899431913bb66c4398cc66e27fe48bb87ef07dd89e993fac7598a3d599da10c57b8ba6b5bf178f4f13842573ace87a1646eb26f03c022bd49958ef14b73834df9c62ee813f72040387b0fd94f591e32e5641f6ce2193ad26921d962174c8e8ed1837504a90af669c33c2a5aadfe300e8801458b3b7a28b4c850ee0bcf9878958c911098973c366a8f052e12e94caaf8b91d4443391052dbd6617f91271dbf452d05a33b7d2ae0b4866a433737efdda46d16fb931f166d337552b659ae2155f067f2ed87496be51805ee2b3085810df78be40ca7460223e6f4deefa69c7bea5c8eca9f51512f9a83620a7e5b209bd5627ec9d64800be0144b1eb8b10c0896b8b119132afb1f51102b5782a5a7c960459f44a172839c923981dd941ed83ec63f1c3f2f7e755ad19bd1b74f7a8861e92f3bc9e179c540014c106de3ccee0a517c83c6d4c45246a4b40388ab7b1986700aa71c2af572862c0701eb909922742c6555a48a882323c44c9ef3c9137e027ebc0e301946d1b54176e6a58a01dce485ce8fd8ed5f830f49d5c6f61550fdb0f46ab5d10a94f0816dde8fc51dd831dc323b467f79210da67d44de33ca0f2ba597f0cd09768e453aec883810c09c2a3884372b025e3f48f1ddbfa4edeef9f188487296cf78097c25890982c743ef96a93a33a638223309bb2c8e6ca33d0c3b1d48878b88ec36b4ff6662c409974b56e676f2b7d47ca447812f1df15d5f92405ff93e6bcd08c8923ddb8e65712726bff0df0e4a546b9bf087308e86f92e6540d83d4cd0666d25bf321960ccd9c2684c9560002d6ea27942f2aaef19c24bd49dca9fd48927d2961f0eb6c20b07c41d9503e55cae30bc7b9a46e2ed584793371173d35b23102e91f2bb88d25361ffbc733ccb66ffeeddd375348803ef3decac492eacef165d803c8b66cf6067c86757c5b4f9758b68f41e7d5f8339a44ebd15d8664409a083f9d96900d93971f8b6787833a4110d03f69c4b88799492bac2f1fe7bf8efe7fab3cfd194708cb146099fc37e55fd4a9777a372593ddd24e7bea812a6584ad2ea3c33c7a9053319ed436f2d6cbb6a7573c6a491b975a04c08446ebda5ec520fba2830b2a16f3a7f6e5d218328495e383adb814b059c553ac1b45d17ca1aae290967b3583343726620d2cc68478be8eb39a3c6bf1e186b53a5538a4b84a9e9cd041da5a79409830840a17c842bc45481c032a2f716078b30bd8e127263fe55083903c749dc52a48e86c60937a3e3bc015d10400b3006c528a55e0c529f0aff3d0d38c1a1c9d2c914ece6990b2eb731abafaf744a19c995221b4d51b5f870540225b55c796851a2f295d4b2762814bd83142c2cc09ac29903d22bdeac7ae74cb34414d6c15e870052600e281493b430d9b6775b0cb3260844de84c1e8e0b08ff4b132484ad16da9d58f060a86eed50e2908d8c24c7d1f0fd5728b3859e076c26212fe43c26db85c9a7c9bc090c4af9865d28a6a5eeb367b08d7d81c178324c998b81351e4e8f0991ea447eb9d63fe096e989770338858e2339e50a1594fd12346d19b686047326a489efdb7a553966b413785afb67fe93316e445e1969401c0453f71862776312cefef2c645d1db88dcf0f503cd1544c1553f33935c17c7f5bc4e47a9c39628e654238dda6cced57bccad93157761b85b2dc76e82f720ff7cd9af7caf491442d1e949d4a38062c4b9e0d6016b218122abf3e7d11dd1a2167f017bad834e9d46e51c3aea6a3f529f58e494daf30f98b2d9dc5a9fff2114b935e952c3229ac47867a24f331b3e61e6e691166c8b6c769f5c083818d0acb2745a4b9692752bfffbfad4aae9953e8980cdbc6daad9134877b704c61a8d653a9d482be474e8cc0f5dd672ca1f0d8615c54092065ee2316d16ce29209b241d5266fe6e763f4251d8d9496e32ca47ce0412e499a3aacd83d9a30da96f6ec2c4083725dbb807cc282c7de2118f93a92c4975eca0e1773f5f8c9a76fd46efd5b6a452a1bf9d7ae4e9776d5f079841eea711af2e404abaa4df33e4f2451ca4deed5e506e3cf5cb4dbd55c16631cd7b6692621f51375a64a3ccb1b2a477e0aa03a0d1bf9f7fe3f6c12fcba5bc391dadea018e3b15c6e95a304751cbf5b1d0b09f1fbab51197b0226f3452b4c86ccef8e7ad604adbe534b995585925210cf276c6a223ed85400ad12004a1a89a8e5cdacea0d44d804f481f48ab8152582505e9802ae7bfdb08bc9ecfac3abe9f622e07cc0b3d7620af19cc4442ec5fd33344858771004f5a58629ab9b2c6238a53b2101ed0a93e0824b674fa7171aa5e3415aa48360cd07dfd17b0380cfc18f627eace1d2b9b92ad7846171666bcceac1c2cf1b81e4264090d65e2ddbe2c048b39a37a2cecce3bd36fd1f40d084f27d6dc6045485be9992ccb4715ede65666b6d7413eaf383402b3ccd675f0d75613be9595992e26b01c349ca3b018df11a6aa06a422009d1ef505bf247a3e1e76926e8de5c93d2232e335978d8931e45fc72be3478741b920c19051bc8c076bef6d35a282a3b46df40ab55560041781142b8ee8c0c61c12122512a127e92d77a2955b16d113bf5320c8e1e2834d724bd5ed38557412f14d687f138285379fcfe419b5ae068150f860115b297bf8a50a4ffdee9c0d91016aae92923fe0189573fdc08e1ee1dbe7742afac158e7de1d41eb979e7b11f5ed1ca560d3ca4a71ca539d048c94f156f1d0dd9a88603ecd60d7c751e63c7b22e4e4bb5ef878ee110c8d18ef01d36d61659bd07ac353c35f4eb9d0efb0b7abcc0c1dabf8b460e8ed143b57d2c2fffdb58a0c337a5dcc2401496621f00cb548f760ac920a5e8e2fd435d72840d0875cbff933a4a356b4896db47dd3c5904ee03059d3e9e445320f7eb3d96328e00e0653b822e2eac25afa62096c5a3d28c52fb7e4e8a5a7e2c017bc3bf90ec4cea8b5295450c6c5f66d4c02714ff1116d1cbf8c1da3bc05c3d9a0fc42614b7672a006fb02047d4fa73b8ad8dd502dd162ab2edf10a6d953231fe7917f719ca0f4fa6eb5d854b5a14873eb900ab1b6f62fb5d2817d9c5073f1be900eb620ea46ca1248ca497f56e2321403ec15facaa76e5cce455826d1131cc33f467c999e71ab81d31327975c7b2a6e5713a51060e0f9a92e52f50be06eb2e6f768b51e8bddd00d739a43d3b4a918f781dcc7599d79887dc8e47c7bb62101ce9c5ed4f50b4b2ce501c97054a2e31e2dcdb811c1e4147dc3a38d5caaedd755501b45c2d126d3a10e5d2b373f3c2927a5a2ba438a506c0055bfac4ed40571fa68e08ce4da3233808ddf525029c92266f30de1ae3f63cb445591b9e5281b261b5b2a22bda69ad2c1a502d4d54fbe60ac8eb5b060468309b2bd602f0464894f87e384b04e2de46c4de03e21d965713d1e0b211a5559ee921aa582b8ffaaccde846e9896f1f9ca30efdfce600bfd53f7b0f7a6f757be0cc93fd14cf26c73a92c2bc427449c438ac1e500650a2bd6c2c0dda13925a1cf3fe3f9f3ba5466c8f421a54e5b195215a695c7099e07f746d49510eecffe5d87d2316d099a52b63d732839de11d4ffa90ab055b5da085aa0a966a3565659b5da57098ff006fa0465c1fb00bf382e714564ece06c512d6bc6f216e74d5a47410db394a85c13b014147ca80905bc2f06be6555b15b508c03e72503b75c96a00d4b7949f1183931520954eaf0ed1e1cf0b2cc70d99c4b67a0fde5e1967244192dc155c98aafb44d90ae6f3e0393fc14403a08f70a730aebac7784f35f91206e8cb73ff238d3587288911eda5a289d86543e4cd13f7baf87448f88b63cdc3b3496f0f676e4d997ae2aaf8038593b3509ca9ed06553605811fe99a04201db4236deb22a698a29c68f36ca82770d8d14a7917458dd067472759a6daaccbb9f1ad3aeddb588a165ba0a665b8a97eebe0b69fdde3fc2ad1853344016712df630aa074b9bd4e81d2d9e4b21bc8b9d62aef165fc6005e14f900e388fa7d7c2c8c7624f9c5ad769addeecb1cbd38e109b526c346ef046a6dd574769948e71a1ffcc7fb94ed3ac398ed1a7eb347160467dd095f2ba66da4306400b5e49cfa9f96ceaf2901da946f32fccd191442045b8111fe95d6dfc098bdbe38ab3ff756cd0393df1f57bdf87b665beb2b9f81b719fa4299726d911ac3eb14b22b3304d1650a1e340ea46d7b3296b6d8870d355f77f0654b04ceb23c9e0ef75cac20e430cc3f025134ee9c7244a43d44e38aa604f48e3011f98c33a32a99c61000db28c84d82ab3f9d4dbcf4dde02ec4a8ab6b837451e309db76da39702db804873cfa019b59f30cf8306920744ea87bd99f5ea08499d7ef15959bb592a13ff61f873a23757a46f7c635f9ac8304d7a8f0a9c8a8f8b5929fa4756e3dba981492f6ac19b61774fd4bc4a2405871492f6122faad0ba8e1b103591288387ab481a0ea3832d39de102760058c406acbd9b65df88cb2a3b0f5599c4524978479e880de612271b369cc66ed1ae99d80b132b8054ccbcf44eb09451c6313dc524700071bba7e048ac4314444946c2d74993102559eb3573713c6d63c42f65a8bb57dd873ea7e0bfc1e1287c45310ce042c162999c84fa00989beb2691054464d2fc5c96158b6ad1b59a998b71b8b5adef26ad588d6d5bf206962864c217bec2c2a95a65fbad5781ddec39af36c088ba19c7a01c6cd8efd59d34c43cd6aba668e44f7c6ae42dcf2c3b01b6b8cf25bb4e87bfed6462e66ca256b136aa84276bca9de0120a3145312543568282582e447872081219549813ce1095b08c7462aca0fac286437c981e8c8c5964941a22876046c5c3a7802cd8779da1ad84bdd8a31d81c006ce11ed5bfa289fa1ed56492e01247e0ea9334010f676586c5a6a9d533ad6b21a42856c3b74cbbae980b3444184f21ddf42dec291a28738dd8bfc925b9b6baa3972140d4b2df43f205fc52301f3c43187e1d01472b31ff422d9d580e996a3f2a9bc26345d7f47a9b62b1bd7d5e756d50baac3dd9f73c7293da33682c31b03ba972204ca04d0a11065084770601c300ab7f6c403ebf0dae73d9c69e7b64affdd2a1f0c287a423942da89cb98d3565970723f9d6f695a04b5eede32d2d585c4442a25f078428d4e7540af9304165adc2f547998ecd0b510ae49f34720808829782894c671fd8f24e8bdaccc8ef93b6be9b67b37c5955bfd050e1e65e42903d3560c3423fbe9ee23498611633cd7d281d29f67a0be8a036c84e4113bc150bb9872373f83499e0808140c5ce127a14cfb40226ec24ea0168c6abcd7409df4432fd9ea44cce797c2fb89e83e985f4b3a62e0914ae362e39b884dee808931a080413a4c3d8a055b7c9f4e461b5875c0ba507fc2e0eca8ad78e7ca550e510a2deb5c4b3e6d2d963ba08a49d8fe1b3ba07281ddc234f46e5050a6c09dadfeb1283a19f02c81a042f606ede252e0be0a49f33883d269782f5faad65a9cd1509dd6aea5321c2c1a2cf300a4da6ddafe0f50bb62411eab1e49800fa3494838b30578d6926911e64802ce3756dc5b0607008e858383fc02dc81444fee824e92571550a544f92bfa860dc7fbcf96f0ed0d7ba011e788ab6e0d1f7f839d3f2926af360d8fd9e276e7d834666601243fbb098d22042e8fbf3e0a02355a106705d5343db13be5f040ec3c892cc7e3b6667f904b32a485b7a6699bc97c2e6be8341243f0697c32df14fd060a1ae7d3f28cd129d985fdaaaf0ecb972385c9251d05697d4a95434f2e84c933c35d672001fd2066023b5040ed1fdedcca6801922b301f7b2f577eaad6b00c3b778a96ab85112b29ce2b6d37a919d263060b49cbe21523f8e546fa0bf517b84bbb6a976e2123d5544f94e99b0400f86c6670970896445d00b966494a7a58b62027d0172b8ce0760f3dffc30e1bb133fb017094b16ed978422929f97b604b5df52a721909d4b26ea737a870efa1f2ecee0fe994e8b5275d8d634085c5892c22912ac64be5237b40f00a09b13f5698dd6eece0d9f89cb5d70c08bc6775569a0c74a999640caacd892944dbcb3336e8941b01a1175f57bf27d0e872ddb94bc6699c7b8b9e603ccd401c11ce7e0f350c3d38bca00e3bf5e0842057615c1e879cac89f5a73f2d2faef41ca599d2387c56c913a73435b643c90624d2b744eef9314a3add7b85a61d8022b0a6ce8164cb3d481b847252ee820fe17fbdfbcbb9994852f844d8ee5615723c9393e4a596d858347afe0dfd9832e5f0a80ec8f6ca61bf6841bb60e7ca7cadb057bf41c8b8eb4d7fe16008ae05186f5e14a6075f4e6df9a1875f20de209cc33bdb85a48b00684922ad2107076981807f010abc063de72f97ad500348c0176807820bcc242702f0c22bc000e8c558629bd037005b5af8de32d34c864bafeb845a5bbb621bfc286f587500c55c10fe3ae4a4a878eba0b06528e97fd75ace677ac0c0815b6e7a2baf21d1457e3edd35ee17842e5766e24ed9d268c51b88614f71b5540442f717fd35a002d3abe784f2012c912196e16514548aba933c22eb130aba5ee2955c387856f2ca0dea65fd01e6d0cf1203bb6ec8637be758bb44d7b75a31b6d66ad7c020ee30f4415ca37e0e05197b2dd0f658576be0ec21646b3e13ac1d515e000877eb876a8f34f51c35e94c20b4da188e5e2570c890eaeca4835615b0386057b4fed12d501e211257da9545b68d1bc782612a14cc1b62af5e469c028b6dfed1299ccfa9c7f0467db05a74772d6addbfa430ad56793eaf7ac4e6a6cbba1c7e4d757ae8ae0a24c933b57d5e05cea15c682eddd60187ddc207ce588497c1d948000f84d206e1d1cf3504c4b9cd7a538f573b17a84db640e95765e385a7bb082cb93c92957cc68fe944cc6826d4da81aaeaebb68831af4347b4c859b3a4f6192937de8ab240d33494b735382ccfdc4c6fc11152e07970f98edf0c8394be5ea318cef0eec4f8142573643ad5fdeba63dd0fbf0340119567bad5f180998b633623630385abd1010c5e4c5767cd07c0debfa8a168a9fab9b1719427990737d0acaa5a56fbb11c28551d43e7b18069911ea55dbe525f75660ba16cd62ab645fcf4bd873fd3c4ad3c3981729a22ef371a7ed9dc5d78ea2cad42c00ee198d79195505a5fd58013dfdcbec3d395f9d400589cdc53ac38c1ce0fae2d5bf93a906d494b82846239afa937693e9cc6be2e35323e0e45d35c1bbb3dfaf12730baf0764cfb15209244ba567e92f161f8a3096eaaf1211460870b80a8fe2d5c1387689e696a0e040a0bb4245cac088676a7a7b963b34a4d146e768bd7e40a6e840ed651769dfe32f61e0a518c34fd3ae75e1223f2d207ac169c82d1c376e18ef8cd688a38e242167ee26f2aae89eec9180e321204eba027ec4fef032f65a527460119ef46b4b0743a6b3515870a46166222835558b0dded55c5c8a0f9319d5b469577162883e69bf0cc5e36df91adfebd6fcad2e36ee8bd7fe3c605e2fa18a14cec503749b8b045521c4e9b1649df291d2cd25c40a17a93a13ca5ae299e6923be454b36a9bfc3819b1952a9bec20c24509c6640b0924d35e91ec8b824feb84a57920f57469a2e4f42d959bf16d22919109a6827cb46a78ff64d27902103e78543639e3a7b0f0899f26dc8cd3e1480ad58a2953ee561733fe1d06d102ce8c90479bdce2d3224c1b689479b76d83fd33bfdfc36e39dc7214b50759b4886030348bfbca8b130b05355dbb3fd375d7f7729192a72db4bdc207e8a664ff753f8e2b7768b0ff67957bc14cff790a566361cadc3367fbdbd08dd1c5e785a3692c3bf24a4778290a8522302978970e5480c690cd3db2e75bac7a712eaaf9ccc6c61d05d9877198d4a4a33f52e44294b349c1351f3fda863243492a9f3e9dc187a1d42c9196ca9ffa15af12234c4d254d0678e4de910afdd4e547fe4103afe7c6750d6cf0a37093ffb3fc25dc01ee955d57cf3af69f02c0215df68b2d2c1d318125a735d803038385373eb742e50591fc800b9a799731e468c8654a7dbf43ce86684f7c64c8939d7f4b563f9cede26fbbdcc66aacdecf603ceddafd6381331fa0ecfaa1440d500aea27805ebcb4133a74965752edf2d63d031a45c07771566c249f30391cc0663bb433920a18aa0e7ea63890f39512b2147b8c98aff7990e8bb9d8a24848507121c52875705036404aabff60b65e4d65c22725bdcfd97091293eef8324698e3f261e6894712daa53c7d49d8fec450d7c41d43bbff7ef6e2567411ccb9701d8fcd004dcb8f039d5ff923a03e3dfdb003e1bda22a866c99cf4e280b16eb6c0eaa95ce738356130de58e414da7710a6ca03a90023ce9c1d359720265f2c647248d749448ad8ab758caf49f11f2bbf5b4edcf6ab5dc00d4c2fde080e45981ff874435ba35a9139e986179848698b481a38f97aea635e5da1a1b082f17fd68917187d39df9e920322ba535cd1d01603606fab67594fc4d3565636f0fe020cfe8266c3a05cb0b2e011f2568d933a027739c86232423a39559489aee0d2f660da9ed0ef2223b1a5d5ba0186d7a6b630b147e0c6d21a8d65cf0731f8e9a8bc328121f7a96a60660ff27eb7fba40de49318418921725f1c37b0b1208689ae4f7f1c97e9b844d2c2f5684efc8722352469621aff339946e0235c7b8c619619b4bf477e1f7e5af4751027160be6706e30a573e52cfca2db45e007f46e3603f862513dfc253cfed582ebf86c04783a8abce33dc66906c6ec789c13ed3f3e61a6403edafe6b439a990a94712a8da862ea18909309f1e15da8b8812d95fde3b4595f624589fc045d309f287b5a5f22d8c50df6b7c9d69355a9dc9528f1dca2be79b24ace35632d002c45a672f295a85926aa9abaf421f6c9dc02418e68da3dd6303f6dddaee5068f014720a9333690e967c52541577ed438df38f8840c54e6044c7dab9409e271a4e0971f41d769a6855690171940aa8e630919007ca7d1b531ba2a28e73c8711ba2a16ec960591b2735a1df2ec8a5c4e559efeb618119f1949763f8d3ad5d3c1a13c2cc76c65b1247550fc56a98004c10dc4aa26c71820d1a268b7f5f1a8c9c28648130b77a340b8408bae9ebe062d14594a7af3a2b66135c144c1958109833bb5c082b349a0f88153a60f496253607689dff9fb5d0751a3990cc9ee5369a09cf11e2e6ef4f2f4fbc485c10d2b599959946722296741ec315d893d2ba0a469086ed0b704802be95535b4be6784b3033665f6d8ac4708d8bebb1499f56343eb4c018fed659f153996de7c5608778acc0e6dcae102b5109e4af790ca528c11ad5f22563cdff474eb3d205a968c5ae89a1ab5185c1e9a83d9bd6518f64f5f5c231188835a8076a9848d6bc6a9c3239432a4b3dfcb83d109dd851e4966d5c11ce0ed56579080ad984349f5c21fbacf54a533029020a13abfcde1e3cd4c08cc4aad4b7f0e8b70f2d26d9cf0f45097ed96d749aa52ba5f269de075f58ba5323d48374bfc4a69aeae59e20f9da4e0fea007366e811d44f89c0ff941915304ec2da0fd40e087b0b010c5e7fb3a1b15869328831e09b146f928bf84ca0e723913e65180268fa183a01a967211f516f44cd23e78fbf11886f6bd31518cacad4ea292b9baae82157a7f07a1f9c921b0124d6a1b84e0f4e94340e22ebb9540445c2242c26f46e121c44ca739770c21f0d79bfc1f0a21b08ac1a62997329140b9ac0ee2e4f0abd1841097c0e478cbbcd7d87e3692e3bddda51c6fe46172bccb2b49c988f4cacc467761e9bda6d8841020798852d4cb487afa90a66044843633f42aeda7c4634748263a826f7e6c716bebbc0282bb9b0a2bb64586510255f5610812b553560e9bff9216065f69ff98b329bfb08260a446c0f0392df4a000097c626b9704fd374798b816790d1aa980a916b2a0f5c81b4e84b1439685481d19b3aa951affd2a10164082260d4abc85690ffd88a372a6864b50e43046d78ec4543cca8236690f8ffc224531822318319fc74f1b5283e4a06e1f597b0e7d2f88ceb3edc721516626e346f0467898830e92e4e65f5930538fcdf08fd902f379e5586b39c844e126d34f96fa766ee72be3022bfc7dc4fe19a18267be10bd41cdd968144dfe318b7df421e5b9e790cc743530fc33ccf10553a9135ee8940f3de66ebe6be97cd9580f3292cd007ca8adc456ac9227114e20210efaf0b0d75381f7a27ac2d1229235b91def09acb551059a44f015b1ace6bed269e75b861084ba3828fcd30e61a1aad05388251d48a61e64e14a5ff68eba8632dbdd149123b8987169fa3c50e95b1b8a1e6d4cd79e591f51f4b595b6ee7f38a0601caedf274b853c2783a1e2def7525a03752d44f82e6aceb53d7f158256ab5ad1d4fce2ad6283d4d4a5171df4a09730ac5c6d5ed026b86dcb5bd25f8829f652155d813146d7b4abfc744d11c225d14d2a31220d3978fd5ef2175f1e6aacd827117c312eb12319bf905c0741cce21d6e438f6af9fe1d9e7236d1b317677427500135084c6ab4905e7097c006553ec031101e762eceab3cf011359045ec35ea43693a8dddcbc72052f1356fe819b051be42ff1f1de48bd39cff5dff63e04898dfb6aeb5750d93a9c5573e1e292c707115754b38e758787066dafe481630eca4e256bbe328f802c2d050270a8c69a6c96e9a14386c8d7936053cb37649adbec1706ba86014770e8a45ebfcead2b85174729a8e9f7eb76b56debe6d39075c6ef37aaa4363e8bfd7bb764f7581de99500301b92f67c5920d396762ad99c8b3c623149741e176c7165cf137f84131f57c9c08360b39e386eaf939c1610ec72b1d514c26fcfe0d4963f37da06af3dc152f6d2890b4abbfb34dc3d651d6188856fc9a8113890b01f3deda67045168e1f1dcc01b5fba8fb95df7f7d6c75698647deb20252d6a6ae7dd6065234d826682abc64f8da11c2c73cda8d4ed89a8b86f916417dc94ba2f7bd2a7a8e9100c8411bd2197dfccf0a5603e6506ce762e817fad0430511e5a13967482a3ffbf92c60d826aac19ced544d22d1288d07d9ea7d460ff35aa2ea82a98e79a9e2bab0c28604167f1c1878fe4b4ecf3bc36956798e676767b78fb3b515a75a34a714377f983100764b61358ceb4152961443ca4d2d334abdbf553550eb92137924679c852f16815af77b2015ba0817b9a98ddf3ba1d11879dc87b09ad52c8eaf6719ee3e654c77e924eb1a8b8369e58545b46c5d8fb2f30be78f4aa6424230e7970b50e303819bc7762a96d9a79f354ff7172d117fd0acd6bfd41377f5dcaa4a4e0dd397d8765b159f65492070c3657527d8e7ac95cdde897d54f34eac746bccaaf12b41f0c3254ed1f11a3b8fc2fa55d3e0a82e84cff29b5f3ff828772d1e2d0009c65225fc98517051c4b655aad449951a6d09e41f305190bf952a5ca77a11053bd161b0ead1330ae6d7941a8e07667d5a9311dd65879dc7a2857d6afad4b359a66943fab6de1b2e5651512a0a20cffc7ebcce74d7f210582d414570c8dd5ed4671e0088280fbe57f599cf81d4fe7edaaa9bc68d83f8946afe4d72c5bf4bbe105e0e576ba343c0c46ed69c37b6249e5730d8601fabc689b939f6e9111e782143dd390bbc369ca31f33de4e6bbddeaf88fb45de23c181f3639a35d7687792605f888025561aa7022d7f75ac4f46151654d1d90f902cfeab15ba5e58195b0c5a73b24931962ef7d281dacccb2ddb9b51b93461c5e273f6cbb926b5ff32720c67b3146e9e38a173660b798edc4c982f3c5ef0cff9f9d26bfc40c436ec346f1f728cc50e3ca14da161ef0d187f4386a308ae7e0dddc5d844dd73df681dd80949beac709d5780a6048bac8a36a0f008b590677a2a6c6a1626d30b4d074872d316ebab519bb9ac070bae0a8b03d9acfd5a1a83192e8562fc099638fa5476ec4e0877dd1b82d59065e97389b324b9d25fcef07eb24a630c8e295412caea10b9be9dfe867d9ae8857486970f7ff2e57faf7fca378fbef8a9dffb11f7695a9abb392e810104e39a22c239411d1fd4a05f7b49fac2117aa46247348a90c21e11289090921db95ea5234ba3ea04a43efcae44efe77016d39fe165ccf12a05b32c9e266fae82c0488cfb8eb68b59da389fda6593c92104d7726ac7c922c42dd562d0173e4eeac669432c165077823f0a8f017f9a07a712b4722873538d5985170bd6bed00281060ccec2aa9b306bcacb79e19851954b7ac143aa05d18f46d696492c46ed831fd14263c114ed5c8c78f3170b1c9e0ec46083afa31a3976d4e1720892927f21e28bac3a562a87d8460d6dad353984ec8148a28e0e018c107e4ff305026f312cc49dd04b4cf07891da4abf302175c6f4da4d407573babfbd286bbd215ae9f249fc533016d5823f1f7ca170113180534d4a0a75df0026a4208055c7dff68365e640386f4a7259dc9b52b64012268ef86018d20a16cedcf7fc2147ea8a61c818b65d8be736f9a33cffb6f4298c3ba464825364a771307f0e2245e7801941803c53406022d16d3e18ba5ec9c3c5ede66789500616c13e36f9e5e7e6535b6bc3e0fb6128b9c06c14b1871b6d270071a4869ce23b4783766dc029a976dc5e05879f7302b8ce1ca4d856836b92b479ff7ceed694cac98cf6da1424eec724cc0ca96a758c1fd69a7367da0bb5773150f11948b13152b162ab30ced998809be15db5327d7609c217d8506c7a2a9d5c7ec6ad8006da39e3c306146c814a2da24e81369f58a603fc2c81e9f940b1ab89ed40d431dd59221b69e860347044a18660d9ee24a4dba4582bf79368d883b0f208026e6f5ba5317eb5db45e5472a7793f568655597509ce5bd2f0b371f39a77c737774ee53933d32f6375001b010ee97628612073c7d503fba3249c7c892130785493b5b9ea1b7a13817b281e978c289df8507d82bb2e44dc798f15a91e5563d5f28115d590f8ea5d5f368d212c8f9661cc5ee57b68cb01149db4798b0065b2a0aa02222c7d3fb0b880e82f5d3819b614721cf56b335219c5e0f5994c9d3d9c5912f721aee3b184e4732715f71a2cb23dad766c571241e53d55e0af52fb1916fd5fa699b418faff598d3619583413a1e32556525c6bfc403136650f6ef87ed2c1c4de256e14132fb3b1e498a0cef87e2357e5c7145ec605d7dad4fa9723d174f9cc76412b1fa269de98042469845b6b2105cb64370da82a18e668bc4b182ae79053dfc8e8533d68a2026221e9ddc285c826fb55763d06e107f4b65f61f8bd7a6ed68e22970280d866ecfb8d3e3c6ab6c21f7f2a46e71b4bd1ad10e49d26ea8d221065cd3d523c00f8c09a6053ddd3b9bfe3ce5365c7a36ee2320d2b892dc33f72abd27436f23bd165c822a080cbc4811de8af64cedb9b4e2cad96a6ce9e9f4fce5432142cde43944c477856635a842977984529b6d43e575499a98dd7959cd2ac0cce6fce23a671b2b154833937b6381549b21f655f3890aba2739ef4bb2859ac5534b46d46ceeca3f0c5e1c949d834edf2b2e4a4e9ccb1d252ae3a02cc434f46adffe0f5ebd407aac94d0828a3974e0e127881a3a30a1d928a31978c47c8d7531edf7993982d0940950681bfd77bec4099d082a8ee80b107f7309bbc81f9d6954f147db17724d909f38cd8a34c9864e978e58eb6067c2680e61ee5a59d09f23c4990053173d8e7aa40d45175db6fb9010054a34e5329040a05ad68acd335610c611f812f6e0ed2c7c897ddfcf12734eee3cc31fab48071c08c45be4cb2fe1b4ace30e65afd0fbe76369fd951e0c242ff7416e2cc6b46bbe59a4ea9551fb01af8d4bc0303ec031348b49f77fd36d1444055d4eee3a778c983629543f1fad81c1958be999b160ca7a62220bce9c233963120cd05e478c9b1deb3a250aca8535e4f8ae3874b2415f4f9526916bae0296a46fab037ddfccb730ac923ce85231d051c9f8f64a37e43937806b68097f30cd22bda4e8935336023b670c4a508a61c38676c747053109ae53579894a9e28b456a817ed45e2e2a0a2ef6b1455a4c720315daa5378116de065c3ea456353ea69443921ad20e54fba92200b540977bca44d26cb0444a6d0fab973c2ef8b98694a09b1c44e7cd047f3c4da7e7a03846177a3773680fc63bba43f21d34b1a44ce8551f15cefab13af9e95dffde6e36f6e8e84e49e2b403706de5fa86e68a8a0d38c9a8063833c4b94464026d6fa84a857e439b93cd0e6a1b74014ce914a854549e4ded46c29b1b9ef4d92da3e6470a4a0496efc925734f34407066b777528258797174e294ec2857b1647988ec61840976dbf4da9fa63196eaff0b9bdf2ac9446e3518518346e63a96fba3360d769be52b6b8d572982b36e7a25a431cea32ba86d99138450c65f4922b7014b23f13db201ae224c8f06aba50f9712031445ea7240b6181df22b6e6587c713bbca22f8dc394329548ca6b17030a623abdde8955551ebb23e0712430fdfcbd3ae92af2f81fa104374a60cb7c4d3c50c026dfd3fcce877200a53dc0180a229a62b2d25d7c0e8ffc9eaf60db6fa16dd10525b6b5e33b681976dd9413cef4d564ee4c04417b5ad53fefc850eecd3a8dacc9bce1d22f146740e8c1d7472d14bbba3658e25802a2e8376fa4419e4f4d62d0f97562d5fbddaa1d3ad7ee1939039ee1fe7b22a2d750476284ae4d3da2d2337e40c77a9ff4783749f14a3f450475906b164037a6bf4409c4a3997d6323cba787fc2328f1909ae3266864c7be592d23a214234e23fc02362a25bc195ebaca45983df7022da912b1ca747a0c9d29701b0714b0a8545b39c1891a9cf1f4b988e86daed65a69886f146e6a9cee33674ae41634e3e20d119639dc965eb81806d3d0d68c3d5bc4720da27290ea35d41a513c4a6e0ae074dabc0f397d497f219571cf9f15c10bac82f14a9c45fdb8ae35c533b5f853460e9658bf40e99a81b38fd8318375ee9b6e546f550a2006e98b775725dcf1a299f10ab32ba213e2fd6b69f6c510b63b5b9622dd0eaa07b12494effd62e6b2a4a593bbdee706b2b53bd16ba2a1196879fa78798767eabb4ceae0b9d52a6690d74448abcb50a1f43f950815473015975729b60a487b11c02203f4889eb6bc3a48643bccccb9840aea2ab0e1efd70aec4528fbd6f2e852164a944980565693845bc04a0de724c2ff4a7ee03bb081f991070c9fdb0d506e1084a231013e32d06e1198d32c8c8ec448d8b81b4b151304179033aa66aa6c83d447622e9208ee6bbcac8cceb1b20ae522457a7fa9179511059ea396342437d2feacc51c7c4ec199ccff69bc0c0434b6555d44f75eef2170dc9972d68d7939c0e637bfb41f11c5d2384cac426827d10b3b9e97450b7261075e011f881347e5114cb13997ecfc60084ee2168de1dcfea59c9897cfe2fc02c9e347ded97485fee27c2dba843e6f4ec57e337b49f677cf3d1e9d4c42848e4a4d179ad0c1bdf422ceb811dcff90284b81cd7784d424ffc7f6af10f8923e9990016315b3fb1f50b126c28a2142ac98742a4739bc032fa0858a37fba741f20be0cfd3b19465e178992e11c119d8d3f406566147fd2741d91bf68b97478a674e19943510f5d4c0b081bab4927e927819196b1043792a3c03499228f8140a1d6439c026a8638328783ca9fa18e512a0bbf1830e887c7afe55b1cd8be895e1224a018320a384bf5eb0253564f427e9b38f25a94000f6ce6b9c1cc389e6347ff1c2a94a697a6c343776303ba4c4ff43d923dd454d8f2a05b715e818241ce46060d1152ffa35c2f09eb38635417f97ff9d106a092418b959905995ad31d303f6699460c79fa854bd6e37a186dfe2f8c39cc727833275c23eae2f2aabb903d1488597f143c13e6603b2f7448cfc28746fe02d746988a80fce8e7cb9b51f23180183eccd1933c3e3586e832821b410f4a9521dafbb40cfa6cf078dc3e65c71075281744fb2e6b6e01c5bca1c8cd11ae6b41d76ab82233c6ae6caf190ffce5bf557eaad523c1758f10a6137322e3bf8921140ff1c44bc2f46d5fccf4cee39f4de3a854ad50d7f3897aade66daff0d8b15de0d592b64a889d4c1323c79d8d138d0b805463450ee135cef3a1aa188afd7e90af9a9066d8e3088b1f768097c10f1fb8013594dc4717484f8685d25bcca62e1fad73d67956d566657b2f2ad3309ba57ce65a06a7aa98d8eba7dab0fdf96c947a48161066268cbadb9e1f1912044a62e872e5b294bf35a9143cca01ea3f14c436ee15ac43bed1bc0d072b9c45da9f57c16f89b24851427102040059019a1a146054968f867c276276d668b3c752d54c221e01263f21044f5f7027ed28456364200785b0258c0e1dd9ce1c635a80078ae2f62fd0b0f1dc5de404df74bf12ce3ff1d10a8f9332b62a1017b6e8ef9e2cb49a1b8aeed420a1d3422c370b03de8feeac3f0f4ad9f5ea45875f95178fc6086c2be660178a3e23ea3e6ff10927f0776b88e50e3a72e1027a9471b6904f8867d345941c7bb4b1816e9573258158e4ba392ead97e3eec428f6fdddc6ed0d9ee62b15398e8def8960e6d0d5f0e2c175894f7905cc8b200ff4ca0147c1cf85201ffcc97df085db2e9565d89cbc69ab354190cd22b7713a5603dabb9b1447335eaffbcf645960c66c46086e266554294108c257171b91537e751da80ba560219314c3f55fc6d05198bc021c0b3d2b84f3042cf9ba3585484acf53b9b6853876fd4b6de9813b8bcc8156f68db06b665e011ca3590f47e18ef1ca5980b1cbe8b6ab7fbf1f57fc9041e46930dcfc28dc8bd342fc9af947876774d7d2ddcf304a829f4632108745209f32829dfc221b13e8b4719bba50b5058ca1964f2b56a2036fc298ed426fb048285c98c2d8cf6f8f36adc3dfc4c31c6512553cb6a9c58247fc7834a48f2e402ecac58def374108b92879b77521de26076be56dd2f30559eb40694271d68716e921b07b680eb0d3d280e32cf978e41f24ed78c0f7e98f58fed6a8e60bf5e15d227ae1592ae346ca659052021080ac39199a67eec84233ff310d0ae0e9a7848552df9e3fd46a7d3f72c999a8a6019c1f3da9f2d1679a97d16706df92d547062a9974f50d897f2446148acb54b4f3ba2a07da7bcdc68329462823330d7e06b392494394f91dd53735cd1de3643f6306c8de2af3cec869d97facd3578bef4aed2da6b9633c632bdf50c1a24b325147fe29140cc719eb2018941ea3ae7f7bf681745261b2c0a3a9cf63769e1922df6a50b7cd7b97de35a3db74d469313ce4fbb1d48419c2231fdc7ca108d454bc82b58388fe75cd2e41b43b9e1067a3e71b6a2684dfc333aad0d74242d3b41eeaf3def0545b43d3514bb9e373545b405298883cd333b50b5a5a22835d01c5416424cb49663e8bd176bb5c4705e1127348ae67a66fd8ced114cf86e73198b9a8926cbd59d88577f3a0f926e9c6accafe1920660d683686185b70954b85108435fb13d5724b7ffa677129293a4ff6cca71bcf23115424ed0ac267bc9dd3b940e82ab41d68279db2df74a4a5e22e99bccf2c2f464c1a611f0041192321490b9b3c0fd7ba79bc58de2b35cb417247aaace4f342ffae5dc237500a5ed3eb69e1e6ac4748dcb2e1139ebe5612c011b7dc4fa639a12d66c309ce7c194cf489a3d9e4deab569d9fd347ee47c785ccd71cbd1f7f27671834e3acf96d46c00a786632af2258ebf1339359ca428a1c8b5d9e3d65e26f9ef70e787a9a5109adba7f3aeb27c79bf906341c34f50255e8bd0154c3a9b8ad1190f17ccd8ba68bfcb432189b080534e5768254891d97c40e0b4cb3d125283c63c368833c08da8925c7b081e562b6ee4c805fbb3f58f718d4fe75a5d300c6335a88404527783c459e42e1e2bf3da19f5e1e4bb0d06c6ed826db31f7e99d5dcd052513da566f15037284204ac6a3557b5817a4c143c3d35ee92106973ce6ca00efc0c38b835660920869e04e85b4b326f86acefb8254dec262fc93d0beefe919783b83c2e9a0b12da2ca3caaeb860957b0405a5bb6b4d3356a6064275f863548995f1110bf23ecd25984e3568aea7572ba476599f27d60713131a9a0e70dc3a5a5ba5f56f42db739039947a7e398ddcf91a5c39985a4a02cdfacbaae106c126c790babb2b09922732ec4d47d5ccd5d566ff8642d32a8379f275c2ec25d8eb5e0f2ec0d80c4bf53bc3fdd41066a7f0438f375f84c299c0a051a85d1c050a1ed3bc6dde315f5eb20061a8558810d3213b8e004ca7f8332e322ebde4f7fbd7f2dd5107f3f0c597e231fa50c8236b23bc6e902d0e711978e13cf20371e9bbf72b14d6e6145fa08c076c741f80387b2179c0d6d8f8785d14eefdfa7ef41ce864fd898055411b7fb8bf7a67a5ca2a7b3c02c29e61d2556eebdc69d42622123b3ce78ca952a2deeab6776c230f7cff2cef89e91c791479073eda87c0dadc68fc8947a24c535aba9c6053ab1fbfdd503330176354eb3be1b7a7a3f2cbd007a7a8292d15c2e7760325449d64507b4f41ffcfa2de31d40d7d0eba1419407069001d548a6e73bb8bece7c88a508b2a1ae02cb1d4032a37e902fb56168e841550cbc0b9fef9ea3c7186c84bde4da69710e482aa3c157ae6a5b4f2708f38e51b91a55827f5c5b01262f84a42ecbc5d5a3060c1f9c457f4d46390151832642d0ddaf3bb06485f1b5c95dab7b54501d0ceb6bfac441d939f8b34a86698995ae137b70bdad4428fea98dad15339b26bff97f6e8827d4bd583ca67e0f3c1b3e1d69dbec2d2ed46860ee2c252981956753523d45d4ee9509270a501d874cb24eef76e1beccf63b6a0ba0472ccc9215782a33289c092fc1fa41ed34df0c5e580aa74e6c2b50bcec6d787ff2d074c15f9e82411fa70f5fe5308fbfea3b0f485051fc99a29d0caba6fb3744f680b6fb82f1b645db7b5641c0aa8b4f5e3c1bd926229c18c69439e40cbc67e77369279ebac52174ea6d903b11d20698a32aace5b20a8d0bddae4750b3cce959eb2e67290423c5a1a74858c60177e5e33565c18c616ccfc0219315da6d1882c4a56cb6172c60f8bb0f0c086661e34701504aed3d7d6a5a81e6156e482c3f74cbde1156da3283cc3270ef9202fdd6e438e1fe9f35c611163efa1c703247802c5de878bec456fb27f81f71e6a23c54412cc6ee053b94f75918cc5dea341abc15da895082d8ee38f5e0029d0ad074a8e7c0d3845b8f594724266679c3cecfdc5a613872f16ec4b691ca51143ca10004fe85404815f469e566f89a83fa59212526d7b9feb62b45c898419e78232067b2776262e3225895877b1f9e189160fcdfb4837abc0df56238bb7f55c41ae34df1816368b784aa6d38bd470121389198ad0dc884da9278c10740635ab62bb638a8a539859f3ec874b7a262e6e8cfbe142aecd25937a3dd802497662e197ae9747ebafc72624c9c530a16bfc933d4f0b5f2e3ba163f9f36356728181c8ab2138b955eb01c88bdd1322daedf4141f307e186d0f05983143c178b8687306354069caf1d937b6c8086c440523e5a12a03b01a944110b89161402b73feddc5e7004ff7ce492ab87c2d5d24f4bc163e201df4773e2ae695c392d5dcdce6dc57902d217bc542645ba85e284d26c746c6cbacaa4415b71626740346df3d3712a8f111069877727f720deee0361da5ceeb1c0ea6e8284a579298ba75d1b985207b2d1879b3ed083ecb4e8b0b08e5e74c14310fb7e2b4ff75069833b5619361eed5ab45031dc27bd7987e412dbb7b39917f7d87c0af904dd076db1f88091211dd0b62210ae287b101971f71019e5898a925142e303dba0cd7a669d42a266c0f29c88e82eab9591c2294001e86c92378007b643d416ee108dfeafa8b57d76e68a2746c853712efb65ac315f8086fc97a420e372d5a001638b64bd2b44b383f5f21999b74e5e8c831526c6f8a40a6628891973553534cfb4d18b6bf2f41fa009e8a2fbd24e2d1ee0eb0b9cc1bbded316ea369609afe61aae588b40f4e79db8325de89743f97199f2a0687e639be24c5787a4848104c1649975e6eb2feb00b03061d811d87f5dd0be4da9b1be0b656efb7e9b15fdd43407cd4aff560062a2631b6a61a6bd787f453ae31827a1597238a2e804fba7dcf0fda9939f8f9f631ef53a189ca3063188794261ab61cc8d6ba57a61672c1f45cdd755e4ac2a8a1c3e84ef04756eb3b3e84f44722d14db131a6e54fa87f3be1b5a6fc1d43c5792272e4fbc30550d27873eabaf6d3d6db052e14431908541df7d99fae59b320b8ac71781f31162f15baa6e539a0a1af52704b030143e070bb68085055038d3d9dd62ae5941a52eedb34cc846666605ac6aa0fb74ab860176bae5ac08f2262af9fd0fe7afb276797f9559df36ecbd6463a3cbe52ab7e245d68ba0716e6f843a03b6041a0ca2d9fba15867864ff4c187f89d16c4296a8d736833c44be46f2eaf3d82544ccd9f8e7ef4daad51074dcb189e41f495e4021d9cfae3a67ea1a147f185a6d23bce5df827b1a01527bb7e1073cb5be2df0bc579fb1b53407a80fbba9ee25e18f76c3435b7ff0c800f00ddab191d38a61cbeafc9d0cb540b0098bde69771d177d787bae3abda7f50ecbe55f7ffba9dbfcec6530e224f7bfb2fa7b0306ead5f47ce4818548740d2b4e6a2ad84ec0d70617d09cd20d6d6cd6ac061bcc379dd64182604fa15db5da82ac77c81c52698eeedf52fcec0ad171f4e9ce442326a2987cdf712182e6e6d31b02d5edb25650cd3e43c374b6b939403315d3cd25b74abed79a33fa26f0bd76571c0aacb2da87628a53062f8ae319654a3acd1cf9fca1a887200deaa987021d39f95d4755cdca992bef28244b7f68b2cefda30281ec6cd4ed6c4ad84874dfec2e74e23684dc70076b2f9400c628ad95c1530dc32f23165df90ae66b25403efad45a8aef83eb58b656e57082790a31f35b54539b6bc13e196d52da139ac7e3dc6f375812e550a78a8c3cc03b58deb4e0e1ead5e53e613d6c3e25d331f38786973115f03533d3248a724b79e04b5a7249416abdf5b02de58054fc4cf8251536acf7f685c08458815c15e80e87420f727da0237157dda937791ee37dbf7abf9f7cb5fdf3410f05756f722db6fd2f3a091cefea7051e32fd76f677952f28f76fbb2b237dcc84671f02539e115fc60c295c9959dc3e0b14f3f6513686060de18f5ae2b37917cf3ce27e273a78849e53e59450573dc6fe82606fe16d4416373e7fc8738353fa3af662f6ee42dcf578d225e61349fe66daed2494b58ef36d8f4805b8732022e512e88b55635e21e5c2ff4feb6459b98a8cffc98605179c5194b89480881c9c002aa0fe94c8cbc2861c6b904e1df9e2a34c8ac664736d0a50ad5b3f47e94fa9a0738f559c65db5d11b20e14c8abd86f39d936e125125e62c1f5a5774e46a31bad445428274e11cb807537c0048a46c6186469eee4d460fe35f4d14c14c75f5987a26742906070713f8aeaef5ccb781c72ae170816ac147b2697abc164fce88150f397ea42542e60fa89c5003334b20c3577ba4a0813d39b7e96b9043acac0bcaa690bb2fef9a53e0d0236f98c1af45a81e2933dbc99a75ab90e45d098d7d25c6655ac53e3745e2beba9cffd16a4fbec5d70a5cbe95eb25f9022d9ab7b57915f8116d9cd41f2d729c0d8c177bff53a4169c08cb4b8db9cbbb78b4235d982176a89c1c205867d2099f7153e82718c0151b8f3443602a5f0bebc4ec08a69879f2c45668f5e5fecc91bb71a5fd33432fb5d100a553e9988e0b7fd9693f187014e595b423015de2873094a0930602dc84c42faadd4a09c9a4650a3d26f6468ec4b41d8223eefc9e8c1eaac0367353aa4c4b8a467e86f4b38ce369f02c326e5158e0e11898de34f63252b9ee353bf66b822beaa3dad78ca170430a1565afe413369282e4a649ed3ad9497a52182823209470202faf29fe3e676c5b66d49d07e2460ec50f27625aadaf3a8d1f8579bd5f1fc4d9e27c43cac2e006ea0665457ca216a03c171c6e0a292c4975302d20049473b6d569417e699043d3c71f5730e2e2951e6dc07b7f46c2d3bcea66294aabf5f709e69d3e1ab1f8f482b0d1231a2380185e3016e7da768be4c4f1b69cf0f8d6df71e7b923499d16bf46151d42f77d7a387bdd45f436ddf39cc02674b48dcea76747833f4cf4b78dfaa06b19e80c37cc5852f641c396827e22a7768ba2631640c8ef629cae0ce84d97e80c3025bd0182aac95565ba7e2ec95c8176aaa68ad1082e45bccb0918afff364bfe3b2d59a45ebfd451b52dc8e5713d9f50ea4ef1ec2430e819cbd25029a54c6600ed69f56cf49c4ca2c6f773057b1b00a0f37f9b8b1fa0848aeb9888340d54b944ae3ceecdbea14064d6ae268ad8c084c6185e4fe1289d33b8b09b279240acdc09ba1e73f9d961e5c44c2dcc629a64991431ce0e2bd7485e4ec35799b4b040a0c1bcc1c1c3babd3feba05f3931e2dcddd26219c2f7f3001cee6965a402dc0c8f07c461ae10a82834e60fd453a130d3cf756ce9f5ba18107c80618b7c9b6bc370b86c4cabbaa58dfae9e829d212a7ad8a7cf66bb914ae004365c15c56cdc17e5a64878533674be6633ef7508cad1cbebf367da261bdffce20c04c032c0f769299bdd63c2a9dc653d6bf48d37de5d1602e0ab1cd43db37bfb6023ff53a996cb4a4fe3ea2825d006a16ffe079970e8c3f64bdbc8973deeef3bdffddba6ec09c3c2306c7d3246c1a6df7a80316628c3a361d8164791267efc8793c2f27dbe6adc2fbfc07703cdcc725574b405ed11c9cffb623d945225845fe464d36a918727588486a30217abbfbd83b2b94dcfda69135410096458bf788adff2048d2b277f947a9efc41c93af95b09e9c95f49d8c99f7c7b38f957e7b96d88dbcd87e7172bac6c40ac9f4dad99e661551ce052d32fe0ad644a472eef459e7d7f9d31b7f51467928a8201553434a9aefd919b62fa42e962eee610da75b4dd8db79a4d3a7cf3f5a659984a65b8eef70033b0bcea3f5ac842d8254f00b297015cd080f6644c32d85bfd3dc20eb1798640c4fe73b690f59a5685e5918c936c7d885ae7b05aff41e9fd8da150aa4ba2c57458fc8558cabbb9a5eb015d5287fe1e6d86255f1d6fab7f8207183e631bdad03edf8907b4821193a5bf22349185096ddf86df999af5e621477a8bb61d72515b06354a6a4e549f0d6f4ed6db6cac0c75697dab6eeb5b4277e61c71b6941eb2529a2d4217ed81d085e641c80d0ebab440b3195feaa00d8b7511d7f415976ae11f691dd0782d4a257c862bd04a96a2d7cd158678ffbf11c44474e5aa14909eb8e21fd4fa8020961fb328556e3d1dfe02e32e5741f3c6091bee36276b88382f1561892c5a84ced8a0da45a24c09a5e1e425a7faba8759d8cc12af1931ec4befc38bbb68457e4e925bf1c1128bd09707e2b3ea1bd6f820002dc7091a3a74d68a4744c071ed4982d830f28723180b335dc21ef6a8873dbeb0d1d7c33a9fc025e2af4e721b0d83d13443afe14a59f76aa7eb5c6eb7a7c84d51dbfe38e10f1bd273603f068ce7427f4ec8c786f518e8cf01e7b9b09f13feb1213d06f69ed73a1b00789eeacfb102ab97301e39acf1aa4d62070634ae320c55d65e6d9ad5b7adead8ab0f4b9535579d66f56daa36e6eac3526ded55a75d651b558f75d5b0a85ef3ea69acda565ef57e76d6fe8fa03522ae9768d6f300ddfb3591fdff8379cce2f24b1f2cf116ffd790db9db9c0b6d223796081cfefece4e725cc7b4303c11e7d3fa139193372afbed43e6270ec7d80867c3a0742a76fac56f640e9dc18ac592a154c91cc6a36438e1c28d64cd15680c53b21adecbc59611672dd850fbed1eb95ff63a3e48785b711f0c5438418ee210a79f30f0b790965488212ffb98375fe153a5abe65e5c5a1c65df55ddcaaa87c79db67a8e5e136614c10d1e284dd149e08690c98e9e262b9a28893de092511b4a1e00319d837145c927828ac0a86b7953164ab5c55a905e984197a959ad70dec4857199689dffbdfbeae914ac5277af374be22cd896479d0e786caa1b206fdd813f0ee98f50a5b70d4252d568f8f4ef7581507958ad0ae861348d5bad258f836f3fcaa870b8b2cbef5685abc428f541cb0329d983227994feb1cd2787833411f5288c7a4f159227eae82ddee1bcb3041aeccf36e1c3e2bd0c9c05952eed317f51b27e686fe53e1573412a74c3e79f4bc40a3eb961f43071da8a8956faec00333f939d8400d75c1388d96d24e4b792d112b51e2e8ef0a1dfc10ffbe80b3dcd48e18fe69bc7c2b9bb2d84090ad03f060cd47aef2d75999f20fbc9c5e0038873231f691e8300f0d937283863c8c33dcc29743d0c9da34d40ae982781b3bb8d57bbb1e0875e51c325fbb428dc7b524ae4f28dc4ae25e6f87eb1dbe2d2e6ce6e639ba307ca531367ce6f7a290322b9cd33f7bbd5b186f916cd031b93fc49d217c23153148d081c83034c00322c93dba8aa2edfed4ce1a26c904c4df3b6a2af27e450bb9963c9755265648f1504355a8a9bfcaab2e2e1ee130e83669068f8193bc030177a3cdc505347e2f85331cb99f76a52a34c9bb67891b0fb2668a18de4f8ad00404f214c0befe54004e5d05b794e7e8906cc7bbb53dab71a6fa7d293ac5c51340b8a1bcbbd052d31491cd2be2579570ad251a1e4b927d39dca3a75b8c40555459e91c1146902ff1e840c723163436a179e34efe24ca188cd9529c8c95072c9037c13f00a0354c898e260411db115e6e0cbe1a1c6011e5a453deb2fe30ae5c5140937f0bed70bf0621ae14179055f22554eeae31e2d30139b7be480c897c36c43de0d6cdbf4db30428cb77656f06652094927ec24442460d41ff59a50a74192215a19cc0cdba2588bda407a43e49ab11bf49ac799d2c5db24dfc8547a1f46f4aa1dca84ec92e171df0d2a432e1ebfb935e8b5c2089cb717f1f27ae96750d4318e0756a8dcda69b5416e00e0b3a58700c17abf892f89e42798b83aee19344269f1c505e01c97049cb0d1420872d3afdb9fed72de9a0eca0df195453b31f2bb6ae8fa6926a4948af57d7ab0c838598836be1546c8ea14aab616d14d5ae6405797db1a98d683eaeff729becbb02cbe43bc0cb44ee7495c77cb93a0ce7aa63d251309fdca6f17ac1433d0bad2d1df5f5a5f63725ece921bf83bf6d1d88fafdb27debbf4cf351a38cd484546dc13494c4de5bc64cd51f8270679e89de8e5bdc359e03a4c107c2746c72cb511abed9ff3c7c89dd7c32423085991cc55b07adcc01d7908052748a0ac817313b35dd3e9594a4ec6970c490160e58d2a20638a5007793b1428cbb7fb0b3902d0edaf6c0ddcef58bb66701742ed555e771a73b458ca6cd211cc0d24ea6fd18e4013c4b155fc095aa8bc04ae282af5a4995a660ade8a0b125b663d85b80917ee16ce6a61b7d9c3f73779dbd9e151703946a03e79cbb5fc4b9328094fd755bf9a0e5968ecb6c38bfa4b97d7c2d6e8ebca409fc64b1dbd2197cb14a67baabd1363a12153b39bc0ba7adfe4078055c17fbca495080245b3a8d2e7e4b72806e750d46cfa0bc3116fdd5a32d326be1b4f82c212e1e7ad9390d221d68a61dfc39df3e3ca4eef4b835c47d2b9e3cb346bf2771778b869eb38bfa1b0cfe30a6541ae4361d8371230ab0c438e42fe903165a47ea98dc9049c737621d724fdf4ad0067a43cf8aedb906991d21dea3ccbb5c424f23ee5dddf49ce5cd8e56a666bfd19ef5cd7dce470640265fcc937d78d65f72c23bf8cd0d869c24418359455a488d36ba9c4f18757c72e2e0abc2f97bf5327b71ed42bfa2da8c8243ee825b332cefac021bd35dade4c3e2ae95281abd16758d899126ddb227516f9e44cc9082d57ede8463b1b356aabdf94fd2237517ee7fed14f20215e02ea38ba2d7b4dc1d90972ba234112bf39ea5c906ae7ef178df4a199bb94395a2fe1fbd18d5233675a279c95164bb606dd32896925587d8c2cb5aafadb11a281a302e25465b8fdb585b17cb85979a7a8af564587b7943547893c36f966133686fdfe9bd548d9bd7a7c1d0f7ab3befa4930d06ee0cdaa5cbf6f4917c7efd06ab8419aa5fb6a32a5c914934cf6fdb89c32f53a82dcb813015502f85611781cc2621d0225e486d01cce4a267ab7438141d1beaf5105587a0226be8c6bf4c447b3d9094cc9db1ed49d91a0a51a9a08284fc3068e8395c70aab4a777a1751cfffb998867cb745c7dc69ecef6ad3ef0896bca87302d522229491e45043ee08cfcaade8a8750382533d1a16a7712ff07b73ab3166fc787bc351879d0780156daf42a805a622d61fa9859fa8d10afc9d54cb014a17a587909586f3528ee1ec2c92e509612ef98f0e2309f58bbaccedaf702b443cbd2895d7e6657d3b7bd6601da15aa98e5f0055a2ccccadfbd12f8c211a61e20764986aad4606dca5811b00e83286f068a2aea0536df800e1a7cf0a5af95da8f73d8d89a918a86b5df5b39ab798768eb97d9cf3ca40f48584ca848130b0af1332bc7df163f75494672a2ebda5f364b7f44594c64b331d7d7604c861302d0d94b59dac11f372ba7e456aa83d9d2bec8c2a22e0dc2dc689d55d30c2ea7bbd4249f53cfe135eee78462de2c83e389e8e87da13b13d58537307d2d434af4f0bb75b120c8879b548a3bf62819c1214881c697232c2d121bc5e9029efad98ff1bb6423fdc8593faad54768fa49d75052c8cd06e4944038efa198392c6c2d6486422cdbefa0a662a35f0a1aadb681c207166af67ddba68649d59e8daa0c588a02a619f5fe03ad85527db56065232f96be8d16f2e371a15b4c253a74cffdeef4e8558ec44567d6856269e17da1ea895947e9a17bb61cb586ace373e4dedbcf8e8d4e1417dd1d463acd755c38708b0a77f0cce86cbac362ea0acbcb8f8db188a55cfb0ed64ff60fb95797efab79957f421803b648b00ca734e57703c6a5ae62c18e54707ba0bbdd34c72cc3d56ad3e186a508973f616cd2927879f6999aa5d7d4ffb97ee0c233b2c558cec9cee6d6fbecdd0588a12034d46502fe28a76305d4a63ebe31659f6aa725787033e08a8cd900d1f9132e7fa8b0fef381ef26668ad80a71448a1d74c9d4637d35bbeb3d56f582a7231d928b78189091cfddba90ec378d5044c581f82a20783817b88f0693e71260efa270f5577bf48fb1a4cd34f5998d98b19a5838c430766ef969a127b46334148de499cde245f19d73eabf3b424e9f09e7964d0e526ec7275510c51931c10ecf0a7c7cfb5110d27060d3c3d3ffdc01a62b7756e8737481152cd2337debab5c01df519da22e0e305dfb9f28a531d6dd22d2b6e894f662fc60a8ddaa6ec59b9ead501ad39346b9c13ff2870129ae59bbe1c5d0304a813ab60a3f855f291a042e7a00f86ab56c66422755aa34077aefd338b55bdc2eb8056ce03da00566a78ce23f15703d41b988b00edb34638734fe3ba915ee97672be46da3a389134fac5c351dd88c7eab563a86e5794be90ea1005171717429d159508e4717cc98853f504f1976d0d49050bbbfcdb3413e0e459dd6f42b74b04555fa3971335a8660032c7f6ac5ba29a6c04497025063a5b3f2430c7bf6d10c15c308cc037dd177f1ca4dbc3334e067920f078942885dad8136815eee93ee01451b3638a79db42a2169e90c0144a503ba6faa7c5a30141a37079d9c1aac1bf75499a599a3bd1333d9a4dc6d957636a2dddc6b0d63ee66ca4679f5e5bc41c866ef25645c4fec0bd6dc6800c7df6573b0784e66bd9dffa15b7e2ed6b45e44b2c446bdc728fe96365ada24b4899429a5aa07a907b20731de3396db7d99b590d8ed9bc69c26a8f6cc53c7bcc77bbca746d4f1036804cbfd0b4eb6c27096bf163cd7b1b8f843a5559565436ff5c0329f2cebaeb065d6ca5a592b75b356d6ea629f1b60a7deb8fe9e368475ffcb538e88e2329fdadd9d9da18004cb4ef6d6c46b21dc757313d6c05e9ef12f6996856ebeb065afc458cdd0034198e3462331c2574822d1605a17b55acb3e24fbd80efb9b9cb3dfd4029f5a0a2aa2bcda27870524a89c220a40695f6400a8eccb30a77f8e60c40a50394536190c01a58d4e8a645dfca0b2d149cc7c0ee9a8e560cb7a9dd4746cf35829b414db2ca0a9e82c5a082a803247ed88edb164327cc230ac62b95bd6b8be1bd89602c553d90e82a5709d6d7278c63fc9131538b93a5c7f250da5a1384dffa9775a49145bb68f92f6f1f1b9e2d33ede8fcb85d06dae892d4d26cf9dd26e10860e0b5b6badb5c27eaa5c7f6f4915f9c49f3ff30c17bdc7f008b664d70b318461183e69c31486190f9ecf38317d8d6db66fb07bb69c87fc4d4aebcdb6ab6977cb6ea5979b757afd3e2ea47dcd3e4dac9a266edbf669a2563531e3b84f1369a789d3f33e4df4af418ed3402ea4bdf6739b4e67a8b932e15524b3561bf41ee441d383466fdf8e39f647f48da0caf926d35ca5e6181281dda423d8f9620718f6de248207d56a6d18fe6b4f722d49d8c9def6cdb164588cc8e58da03cc8825b8b6d188aebef416c33ba2e12ddcf7fb8e4ff719c0ffb2d634e8b8fd17b4a74d52cc5f8207dcb93464fc5f4b73ce95dc4181f2feff22fa3abc6987ed2e83cad598ae9910647b9bccbe82da3ef60b1a5fffc7094dee92873a4bd151985435f0acef7441cfa96bde33d5ec575865d6ae9cf13b76c495eb7e2884b3b2cbef4a0ee0a5b7ad0f50f5961370faa1ee441ae1909b9680a0ce32e4e266fce9ecc9d83e31132cd1375aaa1c07a610dffeef628e3b2a5e97a6832997e1080982d1b093bd9b55a1b86ff640f8c5872eb3c91e43f4e9d2747f99b4c24aa6f8f259d637fc84a48c5bf37f3c4367c47c03ec7213ce35fc5b041d7df3b21d8b25eaf5ec37b33579b0b0bdbcf5858224e7c70cf4fa4fb7e22dcbf2c1127f389f4774f849febefde477ff773f4c1fdddebc0cffd7dfa227fb8f7e7ba691947e79c1f0d8cd2e9e7cf5a7307dd7af282c168ca11528a20a3882c538c5072798a11474e97a714a17379b290596ef38471fb656cdc2e4763988c1491830b809efcf0451358644f04ed2066042fa45081d7f5d7f43ff901c1967f7f66a3056520ddf9b57263997df69a902ccb5e4876671965947183b0a590ec4e127569414c21220a9e5b1ab9730a11aa4b5e9e4283d4f5c0a7ce5f6659f6b4e73ac8636ce27aeebade7ce27a544aa9ddac0451bed0e27bfe8c6dbce751bb990cd9fd4240b588dd0f88eef79ef641b91e371196a710c1da7c76b4ebbaacebb4aeebbaebbaaeab3442a59125d77b16790a1139b89de8d5923ffbd0975ce8b3a7cfbf81107fc97d22b0dc1efcd087c0186e22102af9b9f7d92235e33d8b65df9a6559c6bf818c72bf01eee773ef4f4108703fb99ff5bbeb5f4e1018a94c8d78ad6d01032ba00401e5226b910294d7af32a85cf141ac092ab030620951a05c64580ea84e81932b8ea05c6401098a882e584340b9c84160c23f00630a2b5e2817bd9613503909b0a204305411b0065074c1990055c4250accb1f0c5155817414ba2479079ea2c30488207657a82eaef187fbe62901f2f6b90213de6c93610ac5f55a3b2d7d9c10554f6aa46695fda981ed9c8d787a3b43186c798ec6bd07e1b8938f15143f6db673db6bf71ee20e29059ead7c48fc7fe187b38d9a679cabe633dc64c39ce1c3b32d9dad698f06c9f9366da568fe0b88e2733333328e20f71b6e219511019a1ed99a396cf65babbbc7c4e22bdbcf44b167221895e605e606060482e2d3030230b030323820981303030a6ef081818b549d90be8d840d43a3ac9b4df1060e7e74db5cfb2186d9421bbda6be39091ce39c5f058c6e9f63b3c6a1b9d506d72f6f46f0865c86ef6d938c4493a7e9b17b69b099e4743566cc6aeaff1950361e8bccf8644d5855d5a5a5cdc65489614926a584aaa2f4cc8902c2924d5b0a1157186621c304570bfeff648e90c1afc62a2460d7007c7732c71b03b8ecb658d0e00046005772bffa228ae100000d48811451a33421544981792288a2e62cb48b4a2288adb8d503f4c10301542fda60e0aee4dbd7e2f31f0d869fae4d12dabb53bbac3a33e5a86d73f2ad6eee77b9ab83d48df031dc0c2adcfd973200cd97b1e2883e952eefb6655fb8e538159a0ef8930cc02fd4e24f50dfa2dda02e4606bfdb8bfb1d2281e33151f9e253a299816507a5849b2c47ea834e151e96081b9a028610565b9f2734d36c2c892f4370c3f549af05015d5c102734109ca72e5a7d5c48fb80a088b14572b212388af849ab08d23d484a53c43fe6c49b0d47dc451da92904d3ae90c997886df6b8da76ffdf48672e0895d77e09329ed9fb77bce1962e2d567999bbdf7b494b9b5fc5b431bf692e600d23766a8095bfbb217da81adef75fb57e7a4d99d978e65ce659ea9d5e7e7dae9b3c6d03964fac60c8de09429edd7f92ff48df933942972ed7803cf88e6bfd0fd7c8e9bdd97fe897eed1796bee823e3d055e66affc5c860aff6f66a74d478e079b67b2ce9ac3c8363a66e69a2226dcba856e9b773f9371209766bfd2a4f8d1a402187b8b0fef9cb1385bcb01ee86ec30fd7696041e38aa661c5695041411a55501a5664f5d3401a57341a3ab065ad5078847868da130641d118131a998cfe1b63c0716bd2334fa3b185e0528bb5249801a3f7e726d7ff13ab0ecff868ac3a70c95f0549ae33b9fedb58c1d6f5076b60cb4ed59d79aaa9593ac2340d0493e00998a6590eaac016b89aa7518ae7ba3796e093eb60cf0559d77f648148f1d7752f1f0c0f56e3c6badde0a4bfb644db71d2e7a8f138e94f6baaa6fcd44baa2a49dda94d564faec36ef9654328e196953584eb9632b7f25cf7da73fde964398fd3388d97ef37b80f315f9873cef18629654a3fdcba1bc7496ff5ddd1aded38cd12b6692534609a0e82497fd776b6160176903ad2430b92b0cddc6cf0021f569d5167ff66ad36744a07ce11827a4fc039b656df50b1cdccc672b3010fd7fb5bc94eb35a9da36530c4660312b535f5b5c014db4c5005aa463da08ab278c66b84cdd258990f8e934286f8973575fd6b6a9e6a543e2bd6ada954cb2ae4364cf0b232461b943603b14db6c3013edd3013ae9341ce53894bfe3555ea2c79e85231745fb0d8925d2f5bd8b232d0c5c2960c04040808080808482aebc2ab3cd6016c03639b1648cd890ab365e6c4f5274b7cf2deb7b164e1fa6b238f954bfdee97244992244918100d69f5b79189e405bbb0da370ff266e36b61b5f24328b0f3fb6f9cebf80fc4d9872fe3343463923dcd9e34956c8462f9d7ce609aea248dc7a4ff2686fe3222934e83a3b4d1ce12aa4ab1760ad114a2299c64dd32337f562c8f22d10ed6da2eec17c26249eeaec2120478ccc528016042d52f57b84c6730033cf1fb4e6cd4a42213efaba8aa28ef452f2c8f369ca4945d3079c9399151212feccc28cd28fd8981679c131b55b9dfc184aadf456105f8f08c27a0ec299759289b07d73f014cc37ce253ff48c1a40ba88f7b23288f137b25366b76cf7d37f62aa69b15d3df8df5ebd83c63b76298935d935d935d935df3cbbec2960d639bee877148f27335710efafdd65f065ce217c628824b7c11d03798d422b8e4ef210fcff8c3fc63f8af551bc311068b7d3f54697087a6c39cf3e7e9fbe8ffffffd31fcaf8fff7fa3eb0dcad3e7687e8c630a309b67c8e39410441c0f7f9186af569f6f18921e59d01e13d1c4257c8fc6c903cd39f652de220a4823b42f7035d864f08ea9de30c3c799640c0226012709017135ce798d3799b7bced07c2a6a16d75d0831f08c3fc782c4623113cfe090e91c25bed1cf527418e0762cc8ceb6e3eeee5ebd6358ec0b37947ed862c4ec08ddf9eca7ef79e61b6f706f0c230c70085b86b77beeab2b8c76d9806301f1472a35436d4c919776a77e6ec794f8d1aafcffff9b4c24c902125419e670155be400085544e3620928facfafee6920b659c0f55ed9fa965c3d7105f87bee5eb97f9e7eccf99aaff99a2f7e0d619bf9fec4c91e1f01e7e824f8864b098e82b6c38f2043aad8ef961c04430c0dd9d3af211b6bb0ad76f9f8f7ca7fd542f8b265b7c856abd56ab5baf5e3dee1a0b62a1293c562b1582c56b358ff930536cf9cac56ef78e8fbc6927b4dcb3e0a665f4118b2394947b0f46fe62c8decdc0dcce79e8a25c3eef7a5919dcb11117d4e8c8f51072328f0fdc3197cf222b8f3150f564e912941200125b2d77ffb611b866234e6d8d1df3828c6f800dfe55d8ca03c2b76508c8f960e9a2577e119fd68f4951d9de5bd6061bd10c1961e731ff7f1d84b15b6741f9febcfeaa016ca1660f8c6728244640045092191512c506454f81d16b69c574c16abb63c0793b81038b3e46f3291e43fec4b86897f71867409f8d445e0923f126e9614ce84c160305863a971cbc6a2691af91e15fb950bab721da7099aa71eb34aa172458b56f29dacf708c3fbd34a5a89efd430ba73f574bb8603eb7f33bd3d879818ec5c6596a22e425c582b9674b2c5509db38adc45b7acb754036c82259dec1d78ac13e3e9739417022e4f89e2c37d02c5de16fb4e07f80b86c5499f3dd7759c74d5f539291deb9d3a3d8f9011e41e86bbae4bb93ea35ccf71c96979d17b45b0255dc5f48fde084a24c6ccb76f0445c988f908fde8a7e843f4966671d26bcee843df22da9c1c582afe480c99b0a5b358568a97fc6bb5360c3328604e2847f4a3508aed7eba57e7ea7c32203fb5fc774b1a03822d69ac95f9f8e9eb341f6c99b5b29e0da873358cc62a3886df58fe77598b1b4bd3cc6a7c604b2a856da6d028fad4b966c99ffec0fb925ed17d49b9a046985fd2245c20055c9ee2e2e2662db6d1ae7f9604db68efef699d6b9e68b5218d75ae4bde8eb3273c7383d83c6538e892bf675cb0ae58fd401545d6444ccc96540a95e2343ece00d5a35a46f6d293ace5a47f925b3a14ad0596fecf7f0d8461e41ecd4933d1ef038c7045091a2f4f714189b56e3ce6c796dee3b99ab8963069e9cbbd0d07c4362db00d6df9f9d965288a10e27a2d226da13197c7df092c4f71c2078aebcf77b6cf902a6b39e166ad79a231fa04ebf29428539a785def99a7ac35e5092c539ed082092f1e5069dd2996300fa8f05cffec4906e5fad71b121bd5a2df39c305b67a7737d7dd3e335cd06f0158e5e85b12d7a75c9ddee3ae9e96eb6766509c663ed348f1e13902b131e9dfb8f75590c7d318dbcc9fff52862db3d43d128b42a1601b3ad23178c6798097c6aad8d27be81036e634d90f519694c0ca2d6996eb1f4e61cbac15a3e1e61c59915cc2662eefc97ab21614d655b7cc5ad90da8d8d4afbba338a885ec3a0b7cb25cf21771a2eb2c2a4d220eea2141414141414356b40a9b6c3033576631366dd398bc8ec251abb547666d9ab1bcf96da2f695823bc8ab8d96c4699f06ee083d38963517fc4d0c1aa3405fdc50d302d18fecc8be68649aa79691bdc4b930a0e5e432dad08285b1d830862df9f563ecd6dce564bfa6698e849e7eaf9d749a17bb654318b6ac644d3b79bf1fed9c3dd670b29ec0765fd65bb20bfcc41a937d3796360361e0464a5e6feee06ab5fe55e1b14c29aa2c4262d3b29d79dac6d0b5b17687303c58ef96610c77c1906db21d26b6e3f1ce49129c83d4375a6c436194e89ab0cd7c52e710f9860be0fa97309e653bdc4fb7c3137a851d0febab2185d932dbb9e4cececececece8ea85585688f27f364ce7e76d7d1038ac852adb53689867517dd32311b4d0216caebcacfb26c766aa7837a49bbbab395d33815204ed31f7aff21f3f4bdf79fd8bdd775cf898c0299789f79ef39f78fdbff8d9d9a25d52c1920b4028be3a403b13aa6565a06cc5dca921603359525ae5b3614b2d2a64b6c7052b483dd5153a36535e4e660113ab68d0b2f2ca595ab349fb2675b435ed8d9bdc4a585cb75931d992693c96432994cb3566bc3903479405ae59ec57558739aa609c80464b22691c994e32c98e2041254110ec9112811903da144a39398ec996deaf5df78d8660157545f243615d504b96dba66cb96355657eba16375f48ab0a5c75af5b5d0bbd6ad81ccaed1938fc1257fc275a723a7023b369598077dc85b3fb6c67ab223b98da5a93479ec04b6742c589ca6ec18908d309c663ec902e914dbf0e53c86a3c6e4a4af566cd331efc17f15f355cc574042a368ace167c983b0292a4ed6d7365ad671c7fc8c6674344d95c73c88052ef9d728312962269e7999a82cf198c7ea0af496215a4878df9c81674c24a55eefac64e008304dfd2a537daa8f0f57b94a67680301d3642408e225e9a20571b2fb8797806033986cc8740e08902f5421bdc5b15a1f36125c84ad1b906abb1e9b244bf2e6851848b25b9b6b2e77ab63fb19db6f5f026073bd54b1e54f72dac832b16462624bd2a4a1ff9f4dfaf384f779dfd951546bc85a300c59ad3db195393be3c66bf70dee81ccd3e5923f57ed04dab6ea373ce3cf72b1582c1657371d374e368bc57de16962741c8967ba91e425ff26bdbcd4a7d6e285737416ac02db741078c66d98b66df3486ce39486506cbd2549fb9d256c13ea2cf8d42d2eadd8c6a1f889fb2aaf700ceb852bf117dbb4dc530c5cf20f9fb837f12555c71ef124ad049faa0ea0e8b2586e05966729c8f71228d647eedee0241027bdfbfdf224ae013e75165cf2976232954aa2f8027a01f9caab413a822dbb45ca38e3be629f1802cff56f2db0748eed5b6c2d78bc94b02599dd9244ba2114dbdc37ea6b608c270079bd5eafd76b76f7eba5c542477855aed76a6d1872f8ffaaaf202658e699155dad66ac6ae6c9e45c735d3535975f3ffaa7f2ec08c12ed79daef0ce39524ae7970cab4eb0432ac7a71170c99fe346a321b5776265d46aedff1776392d8413ad1fa08a7043f800d57d0e0b4850456850dde8a4ec57c332180cc6fd42f0a261482c8cb9635f10b661ae613ce32f433eacd5629b5e750f5cf20fc3d188d3b8da2037eee8ec5b487663b2f16b62ffc6fc3b0806e4ed8098b0060cd630186c4b85506032916418fef0d6010a123da8229b9420504e9eef9c3d6cb331c1a71ac54ac1548c804fcd44942e81aa97e8257ef8bd310ee8184bd2746c696b845a0eb60cefcac1ef9e9e9e9e9e9e9eeef9e196c0ccfcd99cd99c324c273e5071996ccf6005ec36a69ccc2fe224a65a61a71151485645266a824d71cb031c806dfa3f0a4ea8828721ba584d81722b331882142cc8a2478707943fd7865579534ba9e392d3885c8a1ef43dfc7ff8dfc4e0ca329c9ad512b0eb4488199d94d2e7e197f21cd9b3e1a79a39e2e81b97cbe572dd48d183d591cb3d40422501977b8084756bb5a19b4ca2327edaf5c978cf29d3d3dee69f97ff663215c76f8ae46dd73cb1af9c5c72fd7b2ced6d15cf20615ff3bbc1878441352f30b0ec426e08c2d2f71bf875691028b8a7b8dea2819d545ae5e2c1dd6eb16cdf925f9dba4cea8f97ab5d292f881b6fb2d137841999cd916783cdce4708c3728fc72b244cde1edb354bfe2e977705c8742b3664c5d2efcaf5675850898a0d0244cb461f16a8f5a63a95621b325e681c3f71d9f748f11390590ac34fddc44b2fd2c481e30299960613db414c930126a3300d8e936c03e434f4b9a0bf61d8208e33c0341f93fed958b9cefbc090c9025ce7691f08ce100a6f8f373e7565a968694162475b8b67ecb8b5b656b7cf4929a57466d9ccb21108a574b4a19fb3cc9015ab51fffa9e4f181eec16b262391ea2ff40226c8a95da627fd27c7c2a6b9eb4d72cf1380d578ff84903aa3a308d16e4a46b5160a7d161a5369d4de534b179ea23db6b9e3ae59bcf3c09c9e2c3dd2d36372027fd373098f4df94781f1812d9518bf78121911db5b4930f0c89eca8c5e50343223b6a7189cdd3c6036f6030cd660226ddb7d43c8dc62d082e7916bb1b0db6d4d6e46e48369611b6dc5a2f1fd6dc7ae6c9fee86bb5360cff6bcab4c15e5a74aa553ca3f3b3f9380d07da518b0ba96b6e14e2a47f8e38c449ffbee69620e8ef6e168b63b17e6789930ec383ad3a5b2b64c5965b2b02dc0d812af048147ce6895d7b6940f30426712dc8694015683ee00ea80428fe3cb98b58d00578c6bf0b1b3864e02161c56a9acc01ae7f5883a4851d18b67618665f8421199a9ad6df361ddbb6755ef2d739e2790c322bec7e0ed9c2f66a3b8dbebe08044cfa83de7310274722f5d2fc2adad04bf32d08482f8d989cdafb74ceaf8eb067e8a46b7724f6dcd0db52c8931b1a9bb59af71b716851076963db9e2ff7a4141337f2602a65583f668eadc4c925acc5dd49d243d60843d0412772780a2653b050394510e0c31228a0b42f828012447105aadb7440e568dfe5e05baec0333aae2b802ea0139d6835d07efb0a68bf8d31b302db73a81e4e938ddadb30c8101c2054cac9470f86350ef5ad0a2fa3d16ce4e093058065284c73523add338d9a4ca64dcba8b561ad0d53154dab2a928ac433a42c23b10dfbab48b70718c840a5fa81400c532357d3b1fe53fc2ac7829c3a35735464a8542a958a54a9361d1d3a74b40e2fb98e5ec23f1d59a6836d422f3787f67fbf3e1843437dee6ba8cf8d356c6fbdcb200cd5880f64ecd040e504103f28414d60071a9441043196e860069bc85b0dda73da6fda1341f56f3d56edb79c6d133514394b74fc204370804c066198389c6a85a48a98ab6894852dc330c481c16030180efd81c7e2d839265f54dff0af4ec536c172df58c1b582cbe572b9b21478bd5aad56abd5aa86bcb0b3b30ff96d7412173947f7c0377ce019ff52002fe2f0a7a52b02c54675df77600f909fc0adc2d52a0bbd1fb8a8822a3287806290c9078e3f6649c401324b44b01e03b6e95592663949bf5f6c60afd818acb2ce4193a47bc5334ad8b2e687051cc7ff6b7eac5eabd56a95d1b95a550ff5b49060ee44ce90472925e709038db3040bbb71e1fabf5ae5820b150683c16038ad96cb090e674dcd8fad66c82ca528a5b6fae0f5019ee9e76e8f41b2d8b297e89eb259ada46c9abdb605116b4cd586644d8debca0a7684b8eef95779e64d97bcee7831fe4368f07e7b1fde6fdf3de610e99efb6dfc3e87881322f5b7fec4d4ca7160cb4e1121b27ded3ea6df47fded7dc4f44843fded6ba8a31d6be8c656e164599665db4ac7c94ef5604b86a5623aa6c7981e5b1d47947f039807df740e1d7dc34f3ff35c850e17cd5ec7bf0e6d27732f891320274f605df48debdcf39c522c47a162ddf2af6a75fd65388a1c92dc1ef344c7981f5961cbbfd9983a400cd5ef69a08f1c157a50f4b31ab4dc6bc073ddd94109308a8ee12cf987848d80115e5c44e149e284104674308517ecf860091e44d16117810d884842c9ce1043e8005584162b86c4164e408107148f01860b9820038817f01043bd70821f24769ae04511c040f9fb379d9e28e4be6d21b727a272e592a61a9e8ec5aaa44db47def78bf7df97387c5da444a8e701d27037cb2cc2506e3fab7499bf44e6a04ab7ddb566393216ddb0644c8909c1a1aa3405fb4200486c02fc4c49e460cb03fbf796abce45eaaa9e1a9a9d9b69f53f453247a065b241a6f9822101b703ae5343fc5edc56ed5a47a87c5309cb90571d286f9cd77dee0e43604a7b497e464c9586a4227b7bf53d4ee0eaee2fc849c04c6d73d3dff9082307430eb646a9ff7313b482ffb76d4dced356b415148140245a391e7b5fc376a1965df6735cd6ad68a342d04825c58eebbdf3eb1a4975627bb668e3523efc7c463973bd16a771dd97bd9d7a66eb51880ef82a1eb6533f3ce38db42f445d7a324a53274febc73d26d6e74fbeae5e199b55a1b86ff2469ea3e0e84c1033ff0f340204256644521db8216bcc09060482f307fe340b86ab6b4b86c624ea7fc88d73c4e6a5bd8d2de1a6fb14df6348460d29ffbd20279669a56f2aeaa4aae9397679eeaf414074defba92d08a42e0e73dad65d35ee264bfd33a67af9498bc1ab53ccc935ede69883344204230e9ced19defa31617d20b8c0aa1672f50b02af0388d5faf9bcb14b5dba246ca5ee85421e4be300cbbd32e0d51ac2385d1b1ce89e5bcdd8843dfd253d365345d5c462efe4d0586f473e4c117e6fd1b0643a2898119fdc8cbe8499c147de5227aca55ae936556f494eb38e947445f79921c3ffda0af1e1c6873d67e2ac5c919f3d43e29a01d18cb573ca91df4f6d83dce40409cf41c27fd5f4cb873104f3f9dc15dc21ada735d7d8f137dcca0bdfb6c9eeff9d9fff6dacfeebafbacd3c23b438fda3c5cf2af48d4ef23f8344489eb4f80236ce9a9920f6dd27a32f2e00b857bff1f9ed788258c5a4a622b146fc6ca6629ea295769337ab01b0f37baa774e8ca93ccd0711a1c86e4d44fdd6ddcb66edbbc6dfbb60ddcb6d0b689b6cdb677bbbb15c79cdf9ce09ca1394573da394773b6ccefd1e43faf3672f7d43cdfc7e3739409678c21597978dca58227e08921a610d7df0b819fd771d5fa3f57b7f736f16fe598347935e454d9972a99a6fd601b67544d8f1f14e0d307fc0942000ae2334813967e2cbc592cc8dcd1bc5631fba4429db32ba74205b240e6e9e70ad5b442df6440f0c06cc346e70899fd6f9cce2a93e7e4396dc87cdacf4bb50f4c4a5d87161275db802ce0e48ffeed290f4c93023e851307bbb8895858be3d0ae9cb3ca33d05b8e4ff23f54aa552a95488230c71a452ad1eac90c06038323019980cce3cc9c8c06460323263f5c2fad7b45003ab81d5c06a603670421c30180c06c359b17e7eef958bf269246dc2c793024ae9143bc0b0eff77a5c5dbd2fc3d07454e83d51048a409128257a0b5a11113cadeb7a9cb6698c8f4f8cf1f181a1181fa2075f347a2aa67bf045dd8bbad087c0de8972a7a7fd44719fc7b988ca0a09fda1f3a8642e16253d0bd18c0c0000004314000028100a860322d170402e9935351f14800a7d904278589b4aa35992a3309032c6284318218680c00080c8cc681404b5b220f9cc5e6bd3492d34d766ddd02c8c3e5fa64eb3cd378e510d666d1b230dfe3827b357333cb6b240192658e0e40adc68a8da53dcc0ef3aeb9cd64ac2b925bd57efe8b3df3d2dbc1df83114630bda482d40e9e1b9747963bd8ab829dae53fa6c4e850e6f0e8038763e253f4534041e8b89b2ec538e2c7710d05ac49417048c945506497e0682b7cb2cb558305b36d020dfe0442cd6c589b98d83cb5928168f71069bc42595e49322875ab49e1755a1729a952358eb4391f9102d398bca7f0927416c399688e726de656ae55d349e8083006eaf9fca3fc09962a3cb3c1338ae7a80ac8e6f22c2c4485ce3b26257b273eab4bab644876215b5d49c7543c8589c62e99b76e538bc91cdd84935f78c136983a2e0f0f92645886b678f5c68417adc31aee1de48dc9dfbd002e7bcef52029a641c280b920a09a1550cd8572430c4e32e424f2a4f625cfc67b35627bff09844e73fb5ee50d969db3de64d32a84badd967a3e2295b150359926226f699b81e428533202ccea88d7c44fca73debe9b286d9990cac1909064ae6fa37733ec4edfb9360f483889a74f3f7062785aa73e81c596e60e88c8b01e256836902013d5095ec93e349fe6ce77496ff5902a8a09d68930d87c6750bee58e8d4e62937f7fd114528bc8c2ec13afe011a6b087d7d1a67d4b95dc57498d2ad83a113e2a4b9fc2cf5dab0ea343a9343309990c806b9428539b84df61d5fcc8d6a7576c96c22bfe4520d9d17b8ae171d25c5eca69f7633f2c83c4d4d2dbdee80d06c2b50958f9a948f8a1d488f06105eb7203496cf25394c87591e510a3aec8978d4b0c0ee01e25ee8c6a70ce548642803d21d5d00782cef316e80e3d55ff7f64c4dc40c0e1426a8d4feb5beb29c3fc9a25f817452759269314a45d215ce057716325e084db2414ba0c7019e4a0557cb24649159269c222f36ddd224944e262ce5f1c9d4432653bf413aaf2d49136e2c7458742dc2c92d4a4b04f8fecdea2ec63279ace4149722b51e5a2acee0a2f77030efaf01778e4631ca607337c04fcf1f9bbb595a589c8ce43fc6888a9ed9a6560dec997ff553ef856316160dee4088b4909b5186b7a15a80c7181490fb41f67c480888b974d4a1273388ef516d1c4536b5c9a5c139956d8b579f653ecc71445914fa1ac3a00e7c3e8137f4d50fa6841014a3d84b4764c054306be24302568e644cd1c3b41b30c23fbf3dd4f9c4bd50d5be0c5a0e8646846649f22eea8ca7903779fe88b25ee59c295f5a1fe74e0fb66f85507ecc6e7a8f24fd6beccc5f1ad72388bbd51620d3d0584b8068c2746656dfc0d468df97494768f935143a44efdb5868bda432d40c53bd399b3ca751a7daf4182fa07fa22b74dc2bbc3954d956653a3221c022d66e2427cf1116b4a3542f4d0ad54abe3b0a428d08d783580e265f872ff5415a37cd2c290cf0ab3cbc11dba9f0614cace9a8a6cfc2732b412f8f549490dcc598a78204bd7c5a26db73cc26e2fba11812c67582944b047ced9fc0e53a94022583108b3e6493e77195fb92c049b92c3346e3fa3b10a2ea307ea2acbb89336e2c82f7f90a38218c766726a2b3e56e65f3494365c02100b28bb8c0c40ad5e5c69bebd12d7ce85a5671d7039e71375566f919af789c3c05516778e3629a0100de9d4c0b8eb8bc15aede334edcc4e45dce45a80eed14f8bb0e94411b3c1a9a426b5bcfbc8de7c8205237777fd631ce7f2d493ced6ffc40ed7395f823b74bb58fb866c67a2ccba87e6d20ad94e54ea840493c026442fa60bf244ff9506194cf84d3cb9c66736044027fbc0c2a58cea051a34eb3977ebadbbeb85fbf55c063a4d99a49ad8ef100d32bb6d4c178585e02ec62bc71c472adda82f830c4ea6574786a30b55fc1fa6845e8edef03448ea162239171a5ff2436e1399c22b1b0ce5f3d4a689e1a034023c7bb6c71e67d1919edbc847b0a428f1402e4d85837c5d00d2c6e8330945913a058132eda3231634b829d55d6cc83bfaec8abf06240e6eb71319f4c4edad4c043e5a93925d18bde8e37bd5671ecdd472dfa7f7d9fae404fd2cab4130ae9db3d9a83a6c3b20df635e68d96fc0616306bbfe876bc7f62433b9ba44a1759a6216bbfb677201c3c237605936a03f0b80029e38ec1957166add2984bd5f5f6119db2a9cf1647d10b132b746ad72a313cde214316211d309b0c07168cc0b8a642863b05dff53d18288c33920979e68e12fd252b77c49426e8579ae15e23d660c9a5fc2b8275e72d026a8a667790e8b915c3fea82c56fd4da04782132a871225e13727acf4a14bb26c4dc6559944af29febcb46b0929d1e02df855836fe4e440d7e9675239269554f504b0d4c6edd59cbe989b31dba58dd7d05b3d9cc04874261bc8c6832b66a0d845095245f19f1041b59e8ed39f559d99f35c8b70901297295fda7fb6adefd5db117fe092ef20b0f1e0d74c7633977b691c153178c3f45b46ab2d04d51a390080bf51571d6e611a28a08b230317e47822fdbc2f8e580752eca87dc20416b0918791a6f0343a1caf112c740c43f9614366557f6dcca5a9943157e3a99bb70ca190ac526ace5a055caf112d385674364832b58648682337e17165d2215b2c1af89f4f9144774e1c135399f6eb018c5a6c49fa527af9fdc04b9b37fc9e5f6d6ec6813c334b8ade6fdb9e561efe564685d8851b32676ea0b145fc8694725491e8866e7de41d84e51ab884ecc48b0cb8094665b8689439e51aa1121ced1a13888c2442e823115cfa156b3f854c216171a64e766d3869c96a165fe74872e309c22f94dab696bca927b6a1a2847640a356dac515bfd8dd4e1b4573c3d670e2e98328db213d28594db5bb514b004992e3ab5f54eb324b0fdd74ba9b290eadb5b48140b85feb675ee4e965b9bfe929efe8e587f298dd67ffdfa291f248cbbb0f6049701cf6a64b57248e96540fda2f624513470dc62d05bd7455bec7106eea22ecac93ea14430a3321eb55faddea25b0a2103fa403cb228ad464b25edee9fea2de470da67139ae2c6cc9d9300880f9f5dc815f850348da410f14bc08906395d521fd4e52c486eb64c96cef7e3c38d575c384f09fb2b3361a1b75204e7f5fb464681b24b1c964c7fea2f46048da41751c2ba880dde09a48e886db58fbea804f3da3216a124da816811cf50534b82f3028a881dd0eee825101e39d157c2a2388e298425cfa4acc75bc2358e4f319b4f2ff2922e5b5b874d135efff9a564ec64a63f7b0f5a2b7bd3af6c4d1f51978bc27fff6f0744b587ca7c1cffe999bf6298c9cc8d5254ac1bf008fa2853c743f705fa88c8dc6f81c0028e4cd38cd6131ff14ffb58866cd14e88dde50e09b516e78eb5a7b31a37a90c49d6023d7edc20261524578857a907d139d6797b87bb7dec7e72e4e5154c3919a79c4f9c226ab140bcaf3b83c542b2b307191d187a7af02e1d5c444a680c55c42f61f3dfe5411bde8001c7bb065fc59020ba4e1de2fa0339ec9f7f67499efa0ff46000c3808019f7a04a01b448f198c36e9b8e251e7f3254acb7a7e2ad911d11ec74f225f6404c507766abab8481aa52fbb266ecc9f133b846bcc9427f7f2c9ce0d1c6aaec1fef4068e43525f3dba49189f67ae87229848a03dd352d21b7485a33c70f4243f575937285170b987ad1b826e853fb603a586a9c337b905c5a4446848fb1d43d454dd8270cefe6cbb00f42dc4fd4473f14cc7a5bb301caa190d9f18a95b27d6890d42b89fa4e7cfbb7e7a74d47400c8d9d61a9dd6383ca342ad5991ee506bb646ef2bf107a4d6404d5a0fa79511b4a3142c88a5b0884c626a5181ab542ece0541d39ca979e1a3c61d5fc98c6d2425575f673b1cea9670fa452834891cdd984de0933b2fcbcf20c351cec0340a9bebd639c501bfadfd31a56239f15157562df829a5bbb495708d0e5f9aed5c68a05d19a24540759b76b3c5b40d6e5f3e3b6c10456ed01093abda0189a28f5c2fbfe20fe55753529cc3355c44d67e032dcc8a2755756a32b1b1d6f230b312cc6dd319fc669fe7db9e468be156a14af8f8c4f87a96bc435068bfb4cdaa72fbde0829f3492d353d0e7f9300e69501b7b8a15502b74a1f64fbda140dcb703a8edd30986488fee286a3af049570e173a5be020c674478614c5be9a1ebabbfe2aa49051bff1fd0b3da17d76f501cd46dc95de8f323f6c3ba5795fd32c5d5b9b670b192eab5494c49e1638f93555c22515fcf792ad84f1ed0f51758ca0245ac30521e5821846ba1daba943fcff3f95f732aa65aa812d26d8cf2ed5475106ab5e732ef1bbc8d9cb9fe059a2070e0e34698970bb3291dc03a822f231c92432ec946a76081825f2ed14061e50e8528d5be0e5b0619517e9d9ef95e905d98cc97c24dc84e00bb811368179f898319d2aaf992baa73393ce00fe7c02f7867cb7161214dd761f597f033f1d59aae5309241c8d2250c532b37ea2bbca68eb2b71cb74aaffcd24232bf58919e5b4a247c1c939f534129583c2021a5599218e73aa013d73ea1068169102cb4a9c3247fefd293aeb4815859c1870de770af2ce275e1fecf0160855599892fb51f33fa3118ee08b27839cff185b0051a247a9d35eefa850db992a3dbd38e1024f9daf097926cc088ab191c578a23545c4bb7932b71d1ac33418cd43247640198a2bc905775d290c266dfab2751ba7c0a23703503bd16c2ac4deefd8fdc7d5e4ee4b2bfc147ee8d359b7907cb6a8c471528d2cb4a804a885c54a5975230fa1f25d0f04b150d0c46289e864a41b27ddcb2e1086b3534799f6b0fb2183e0bae2b5dc490e31855d569bb055d2da64f3eef297f7d9736c0b1853acb01e9e31ef7f6b54fe188d43e7fa8e604cbb6bb534175dadbbbb1837a17cd82cb058664756a71e68d9b70db0c4adf7f6bf7d2b22e752fcc0081be352a58402e472b463285d63dd8ab8cecca7f1f5022ef9c5619889dd7bcaf3f869506a855f5632ef2ed7eb7b11987c4a461923723983daec943d648c45ef421a6ac334805c6dac5bc496c83f043705385281f4d0d0047a557087fb74a7c1c18da86dd08131a7a015ccd3405cc01a440728f5713169c5d10778b0abdad986b3ec829aed2eef706daf42f5fda349eac87fe58628655044796c3ebcc215e49d934a7bfd57dabc49f09b1d12f011be0798da76722cf3889b6634d2f8c94f2ef82521d41aadc757f00632a48bc9587c151e2f414ea83c0460aacd23a496795f9a82a62385a87d9132be6c69dbad6eb8398df80f5480a71de1cf099d39e005c46f114910da7ad29b24689854c8f012cbf97c2db7b586a6e38e34e437afcf81a9e05714502b704c9c32dd84ab64fe0d360284f1c080c0a94a3810e0b60a7f049d5f993e9594bc7cf53ee35cd964d318a7f5f3c05e79c604046e82944c368f72b585973e184c8c9401ae15d57bf087ff1d464c9ebdb21f0c02881ee38280d524b22693bae9e902a7dbd414a16a25cabaec532c4fff0d8b6d5e90ab6fb688c902e7381d60e3a8fc49fab03e4080b599407b31de814cc1b9579f7ea7dc4610afa6a628be038608ed464047d0d531d8ec0e8264c17bdd463055467df7b2686ec6e04a8c59027aa86c46a9e5df0482f4323d20e2127d7e6979a550fec363bb19e570aaa6c50668f7cffc3c6a36a344431a5a8eb9abd56bc2dfa77de3801022d20f1e4e732707e796f83cf8f17bb68a825212575a0cbbe13653bd4aad488cc43673534c84de359260bc38ac4ef4cc11a7cd047eb51887044d75a016b5cdf83038f6521aedb681aa0de57bddcbaed920175c1bbaa86b67334124c984286bcd28ace9dd8d85b29f06440dd18dc35233633f439df75def2805dfd0799cf9f87c8d493448157927c073c8a20724d72b426c8824f1b44270e289d45171f126a8bb0e763f97f201fc640953805ca5ca681284a98dd32f10ef3bd62555a1696c45c393aaa0dee02f0ee949969280ce93c4182f2e4db8b8bd51d5a3e9f6f85c34e5086cb640dc7d2c8c439660b3eb3c58ed956d07b000842e5a572c6739db672943b6cafdb7b88e5a4905c24df2de942efae40a9f0c8a368cf1fb2399fcd0b4565e8f9922febf11cac81c3cd302b903eea1c195afac19f40d7f664ee8c1c2b1c467fe34eca5d2f0da2a0d83c02ce69fc166be5b68ae258680e95c8b73cc9d129720ae3e8bac0028bb2072472c3c68884c6053681e515c1722d7f3819a6f88054b91c65d0162a79255c63c95e39472a384a8605648c2d5efe43141073ee5b6ee9594e91fe7ef6a8201d39489bbdabe6ec269d9a4764465b0ccb274984c9e0e3d3682d018d61225ffb4ae14764d8c0c2a518f42a4384b514bc049e54dde2094514c0bcb8522d8aab855aadfb06e4b9f81107acc9456517d22031cd148d449ef204eb4030150641797512a3938b0bc9c9a03727cd0d7b280d46933b2c8e246b508dee97b60fbd0fd94e520ba782bb5144c36795d2cc86cfbe23c0dda84b6853a4313a15fb3ac058acfa771938141253681036325d84b020cc2a186b076df61b30e2564daf21ed95c5de7514252463b3934b4393a1a69e9c95c15db079148e6cafc7dceb86cc49066589653550af01a94ddc3700031578d0f88846eb75c750d791f70c3ab508c6a43084e82f5849132f2480a10bf82b177e5795bb4e23f96a3898caa3cb90a10bf42cfd9a771c18cb7914859db3406096ba12297f729daef7ef68721c860b9e2ac52aea3790ce907910683428cf9edbb902c3d0e5d71ad4936d855299261cd712b7b92c75250e11af43241e55b83dad873736e6aabe521ab418e0bd34c3ef67dc761d0dd544d1d45de63082b24d08cb2d6268f79d8433ca7bcdc97133f54625e6d0dc9f8392d8ffea88833cba64fd450829bbeb0a2e698786f183c4ca4fd4b7e741f41f56a989bfa9129a8eb79ff7fedae0effbe57601dd2dadda6c886a821ca7f498e4c41ab227cca9f3859f37c1fa7a2159301261c14f8e974b70a8a0efd63430cabbb3348875e3181c7359cf3471b9459e3bb1b37d8a8f7e4c6fd397501a53acea5744c712c5e2f89906953341c612447eef4c0e7b59ed9f2038ff8d093aa6e5ec1b96f1cd03de966b3fe3d8a908c69653e251ccbb09f2d3cb77e8b9d05ab38031f8180149c62deab136254137a07451f5690b2197392943fd0f60cb332c780ac63bb741ca6761c9580ecc10d0df4d7ab6f5ee2c29c3249cde8220ba07a440b54e723479f5e8dbc3f00c3dceac46564191c45a5a75c9e54bf8010d96071769392efd718b94653dad26cd21a68bd39d00ec9adeac6d39353753ce773c7bcdf63407096b7b78f11fbf2ba27d1a153f1df68419ad7fb2b9f32fe438aa2cafb18eed9fe9e2fc8a6c46375c128b53483aa8d7219e7b74ce49ca83a9da719358e2e75f43dfa348cf786b7c901d0b068f167974a71ef85f15abab42d9b613d65796fdb3eb45cadd2ab41c15b377612e7c70378db10289730e717231c6aaf4b1e8410161565cfd801fe77ae039f44b6eb4d5609a45a289dd644e4467b40b07a55f4d199c1d3abf5127b0a64db4418c32f52f93018b3338752146524982810eab0b51be033007614d9ca3c92af5dd449c9e978e69556c30c21f092a653508b37768f25b06742bad8b766921621b098b8d5daf815444c31425a38905e54b562568b96edd2d5e054480e787cfc6a011aa83db25833eb2c0d5577f1a4a66d8997311be975b30e56a8d3c86a82ace881e3e68c1ec6f04a27ead00af81e2374eeef410696de52c2e82ce4785b9e9e5cb3a72754acd9045f5e8255f1c5e8d0a128a9b19b477df0d7c6d40ca91b18a51e36f372c871e55faea6c408b45f46413cc397deafb28e6ef299fdca6f55ce7e6eecd5f004e334f97df96fd921ff6b7a5151d10b8d4efc0e512ce957bc56e6c0e7f721ec1d08fe625e85ec3c4d00bd1b8c3dc76757d6f116c33f6d508ef9e89f665c92d3982efab761496dab028b4c90550d72b112b74622fccc8b50401864c1830c2bc9398611c2dbf5b1e8af72bc254aa268e9bff8ce9039af739298ed003322c808ebaf34480d1c13a6c4f03a9f2d3cfb86253aea5c35825174781b7058531441590759e61a0fc7a13db7cd56f53830d9b9a16cb1077f4c8345ae64b316abacf9d1a4ebca4704b720fc7544e38df566db9c74a0579ccd52dadd0a2ba858bcf521f5ade825024fec2dd486942509838fcdd8f49dd9ba15a321f7a49d62d4861e683e31138a674ef1a2901882d1c289a5de8d830a0ecf55023966dcb0fe0378669460f5d5ebb6c9cfa6d810deca5618d5735b2e8e86744af37d0d4585e4f15aa9767be498985b1ace1e24501592ef0d65beb6f2e5e61a7d3983d9e4f82e463352b76520096610502f45f99307ccdbb2f9694d232497ba50088e3e5e76a5e26fc664ab59b1d0f81e49e8d54bf51f0fa1545f833740b4c4518fa86e437a6b9f47c7bed97840d6982a925bf928657b0ad46eeca8c03bb67f633e45a2e91ca9b9d994b47eec72bb13363eb30db9238db70a977494fe8bc4a878ed4e102fed583394986b7ecd648e86572aa081eb0df5d37e658ea4c90b347490d5bd00ddaa3a901f1bbff322b54afb6980063691476a4753f7e8c2cdde97525c398f52354889b712024e12408b64ef2c424826f7578d346e9d29f0c770798d41c1d28d4e8f1dae0c1bfb0e9d026d587021a4855c5dd8301830cfe21b8700e4ddcea802de65f0288a851471e95854ba8b6f43dca659a3ee2d1083c6087d31d3589b1e29af27c79598c4b7619f7ca63cfd034ae346ddd10ba8d43644b181683e8458ef9a7a05113ad8c48dc330e27864857003371aa91b5acf1e79ea87ff4c50b3042b9965ad4837bd8686985ecb24d89ea5e68f8d0f1d5ccc2c46b730fa11e94026d4f5a603b5c0da8c37e565821aca6f19c8ce5981ccdb6a272dcad28045a93475c62d2e270b38aaaa571f647c16bca172bd621f0cd4144b6eb56ce0d655889847767ed4633c2adea0e61d785fa16d01e1516383a71c12bbe08d73c7290cdb727b6af162020f25f105e6ecea13bec5f585bb4223aec4b8929a91382d6a68318b308ad1643a7789c8e3bcc748df1ef9c3d8317771109311395936e469cbfaf00fb0b7b5f495ac5f25eaba9af7052138e2cc04b5da6c667b222cfd931b6b8ac79b337d028a56e76e93c440f6416e2c93c8d536e6a4e9ee27c7410559964a9d480f5c693bbcad3201e4773b6a13714f253a6c4b3cd9afb493bbe68bfb615bba417313b151890a33372dfe06483875c0066cc7ce778097c66f372476f51483f1a827470654122db922082f6e92d339c60ad357b33ff03a35d4e5e4b006262217719798d30b2906ff1c7d335f5d5e19e7551d0f4c5a79bc3c24edbc116996221f5c4847b43cc03fc798c125c7229e656e974bd48376009458b08392a0de25a82615299be37f4304071f9076e375a597c8f05a1a4545c675b1f9aa8547d47c6d4a5807565c828c409d23fff6e94610835fc19b2fd3a4e6f9b6d3675b9bec26627819421ec1420d437834fdfa3660df53e674aba00d2b7e9567be14829d9013ae48b0aa56d60b15034aca8fa33987dd0eb878c941235993aa13741f3aafe5e1814c2bc63a510e3730fdbf641811359760d6fc1f67693cb0856df356bfc40f030927808576943851220516a2e89525b11adc67ab465c455a490e6defb0f3d8753e108ecc664213da2edb457251c42689f19c50c84b7d2e379309e66a793aa89d67e480de06daaec01f4f8a1444d8ce8a57f7691cd03af6d82c9473245230cb797540745ec5f9dd8ce1f4a0cfa04b8f093c8291314b098a88f4ef8ef3e98700fefd639ac1d97e49b17cc68c9472f6a4bba9de5d510966110fb0d464e5e06c0b27ca6d90910d20048bd3e123b9b69327733f14fc5ace278204696197bb5e0d4d4346cffea93356749be7b69e81f6f5000316efd449942c7da8f5ef2eccd4c42dcc49e99cbc9ac8512d32f70313ba53dfe32c760104baa3c735ec398dd6cdab46938e0afd36c09200f8109f6397b631892339d64f5a3d202dfbad638ecd2ab80e586f485792d4b3119533ededc65c5b24f0711afbd7154ab6f87d86437eef0342e58998a6ed48d5de90ec4aa054e92a18f0161aab97e89d9c135b2c3362cb55f194f0e6708d90b36d12b40c7358b7734e1929125f0567029fb2243bc1b0ce75657206815e31ca62c4635abc1a3917e51c934117e1be88bae0b41dad6e0553b77de79754db39496f12f71ceb7dca23e3e2f74704ac21cdd265f36d83453e705cb5298f4db5694960a48e6df389bb49fcbb9da40d36f43bf53e43eb6e77a0841b9e7a952dd8fecac89ce94b519da14393ccd9c10c107ab626f86d1403c56ef2633ed02e5f527be7c3c7af9d63417b065800aeed4cd6f63bd307b0525743d410666cf8f7ce6b2cc3271f04457644a26cc173c983f69944d03538d662e6d84325c5ca78a881a00f338a6d9287e4422682319c3d2dc38eeb2e37a42177789c9979ac762c1000ca2f1da35e466a73ca5e4928d3f15d83cab21eb80e89e1f330f5ef9b97916064a4d2e32bf8004d40aba154e408499ea528b6f897d1366f566f919077f00aeb712de4f8dd6ac3e2ab7b80d657776db871a979ed4860b357cc02718f1e52002b2088c28fa23193f509e2cd8ad06c41f1a0aa2030667868ca91aa94d9a19997b75d282e38c217e860ad8e0fdb5cb2bdaa56e9bbfe77943f9f30efc8b54ec34ab46bfb2fbf5c84d0d2f62688d84bc99f1639afaee5debef25ab74f7e4bb6448362ea59f3bf249c21b06e7f49f4a937b8a236b4458fe87d9492ae0e2935b45274ac00384758f49a9dc29446641804637145094ee13659cbb623fdb7b2316290e19649f12ac947999f19de34f4caac7f8a86c6d93ef95dd52188280d24e7f61e238399abc6ea75e3aa58dcdc9268838a07419b848d06425f3f5c18b3a6618602a6f49bdf1f3c30d999fdc7ded6d3fd65a74c5dad82196249e85b187d6ea1a58244c5fd3ad76cf7052243f595067d3847b5f6b38106fdfe3ce95f3e2fc5101b46c6e7b98407afa87f94f2c1838253c920adf96f55e1a257671811c6e18752756eeededd804638f45d551fccaaa2c9c049d98878bd3a842d1f68248a49c82dc760e90d5b8c3c888f9bbc6c4a68f1a0d406cbb3ab3314abfec1c6e2e0a4dc90e1cde9688018b3a2100bb6182555f4fdc1856b45d378aaec4be917989f65e9894be3d0878a2a8be32f71efbf2a072205e95793edef304a75a24c6ab6ec1900e509dd49ca7a828865b7e2d6ca091102dfd8886358a42f731e368698f8132059ded9668683de359946a3784f99ffa88cd4a7b4467eefba92f9b829ad934b974b41661a4539f19874509aa21b9e0e53c49f13f775b4d65015e91401e7f5023ca8cff4ae7c2e48b0f3603b26b692e8c357c6cd2f4120b388c40a9e2edf496d872aa14c75aac6c0401926c584e73d760bcbe13296fe49f47c0b9ff38d8b2d8baa69191e68ee0b1fa49f4fcf6e8492581af2090d610d9a2ce9d74634eece9fdea7db0edb9ba855581af035711f1ad5aa675ec070e1930594fd473093445e2e39ef090f30161a1b953f4bf70c17d690a9be5a9a3b2e6c94542d6f285b3e8f4b04604130a6a2cfb9b01827b1ccfe20a6df8779861afd355d532ea99e77bdece500893956ac257358023473e2ee2f2ba23955daeaa8ab3909723371a3f4525aba6fd5821da562edb713898419cb1ee4bb2ddd56d0efd05a04adfaa9780a0aa4d54e6a06b6f1d37b21ec094270185b585af17e832768d741f80592fcdf82276ed40b900003b7d8d69893290f32a2eafd495409af8aa3c28f932a4ad3992ac68e862c3ed8757baaf9d0895bab16a05c55faa752597b6b464340cb3f60c8bb09c74bb57534a266359cf9ca9ffecf2cff9cc7ad976c0a915c02b8e27e2cc7964df3cfd606124e29094dc91b7cc3754768db1e9686ccec4a1278797c2232fc58d990cfc64ed7f67cea084c80482d26ce2d68ee8a89cbdafda9d29092dcf65d5a0d1c5cd1352581eb5085cb53c27b427bfa8ac4f9b98f46d18d8b872b18744844e573850d12240da01477e4642e448d92413c670ae8a4a3f4d8c26e349752b46a7019f3a47d56ea0ac6a6d7b02ae33a0bd8df4ecf19d363a0f83b28ca6ab4195d215fbb35fb44a1cfd736efa4d164aeaa3d3930c5786967753c662eb4f264aeda54019e345d27485726413e812b93a0a3228853979dd9565c9457b08a8cb62e4512495ab044c89ba627b22e6b5b02746b96973346f7d03a21ccb2cfde7570d8111ed27f22fe5fade88cd256aab2bcd2c1329a0778b324b931d9b03fbd9a41ec161b860e82859943e64b28e800b28db506aba65c6387c9162702653e47b3b81653a403f05502dfb4bbdce7be4984bb1d3450326b94770dadec5dbfba5fe18097d7d1e850441b65bf7302ce9cd6b44e7210dfaf88a87eec6193b6431d3670f9dcaeebdcf4a713019430d338244abe3509432dd97d41862940c0c624ccb785f0b2424ddf59d203216ece1de9139c111d5bd3f90532ac23c8e134fd6cfaa2461eb8b21a178a1ea9c87ab905e981f90128c9bab4a4c1c40251fda8143b5f35d91facd50c4481ff3ac37d205d943c5cb8275a15d08076cd972ca228246d8c59257f8ea5b933a05e09ef06e62f108f296848cca9d82b66d733541c1768a5f21dba2dfdfe1b400b5b4efb94e15b1a255923db020c17cee8a8db3b800920cd933f03613de04d33ef5cc1e4ca88e63a6142dbff2c5da9bf3c340302a8f36b4c7521f13c910b2c6a0330b6638b4ce235bbc417ee7be721ba19876387b78ad9a1c9b44aff526d9c965860b404e46add946e6ad1df54845662db207a7fcf121799f2a967160c092036cf1dc73f45eb207a4c12403cff8e66ff4851e449872ff2fdddcaf84f9a7488ca34bdabc770055a34f1f0dce637f39441bdc7f728f0159e72c4a6287bf47ce2f572ec371d04ecfe133f4e1c7b02969b6962843468d012d539b6b51ccebd58db2f342f1b8f44d644a9ab3668c383f8ef4a45b4f67ce006254bd79537fd634978d30a6bb4c33a6839f56301521b05ca2a6d4e7063eb1c2d4ff822c0b4826f4c64f058010402eb571b7f80995ce52348be374f0721f206e39301cd30ef089733f0ab146ca959e9a555d17af546a3326a4c20123554af6f9cabfc0efb8f00408276d5f9f0d4b56a8aa019cd716891f47270d61f5c87e0bc63a036f36d7df1a18a962808678e0ce3a5fb0eb74845ff52950eaae3d5606663d24477e4096375ae12a05d21c6f79244275ada5174af269c7f57f97eed1c66d9be2fc3a6d8aff60e2c5ce3bbb445809847d2d9a99fe85e9cca4f42b487629fe7cfa6e82d10891c538ec3b8027769eac83fa75bb5a479b19d7fa401e7113fa938cfe4f675c8afaadbc9a69ddbcc9e874fc9cafb196c5e3311eacca2eb2bf328e228797ddef29273be545903003ade81e59fbcf2a11d81921024743f301eae1e90650bd8c3331f093f8a375cea55ee8bcfd0e788b85a25fb5e500ab64def3cd92b7f07be1f445ac683190a3002d9212953c8802078455d43ecdd5b0e6e0aa7882c1269184078f8328be6d485351d5502cce6fbd412886548010c32b43f47de36f9a5c2f0d281b2b6bf25b2e7014c60e7a5995eaf96855106f697a04d5ea492d8e87b911e33b9730f2d6dd9c7c44b18d2daf2cce4cbd6d2eeb11f03cf99b153a1d2552eade32298672658f5e8c12ccf50dd36957f0c09668c8c7ec03c56dd5885af5093ad69462fe7dd32f2417d1cd4a121b1b9c010fd7ca4db3d156739afc5956b0b5771e56c59fd67a635c773e4af3c4191f2f0d70eb98c454c86dadaafa997719ac723f6f65865835205752593adc8aea7326c71e4ca16461c8641992c3cb3274109cf515d99cd9cda3d065ff07ffd10ecf589a13ae6aa6003eef4e74070e3f0a885b2ea132cc8383a6f6784a4ed0e912c6b41b095000e2c8388f9670b5254fba4231f0e3f616ed2ca4d4559ebeda285f9f2c66063c27c2930c43105847b22c29000f43303eea39a5f12da726441509837cc9e26ff7e3716cb9117539e7195a7302bcf1b93482357de45b4f77a793c5349ad454e15ec6bee91b6c1700c5860ee778d16cd7a3af5b8a36e9768790440b1615f05a8991271d5d57ef1301464480fafeeab943d7d31582383945f422c2eb0d5e8adb477aab441077b34761da4b9cd730c08a2cd457dcd7cbe2052e439c17e8b41de898b335a9b0aa9e31a174cd9e15c5f091b3d02d4978ff90ab765d26780ab00fe4cc587f5edbf85b067be6759b8ff3212d56d3980616218db8154d06a1d4a163f461919026f3d742b1dcfa703d456f2fa34cc645b6810da965a76f16af533ba70ab78efd07f300147684df6cec0c79c56234794592d3e806fa1ac675f1387d5277820ebf07608eb29e360857391cd83c77682ad8e828017c425d916843aa0da209371b8299ba1f294e6d4825fe46080b730fb86cc060d3cc2c42418c8551241dc39b602354a1202b2df473a126a3046974c25cf8d05836823b3e9c4d843360fdc5fd5ef25cd87062b2b92b0e37674a5d635ff3e58db1024bac7a9ef7c5708ed0ce3d9846e5d1a089f8c31c859f5e656c892f212f416b4ce15eb956dad2a0660b485c43a854f9be623436971defdbf7331d571ff7cc815930b2c776892680cb1d90910c1c444410b0d8409f5725aef7c4d1268c89b6728f01f4648b73a3ad2c4a2c1930251ab8d5a12fd65d5673d05501b7112937e366ffcd9406435d19b6d4b6c7d592df665b0f2836be222b079e4582363586fe9db8dbed08a074c8fc9ff02478274a1a812489c359cde6df5e97481ac0a90500c3032b89027f2861b13ca1278ef10f9e602d40c8bfc57bdacda053db10dd2c6b62e2954857b1cbcb9829952a2e6b00628426f53b22b041f615726f82ac670598cad4d04ca803f4575e9c9fe6dffa8c220f9e20364d90de67eaf407eea6ca4f13cdb48240c9f1702e0a30a455338cbc068666f80f03156a179a98cf65529647cdf26a6e068ff2dae76278c8c85f56d619556ae934ac2cd92385fb5e4f4620d57ba662d1ece5cc2c30209b1e94a07c2239cab633f42aadb40d1b848bb26fef282cfa7ef57f76c61c880cef7a0168f351c8ccd8b425ce616b50791fa2da1760cd452bb59c2c60c1fc5845cb1f1b5e8faa7b0f8c67070fd582d2d2bdff8df6d6421c9d2fb564ca822a01dbe538545392f87ab8cf2ad3be1815efa8f41b58337f51ad1c67d1306b3d01fcbbad76aeaf0b3d9848d9f545a6c6827b4e22a005a20f097eba06089100ef949d17a36f7eb239ee40cb1a35780ee39b5c53e426173e8f2dbc3babfd008e7914f6cd1e54498e148187bf25b012d5c7f0eb2090ddb951f8f36a01a1f09537068a4d072ddf371ee6684d31b22c3f13469ba509518fa3a99954ac55772eca5cbeb22ad7e321fe96b09441a617cb61c157b2e1cc80f67ee1efeb616b2daecaab9707e5fad23dad6dd18856c012bceff01480b7934153f122b6ad4579ee71a362bba2cdf82509a8db4fd67ae36f8023d5b03a7a91efab38b081c375f59220a60c3a39461984f0502a7214cea89852ab33aace085e11a185665ee8e618ab3e7984d722faa67489f79a651a0fbff8035ab8a79645d737f3224104f7b1519133832721741c08b35622e63aeadc50361a8709df3006598259007d577a636566ff766be70844dd47eedbdf6cc0d7269c9e0d9502ff8f486142465ab72a4d7b5f6816eae59d8e33c4517f098551a52b63dbd556cf67ed7c1109a0a54cea89f697a9fefddd08b0f4e0333e6ac79e896ac1c195d45a7ac4f4e4d2681e2317f480ab471367a5995bb6fc6d19610c72d7ef0755e32139d8d8736be9df7997affa1e5afc5728d20fa9c9ca6409ba9587a60d099871cae703def82cd99409866ebc37d9c1b8f510db729f19a3f358478a3eec285ee8cce3faf2af48a285af253458ce95b8f0b9ebdf4d5b8b5d387b07fc6a6ed1f02d4c622206bdea0ecdc5a8b11ca0e7d0165873e303493eb9a6c7da2f3fec31409b6dc5f08641a42b53705bc82cdb06562e73c67573ea413656881620d1414647e1a2216aaf8dd1753b9742c6402751b5e26edfaa90525571f53d738b6951ca5d64530a0f22c3d1b6be0de0d6d4397b8766ba615114c4eeede03bad671feb6b86821d545575e18289d4123cd89faa803667809ccc74449f1e18b089a826379b784e21046f081e182caee05c653225b61f3e0f9abb6afa3581f696d7c0c7d046b3c0182dcc8688acc81c36826c98d534c754aeaccb0e3142fc2a890a36892b17d782044b9471917c90dd3a8fccc0b1cdea722debd1af90c6cdc1735f813fbd429dd75af8bdd77bb6e1ab7ac6ae786bad7027c8f743206e83bbf5060e2aaf8f4989a8a9b648bf0ca68e74695fc0606b276e47d5ffb2da06a6c31e2f7855f92e853c83673cc4c067679f25ad838f2ed690bd63a9f4bafc42006031e8c842475cfe711667f3bed9b1d85b3ddfc9dbd3ed2bb8afa1ecbc7e6c9cfe342ac5086d716572e35280649624866c4faff2692a67ebfeb9764425f8656e4f9bd17c60277486649c08289bc5f8dbe5bcaf443c9e7f8db8e31d9d294ada1290e5345ec3f18af0b598bc155d3f3b2ec75e8833afdda490e9f947e11939a5e122c301bbe0663cb5105a52a570ce08ab1ce5855424a08c0882aba1706473c44c48575d5605f848780813a23045f57a103c069d4d12e39aba7e6b0a9c02a652b6797a060acc2f8850e30b960dbf0b4b438304ab6fa7e0dcc59133390d8cc91f478fcd63ec196aa25a157e41dc1a710298b2a708966b0584e28d1ae1c280349a22c66b2430fbbd6557e233f989614bc8fb79ce5077aed9d804a1a8e7a387fc23d4aa81fb1ce117649371c91704786aa6a65e0878abf9bdaca5d43e20a6e7f01dbd8c8bce09437ee9fafd899461568145e2c37c7a43ac32e2486ba0f138a9670aed744c135d3687ef09357bdd1044457bd7ac52baf13c77c9d6baf7cfd55aebce6a297c692f6e65d77a1cb6e77dd9dae4237bbed6ad75deea68bed527537b5120596f9076d332cb515d877337d1c147ed27f9cec77aeeaed1d1bfce072a585ce39287ecece856464dfe73442df7c1b24a8df7cb7f48268cd9f030fc6005c36eb98810d712b000a3e0b26aab62a81c5f8f4eea2549554ceb9bd7e40b84825d6c552bade7293b768d0dae1f2639a9e9595418470f9cd4e84cb07e7b8af4def71238d46d58690beb5cf1c76134c892004b2ff6c1ef28f60570e5d0e30c4b5831f2104f6eb74ec292e0abe6ad26f2ccd0f76fd2e63e8f1f599a8ad5e9998d6b722fdc26ffc7ae81281a8210ebdfb33ddf2221ea6c2e689c73735c1aee759360386deb945068d65fe2ab3e8a806e3063618a791732c55c8b25e85e8b2281d85c494a34db4ea169249a93eee6ec2900f0a837401b935c4ce0cdafe0c99557ac103404fd07ac0b6f6ac073365234156b0cc3fbb051cfa4b7166caf34a2f0754b433ebb1b364a1cf77862ecd1a2ba063b8cb5b19ba21490daca4391c83d44099751d69ce7c30308acee3341f48f87680cc4c8a4fb84a263fd68e79d65d1f8d0a24021a5c643eb861bbca481475dc1634d4b003f121d4ab539e3a68e61ad53671c21d70a6ed7b75b298ea1617c40ba905cc95826fc6a95c43018d8562974a77c46b1ca33564950bf5dda91de16a40482db2568473973dc568ea8e2748dc4aca8536e80cab8241509e224550f7ecee1b67dd005087aac127194905e822f414da0c7581327fa65906674a9853c2cf2f19b517f5809efce85cc3dd150e5a17660f262dd4e43490ea69f19bea1a5606bf83e7a443a27e1eba1dd129b030f059b380830550c3798e6fa48c46bc99ae39623819129df09a61839ac945b452a81cbc79cb6a4860ae396c39bace4a4398a6108f2333ee04142ed46e59badc6b327d2ddba06220472b7028f308f4e10752d6c1e73fe3a500e11d77e56f2bb50198b35fe1c2f02cc599757a4788a3d2e99d1766b383fc9537c8771c963c12fa85fcaa6099358190aedfb6be394f33d0d352864aeb2e3a17b0fbae9131b48980d5608c22a4b7934cf5d33515caf807081884817013538803a45e7fda4d18587b69996c088ca11541d0d449604f521b767569b0f349bc2c84e2197f93512f671a5dee23f3b86de1ff4cd99624badee75c9d3451e444e14a51fe1e051beef3744edd0e0828beedc371a537cf9406c518b38ac5556071ec6907adb9848885479b4bb354098c07da6d0dfaeff973b528638c7f1a2740f14d06562f8b7ca085bbf373f54e957b956f56ab6ea7029b09dbf0d6c23e21fc05c4ca06401379851700017158edb9afa0ef507879d5109b7e65f0ddbe2948ec12fc6da51018637f00c1c526567d71a0874a5e5239371aca33ff6d1d001b1100ee19f2d8b03b53975e5fdc3dc5360ab3aa7a376ecd0cad9acd735da2562f140fa53bde46763c0bef5c7def1fbff28a9321fe6ef8384e37d0270347f0447c8a9a68c07b606911ed1f284921667fb220b3a6f7b50cfa18b4684b162d373726dd8320e3842709447a0542bec52e9c9255a77e57b9b30204de231f7a77f0183449a899a4290c82afad7199adea6ebbf6813612b74dab82d0b5027a9d8ded3fad20584e69f584271cc1c2d789b6e636adbf7cb780e3615dab7f9b6b245c7bd5ceff621c27bb715b37484fd71545132317a6374871a58d4c2afa5e71f99ae400e1084e995d383ab043037568c5896bdea1a29a4a15f325bb77a3c3ac8b1335715624b6bbe4ce09c2d1052f7f1669ab87809350c22f770d351f4c2531aa333d4620e7fa696872c2af81a426cab900544e129a5bd93df614ffdaea2a460c5654373bf57ee01b5a103cd86ca25433d0555cbc0e710031288d88d5f8dabfb31b07469cb691cd08dbf96be15b7cc7a73e4ea20b3f9dfbcd7701266c492dae64ac3f7121b23116a3156d0d81054be6f42289511992717198cd343479d44416485a0420cf522a38a58ba4a5f625ecfa5364eeeb4f3cb4ad7291a2ce96eda08c74005b71972bfc766e58b8521ff81e0c2f454f14e378ba4c061e2b58f8f4ce5f9b7ee127c567d9187468b6dc874f5acba749a807234b774473c238270f933819c447e915dd5694ab2ae0febd9ecc3f2bd98392700d9f7b26bd401e2a9d215880f28a6b29ee27737d2647399c1a011e10ba66aeee5b5f0f10eb9e87e4bece337119c961b1d73400671f47133060110b77631d43f8844333c30190062d4aae812e8c4f2703ca9fead86210e56dbf9637c63ee9a27ff18aa1946ffc48d5e4b545d739a1dfa66898c436e8711488c738aef4d1ef8c0da652fc7d9ab8010ce88bab2ccbe656382372251db130be9594c5cdaeaea66b4e8afcb84fe10e3de93203c1f4e9d8da73d06635702acf94eead99c745a9e8408b65b259e33579c1791c2686b76cdea8d7ec0f58da99bdbd743ee1b17f7e384c0f8f5538475cb0d8f4a076840abfeec9b306e917b86f85f7f844021476d496a9e4e754c010449a65ec335a3a26f48aa4b59cb2ef4336f270f56a07d62cf6ae7dae8b39b173955a0da2aa69c143a6313fa2d78ac77c0a141f28ea20acc1b16ff469f9b70954bcdcb25788c26c17807987a56b786d5347a54f855dafdd609182364bd7fa21d65af0df75bee0b31e547d007b821cd6a0266ff02da877322e370f379b14fe0fc8f638812e4bb02268fb17af4cbb1d9139442ddeab4d771eb90530f63ae1d68caafe927dad7c1b072a415087d99c7c0e83d2869ae58cdbcaa396c2f961a75db28d2874117b87a9a3ec035d6a28fc19ffe62c97e37a6056adc8e0437101490c678b5980e0df6ce1053c0006c6656e7995d7871d4f3bfad48dfc6e8e1d343961b3b3ac24543bc9ac84df0e482b233e6289a77bb3d711199351e814094dbbabfca34fc3823c9d62f853318b8f3dc4bda2c099843e0b7135500d2023b8b2e978cd7c25e3c32a7ba03e98a987effd21af6c8ecb6ba4cdd7885a69dff224115fca985f099626f4cca8e79e361b23dcbc6605427669645a942be1b0b1dbadd05be990c1b765740f462ceddc13509002c4027d31145709cf027a34ef722396f759352eb156f9ad5117c8e405e6eae8d18264dd40a5f2371f3b227a10e8053156a77d1f00fcc722709c868e6e0dc0f8e8e71a7d836e07a5d7962653a6a448152c470ee9987a99c846fea95a91270e16c5c845ae8cbe52c36036797578e7d187559455c24a9cd3293e88d187f5803870190dc07d0e50520d19a925ba20ffce9b944a6a1ae7fe2926b47c07f5394360c00d15df0df76c460b4bf7fe43e5e305ea26551196503a8d0784b8088a85cf9b7122a1be2c6b4d6b8aac6278121bcb6df67433bb8082486767328026f8d63f14432c8b9d115b229b046467776cc0e96d8593a4f0996da2dd44a3d243cdbc9ba74d0893d6124bb07f59dfaf9b20773325a214ca8efa59231f877de9de1c59b23685ab9c2004487be2caa590f65134ed9a4146e5c0ace8b1b27fd3d878fd076224f76e8c9103278c5cea5e9be340562d778d83d292c932ad6a7610afbd0fda0fdefeb6fa40774d4bce56a84c023961c3b162e5a6f7d782dd296b6ac8136551dc82c37a6948291e2910822f490c09ca8f8cda08c9089898cc00f62d2f0e8945bea351db5da1fe41c4b4e4949e486a4eb18c1e121c38f18630f447301d61e031b5799f1b6b2225b9c125fca7d5c4fe5ec015f0aa06b9fff76a6c0994986927eb9618370abbfd8644bc299df8a56249f290fc7de633187ed07004d7ab92fe8f09b9a28076aa0a73757448586731066c2df202cefb610141fac16bd0cdf1d946284113464d5d6d5bd06b94a12b7999a7254f593e88b4e7bc44d88936def40acd80beedeede25aa815656f340cfb0c092393362cdc23ddebd5478a5d14be8db0b85bdc414e917fd2520fe6a0c0ac02f2142c8446a06539ede84fb50302b951422c7786dd36206b32648004da3ae15d8b7b16682b7eb13fe4a4941554444f78e837afbf6c443436f290761930cefa64dad78798bb1ca3bef54dffb178954819fdf1741e4f53cdfd89c698e3a31c610f89dae29092c8fce941bd21b1ffd17fa833b263bf262d985777bef2b8f7c98c22881f8451b8ac9df03cff692570d7644dc250b4aa0dcf1496755dde8359ee17153309ea60d9d102b1c7d74b16b2651d264f0a3b775a90193266f62c4f14b1a31034ef41d963c736df4b00123ccf8fc008b262cee2317935ef4141c60287777341da011d5bf2ba2d23e2b3dc69942a2790085d5fa65116e885496502214365f126678f1e96d903b9bea8710cab4c0ac64885df61de06e700d507a7d2f22f865e062a590e5e078581a01ae0f58a3937a78611815a6da8cc1de712ec8f51864981d52612ab48413c62cdc885aec5b71a3931b48eefd9d708cb747a4fe35b3a0aedb3e9d7b26a9f1484a47a213867f15157e2403d41d90a3a8ff39e3ab738a40617a164e4bd71b1c3a75c32dbaec4717db7febe1653bb5d90c335f0bb82fc81add0c1fe613974446ce24bd48407f4cef23a60063e19778b25cd3be0af5393a298326c5b12c2a4b7935d50589736b494582fb786fd62316f6b7bba09294bae4a4b8224bf4102eb067e5595f095566c18b94932aa60638ae5a299d8ba8948c71702a356dfca6319d6787ab9ff9db2d196480bcf7483e6357d8776ce700b045f69a3b83c7690c54bc45931ad9142a9f500838c50828dbfba4829f5cb96816d9d38cb851625c397352ac666f2cdf688bb1eede289ace80d276eb225af4f4052a29467f7a24b77106fb2154fb71da3ac694ac3bc46906e54a7f695fd341297e586e5053143ae22600e7a82cfd11a7d7facaf1c23e2dc69544eec7f0e511f7139abed2f6d7d1f7fcbea18497f9484f5e0a38cc2346fafbf033ed286707bc5cc97a621ea77e3406f53a331fd4fd5eb643ec60df558eae1fe4de08adff937978c3bfa4d2f20a4156d952be9ab4f51e9719e9b33d34f2061d3e2f956255b4b0643851162494906402dd17b2c04d68e7ce5a65425914797640ed91e6e3d8d7aba0f4915fa4a355572013fa18abad8f70fd8645c27f86ac80b8ba80331e79f9e1901678656590c93096d635c4d64e09e906ad87a1d7c5a52d031d15599f01b8230f4737edb7f2623ae22047fd8c9074e9b9b8a8d9aae7538e6ecf1bb772545c8cd582f76994737d691ec8372e2d8e755faabf95d01566d6521b1c4001813a1ab0c46237373a21bd0f1236f64fdfd28e5bc23dc404d993227c1f98c202d34ff83526de75088dba4de2a58d1a430a089d0a745a0fbac706f41c9e9793f78b8fb72ef8903927fd72404a82a485483f00a60a78a58f8ff68f798c6a3bcf834204d7f2736bb1a8ed93740136929c01c7b789b867bd82fc98f98a6ac2a3d55ed0f79cf8ca360def2e3d80af00dbd51779ed732fcbd7a8111b03b4ee54e62e55a02e0e5724b8aae7e77d33b45a3d5f9d8aff55c988f66850c27898c244a96dade006d7023e2b4d03154cc7474b206bcd7436619a9fa207788bca8e7135b9918960fa77862db313d6b5df4ecc4a266a6d94e1bc08b8bd534e71cce7a9b96f63de77fcc5d03b177173f37d253bff66292b1f56a696ec3ebb9033ce26c7a5d2c6bd21f9460064bb072e353faad7f744275c230602f3dcaae68f8db2c7cc4c2bf89d486a01e5c51c260019d4da82cfc490f5e785eade26108d2d1b556156882370157483ef52011a157cdac2362ee5bf03ab90ecfecb1604a61bd72f97806eb811c1b6e18613b23548d57098079c3cef0bddac758303b7cdc899a4846b68bc4966037ad4282c74a4fe9bcb558f6c19a662202275dfed490b128b8eb1e261800a65fd32b34a42daee25859a1128a16cf86c9d1cf7fe985f2e130e7083f8b980fc1085d6e25971d84adbfbd179f5380e8a008326f9518866828f081e870ea8c2959051c59d9d2a18c09a5512783089f4f217cecb172b12bc4a6f0d52e44998c2162933044d5c9990226567513e2ae98e73f7de67a951ca41ea3fa2b9f56756c4c7f26e65f6f3eb7c9a20a261a8f3109bd858d012f94bc97c83c5adbae4a60a8623e91ed53b3fa2656c787abbb85240adecc25864256857742949a14ee16573de3287bc82a0b7afa77927aa5dfbb0b24d7f69e13fefd474bfc24a36ab909852a79d22e814b3b1b08c7c2877e6e827640a2f04bb516a68334ea184a91ed2ee04ff2220ea692a3b0ff63327800d2d2e2a8e4b04e60fed3e8be0982a0f8e5d9691b8530c1bec839063908bbd72bdfee210963e6f6d23dbb79cc95804922ede2c4083457fb4a490a9a494281257639a7b03926d4a25d8a92750ad6e0801427073545729249c0883f1d5820ff4609196d804533261b060b972c326e480011b4f2293e1eb847b41253e301b9aad19e34e448bee8edc23a9a054e9fb3f5f72e1d8ab2eafcf2c094cefced2a901d55f8b45cb225627c56787a487d435eeedb3b804d2da19371533fb831aac0f7a7bedd93d875c38bf8f6538da0d0eba65c784184d2adf2bee7aa7ae4455875e6f9c252956f195b848bd5982c58fb30da67e4ad2bbb7e7ca1e6f3a465c4e676a2b93c1085f8a80132bc7b6f7723dcbe239e72dc4fa5862425c7b12a86f53f5b0772614b08c4ebe9ab517cb5df3e0662c1193c91e9666cc3a6b9148b01db6bab5c36690f081fb48a552bd61ab73fe65d4c6192674f08ea8c764c4d993d661f1a52835ff84c6d68bf0599f829d77d4938449da80cf9d8853f9331117d4ce9702a03a196a1aad3085225d0e1546adda52ae909df79fb2658d386144c5d92345d52bb65c7b9de2c973c8dc5ea810fd1259ef7b45e54fb43aa50314931d8ad7abdeb9ce3da950c38ccb7205dc95811c4f0ead999453fa945b5372566f0ca3e3f28ab221e8f848911bc0aef239ea692e142f136b7f53929ac0b5bacd69ce6fe8e4dda0b9acc9f3bda2f5624aad4dffe8cf701d514be8a54745c014fbe8cb22f5177a146530d2de29dba52b2e882862a038868e0deaa235feb14a99950b7611f72d57d57944a7685f34130029d2c2c3d0d5ca9ad3bdc4f4610311e87258c19276bce586058f440be6a48d470f51c19c6639bf595ed02ddc0011b17d1dfd2aa729451092e3cfa3ef0219a66120162b3e9795f55232fc6946b0851c82a80efaf14d8369b9b7ea58d7823515f01bccaad2e71730df20cd8ea1bef4a5f5fb2abbba4f41664434219023fc591030e8fd533f0072cfd3668f2b2bf38a385a088c004c384f3ae8fcc364382f489c06ce60e8c337ae0b60f34eca2b8d124c6d312d8241d9e7df9598b1e147c3fbbfc8f2dc6a45d8fd0c048b4bd6e24b77c04b71e04a954828a5a330c97dddaed9750667e5fe7542920ac295ed4fb5866a0375b42a7575cc3b5cb684fbc0aa74bd0e7b62db9faeb9715b3ae306a35f3aa0b1193ca07aa710733ffd64e15224f9e2d42ca6c21a022578c55c675987dd375eae447a7a97084a51c7cae7c74459df4f873ebede1e72c68a31297ea5252289d28e6155b040509b739e6421143970584ffaef2d56ebcc1b1ffc310cd20a0fd7358fd488e83b89dfe410796aa3bd3eb2bc6d55fc3f2a1e008b6a6f933567bafbecf717caabbb01604a3b6de4e75b1fdac45d55b94d68e2e36aeebac012eb6efc752c35d70d633dbeb3d9183bf154f538aa7b92ba5742e2abe7af501064d5f7c38a364fc6eb17ea66b7621561d64ef0c33407fc65235f0e434d8630734191ee9933846be042e0292ff9d19c7aa26e70073879e3d973565d800d794459521686870de57888251d4f420577ce7ed02acc8f87752455811e46066c82c33ca536dbb89f4e70ff78e5c443f9bee14b7019f7e2ca701b841ccc9316ec08cbc825b1811c624babcfda0206aa85ddbacaa4e9c95274c5f6dd32a4e32f17678a0eb4989863ed418e4c77c5c4245d3a8dd7dab49385dd3e663f046a890c6eed0bea8ca312a6f49e939f6ecb408dd2b2900168c2d0c5ea9e88cba7495d39ffe9a2263ec651c2bb5a315f6aa708e2db2b89dce8160216a0c4c8bd14f3d535315c466b018210c3d31f465f869431c3ca9ec1910028ca80df90dd27cac9eec6c0da18700d025772775c9348f64bef1b49f51e879c4dffb8be41922f2e077f220f95b3aa0aacf89a07f82c9260dba7ac62b93aea6f1e1bb659126337b324d387f35118c0c1162af24fe000b441d32d9203d4106e5e4136d05d51d7490beb06768e8d9b5b2035bb8618610f79cf6a10694af2eacb57b740ecec3d53568a56c5da2fe2431995134f044a4564637d5c4aa0664fb577917bab48a6d1a57104f831b68377b2a9b5a627bc54a4f6b0fc263e4e1529b9c888c02d9aeac42549e8c5a69033ebe45554fa5d10af5336873cd23fe900c95969467384b30e5bea78a01c0e35beb13dea287bf67781eed641d5d8d2526a017021bc2f242818e29b872639ac057aa7e2e46ea196877d18205185fa157834eba6ad321bb5af0bdd536114cf928ece201ae1a2ef5a3af9d0085d7ee57627b12b2198f64d39bb0efd746a1cb4b0775efea93ee4542c9a679faba447c74bfe2b3b42e96183ce537a284deefeccc2bfb085c3033f56739068fe18411f7621b6a236df094aaf6b58f050c3b51f34a8c1476b00bc2555d60206e516de08af27a9ca62d762c8d1a3fe0837404d6708d77802cc1412de75d72e8f083353427bc753addaa56148b484e5b0e9a11aa9cf657cf452059ad3e53037c843048cd7c3cc09474f92d98a32ab9b2706e97b59af0e75d25d516481bafcc0f707cdb4d8590b9b93d77569ab2167620c0ca03bc97f74c249724ca79d174d1c8286f45c5e987fb4f9d9b1063aeb974a60d8d138c45111388298c162ea910f3e216970fa7d83a79edba58dbdea4e72a1ddb83c175639a9f7e14172e18cbb1b6b0bb86978d7fe120f34ca64999a5d28d9da402ef527e39c0a8f19f7505422a780ea8d40af437387032fa206aa3558844b3ebb7aca1f0e2a720ea28749ddb6713294c94e95d7fb2b93e877f30f2bf0b1a1397c5a1ec15058674330b27a23d02f1fc6904faf7eb81df8768e4f024da7cb486c0420131f72ab8dfe66b24b192800bc9af657d048f680d101284018a63faad50d7bf93053cd74842180ba4b844b8012b67553c0f3d6ff81247d43500af78ed6060cc6cc93b54ec6f5bf068ac8d7c22d260ad21e59895f6113072ad942ef1cb74f2cb7c4f54681d2777c9a2e195381b99ca58614a05f757f073b7d0d1c8919fef3fe2c976e69ce8321b7ec3cb7401b7ec0bf85e3ee5bbc857d1a4ea49127357b76db4ed6d55d43abfe978a0fd3232bde81fa9c95759f85d1ff6bed3de8568d9849454e9a695f83aa4a30ee8d1d9cbf9aab470121f5744a69bbd937d0ae1bc5c66196afa6d73720229d8288391dea2387da23bb31fd4ecc820c13ffd6711d07d6a1809f95a5978128c26fe920bf9cac61404d428cd6f81aa48eefd100324d3b9882eedf4e2e612a0412cbbfc4726bde32812011be3a6b7a6a7d9688f020e0865aa2889867daa37dd522de90a8e012a6c8a427ed90ae0127b46270ae16bd9aac28ccb58078e0d921a80b65ac7bfe782706a269fb508ffad1b14581af3f9e5d25cdc87a106a8ec9370e59d164494588a08b36af4664dcadc8f844c622365973505939799f90916c3855240d0eb050ff76e9d86b9945e9a0f4d635985b8642d4ed3904056358310e2a5ede0e17bf2115d3e009167bdaf3e49e15db9aebae09c60f21552454a101bc7a327898689a98521a494d5f4f40a8d42d7aac5efc9a455f324a780cf2f2e5ce50cc707847e7426d8853e26ec1e36bb514f140dc4b167a08656cdd91d5574b995bf402e552f112a1822c3f26d48a05f6d469118bea3afc5099e8c417150f5297f4c822d3e4d2856f87cc3e61935fa52003ee2d9ca2a6daac4eff6cce7d48e7d58b6f002a78bc7894cef7c50c8f8b1eea8c03bd66c8af5944d7f9bcfe4ab951413ae5e446067a2357705c407c93cced1d2eeeab4d8ce0b58cfc2ea586d9b75c72300b99254e30fb9f2489fc2ba69248173d9163c314e78c8e8bad6f99efd61fdd870199786fb18161d93ef076bb2c9b0ff7e1940575158d1242a9c67d9224f727f3141b7da3d828161dfb8d7ba048c2396e8104dc9f185abc41ffde9fb7ac4f14e78622cc614aeb47eeb208263048d0018bb17fefc78195a571c96211fb06868157dfc0263bf50d0880bff8966bae74298941f2055451c9e5e82ed69a1e6a56fb72d70aa33ccb12ae4a06fce06a41c4f4f978d7b9c9eb2ce73c7ea22dc2cf9c2a30b2cdab0aebf9d1ed1a291c898dbf6b9949aa17195f49f4271cd061083c11e153e578c7445769842d27e59bd106319ddb61d9a38bf2a795e63142fd9f38780277055685ac643179b98a3168eccf73d91b34fecf5cf3ff0548b119389c48ccfe81d3e1136cbd14362dbd60e74caa92debee5d50d522cc5e87f43c367b1c4e52c9e04f688736904dec5535a832f700c7899aebbd991e76afaf8400763ac6481d62cd8afa001f666ae5e376e31fceba6a99550e4531ebfb62f933554d9698f34ce45cb5a91290c015a36763bbd0e36640791de29c9110ebc6b1070b70badef78049508f994a296aa943b14a1ed4e335bcf4196dc1437e9a6f348861e10f4806b926dadadddafa197fad8dfe11de132d49d7a3a5922de0973d3739dea620130f111f4766b1dc63e0cd71730d77d5c5d04082de72b36676ae0e18d2796f41e766b6caa70d82c26fc2a6a9921e7e0822f6ea6de0a2c9973ba550a4a33b7b4fb21ef7dff05c318863995491136cd6eef5134eaed321db667e18d57d378c5a3adbdaf68d5a7286e6e4fb8f41641991482bdd056083efeb13be655f5f6afdf65285059c2ce9c994c2391d9fc869fd5700d7fed3890ea7bfedac3dee3edb0d7efb6f6c699c91a7fd66dd5ada0c1648e6991d472a23e936532b5ed12542a0f9279ffbfa569e7676e4bd2b853882d960561124c0b7602b103e31e98acfdea12f85dc222543a5cf2a0d1d416add68958224063163da7d891e682eeeefcbbbd16e6f3fcaf747de370c83450c5ffcc77bc9e746cd2e6b6c0e4af6c83869e66698a8ae686d7cca7032e793b0725cc41b7ba7a83f8b50f15ceb4ac5868d45b5293976aecdfb843e01eb21363419335903d84877581e899ee055c8c9611394f6a7bb5f488d55a630bb034a91f7537d379cf947c38016552a4330fd6eaa627e6fc07854db4127d0e1771e5f005147d3825cb6b9dd4767913ca4960c78ae1880f47ded302b56f77250fb723a846aaae8ebe8be67bb701fb2c46605f318219269fd9d1f936d07f9d0b3d9243a0cd2784e7e32b5e712cf8ccd403e604217f96920fed50287d8fdc28ba12a34f9433479529b469ed41964676ca95c5bb4e3cc5d6072a0265b81804d5508d23c05a7ce011b3870a7949d4ba2dbeb42ea6e1950f154c1d96ea27c84841988e1c992f573e43b33bf162b80aecc39e0e9b44e00894e67b6ac1a47fd73761f904cb9b0a780c695df2935a4711506bdec6c4e7f9623afe6125e104bed3ca06c4bffc59048e680bfc8de6507b20cd5eeb33ad1760a17fd0e7f4969095867c12b22772d7cac632731f3943c661913f6d5f67d3e630ba5e25ac19a95779f7adbc24c6ac86a37685eea61f1d8225fc2169398bcef1f30c5f79dcbef16336daa7b14f208780a6dad0c678395a60d5ae4e87a45ddd02da3f59efe3d5b48735405faa4be847d0f935b2ff2633abec608117d12fcaf4c63df8bacd0670906b87f6e35f49d7f629ef5b6157a4881acd0ec872cb602db9069405f5a1a9f77748d4965a650e90bfdaf92a97d520198bc9d2de7a0c1961691d04e613762b79eae46b402c55354f71f4744c3644c9c1c8f9c79614ff948a33a689fa3a0919676912259ff71853be4e315dd4b76435f210e789d1f58e2738d67f54b5c0a77039a521caa45a5cfdfb8196568dd4a845259d8439955545990c43e1f9b0b0cca4c293863ea38f295c2fd8eab38d9bfd7f464a68afb1e48839fe0d2ad901ae1218cec9407f3bfde259270553e8b08dd9e3ffa32544aff1671eebe318d83d82665db5844308d847498536d018c96c661613beb2cc92ed9630766d2ea9726080aea40066eb27739a317152ca94452f6fd1e41c0a4c3b87aa02c2e7cebf39f0cce2d642eba94542da773a67446b2aab4851c348214c8b0c51ca564909c6851281a5b35082a019b6f43379fbae3cb794d47e66a7d239ada2b6301f69d7b66fa97ca923f8277bb09a7d7bc66a9eef3cd4ac64a1eb22051180e761e324d90a0ce9f32991d10790b8177dc8c65e4eb2bb7474e2fb7a0f87bcd974771b15ca8102e124a1a1c9a3336e649cf8876c49a179f8338ec377252d56904ff200f03f0fe3a54377909f91b62cc9a61f490f4b8c09927dc3405a57bee6bdc9dd7ad5b8292b6cb92b4702f2c742434005ca0177933a230533314b8d7206ba81df857a9ec7ce82f76d8a3ba004e29db5e44f4e5b08670a1552339c5a81e7ae540c6964964e58d870253ab5b05dac986c18b010cc0377c78692728f4095e4acc57d95b08caf318c6bea42f643dcc6348568ce1966b6fb6d122495782850120b7788cb85bc45af115a31d78c3881744831c3ef9a166298a5b3fc0fada51837b0714cca2ebc3605f1bd54161404e7caa0ae0cd4d501bb2640570fec0a015d1bd07583bb7210570decca415c31b02b3580a1b7b5bd88c06e6e4c5849a9177439e16bd525c21a35f122c7aa0da694728b351dc523154a44435c3ce8ad1f0674ede0aeec9a2abb8440f19e5e94e0f810186f82f1402ffb3918d706edf2131c9e78201ef8b94a7ca6443cfb363a2d0d358d13640f0549cb9f7859a7dbe18e84b295dd67438e89827f8c48eb5d6cac32340c619be19060634e7265528459d30021a2233aaf940f45c277ddea98adae59717fe175541465196fe6fde619cda4dbb69ce977004b38af1c9e2f396bcc578d6f791c26eb8a854b2abc2bed57be23662f360dd9f24de2d1b282ce856abf93f622c5f4af7a21d09203467cb60c7dee314ffc52a47f193435e3a103739a05271d306521aa7f00a5b8fc3a9a57970a757d84a586a8d244310535d55120b192e7e954373172bfec598244248814c68b920eae265128935278f6e452a17b0d33a37015ea768ebb153beef89d247d5d48c31d95f905f278bf553ee791009b7e7a6a624aa3370ec58197da1f3e114e4610bef31411c264259bbc7879307b031e6554caa472853a0758560b778d86d051d1040db8ff13868c782fa8a8cfca520738193dbf8559f6865100a06321921d7fc0670c632fda66ff5d619970240eba08286f099891047884c5ea13da3e6f29ab5de91ffa269d09db9947e7ddb49f1ada721b915c382356d7bc10bf5c21701028a471a71a91f2bf0bd66f36a6d27612629860b24f88cf1926517bde490cc2c58b7fb778d9239014180e927f29f2fc29933f6b1773c698ef1cc5d86e756257daeddcd9e7845fe8a1116b273c4889b83fd102522b760c0362f8c3b8dd127f81dd4d50ce37560c3840c6e41608688edfc78c3348abf0a45de823d4a80388bc491d6a99714af6ab074f309de9f172707aa0904cc8abd161e8eafb633a141aabf4cc67c4c9632ce6e3a70c3ca648aa0d199f68aa2c244fefa4540ce9d593afced69d670a93ca463f410c89f6bf20e38d3e6301f4c3040aa52fb85a309a59a503022bd5a09bbb51269988adcc54adc38436d062eaa2f12e466ce94c03bf9ec512407b98e56f2fa458d4da5187c3f0bd59e78f54666733ce60f41d49bb40c85f1e65b94007344d22b0212209d97bef2db79452262903dc0b6d0b480bae769d9f1da31058fa0d6f9c94052e3d7aa63b3e1a94089803b4a6e6364dbc2d85057206293f8f35ef9df4a3b2abb7dba8f20b695844fbfabb381f3f212c9032b494b0c753b79976ba422c03186e43e20889a497f19c73d43deadd04e9bfcee5b0bdb003469e73e9ed34879c4fef5cfb3c9f6e33b92c70fe4affed87cc4324f570f4df9c0f39af34c8782f871bfdc2eb1789a5a7bef9f5b9b94db7f436eb5ae6e204702c22ca21da79ea9d739ceca6e7f98643c66f5cd6808c4bbd1ad7694b07f52b3be772d81e177297fb7e0091f15bd6808cdf7ccb1cd85cc8fd18614c9fd3a31761687eb54ffa0d65e35c59b3c0c59aea1aa40d4615275970032a3634872f62229468d3a0f4f97833bd5b33777f34b77000f23da9d7190427456f01031cb6ce476fe10396acf84fc0a114fae82d78a84208128a29c17c2cea81d20b217d2c1232fa50a3a2c8073a5f249453e4839f36c2e8617c2c3282e79170010f123be420e10224ed92a14da2cd596bad5202517119a6c1a64a2811dda149a494b5ee4c1e58d3f7647af2548908831505cc82020e3bf6dd4f1aeca346f289252d19b5f0f82c8f9fc327cabb78fc16cf19625242caf11952797c168fbfe2f1531e1f7b7c94c73f2df9ce959862b09da09ed7a47c8e2654fe7afc2c7e05fa1c4e947c539cf2ed8e2ac22daac0e155eaf9abd4aeb06153dab5f44d9590b42b160929b52bb4b029ed0adbe797e40cb15df1274d7cc5a021a376fd340d7db5dfa4aca75dd115bf1c663e9ec39b04861c5ea4177278a3b890c30c082687d9d0b77278755e727861df9ea3c99276cd233e7e8b2f4793254d7c9af834f969d71cfaf8ac2f47939f26b126b128ed9a40f8f8ab2f874f94a4a429ed9a467c7c972f87cf149f259f25a276cd1f7cfc962f870f9191d193764da18faffa72f83c393a6a6ad7f4c1c767f972f83435c9699223d4aed9838fbff2e5f0111a1af2a1d2ae59c4c74f7d397ca8f830f930f94869d70cfaf8f8cbe123c547c947c9074abb260f3e3eeacbe103c507c907a94953bbe60e3efee9cbd1a42927c7c992764d1d7c7cefcbe16489131f273e4e84da35813e7ef7e57022e464c8c9509276cd1cbc93244e789cf04869d7c4c1c7b75f8e265294949a5069d724e2e3d32f47132a4d989a3039f969d78c7dfcfbe570f2e324e624d6644abbe60d3e7ef6e56832a5c95293259d764d1b7cfcedcbe144070643d2ae39c4c7af5f0e2748767680da357fde095050500e274ada3585f8f8f2cbe1a4e7a397c3494f4fa269d4aef85409251f5a98dce1b13ded8a2f3f164159f261a61369e85113df4f48691ab744441aaa347fda455944c0477c7b8c4a45dc29984a689bbe2f4b4af9dd2ca34793e62a4d19a549d33094d2118c2a7d5bd8b41606ab0413df2e3bca1051a65d073ff8ee22d8ff44183e3d441a171ee3a1ad410c1e5a213e7b6873f0ed5769d2b8c83666871878f8ce79063e2c29f05b1896026ff9fa759f8e354d7cb5d0b77f14c213431fb26072c06e619306c66d4c466092e9abbe7d356491aff2e5d4914d0dc6bcec9f8eb54f83303e95a9c2bc327550bbe255ba4adf5da794e9349821f9769bc1be2d5368614cdf16066b7b041cb60fec832ed696bc5f3ca1c789181f308704da03660102cd01e31b4825dc7d2c62520379056ef958c4440548e0958f4541344d2860978f454140810a4130d18324fab1e86787125c5aedb458c59aa9897184168090650838c20747d3652b9d316a66f4e0049aab072df03e16158105155293b3a6b26ecb6cb2a89d73cecccad820ab523bb3be75d3e69c53bba91d58735e39b39eb5d65ac339e79c73ce4993d92b2f9ed315a976e79c736a21ce177184c2a94e9361c86846061950a9ecbb7fa78e0da4f04ae6752c59f659292ff0df8fea99aac56566aff3746c208557dd712c29a54b060364950ca972958e6a092d6ae7e138d2806aad35a334649a4ddd54a599b5b5d6fa5de09b9fda0095526699944b98d0a2658a315619da7fdfd1fb94461c7036650fafd37b78a511072ce9d62d51a669aa77f61fb813cd92ac805f3e161511c587335309a7904077807110aa28c2065d037cfa585444cf9c52c4cee401ab3e160535cd2c60968f4541522002a73e1605215101e38f454146334345413cb587cb82832376f00f3b2b38206207d5034be1c08724272062180729d8f1683084a2c243d793748a420ab8253d1e1149f8b02d41ea88b8410f9a12c7c30b6ecf5644440e30c85e3458d2ee8c1556602fbe1dfee126b56006414f92009134846406b0d84e4f8c0718d400a92806db21889d2913ef4dd00e0faa50e443a5c82788221e28b59c98be3443ce9842eddadcda4a2badb45ea799c665de4d96dd6fdb8c80ed9625ec08ecd3a5d174199bd60832075602fb31f1be6623e0ad525a378fd239718431674419fdb3c75bce061ef4b3c1460d0d4ea7323669b8ec5bd63aede7bcda74b9048627caa7632fc718656ab699f7e3807cea9249e7f463e265984f1ed386dab18c80eb8733be85363873c072faf6f2081c9b73ca9ae9a72c300bbc3ca41e01552081d773ce395fd42d3e22c00e90b08325df5ea7b36610964af073ce39e7a4aa17befde221e8a0c937eba3e0185007b0ff7e7adf1955fc2084279c481103a42982f044135bb8e2042b70c1abbbdbc9b715dfdddd4de5aa3eec7e4e9830c6054539a0e2a7e3e92c2012fc74074a0265600421982005195c01083a884f5ce1b3821e1f9e2baa6832850e3c2be0e008df4eef6f4ba0d6b2667b481b05d44024d3370d31a6b70322997a075c2c009ede5581c34ed609a4cb4db970665583dd7dbfdad5daf59ac3e9aad6be3b65f0cc3156cf72d7a0aabacd754eeaa29336d8aa76356e2983745537bb8e9406c1557d7e36ec6fe198aacd00f444f3a5726996f9e8a311ae99b917d6c3613029a594dd63ceb993346f4e0b1096334ca5eb730ae1f661effc9c54e8e1670d92730a5146edc155e2c3ac870a3ffd7eb687c60a1165369fec0748b0ac0f7e7a4fcfcf3a54f4737a7881f85983e40c968928430fa20cbb840863fa84d21a0d7068a1fc74db732fc62c96b43d3f3dac5b883440a2cc929c010351062b4479c552c8f25158f1530a58ba475bb3207c28756cd023c2906ebf1bfa7597b42892e96587fe821b6c29b30a77543a95523e951ceb08dcaef3334e19a65733bd4d17d18e7a379953cf469fecad5a76b2e18ffb83fabc7788d387dab8cebb57de3e31c118e575dc9669f50e69d54f357bb684ae6f105c8c09e9d0b7ec07f4cb738e9ea4807bdce0c37399c3363a8a512a7d8c335105dfd131106790485a3a286d30b6519491797340fef4b9f75e198444ced04924925377123943134919dab34e226d9f98a03c7a11902f542e62e475ca7467caf04c1a1ae4ace6a13d13c868c6e6cff4219233cc26538808a39f05042c3d9c3ede8e57acf2387428a322b10d119625bc5cdc884a88d710d28b442bb4e0c3d2cb483ca20654a078b9e4217e6c2e73cb7abc0125a53cb96cf1d317f27894cf0fc8cc4fe75abe1b80f88a87518af4995b9eb7b0c757b9e7f7bd6c93f21bdad5e22b2b53bae72d8e5a41adb4c81629575a3e7923f5d168b00588976d86f01739edfec9b94dc66f1f8c8337599ee310a5dc1065c8db51989d6fe9e85cbacc3f58bcf3f85607d3951695afc83cbde5f3d152b97c554b956f0022736013c80d0d4a595ac938cb9373a7cf5b6add689adf7fb7b94143891c180e44ec8785a49e50be254c26e9f17185336e4869cdc468b01d072273ce68d70a1532e76f87231254c6f87c58a37d1889987c9412c41351210a4e90a8420c8270829710a4d05112850972b8e2c5e241102ff891c10ea438c10b07e808323881931c1835a10aaf302efd9ce0b3f71dbeddc6051f8b7e64f0edd707831f8b8480e2573e16097124b96eae1481a3f7294726f1232ba0348190d2c7a499d155224de30de520699774b96488f634f1a1d4d188b0850fe50e118ca4ec7929a58cbd6cda351186945e83f4338791c9595bc051de1065bc0c8f6d9033d88f4c78b2849c5718937e49f4a68f8eda01962e67882f9d075c8c096b8c3fc819eeb76f728621d40db0ccf7dedb3344cf0f228832ed522862058ed72bd2648732263cf4183c555dada9691a1749363b6cb82105393ea5a657ba299e51c1ce03e131a46c1bb41b81c31a6ae79c53a6a646073b2ba0028e53686003534c310515173502992377e69c9d67e3d429241cb202a9e7dc05c7255183201ba23cc54212349062838de1d89d96a1be72dae29ccae9cde1fd9c62df32d7282b53c5b6e54d09c69f0dce5b3538540d9ce7dc66a2dc66ee40c91da2abc5b387d6054f2d0f9f87d607f7d0cee0551e5a20de3679ea2e3e9d2136d7c15f2edcb1a366a4b7c32a168cc754db61150bc639b73766284775bff8dcddf310f95f0e3747659ee7fcc7e62b49a74859bbec73d506da0cab58301e9375361d399a44fe8c303820311b0aa5720e6fbee2be244e9deea03245d22e3c9f8043b0e55b39872987b9d5571341ce73f6b96a73f1c58800260070171f974d81392e7399f23448398e9b91f2b40be5ab9619cf791e7a8ef3ef8b9173ff62e45cf5c5c839003e28cff9ddb6d557d320e7311ae468f464a0c0217dce8bac88f2a1dde9796984a7564079f954c9731be7d5bbd9f24c835ca63ab2d2d9d1a29c3e2a87467ea2dced0e50bbb8ec3166477d9e671a4465aa835537d5792cb262ca879487a75d21d551d2d3ae70c692768534c9fbb4abe5e10d312b5335a879b63b4c5cf8ea13221f678a24890df3b67278b14b0e714b0e592ef28cde32d569574863df41d4592c8c83b61cb354d7a0e6590a37d839128dd22ecda9d3242a850651ef084505a6e7a206702c9a02fb9f246220f49b7349c4e0c96fce85e06f7369f3d878f388f2cdb76df3e8dd6c362d009ddb5581e3c7a601805fe7993400c8bdd28af00c1b1a2f78f46e60709b9e4972060c4594114574b9d3fb2cfc2c0f59cff21869b228b339cbfd9b11dc1c7fa86f73007c9bbbf836e73e946b31a01cbbfb5b41ca6ff207c7222a849e737f2eb512131313636388c163dcadbbe75052e758dc51284c03ca711e22df73c8f9e63f361456c2f16444edca4e3d336a1a174efdc5ed4e121eca83dd858c4f83d463befe69907a0cb4b2d01cd84079408d408740811093688ce280c630a6314c6398c6fc9dba639f396f1fbd0d6ecea35d2a1aa3310a4483503936b8b582c8e77c08fdcd83a07e430d915cdef28e06a9cfb770ab645b82bfee6990ba7fbd24eb78b42bc4ce43556bfc880dba0b914f81649cc0b1cf3d87f755391f0140e322002d8820f5b04e9a00640b837c0323003079ea3f04cd6077ecce66c39fa3dde613c549af0676192770188d7e08918ff30fec42e457a0414a6153863aceb0962e56ea9ebf56d220f5f91675eec301c8e703f6e5f052dfbc1af53dcb588139df9cc6da85a2e17d95bfb8788b539e95d395e34c5f7017be50be0b8fca76472bc29cbfe0a1dd497576c7ee4419495e50c2e2e15df110c32451a08f063548bdf3b89d49332fcee1c52f641a9ba9ae41cf4f1e52cb439411442e718e92346cce39f5746c6ea9db2476730e0f918f73a8b90beddb379dfbe2c37c216e517ff9c2aec5b7c3816cf585d4c5ee3cf5962f54a968eca9df983433284b0eef4a0e716a263df5f6ee74d6c4197327efe3b2efa30dda4fa5c2c996bea64105c752e14e4a29a52c929d529a0017605054e0e921cc5bdb0dd9af934aba5a6bed22102a0c9640a930613d3a5767add465a78f8aa458a14fb12229a2d045522475d6dded954ea1ef763ce79c5ff696815101a63011059b137ab4a384a1232a9c6c0c38e2870a5708a2882b98783961084faec0a28a0b928a909ab0528484254746141df93441937e778ee062cc12eeeeee225fa907220c99a39028a35f5a2964468ed1e04c834998f2a88f454990c17ffd1129d2209d3432470039e0ead646cd4ce68743166a6c441ad47724e911918aa288c5a228723e8c52663ca9e425071cc6219b183b5a67fb0be9b4088a294f1d7c1169a451488421dda6332b5a11d83c462a46d0b9387faf76efe4e15a112822a7107b6daeb910f91468495f05bd8aac825edc7741cc92890dd625889650f24b48f958b40414181f8b94a0e2712ad2cc04f1d860083de80009545eedf7de7b1de763bc454a44211ec599a9848b31327a3b7e07a97449b34f19f9ea8a80b1749b4883c364a7a987209648dac10a2fe937220d8e1142b8c24993104028b1e2556bad3d3bca97a15a6b5502e86badb5d65a65ad35b662942f39b5d6aa0492afb5d65a6bf5286bad5eabfba895d2aeb4d6eeee9984207ad02e2075d7eeaf35c6d439e7ac996d89cd39e793a49f73ce39e7b474524ae99c34b3aaa539e77ce2f373ce39e7cc2ca594d239e7a4954e3ae79c3473faf438930579944a2ac252aaa70841330a1592c46048be0e38223939392378f98349f5ce3929addfff71f25afde4a78972ec9daa3ccab93bdfceeeaed33c87f2bae73387d72b4eeca35783d3380f42b53ca4c56b6eadf470dc0f42bd033fae9ffcc7f5c9518eba75eefab5dfcd4134ea2b2caa54aaa565ba8ae50b8b8422f8e9a92fb4f979f2f89ce38f3be57c8c3050393ce5e95cadce799dce19f9ebd3eac42caabc5c9c04b0ec7504e7e5926d0e6f952cdeda881f24fbead3e757e3a5dbae03c1897910cd43223ff39016ef7938efcc41340fad8b5fcdad5f9f5f78e774b13988979998c0c58fac56ab95912338be5aad565c8c050845f0d65ddca65d562e2e2e2e2e2e2e2e2e2e2e2eac1c63015c327e024b0f79bc7559ad56abd56ab562ad56abd56ab55ab1f291951b71c9476294992e2e2e2e2e2e2eae43cdcb251f59659cd8dbbc79fc4efa9d34d2e3e6ddd6fd686fe1d07e3a90ec87ccc791a9823597553ebcbeb9f46e364b4356a54a952ce0d0727899b8787b4c60fe72c946e2d16b88160efad6efd33fc2f4d26f9223485e0ec94088f31ac8de3aceb787e3f4360b994f43e7e4e4e4dce936376088fc2cb770dca70e247b9b87ccaf9966d9d27989a31e63b6cc294eeca5c7ef3cc8f4eec7c9739058e599600fa577cec92fbfa09e80a347ef9483c8a779ca743be28b5066d9f170fa85f7e9ab720e627d7a57432f87b7bd1b1e3ac857ca53373c5499042a2f82f3523967bd1a416495a71e5b28f706a98d160ae5284a5df378f43f824c0f4f3e643e1310a83cfe75c94395498093f3224111235580f00415576c018b2a2f951fc179a9f211163fe5205f8813fb2eb7ae4fdfb23778b30ef033cfb291ca593e233267a86707a693c3085e2488555e38c35abc54d9042a3f62e4088ea752a9148b04b2ca6b88ea2a255ebaea3b62040610a46812042a8e4003a457ca71982c21072d08d183931120e1a552a95443d01c238c5095f113d804abd791222658bd8e1851a552a9542a954ab1a452a9542a95721d6a5ea97c2404443002063e80a20a3ec45e2cbee2478c1cf980d2113f55f8208420b0f04ab911553e825d47470756f352390c7ca95c07c67aa91c765f2ad74131e5e4b05e24c89a7474005f249859e4bc54ae43cd4b958fa45890405194d4c31150207ab5b37cb865240c8c48820aa028a20913bcda531fd6594287064f9aa2387ab1dc809bcee5bcf493147a4418b2ba4d57d7917424a4a42425298d3ea4304a779a4a33f552eb3438e7abe67a3465260e60ed4232854e403c9132429db5ce5a6bf459eb9c73ce7066e6db5148c0d1efe760adb5d65a6ba5b6564a69a0b1a047b7b5d65a6b6da552b214d02ed306e92907983a5d41ad55e626f4ac2d4ad45a8764adb556f9d55a6bad95de202c12a594524a29ed224e2808abc7a61e80ff51f36db0e3fb60b2f9cc87510aef38468a5cbf9b96757480f1d21cc6f2ba33f453852c9f79f46eaa8759d54094f2416648ddc6b8859f5ebf08bca4535a9988c0485c62e715738e4b0f515f7348552f652e129d3565541fafa084073ff02096745dfbe2ebeae8d0afeb3005bca46b1f4c01af5bc48629335dfa1035687e73911b4586a8e1bacc456e9e353f6f148ac5ed01ffb0d7adb5d686d676cf69ad9cb2670eadedaeb76f6b53497477370a093846afd189287bd8173d5e488df9fe80ab771354d1ab6f21c61863cc818b9ff9cbf4ea1e0d35ffa8be65b5d25ae9f4e961ad744e1b16f9da56083fb2a7cde1b63d37bb6ba320620a537c183dde1eb27c1bcca69d76ce9a79cc6c666dadd46809e50d5d97f1618dd5638df1e5f404b787d6d61861c40260edc72590a8fae48f5cb2040e553c774e97b019a3df9f8f7e97dc1ecd49d57ebe3f15ab4807420df634c771425a2371b791a60c754e7309a47d5288096b1e24854efec28bbfc0e2210bdfe7b81cbee4d8e00b2e788b1c5e8d2547cddbbbd1a8834893a67bdca64780639480575209060f675e3c045b78e8979b81218733e04b0e416f91435f71560e592f646f19ea4286c9b0560e59cff2cdee9934f4e690e54340c1d26bdf6cba99541aa4b149d33d53863a8b75354dd334adc8d3eea1ddd33ddd036355893f9726951bcee3a4d2c414a314c6aa92058e455124f9b07b62394f9d73ad7b96b4fcc41ac8c5a9b7500fcda32943fd65b26ad09cead09cb934a94c269cf79c7ab1416f1ebde479d422cf23569e47b87b220cea282bf02a87118ac7bc88d1aeb8720ac2df4f174ef5b17cb741edae7c21eb531f4651d8fcb05d76702887421ac3113de1b28df85090da2593e88bba14e286a064ca87ace7244f266574498f60da004e82b82ba43f2608b87aa51ec606a35f1f1fb66a77cd0d84f5d6bb57f59b4320accf9c3ac1b1bf968dded6eb57cf22d3d38fb9d5441a9c3ce827903e367d2c72e2e839d4f51873bb1d2db85f68fd3a57bfea8393420d4697443662d3ee1ab24cca9aa3f51cab5f577da11c8a992e2c90413336d13d66fb58acd8a3c1e9493e7a8060cd8d18345eccccb0c97a90f4f4abe31660da8e728e76403e8b0abeeef9c981749f4979fa6ed651fffafdaedfcbfae4132221e090555d131a923e358730315618ad9c13e40cf2afc77b93b67661150bc6634e5ff44df36cdb9cfb429ce7502894db888fca2dec3f324779e6d8bbbfee7da190f73cc779afdbb66edb72b47e6f563b698b6083241b2c3d2a6a3182b1c17be517e13c666b6f23e07af56283f8ce9bdb7160df378d83e42b97d4ddb9b5f98f76fc1b0e5cd484298ff3b67e9bb59947efde0f48f759e69c2065a02f75a48c214518526bda9343841bece01d7007e21d1cbd48cb7a7c5d9f996930bee2940111d01e3da7b55aaf5996f38c182e3c78a65df66d749817edaad35560b56930fa107ac0f363d1112ca689267a607d2c3a32a20918cca08a9a38c14b3945ba0a091fc2c02cf133869f4aa8e2a7b39640f4d31de9053f1d449a62866615f4ba4f70dc044d0a25377648268e402f66028b2a7c302f08c5e89b76950541507c62caa78d4c3bef26dec4971c396d403dca9843e3120ec738d48414906ce10947988003093c11a5084c20f184931ac4a224347df4c8c2d98873768843ea2ee05eb0c0d31b7cc9229eb89726bcc2d196a15485733cfaa2051cd21570d1025362079a503246d93e240338df3ac06fef0cbac4b55d9e85d1c7a22c827e001f8ba6b0f3b7cacffbc7a22a489e9b2e001d6c2737bb168e8eb4669953af0e88dfddb1dd6670a2808b31594cf9d4c7a22c90fe5e0fade6f58b1f2a0b1c5bd5c1cfdcd60c3618e38c5cfdb22cacedb2653d5b079f7ef496cd3a40adbb0616b87aacfdd5876400e7e34b0f87f51f36b7ac570b7ecde01402d8e0ac6990c6784a63e02168b4cb86dfd8d1ae968ce15143dfd0ae76a0fe621aa4dc4b0e382646d2ee8e9436c1c518638c20e0a20f3a549448f96ceb3c1c324fbb4ba95fc7d7bbb93336f35a83e050bd0650cf5838a867e057af19a6c129ffde4ce37a35fa33ffd1366dd3786427a384c35e12f6922823f3a9f98fead7c3fe0982fa3a3d1aaed3eb54fb9c7addf1f1f886c8afb986061bc9a97b45e7ba29bba6a710e76f34385dc60a4c9d46bb5e34388d7aa29a70d8dafc7a6bcb3a40eb46e047b1146ec7aed486a8596687ee0a7694cd492cd1de4e4619b2c53b5f396bd5453943124a765ec6c7247a80f22ebe72ae45ddc6095c3fedfcc9bb93774adec5bb961677b92e9300a2e70aa28f47f8588485a5e7629c0b404c0c31842efeb9bb10b35ab5388c77d3d2c24396b7b4b05a2d2d0efe8bb35a5e5aac5a5abcb05afef2e2ac2f6cbdb4f8e4b73c1a5a5a5a582dacd56ab562b5f06858390bc6abd1b26ac9a10b003a292305a31efb8b8eb6ab8bad9717d66a65af8c48545e8d7e568b5bafa9e1408b7739c4f9b0d5b9388b77e3925b5dd6017ee71d27bb2883e5e1ca5d9ceb3ecd5dbe95cb5c01e3afe5e2d8a357a3e5e2e0b7f0556eb9641de0b7607d42e8b7d444182db915447e8b0fa1efe24150efe25de72e9fb74e832ebeca43bc1a2dd925374ca6b3439386c5c2d8cb3c9539ae020e2994cf320fa90f479d70f999a73c1aa85b28ed9a48344a94113f73ece9a06e5de543e4ab72a8f216a74fda1576f4e8e49953a376594f870422e7bd065c3fb9c5d1f9c9a3674fee33334e864e7e7c1927e0b0777cb2ec4f2ea384b1f79276fde8dc25ca6079e6ed4394d162e59973ddf7e22dbe20a8f716befac297dc22b33ef9288f0617ef9288019277f1ceb9ee5a7cf15961e7bda3c365e5f275df10f9abdc79236957d8e28dc400dc0164e8649411fd6a2e18f5c93841777e344f8359276930f396ded1e171f9e1e22d9e39aac54f1e0e97165727a38c1a3f1a4983990b91dfb0063397fec9383165a2c832ef2599b792768529e73cf3ee69d78f944bcffce4e9b83864e6663dd929ddf5ebe2ad0b2d6fdd8b343269ca646ebb28e3e4d666015ba7f625bb7ebb76757e9fe55bf9427ae433c7d7a6a76748680a5cf099a332eac367999f3eaa136164d9cb4ab8dc4a1aac49df4abe36985469d267beb9d6cab20ef063bcf4188f5fe22ccbeecd31dbccec5abb9231394b4f3fe7e9d73b0d1abd18f2e9228df59932b0498dba259f4923955aa6fdf6c5392c9fa40f2f351ac12379991b49157034d29122a9101d6a1775a16fa73c1d63e740e9a40a34581da5056c33db1dbbd6aefb748690f2e8095116b02462c2d14349c4235dee849dcc014b4fd260953cedf4933cf7933b381f3f943b3bed4ae27937d7a90d67bc8df1f6451863edcea457f36eecf7a4e92b112889583c92087505b6117d48283808a9324742a981c68e7ba3babb2c924a7c65e2ab5fe9c4574944d439a722c48e76dca84e5c29be56e1eb15be4220cad41a228c5a6b751bf161ed42128976925031aab7c1ec8b5fad95951d8932d553f0d5b5eac3d72875228ceafdb125b81853eb8976313eb6100f44199d479f51d3ae98301a355218956c3e1d94ebe02f541ee274726f9efa74ca5d96655996d9747b5ebe0dba1061f4e57278318be53974102996d3a06c6aa00e62612cc475db303303828dd4488dd4d80672a8652a876d80abdbae85daa50105ad4481fd45003af8877420335abe9ee51fd72d50d3dccc0a1cbfe60e6a705aab65ab63f3ccb90e85c8ffd1e08f5a4fb7c19a43e99a5f29447ecd2dd4400dce2a969870757bbbe8d56a33efa67a0bb5ab851a9cd9965b9affc802c801b7b68ca3baf4ea12e79b4a834c587ae640edba3e9b4a83424dd34c3535333320e80e04f4b997ae9859c78a98f08121d949d2aee9cdd3edd3ae56ed9e9fb37f2453839369d2f4d24b0e58324da9e4920a4b4e9935c69de9f7eebcae072a1065a44b9993a68676a17f8c34f405a485bca899345dc51cc1cf69829fb25156e0e9311386894a39a7a44d2885b7e3baedc4e97cd8d9af818830a4e34f2e913e0d4a5ff9e451835064142539452e354845f650ad6b50a5d1a0e550f27c96659206a9dc519a342aaafa62cbd8cc8532054f3d942a784b79d08c0a6c352d1f4d24da3a4819a8bff49108833a8a0a0e1b16ca1d9e250d0b1b565d228932b81444192a90336c3498a6c5a9d3b8d13c6a6897d7f98ad3148b83dec4a282a750ed4600394c67015bbe292f616c41bc74ed0b658ccaf3681a2a75e453c733a03fa5a15cf20dc4cb9e06a5cf9ed30da088f2d4fd6733b15ee38c33fad33c5f3438b780c338a5083fa713998e838e2883c60c25e0f67046ce3441ad421ac4a1c13a535fb4c801b770887fab3cc281c794a95e6b787968b9facd2c6b057e418b504bd9d2532ef55c94d172c1e9d7e75cc699f66e60e02ee7b143f06f58ab1c82d82f6b53da563e4ea6a71ebe44195cd2eca09df006c0431cb2029077a6cc0e8bfbe4db9d9d18616cb45d5ce402d07217ce5b3c009f8c3201b28594274d841f25529044d1243dc67c97366e3ce7ccb280e7fcaed75dadd3d932f35e8c592cf79e892daf16617c97091b71775e88b577e3cec56e8c15cb2bdb452ee6331213f30db1721b6b90ae7c738e5badb8956f1f277d6870d1e8431b933f3120a1a7edaa31fac99f2c8624611226916412d62e942522d24c983d4245394efec0268d8ce590857de6ce53e91305ee3cd39cc60d1a1965564e35a114d1d316bff2d03ee988f8a0d8a476b5df22f0114f3f8bf434b451a8671e07707cbf729567de4de6ab0fe4be0de7f87da1fcd5cab9d975b2bb9573ab2fc8c62c1086026b7e6dcfd315a7fae2ab3ef9b6674e59a262d4347888286968680a8fcf9c3346c913238d84b9f018b73d93c6454c6c7a37ee12264f2051105d5f8c8bcf454c781dfb09853f17dffc3e9739786888c8e8fb88c4fa933945b05dc2d99e4c4aa614030aeac1fe7dede2eba696a1cea18686888cb0fc49c5a48ff489c169629c3a456a575325fa8446a152fe884279ea315099333444644424d632a7c884090db56b23923932c7b9542c0614f4110d310de55447d4e04a478de850cb508f439808bbe09e9fb6238bd42e179cb63f793a145aa2580c288849e614913f34168b01057d1ec3d753965a667e72480ac9a09896635f963e43b6c7f6d81e18fc85176230786863b1185050bb60108a31461a09f38f1219c5268d84c162b0180c990ec5246ca888060a9a33d6ae060a9ad7850fe68b8592281693b0586c084b18914913a363f8008203b6a1b1d118353330c6d85b00406c5a6cd7ed6ed6ba7df4a54733cd33cd6e0d901e0e9b969a474bb7acdbeac7846baf5e8d76cdb7f656bdf2e2256e078f28834764a91c068c9979511363e8a3116e998e9416a159483b8f1e38a81a0cf1b766a7edc27b3dc4f36b5dd75c4583cdadebf5a7e7d9d3a7964315fe1ab2eae3cf5e81c58a2c161478649c4bf209d29c89c19244bafdb2a2741d70599679ce5104643e3dce3a10d6739cb56ed354721ce736e273b9d5f90fcea7679fa6b9b5dd17b3edbb1e3d0de7b56ba9dbcc4a7530b21e63381df5ba4df358f1c801995b3aea671c11da02bc39e7b657bc3ab7f2e9acb80efe5ac94374cf0ebbacd56e3d0a2127f6b1a8ca949ff9585445e83397ad2cfb0b06e6c5ac69574d7df2655bbf524a4f3990eeafdfd891caf7d6c43458dd7e30355f2594af2ea14499f1b5c624d0db2cb331328f27b76939f4622646cd0c1bcbc9cf935ee7ed7e925476a7bc7329e5951fce5f6c65ec35b7f6760d56d7b2ad6af14583d56334585fdcf0516bb881478f6a933c20242979555152926fc7ac952778c664dba677e4b28f4d49c9c71438da56c518715ef320d96b1d3b76f4961e3fe931768c339d64e5761ce9fc28f5ec55ac982161efdda8d5c16164623982439611608ee36c8c12985a29734f4c667289cf4f9090b54d99dba8f51194def95aa791108165457424129a7110b8e965ce0b8b8a943b836b58434715883452f63831f408f858e4040a9e93319ef4ccfe6919ea442ca1a714e82952cb179c043355286f731f1575f6928b31fa58e484cec725708da94b393939257855aa13c178e3440922183f9c3fa77f31b5552023d2ca1370d861556699703e3369b8ec0ae03c731b1f2d235d2addf898028711c9864c3a47135f92c85fcfbe2dcbeed558419c94525ecfbeeb3eaa80c3eeb32ccb5e482dcb315bce42fa32f280b7b63ee0ac4b89f2a974523bae01ae01268a30a4b3ac80b3240da5913a4abb3697520a4d9491aecdcc482469e27cc051125df2d4dbe7a96fdffd79da4a61f63787528a979e25f1205f3456d12979f00f587e28633d27f5592b95924ad849545e7a272dcd9ca6764d29a9cc9e43404c8f31d185053864b500677e1dd57ef2a9a150a8e83c6ab0215aab9d3479e3a975ca3aea9ffc9489ccd99d58edd2bcadf7e66d61ba8de3baaeabb5ba8df8b5baad6e51aecd89fa22f53c7a737a9c53ae03db15b950f25069a9c5d9a7ea69c364d57ced1733944eed0a3e1dbeb1c3da1b888ca01cfdc4848228ed1b7c08c1214a0f2ce0248b3bd9a23e3db32d9a75d427d2e0cc7352596b9535c8c8677635d8d060b7272fb7f9ad35f3ea35dfed9bde8da6759601617dcdde63d2742d533fda32b5557d7a763d6bd5498455050e635205d2bdf41eb60269b0fd063a054fbfc1519fa13d3bb620e9b2c00eab603c2629d584a3ee0385ce4b263e1625fdfc9d1ca553ceaed6c448c2d3e012d9438b2091b079830f2138f40e1e15b0a1460d0d9bfa33cb1fd615d8a6bdaec1d99a4e7dd2963541463e5ceda4273dca04156384cca10f20ac53e652c887da8d36435b46b6a44f3f6539c441f29967d3bb6151c1d6e5cca489b154d560744dbbe19c524aa957ead5afe3fcfcc24ec894b29b191314cac1a641797b4cbbeecd79fa4c4b6f15cdb4d658bde5d987bb191bb0a3c1e8f4931186d72925208902e56351139a3e94c1bbc13d387ed83ab72955c5d41f70c4e2763845ed17661edd5a6a53dea35dd86b8a13800ef6ecb381abfc1ada1581b01ee756967976afcdf1d2cc1b4ce59afaeea76a10c7d01d60cd0dee7eed9a20f862264637f86266864d8da42c1856b594fab014acb91183c68b991936747b42a5ddc9fb6e5701bc1263c570cc465abc03968e7770f53cbeb0cf4cd9398d80eade47c41b949293dd9eb7f5aa646ab0f2e8e17d3bdad57da3061bbaa50d914963633d8fe621b0c6a12d873787b8dde6069176c5df41c3263669624853a6fabd2cafeb52de8daac1c8e231259198a4944c9249ca5c244524261403ea5877de8dec6930c6d8b1e4edeeee9eef31b1983aa761b1450e0f8f121eceeb4ede8d97a592259fec69b0121165aad75a2b11be5697d5b9163918b35a8c403221b5773747e77af546523daf95c894a97e6f6579b4bbd9d33bcd934a228ce944264dc52ca62f9459f82a99228cea282b7018a17ce7d369547ff9360e79776d336958bcde15962f4699f6952fe66009b4ea3cd66075c9d43a4dd56d3e1d8cf3109ee7f6e4799e976fc41cdee25f4ffbe1bc9bcdef4d3add8bd234ef78384ee3384dfbed5ef7fc5aeb1c672dd5bc3fcd6d66c7f08d5102ee1eae657cc0c518aea5c4e22393583df368b0df5ebdbedd8b0074ac676d6d56a54a95a6cf3293ebf16623dd6b08af06759be556addf93524a339e55e09ffb3e703787403acef6607be79ba793344fc3d8c631c0d5bfd6f4ea767a7deadd9a59477d9abb577d6318d91d23fec431c074ce49b3147a49d41f8d021763f00e4b600edfebb776d7737aa29852cfc321ce9f3ae53f6eca39af1ffe525fbcdde18a3f9caf28cfad77f276452f94d6b3ecde7c1b9499c7d78a6fdf5df96e236007c74a85dc9bc31996629fc92c7515cbd638746a5bc5c2d4c419b1b3acb7deb9746b61da45ddbabff56edbaef671b3cbb42ccbb2cca79f3adf3eef0b25e7d1eb70bee3aecbebdb759ba97d99cd730551e2111f8b9ac0f34d807d2c6242ecc30570281bf125cfc7e80d25ca9050a4cb0e78070f1e11c674d901872c3a135b3aea530f65d3c74f4618a15422efc7a728cf3d8a9ad2f33a07c27aaf3b6559e67954f3d97d616cfaceed173d0ee7b97af23e7977729b9969367d3dcff372ebe43f3cb77ef2dcbae71647484c3a7db1fb709efb8074bfe5fec2bbe4ab6b5f88d3f3d56de6955b57262ec684f4e8a97b94513d46a49d4913693879eec598c5720fc12a83becad54f02352885688a5c18b00babc687428f4d47ad11e0b07ba83766f9ccab582fde4c8de492e3110c39043ff4687473e82b398c432f396421b1587238a30239240d2953a197432c39a4658a04438221c16aadb5d65e828434699a24b5d252f760016b9244143655990251a1068390264d0c1f520cb9671065a8e726f723c27311df3d58c09a906047485192a428f594a5a6d2ae8da969e6b40b069b50e651bbbaf07ed376eeb3113f73d55763d42a818402aacfa8742d3685492b999a010000005314002028140c078422b15038265484553e14800c92a64e725219a95910a31432c61842882100000000044064660201903e38eb3de841ee805adc29813239aff108b46aea00ee5368f5c454e1dbb9f50d57bcacfb0cea2a528930e4ed788a6b787fc9a547d295c13fa05fde8209b1d1b4b31b18c0d2f84e0074d5620afc02960a45834b953129461ec535b9b1ff227ea5b1b1bb0fc451fb139e3d3d7cf9fcc46621af7bcae73b2319fd2bfa5d579c55c560b119920c73ec05e6835f382d47a515a0394627efca95a3a41737868418ae7928a3075bb2fe2c3085ab012453ac01db100ca4d7c8479a082167611a8be607032d8e5d117cbd49a36d1775029e846a01ffa7b7658d360ae4fe2abd2224c09ef5e4da55b4cec642452c8524cf173a9534da093118d68ddc9333db22947833063262a5ed319885111adb9162f426de0ce1f5fef2f23e641991450a0c124102f647988cc78b6105367df783e8c18a5b2bd388dc6dcb96ae186344dd9846bf27d2ef388449c5bbdd88d4e22df253bc5dd8ee7668ccdd1eb90185799ef1f7740e709f224d1857d3d439b181bd49ad035a53a2b3b0e47e95bbd6a191ef2f02865bf808df98a664379f71e3c86eb00025952c91c0b6ac075ff33aad85955ea153f5bc27393c92b17bd315af0b98953d6578109979f36d8c2d1722902b6fbcd6a4a8c6206c1840278c3428f582a622db744a8a1cc590c062f9dbdf440be6240dfccfa2521539a5eb247e5cfe52b864755b016c4ee18bfc8b270dd5cefe90e627f775d64391800cee56576087f178bbf7202ce7d4dbc043c19d2b48b40e1cf07f078620170383aa926ce3f20025e035e8eab2937d6c7904db7b318654666cd318db12d5ff2ad4a7ab686d200eccd16804ad693a20e261966c463c0976c5ae388b48f38678aea05981ae55fdef9bb285ca531f962d8615e67f17ac558a2941a0f65d44575c2abcd72cfdd87151e1590d20d550492a6936104385b72c5f89120e414899551d3258a3c207a6c25a4ee824e15390efb7891f93137dc1121b3e888813f6f4f0b845c4ab4e5e11ee44d2396382101c4483bd9427d76579ae292753cb6220fc66ba96f25c4af9c33927d71056c214a98e4cab3641bea0245629bf827f8dd66c00d51df8ce5b8efbbeb9c46be5816462d20206f32d6724d5d2cd7fd5a142abe5e8d92bcf34df8b3616f3d6f21d40c4787a0837841e8412b6f300332cc9ccbff8f6833e9af4030e7ace7cfc0f2f78892aa31432c0fda978e80ebd95cf2c1dd492526f8b892b39bb70e8d76ed745c660dce61f0fe6513b1496111ca7d9a026293e724083133e1fcbca73bdfb96cfccb32028a01cd60c039638e1ddca8d9097ccd9f3a39c3c81513958f47648acfcbdb14e1c29ddeb727101e17c26cca1980e79595fa783e2cb7acd20a3acffcdc755fc5e16cac8fa2d780f581301f0933c26d4651ac6269920ebd9b4af47437fe14ef793b1fe33a216a4299cd92d70ef5b52707be2b0617d1bc2fa634dfbf489ec23307dfd29b0b0818a810e7255f6f05a58c3ed06780b2f55525f9fa32facb71e8fc95792bbe9f5d78dbfb04e864ef432a7050d8c896ab095a73a27957e85f559ef02516a234d68e6571b36bfdc3d6fa87c70259c4c1ca33af5b637342cebabd875af18040555fd6dc4f7fad8f5e6d6c5a938b94f69d17c87f76b2c9ca4140f314aecd305a28f5b599ada70a21e4b49028075b2040fe9045a15267dbacb7bf50fdffa88351f41172ec77546a6f74d9f4e3e3f8a45d959d04dd9c69004d298aa3de3e5c9544883b16560b28649b2639a1fd96ed15f5e4a5c05f57c5e8a912ace8410673565071e78d5ec2cc4ad536bf3022c4b7927d134c412d18385adebe470c510a352a18d94580ed352d0c2c4f854aa124dcded2f3db54e520e1fd49bd2bc063b05e5e0a48b7235f75ebb6dfc72da5bc115127e3c28e64b7bbdcd95c9dfa72dc6c7c7d253b43f6ef4b1ef3345486c545c5eb6d66f7f81a9d302a5f5f2730b40442f9d943b1138b11757fbb0bf3836cefa40446c5d2437f0040d59cb562949544de36150264e720a9f41b8b795ed73855d61b095c08b3d4194f62879def1961c56b551457c921d693edbe7c373fb39dd03ed54874dcb76a9460056aa0a9410eaabb8e8c79114c106a71b5bee9a6b817cb4f2384609e740a3a1640443a228533f0d28740ae804a4742d97eafd3787e28d1febeac80ac7e84e94b99645a1017a2793d1cc1315991eea22a85bb90e9655549a3e071505acde8f134da212f6032bbdf83a948ddb65869943824b3d7b8ad3d97dd09e1fe67db27632a0b55709335dc225ef195e42689cd145afc89c438ff4f891a421846edaf3264544e2ce14d98be57f08318c7cdc85182118b7262ec99de23f427ae18439596f182cc71602acf8613790191ff8ae078548cc08e38930d238a5b8631047b93bb21f5ccc405a5f32ec76ca8a68b808b1baae45c2ef8757af4111178219b7da8640ead7e71a910af8ce4d154d0092c56180600d202c9bdea24b63fe169c8687b6e4c453ca7ad28cd268d4bba08f946c69b197ae7b34c082bce29ab20091aabdbdfd12b480186cfbf3ae13f1a6914dba65890e221471a8baeccad6aaa1b52800925cc2ba9f43e0792c6c0805838a679eb1281ead0cc88bca21e426f912196dd3640210e1ba90a4e139c26d1df367aba3f7cdc9125ae2c98835df7a5b1a9338fcd281b79f23b846acce9b14bfd864b23bd08a8ebac00b0e98875812c564ed89b9274597bc248cb9622c7f1d060f3e7ea482866bf09c00538e2c2f99fbf15a272e9994e48b39bc0641943ea055b823c30ede930782df48b514d36f7cf13373dedf114aa6e26169d255831e9c1886a73f3a9318fbd60669138ae6991ea7e9e5ee92352de042ec0929b3670a3cf9d8b0e87014f1065c3d5ae2c7a85b86c0e4d1018ad1d30e2a69c7b6fe22ec02d63103e6080efe139d827da87d504c1031f9e6794744e7124a99dd69ce2c524f9c5210baf1de46d238130d9d6fa0c5dd2a050566489dfabcf8e7a31f49c7122ede3eff0d22ef77e5ebab1fa73440300f5a5d2776bbeee6b6556c72c62da6ad3db5bbe97ea1591a13aad729da07506e8c7b3ac47d6bfc22aa650c019641887bd26be4352bcd163b9489ec5c2afa56f4fd5d47a8957375de08a776aa55aaea0149de260e3d3f758679169f7a1660345fa4011fd8a8a224219fba8702a1a36b9cfbd49af5b0cdb1797f4a51c97f25854c75cada1a46bd7dea0f904c9af2735dd6c89067ac688c39a8309a304949b44530ec7080004c4a1b79f5fac1c5e1a86291d578e38cc7e0d21afda0d385693baa44d32cecd50ce34b5b45ece47220b55c577071c037c1d477922208cd3bb51e99eb02f3f1c9106135a670db491b17431ac0425b243a9491e24d2cf1f280e9319d37fa3ac59e56980bf8824f6866b15fee8c79d9eff338d83f0ca930b75e2612728b937dd1fdc54c769c27db36fe13b2b75ce034546b3a4d15c4effb0f057920f801836af97181d27ff46cea3cf6d4a79e9b886ba37240bed7a2b6cedddbc46c55f40e2813848f9d6307f5a5dc06d91a901211492fd76836e620caad77d188aa030a1a48a6509444c9a009d3bee5a2c8f487149890deb894a3250cba83e712afd090b22b0e4276a00c08a98a65563339c8ecd4fe49267bfbbe23a6f3acd030a7a7676f429f07525c0dc4ba6cf709175215b3754831d8a010c78821239023c8532429b047472a35c468f70026a932e77bf51f44034cc4f02da70966be349ea8ac74d142aa9c3e871b7f4a5b20a528c071461e747afeb39b51ad8945f7249e3955065dd1cec8f7082d53d17988abf76522b2d32d121757cc4a72ef8b7eaf417b363d911163705ace41e79dca7f3be205ff86346a95431ec4e708188443e8edb3a2549f6ce625856cfa995da85c7f45e8c8d9c12ded98e76f9c3a0681b8fae6256e2b2013779fcd9b97e2a785cdc1269f47a19f5621b16c69f5091b77c3e236edd46ad3178840c2202dea1accceb9d0af46cc8bbaa05079c15213f8417cc779c130ec11f98d2f2b8d32c1638462dcbe498b75da2cd627a04048c5e14756b2680dca2d76e7865d0b774e6623f4a654a6b369260ad8b72ddf1398dbb6e6c3f2cf841342d933bf2e98e4982e05293ba5e78c0e5e49940433cab9394e3a44f9230113e8d5cdf23262b6c5a10675ac26ab014301e20e990b618df6d0a04da623036e1da8c0ee677a5b2b904d04bfaa51f8950b7240d2d017712d651a69318880200dbb3822036d4f84c574965a91ab2a64a23aa22de87e8fec5b29b7fe22dad4207fd1c1a80feb55e078204e1209035aa2fa8fdd28d7f33423019654cf338594f746ada6d3533f82535c204d6e95954e870da628dd7146d029cb8473211e40fdb62d4f3fd824431be5440227c2f7cb0e015e2e10d16cd9b8eb6f23025fae1d71f25b70cb36a4d2c64192646e3152c85ec2a08cf62c6b7aee33cbde6dff633605c960347574e73776396d88bc84855253776d802812d21c669f977cd93430dd4640aee7e7d6f85536a7fb478ad3b23c42d7c5496cfcdf02f8f7515aa07204cb92e86ad02468fb3878826336b3064725aed1cf71209098b05e22c418661c1479ca243d2fc672c70b943af5012d709d60ab9310b9a4630ae8dce9c019071cc38957d82b40f8f89eaf87ae8ebfdde3c89a43d408a06706da48020680a02e792117e7df646b261a987b98c9a6f05403b33d6390728d84398abf925e8ca780a88a88cbd02dd3ec3be5d522b488a6b7cb7331667202e6b8fff75fc81024dce4a8a116e29a2570ce80897e28a3adeacb85821406a0f7928b2dc10704a6e021c0676aed92d89cdc065b4bb60146cdba5a44a769c44aa1ec3d87f6b961580f40e14cce69664b9612227b983210df05daa481d22138b7401bdca5adaa610de5597ccbf1d35443bd225b30913568abf490d455b34ed66d11ea0f1ac73787a45b206f61064297841b4b9c562703773051fdf1805c20acc9278b95a0cbd8680462a1bf762fc99995f17856d90bc83448c5270c687575abf8eecd83d25c3e1d1e9fb7802b660973561cf65c93c39314345db02cd9075239dbe6076c3056e640dc3a41f1c6d96d65deb9895a237687f54820d52b679c792c148cf03c2900f75c05a996b5b8487b9e95e02134bd37ad339b3f71fd5fadd0371d24932287e964e366c46219edd54a4f1df60436f51d5cd824325a2c4e95cf46681c4f496ba8c1ee8b8dfcf658cf34bea02e9c83d9edcaac44bda1ae62ad07d72a36a7b9864e8d0cf92c72803a2aa8207dbcbcb8f7a6e54a2f2d3e7d41e6ecbd90ed565c764e5d9d1695372906751e4ad1923f762cfe0ea5aa4b2c638517a3779efa0285e35700290c98b11c253b6ae85de98f19a074e62ccb1d58b95f7981a2d7dad2ac739c12c5bd2ee9f2dd8047d1996c0e95e7291713bc7d11f9dc20df43896b8ba7ba8a6adbf37735db4273ab40ecebe0d46cb6a457bb82a5c26477d4c86887593cb7578f2d27c1550faaae10bdf206446b1f0566e3b1ca9ffc06e7b7218efbbb15d784afa25ea8e634bc6835209d71735b778da5592e1770be931e5c5ac4ee7e72f90f65573019c48212a10a97eb7fc398d616a4f898c0e6e6c860d95d8cc86cd24d860b847e11602d1d04738c7961a85d34b5c93ec0fb2cff5dd9e8a188a40a6748659cd4c17dcd5a54c92b23677afc295be85d604cfeb4dbd392689e2ec8424e50f0177a1f62f00e42147a78f0a1571eeac31817fd6e5471e04c0fa9973a335d82aa45926c4d4f8c5481fed060312735b7b3aa00e32340453fa57c69c77c175203e836814f9234470ce570d0efff966ba21e5372d694c5d89e7dcc0b4ae6633dc3eb1f57f414b862ba4900dcc6170aae1d38c447f51882c0263db00d5579fb0c0814380a15f403b90b98c5ee30e2bfa896be45fb5d01c5efcc42bd89ab7622492338936a281970bb1d4740a7f069e24c11d6ff089becb221a2ff6c904bc289a3ae5dc438085259ddfd35a4f20c260db05f561c50e2fa3384e6261c0e45ed7c5219c585facdc3cd3028503ee85d13761a8ec9faa64180e530cc989833a016d0b786633ef29647212894d4979a9c5b736bf57c0e8105806debf20a31856463d310af5f3f349bbd3efab0647d386b5592793f62985d231b33ed5008b480bf7588629ffbb57edc3ffd1cd8480d7672993bc9d0316235a6a8d20a67f433ea9bb771b6a2d1980f77f465bf30887f00954a564e580c0e6b9cfd70737d680c186e57487aedc35f72b5bc00c97fb491efcdf5c17fc16cc33e9f4d38dee7d26342f51d33702b00903cfc4932b19f8d2884af85b3e58fd298ea59094a90a31d9cdff14b298e6434638aff029def133714e0bd4e2766669dd4274abf3826c50c9fd4ffb6936d4248a19af89ef2056ea7d01514d16c7ea0537c996e269e79548ae0dab245f11025a8d1069096915f966614bbb796b23d715c04da9160ba217d19e45c729443a6dc330a05e32878cdc000ff6a82ebcca021084c56069f9abf2ad7861455091ed0ce27d47c6599b3bdc992124e57299a4fcba04f3cbe6474b6c132bffc8d33238147a820b638ec08ceb4daae08b81ac302b3ea0ab8a202debbe46e0a9857243041d95df293e209666acf00d20cacae1cca2cd8e96045d98a3703d0cee8cc3433c87f5970f20376fb8620db21b76fbeae189570bd5c34e1d8da8848d177451033e324a8909e5de1950cef2b9d18030b57229891caf3517a45fdccaf43ccf025f724054e34045e90b7066fe24de80cde5fb77fa179a020394575b325274d6d55dc79043ec1656111eba75dc6029be9bcb6d3148115b72999077bf02e13fb4bd7ecf20cc97107cae742582337f35fdb74d61efd0bd1e5d82b69f2b274a027fc2ddda40914314b0ae803ba5270e6d034089a1ee2f80ba5dcd7d0c8049a5789eaef22d563be404499daaf98a721683ec92aa377c01951632c7f491a0aa941e4df20f92c01e6917e3279cc276ec03438fa0be22fe3383258202c751fd2643d55c106b3b06c8a3725d0ac955ea4b223e05fab0bbb51d9d5910bd5248c476736860d11114ea2acf3258a4ac39d3e548ad58d41cc0c237ef6d5524d5b728513d29fae1b79f46c2ac8f7ee0816e18386ca748fc032e8f6f006f0138004bfc07897a6325903b6497e48cfcb360ea02fd3ad32f00655812d5bf20051e8954cba1ce1086bb450880a4193aa2e53b296fe4699269c19df1d255d7fc99b0cdac5820bc5fda4214c44c062493047debf217ea25811ad9b5de12274c85e7c4900594bd82f49f0ddddc4e79abe68047e5cb13f286b3e8086208de8335c785e3d9c20194275f88258a7c202676d6c89f1e3241eedec0df147a9bcea1d2c39d1a376b3e79462bc59c7fb7e501d83d7f22436c9247ec506a61c7c912c51a8f6a282f0d995516e7c0195bec8429968655a7d86ec5b4825c01c70dbacc40e75f89a77d34330e5432a0bb70193106925a0ee617c838aa9ea5cc5826da6052d0261cba0c724d8dee16dc0a25f68ff3c50ac7e55c2d8c16eca86ba75c0d6acb6d733ce3591a04fc40d5a87038f770e9ef70867e1c8aea175f8198a93238bca4929f6ab887fad563ac50a2cbd1b53e46ddb0283ee0409a57e62347ed16472f21beff3726dfba25d1003839704c343ed46af7c362a3777e9802dbec426e0edd7a181351cde384ef375905d15e0c0292261aeeeb7d3e67321ecf79169c9fee1aecc4d5d72d53e106c0734cada0591b42b103b012d72d82df4b24351b2f05538dc87a2543b50d344e93501ad43ef5097bab87ff2f6688f953e9ce6166435f88bd3d98de84f382751952ca2a18610c4725909eab59f19a4349d2f1077a944445ad7e22bae368f069e4e03c7bdfcd521f8b2d30f613e03214811ac9001358632f44b655a3a1d17c1bd2883b89f0fc978c02f0216cba9e70ce2bda4bffb117c43eba19f9872f3773c17d715ec7b7048cd5754277887d1b10d942af51a7e39d589fa690533663665efaf4d039ad86a687fc211e16c49ef0653e9c01ef0aeaeda5e0b96af440c9dbf4a764ab5768deb69599e811ac58d38662b0e305626c1dbd3e82562f7fdd1ef6bf5aa7b62eb9c9cfb2447265951770cef3c638ef63c68e5163715fbf11cc730792ae34f638553744e1734a86ec1ef1952591c383805086a51207f444a91aa1a83ff4221e93bc9599b90e7d771f994e0d566e411a44e707fcb6b9e8e0a56df3ab4242289442369817e6b7d8ee82e963ab41bcdde16761bdaba60817701f38112c7bfc8fc354b30a3f9ae2bd1d1a16fa59a560b915930aba19f736996ac079f08e294b95022280521e6a0e4999067f2a9083e5973e7546c1414b65b1836ee71e5bac7e6fb51fa5d2ca12114ee93cc8c1c5134226a4fb89f993d4cdb7c3b865e19c88e7d8d710492334b1cccdd0804784aecb7cb621b7c77e3818e670132923eaf6d735be3e1fa3a12d1a42708bb84c0e8251db1749eb5a98871795b78608fca6b908c384362b2c457cfe41f40990075938ac53c0a90bb2688246ea7347be3dc17a147d3928d4e05c6f64dbf0144b4885d6bc9000df61949dc389b315d527b7065d33e4c5035ebca4b20fca91c1a5811968d3dd93c758deb1da039ad3fe4742d65fab3b3f9e3ed61bad9148ecb9abb7f14386830e6052e240113aa01e69b7c1e5a77f857252eaf9de860969945e86b66e5c1f2b25abe5ecd3d81fec3e71032a2afb34cccf5f6a88aa4c67df0d8475cd3af49f2008edada2c1b07e4dec3464854aa8fb5b4540ded46b634bf1bdaa69cd8e6c9a1ffd0e2c21d50977e75ab83baa379910e30a76d833aad38a3571a4374ff6e2b895379a01879e99195696caa14087e2060e04eef40b8bd72022d705f171f513ffb46d31aad4b45cb78ad4368ba83031147a9c5717d09a9a4456c07c11543a3d989376d3cb9e5ff4576aa110aeb28524fe5a27334328dc3e04f3e322a20ec8b3856db81c4a2a7ceed2773f4468b54a98be4e350e578367935a628927f03b272dc565191325cd2e24f45b40a2d43e539412b937880f0f4fdd5cbfc39fb51a960e3ce0dc58428c455a6799f1d7b2e771eb5e1a58a9d8906212a685ceb17ba216fc671f39f82fa4accc98a08f5d269506016c9ce02c73ea86108b140c4d86c063bc458bf99becd8a00f1fe4810458d26e3bb301c9bee3069e5779e8e2cde37fdee0f456a87d497c4174ddf0daf7c2599cc21d88fcdc99c8af725649bd8da315d22cbe6077583c4f6e4ef5600901ab106b4996b3fd3abb023fc5d960db6705d347124608bf2ca5e792f3c820ee7e6d5d47d10a171ecdc1ae200c2024ad581684ba999094edf385dc1a0fc9730184e0c8bc0e571c0554f88403128fd876a25c7af82a81acf837c01cbc7c0d09c0926372d5cc68fae1e36ecf90288b000fc48cf096ed170a86d2cd5914cbfabab6085f217218aa5e182f13d4d81e8a20590de96521df74081abdd675ac0023b0755a7334d942513f549b37fb8d3e4d0f2cd613575e5dc6c95de63f8423eecc744f6751638d577359b40ef1790638c7c19517f03c1a57c3a86f5a7b4d9a315daba8aac758f707c0e472d7a0ebc0787e5fb098ee63001d91de1cac35de41b9718fbd2ba7c5ba6df40cd81bd6418f9ec28d275ef32efdb55949444d9eed9c3310327c520ffb04c58bea517fb33b058b2078ac69b7c828ca122566c15f0e51f4dc1dba2d014e0793543f95f18ba5a256e4c0eec81ec5a4f5c5f0419c658dfbd898d42ba1c0854e059f778b4e32b20489dba8ec268eb0ffe9f5195cc308ba917eb1269917ffc8a5dca8ebfe2bae2c6770dd0904a2a12079a39d2aff55f58428496b0112afa6c6370d02e3c56b82adf57f7efb656b2fe3b9b7359c0a52061bff34c8e3c657b0d2278cc5e929858ba05f8f50cf5b1be15584124319491f81a4709a95057c6f260659ac175d47f8b2908cc44d2f6dd841e16ebe4e8969f187d956fc0321098662da82e8a3449c3b52debfd5718704e2becc8ce0067104a86520a0d4e15234a25d95a32fce03e0203630e49569e43cb6e75c1c56ed19e7215363072dab6e27ba3fefa409090c07990d332325dc16ab9610d9881326432dcd9d2da44978a5e9b75db46806ee2581978e3037e2ddf574452543ff541d8f8351bb784a53d4004cd2b702c254c93c014e6fb813d4cd1c8e52e88fea8a0f02f8505f37c5aeebfd4341315b627ea55d2e7359f97172495c9efc4528bfd056cc353698f82ab26b9804964b1312de60632bfe26eeed6bb08c9445e0123adc6e381e50c8b72be779746cba3710a98101d7260ac981c53fd1e7897749ac7521ac5586679e97270fb20dc75b5f5858a0f8c62ed82ffcff3c9d55f4dc2cac59684e60d09cb6f12971647765fdc8c0b79b13f446088298b8444915497486d7604c30771af05de1128ad89a008763fbaed40c53cbc93fd64f0a293a39c02bb9e26f740a20ee7a4f1538029f9d28dbbf2e9a4cee8a0576333a9be2efc284b189fe0ec3185792aed3d5bbae3004c4a8d8acea8a5da12a544ac0149d310e72df4cf9cfdb83b70cf27485a05750a430b8722d06089d8f88ecadce181ae9e20bd695f4f50ed74d45ba8f7e3cb4189912e9b1b40fabb064969b06d495d148572536ad678e8ae1138939a375b6b40ced16300ed497b5e5d3f766e547cae9c7ee97c1fb4aedd63e2ff3ac1c5f7b8f6042b13f9567972d38ec4ecbbad75f1117b0f915d56a085404d0e369b660bc9fd278673323e50d4650c109d2ca2da8b28a00ce03a78cdc121807bf2e38c5cdde0b418d76689802d23d789c4cd0ff819554c969b2f257261da6cdfbef7c1dc4c0883b707fb63f024a20592bf67f866d3f949d79de4ed9dda990acd60aebd473e3f46938c3014b6dbae91bf6ee02019b09e29c0c8b876d3fe67aaa700f5824760aab8b82dd3deca1cd9318a65463630fb1fbf542e72468a63181eb5523a7cabf2ecf75dd8856c3d41023d7e1f6146fba7c5993d0c92024b8b7cf1b1f53f0316a955c68bea6928636d32073a7d8a4e3e9d29a32263f1b3bcedff0724f457cb36f861f67228102663cb34686470207fb09a77a13e593dbf8622ca3c6f00e95fff8071a6d7ac400671ce24dffe66ed9dbaa33a914281833e4904fa99123f068522eb4050fc9bb83cd397b9629ccc45d5fc83245f10bc9b431c1fcda4f52d8c6dbe7f8432c39cc7ba4c7555ad11b43c613653790ccd3529ca4964900891759fd8392098428753ce1a80ccbcf826fd88f58591c4c7f46e848823b2d3ddb504243700ac6b3daa0d13f02b0864f548af43c1453671a1f8f9cbd2be96d50bcd36db9bd0d62746f0fd2f8e96bf223bae2d2918f4c05586b916387814dbe0246f86df18fa87a1713dcb60ef2518952c7082d80809109364a82481c7b0fc12e054886e1d2426c63c12079a01083cceafd083de16f9da68ea6c1a2e4050494fc2fe4380499332047758cd6356513b4b3d88bc6a5f83ad7aec5b9239df0ac04f92ac368988dae5d295164dc1869a11d209278d2fd3e7e585e15fd5372c59c36d2133c4c29f1879b384747effcd32df8db46ce852e45892455b55ffac2ee519666bf316b1bda30bf5a836ed4c87388fccf4ea1dd310a8c0627143b7f10f3f0a93177d03b79950d6b42138a68e22a72e6e451d9e0694c45d99780b9b2d74ffa3d18a362a803b4c920532bb2afc2f1fd8c8ca8f3d29827040ab453c8202b09940869c01182bc3c3d5032c050c15955b2e1c06a424ff9ceca9f6eb30d27009e51930a8c958771f541f2fa196836b69c871d3bb4a8f95d21337ba39786ca75a39da62a512a226edd2e895053cb6ca18d7dfc2eca7278ac1088b3086a3b5a66ac120c786eced96877a512479c2c3ede253853fb8433c5e7bc91b495322889c6852b484cb2dee10f2304d3be15e96cf99821b8c9ee9f2ed43708af47238f7812d66f672ce85ac4b1eb256b4da5abafd90a59dc87eb5da4c3a5118649a24343f83472f7af1afc0b62a64bb650e22034a696340b234bdc24c5840bf85f04a21d8b89ad151e4bbbfd4ba8cb15ec7c91e203d89cda6a57e4a00fc1a441523bdb4a9ef087f6d8a8c30e8ba0ff33194ddf446b7118c5618eabe57a2801b8040bccc9d3589de4b4ec320a8932e04b69a8a6d316bf7df251c356d7ecec115b6f97888358b5985516f800a9d2ab2cfe078f1d5514ef5f2243b5beb71455d5d9cbec03c3edd5f3d319d05e43e46b9ae75687b51179e326e4cbf9c6560328a3e24d573c1ed9c9e006a117c258889e98458f44205678a3d29ba242248817f794a9141268930b6798107bf759ce47aac9f3af05a358a31b03464e556dfc21949a0dd2939040e853f0ab9039e5fdf17fdbe4546b58df09712571901cf552d04df4d8093be27003fa00daaef74cd7fbbce66a5b626d050f999c1880a4fb42ef703474337bace2b5f1e404c04ea18fc2f71a7ca935b04f17d2d45241052a49505a33a802b44dffa5f4b12d46c8c52c358203b2d71d7868dc97c5c0123224f7f2d63e24a3c4c22a1335e5d2dbfa445835eb8c3e4422f5a2116c5d90cce21365057c1d8e58ea10ac57679308d9342b613ec1e14e00ecc8d5dc0855f377cb22687d858cef947df73d516ba702d1dc813ccd2175004238cd9615760e757213f94dff00751c98fe14ba26f3982dfa78dc2941d05e2c46546f12cef5c793031b02d4cf042752cbba659381c14e3de475ad90dcfcebb0d28b68a284455c4501851d0e486bb59addfb2a3cee89e6d611270bcd49fdd66293f16d168995d1c4bf83ab0a838bef3517122df71613e96b12210d1d2eb1a4a915b29a5203634e8ee63c16c07d9e7d1b60fc6949309c241682b03d79fe626413727ada262fefab412ee3f4162c8905e0d6018bdb7442afe4c9a63c4b2e4761138a63dcd8e164b709948a525a8b7b4b2a4a9b6692c1b4e63d7584bd0f6b5754d107df8404f3f357228e86cd77c7a96c5a117969026f5f4b91b0919c3a276759956f54fd8ee8919914cdb6ae2919b02cb6b7525d57d1c9df44afdbd8cdd1cbaeaf9349b222c4c7d2b35d869bd54c7cf6c431488eb852ee24eee7436bcedc0d58ee927dc361b2d694c86f93cd124d1af002e4e767b203c30c52af7ec682560fd9c7b1b61eaca2ec2ecd33384ff759e285474538babe673767a36fc85ce44687962439ce2af1c751254360ee422950e95a7099db855edab2a73ec4f3696f98c5bb09edfba12cb36dd5673d5f79bef34c24853f8a49f31896dc9e665308454996ebbb0a5881a4a7ee01c4d71e418664cf8c2ea5eac24195bd04933138d9201b4d4e378859cea80f7886c6cbdcc69c154e90f494cfb7f63423a5027acc7101eaa0f66cdc8ebfb70222efce8816b8d30311ec6ee9252bb175c11da1379354b37a106178839f9cd9e77c4008b811641694ebfa38b39c77927d010c4c184c5a5c3533761195ceb8f2eca99183ec4908e70670558ab4dfa2116f3883ae3c845b9c8dc4fe1d46dc18460cef89e91de09840900a98434aa31696fa3c488a76d0d3eb4bbf1c2a8bb96087d84f7beaae86af999dad6dd9a631320a87ff9048532e45018bc6caa561f0fe6070008137d2e9912ceed4da6da661dc86a09f9bce8cdd2688b892d311cfbce3cb455733c105e5f42b86f8aeb546bba3fb3883acec997c03906668d05d99eb1d00724045a690136c0f995140837bdddcdd303393055c2dd36b82b3ebd374e40c3d02005c8c077cf489534b5e5cee1b6b86d059518ef09b9bf29caa5df4150a7701951d55349cec0f6662951326c2d583074b1e96e2f86fa77cf6a2835dcc02fa648919d398e8fbb6df2c6cca1eb3e5eda0b650ac6abdd8e8bb6a03cf459e53ba38b807bfc5d8c435ba1a5d8a5b5e9e82cfe77b275e7df3e35ba545ad44839d2180136a5b3f3273c494b96aeb28b245e3154d9ec80fd0873169d6b675e354c85483b42bc13d947839e505d82d134fc0c4d3098d1c98f84acc4b4724b8a0186cb0537548fc6312ca16a21037d6139c8d051cc149641ebabd8272ccfe83b31095eb5c33ad23f4cc70daf9e2ae1b1fc6f060fd316c323f9bdcf7f1992e2615081ef832694c8961b8d31bcd4eea5312d849974e99dfc5c9a7f2a875fe8ad706fe18a938ac51b78be09896419e9f27f4264c877fc90e619633673b75cca253c268f3df8be16a70d2f6d099a4e19f3feede03892d18350e3716e2bb1eb144b9f432b27ba0c305cbfecfedaaeb2aa3df2ebfd7610239a07ec2a3c7b0578a10713842c9674ba3111cac0428206e62020ac3cd1d5df8fc873cb0ef7adcbd5551f8d93a788628f49f573e8eb78bfd4fdea2a2bca5e2976d20af7b01fde58b577db83f6fb38be3ea6408118ccdc420d76f6ceeeddde4058ad0b5f73efee007af8963129ef37ea84bb97b64d3e9bf504ceea4412dc3de6c73fd05f5bae1946ed7522e874c45ee7d306ce51e08a04e8501eff2d70132154176bed0ed9da1f1d523274918671582b5860b8c33cad6adc2d24cf4aea12ae7a2d7010d695bf7de7323dbddfa8a3bf4b5c759f07c7afe5321f31a8858b598e38c382b9ec48b4bb19a8a0bebd32b648a4bb5818505c2066140c4cc9e8818540ccab538945b8404c0360d6dab78cee409482295b801aefc4d8a431952551ddc124a658301bb61079e6e6de45ba567628705232dc84b68d2bacf44ba01f4ee2a412a05097408706636cda827e32c6ed29b6cfd97132e5ab76ef32577649b1f8a1ac2365f2d217c758de4117c4d5ef249f1b8dbf2f72f4c637ed1661cbc6862e5a8981b9c8e6ed27e86070248eee6a25d4663074ad0bda0e76a1c468910e11256200814a2321569ca2e7924325249c43250cd2782887ca20fb49bf50c62eb74a8ea48041d981788db8fcb6ac88ab11a7bb1f0aa07ebca07ac603e3bb17502d532682b92dc306cef387f2c8470bf93c14eb1d73e011a25136845cf8592d2a4623af13e004eb2a017c2e447858b519fabdad879914441a0f8bd37f339d20177e9d07354c27777e46741d8c53daa6ba0cd57f39bce8f891b598c4133f6b2b06b8999b86334152e94d5d42f97e9e09521c24e6fb74d5f89d4b85b08ad91ba91408c3443e9cb05389f1ea6ba46438b76f17233c0d0a6e5772456d5ff44f9aedd086a4bca27c6717cad86f019e5a51c587792ab9b2815546f81ee9a60e39357de46b9519d9cd4e6e7094a0255aa13d407722202e9fbab66cc3844faefef4622913528e1b204921d14b5a5fe85c14fa130763b73351fd2ca8ebd8674628992be6b03c217ab0a5c1904f66608aace9628728f24ac25ab863d869bfef3f0ffd928cefef82948a01058b3888a51108308ca6812d053b4a6345194288b8bc3b473003e75b0561bdbef461491c696d4cf92e89b5692c066204a34062e92932c8ae8ce0122f6874033a4d620ede3ed8c133ee7902b4fb00c9914ef42ceafd0dacc98ab9aaf50695d053d6b9d989d81a2aeeea49de11abbdec401ad8551a8e9d7b9c8c474eee5c261781c94aee458372a439300ccef50808a598d960ef1d3a7f449d3c46fb55f6c22aa49d9577abf0ce5def07f4f08588cb749ec24450a3453b7a73e9ec8cfd53ba8453daef4970d698dfffb49c8984e3a20a93386edeb05168030bf01c97a46cbcc4e217d164d27eee6445e01df8e2a64537e1e3396ac25a1da9634b81059c70882d50f0cd3282221022fb85b87012aed6acb5053d914c7d5bf079b67fd146c93e33f5dfb760aaefb95db728aaf220bd0f50db99cb8d6f140bfdd983cb22cbe5c7a2024c2d91088347a35aaf7345f2eba3b767d00fef22eaa103181b39ca45c101fbd2c6c9bb2a219a9ddd104fe4a46df44c96e7c2fba80294718dcfabf682c1336aac7bbc7142bc7159a6ef068abd85c032789642307c8327ecccaca471a40112029f7394c09701a68395118cc2f803cfadc4cd487d49c475f90a4dd32ac0cbecb3e820de2492df9bf789026355771cc202cac66029c9aea716b98ea492600e1893bffc5e3034e327482171f7ac36cc234c6bb4795552f18214f95c9c1d8612532573ed2c072786517cee8b3f7fe6980b30b917d32382411898f2e80caddadc72fbde6cdd3695dee7637c5f376740190b168bab6ba0121d59ceec09b47d3123be4ac773ef4926d4ca89782b00a7da6345df7553ecbcf031a72ec3f6de42111b7406036de0013f0968adb3504d2ce960f52884ee29dca7630d2fc13e3ffb95ee65b2d61c4dc9cb86eb89913aee8a3783e1f270333ad1ea07dc1b02a0c7a997c9456871320d4a985f81c22071e30049c8c52ab11c305c5bf52f97e2c7256afa0a0f7a1db4ee7d684bf82380d5b7f0dfbcb794d545e23e661c18bec6bf4b5718e89c1e67324430e9ec73fad09279d47b668ed1f21aa1428307843125390277c3b36a43b4d1b4d4d201aa7b5e0b059455e7548052243c662ab1c8fa630356462395f473717432d2c79d1891c3ff9260a2d0069976da555ec620e2900479ce55f29fac45ea06e658389dab3e685ac41b513c0c88b091f24d1956816eefc4d14daf23d5de22d5def41553ee224d29f292de124851729796f4aa37ea6fc5748ae2efa622f51ebbdefa4f49006f10248d05525beb0b3fd05e04c608782e16dbc1c2a2c2383e33c29dc214ccfc9e1bdfc153e5e1369c13c94e3d33ae7aebe02f687cf56be5c0bc81f95df89418d21ba9838b842a5a24736ae892252f0784d4e6f2b83dfe65d4575784fe15586434f8b31852308157369e812e3981776fa745140b12ae1a60155c662fa144d75392b139fa6d46ae16874bfcf0827a279e9499778bfb05c368c7b9384e9b7c7f6972860a34f98272d1804e19ca8b75a4005a0d3f2fec8be19697e7b5bffc0128006ff39a87593befae335a987034f4d55765ce8790672f8ce0fbed078de18c57712027e902e7173337c4564bdd27adbf5105aec57715faaf702cc655d079647a2731fbefa8cbcf039743344747177247afbea54a4f367c58a6e4d6fda233c663582d8e5f9a939091d6307ef889cac7175a1dfdb949a6eb87b8defad0162dbc900b0d04fdcc29f78b124c4ad5433c89a578c973a032307ee59a5a1773e24a545802401adcc64a18beb187b7267710bb2b91127bc1de5f465e370a7e66c2e411657565b7049a72bae06357cf4b880412b5f8c3c5b56ab735a1a7f3d30af730e502f6afcf2e990acff136ece9fcf40de3bbfe2e01a89e95f14f1efc40a4f04a8ef4bf127249202b5ef741183975ed2137d6a7b72863609d80f2eb6e1b6ebb9beacdbf0c1fbc7de317d729d767f1a6e7c42f01255ea39b48e94d11cd527547a9005d7c00f64b9c4daa9bdcf96a46512f6f28845359b4a6f2f47c29ec9df132a584d8d6f4540531b8ac1cf6c40db39eb715bc46328b90c1a2f63b53a7dbc8335158c525486c05778d277097863aee0e00327bf5c2b7539182beabe4afaa8ece8dbc265a5f1f15cf5d121868af3a648e6f260cf7aecd73097d21442d25cd348003ae6bf3b0507301c3dd3b7969ae053938be1db8fc80eefeaa33f6516851f9a6c6542d82375c3e11078ebd6cc85104279680c27c70a05c467649ba41f4a569d46dad683cfffcc28aaff5d0fa1dc6d29d7f9aac33b0b986d5db8b05909935a98a52db43c2b942e093d983302edf0b71742b8481719c260771ba365f563263e74231e3e28d2753a8f207818742ed5c39c5e73da2f082fcf4529cab5e4fc2a33e2390f4d2d4fac22fe80f0c2f44902b3924fefe6be2f260a96756daa5e99d6167c919052c9586fdd74d654070bf2df71114cef74fe41b092d7dd74af0a2570b1ad6459433e700c2c436b5ba8f044bf55704889aed445ae162ab7257d4b48c9ad16024ef26e4e229aa273c89a6519ce204d68eaaa826cfcdee10fcd6dc194089e99967120a7e5cbe842a990764a9a6bf0180fe479470e244fec32b096cf78fefc5cbedf4c293263d630f5995e12568bb603a4a70df9279b8ebb1c54cc414e23006c5325cd461632d25a88d62b259f7488f30670a4f64edf75f05b33bf672dee11041f08d6313c4052e9f930bb83bb211401e9a6adb019a436cdcac837ea95503246ef3fb8250218ed30e140ac9503976e0a89470a34a775401c1a3742804eaa3f882dbc6d42bfea95d0170ec799531793adba165872859b131b5fadbb03023c3d31e36603403557328453ccae9e7e27793422be638c536eeaa7f3b2fff30e82d5a7e1f8e2ce0e2735ce4dfb4335bf8deb91f526e72c4a9a4106ca8a4ff67dcc557c40fd0bd90df45da5bb767a9c366bf68b28efd570fec9e513b2098e0ce67b7f8cdb67ea6079a528c2a128f723c323d378400aa0a58000f111e5022cdcbb0f4df41b2ac6932c213288aa7cc83b0ad91e2e22780b20d472c544d638a22464c8bed5bd15cf255ad164643291e7809e71d09ea905893768806b5b847a6991b6bbfd20f37a4ea1aa9caa80379b49f8e8307fca10efcec6b940f2722b881b05770c335ff3d5cc06861ae9f93d67f7e4ee54cde185d2ecc9bcdc0b38ffcdfd1fae94d76987abd7f3929c7d416d5a32f60bc15f46f2dd5346f3844e66fc06594c55bf5a22f38c9b14e6c6a73fb9362713397f31b2eefe9d29d730cc5310004a9daa7385c69ada6796b4afe986228ab36be87cdfc0bb6f28cadde4420d6e00f54216bc6098572fec0ec8e8f2ffb05e8d39be7f9f90af0be562bd755f275123149b5d4d64c7dd5ebe0d6f16faf0bbcae9e5aa158797eb21168330cedba0d978a8152e9840eb4fa58855973265f94f35e37fb4203ea73557d5f8f5c17b2497aaa26d3794ec9fd03cb0a183b1ddb6519b673ff795ab283e09da99c7c33ca792a40ca13f3f82c28415adc9a1df5aba35067ea1147250e9d5642a7868f7b3b66e629016f4e3b6a95e91ce67e46d900dfe032f1d6c18dc55ed8258b7397d1b05a3b40b13550c328e4223c5a8da0669bb42b85319c08f45eda1c8cd449afa4a24b72381f13d1b9801e7521ecfeaafc66513b0d1d7b407447deaab0714a9cc7eeb81e801722b1de891d0cb00d2718d89a27989105fe19938e88f55b8f8d5d12fa1524dfb380aad489dbad325a7e7c0af5c79e424edc90f8263e1e821dbd208544e4a6c5ce65ac66ab457e42e8d74598bf208780b0043b540d0c6aacd0a39e532d95b7aaf35967cb372dad63b499b8163a518b6ac97e5051f7a4f2307c4d4dc0588358c90cfbe819754dcee96866a6455180bb1f81c0c1b4bf46977f182ec7cc66a6dc58f6d65d4ca4f043c47335ebe9d91359656d3a697d4350cbdc0e65533b901be87b6d18c67b3c99f192e574cb3e44d6a9fcfca7fdca1151bafb68bd86bb5b32ce9f201c2474eeba221fea82ed544dc628dc4db2df93057aaa863cd32b9f15b75aeb246a560d199eca647e69cbe73b4159832c33c210a5c2c776b96a4290b0755ac4079bbb4e14aceb5df64c0cd6078cdff2c0b9e50966ac032bf31144a99e574be358658c73eb520656d9efac08081f5b535114819597659432c87c761762e44c29e53f58cdc0d5cd75b99a2dcefe1ebeea660c43ce24cde9128b60970ad2e1fe9897c72c9765b3755d18e3923dd36a3efb2e21e95b67463cc68f99169b0428b4b944c8d400c209cba66b998ecac651488f1f2ecb780800244463ac719f60f9ee22617c11bb847797d48b1845dd285f8bbb965a1f8d48221bc6abbca41f1358d4f10f10df5414428820b48baf75df01d3d2afc6f7e0297e9aa4d403e06c04bc9d013f89cc233a02b9b5d22973032ee0a39ed3f9cdfae3573d3ac87da8c49e30773493e00692aec8ad0dcbd87c121a9c14a8d2792950d1df750e2b867126d67f98da3a616eec81234496ea2f8f367f783d766ccce7e783af9c1ebe7ffd3a3111f1932bab0b177d1649ad4457ccde092afad9cca0711454b5ecef7068ce226c9a520ca41369abc0eb5849eba0f4ac41ed48f6726adb8a1a2f22a458c2589c02f49620e5316efb43fe934ff6cdcbedae0ea0d1ec3b34eb88c9705f24f2d391649b506b74d68d210d61922b2a7fc0a2f219ac10e708913fa8e69ce37df99992052eb61d1ece17f32b74eeb2843ee910b7e6020494c4507e5ff12875494f9aaf4e05bae115000cedd8d2d3f93068afffa2d50810ae455033ca3f138b2bc312c63baeaafb4ca4bccca5e4165c8c83af971db673a41686a1b467fe0c392351ffb0467bd338d0e46a16d461aad178c49cd10cdd0435b4e27945a39e0e8bbd81fe6df23166af606c3fbb35c6c18998a8b815d2ecc7a54b20dd0b82080973609f70a4e8c617c020acd6cf65299be45e4026e2d228a11ff48f03658b641b202b8e52400a514e3e65ee162db4f9fa7a18e35a1f5b129f8706ae4df36696635b3b9c8979dce32be6f7fa5ac65547e82a22ba37c1d0e4fd8e5e637594a476711530805cb815ffd9fc1938bb0debb789be8fe0ae11a7a2c4ddde2905a12207af901243b6b303c9e6d0ca907e0b79e0389843899c66a90276f217097d9f07d2071039e2a3a1ff41b4b4df66fd0a1938ec3845b7dc2f7f50aa8da45c955e716baf9c6f58057aa5c6600122069a59f3311ad24e4d239a4ae5043213728cc51e32a97350100d74709d31eac0a1ecdfa88a6d82b61b1b95e940732add74adfe9649e15cc74230a8087fa11456dc33acfdb13d82d4b6caf63024fc8c7f5c62150eeba1ea69c8a98cefc82f3f7358e7efa3029e25408c336c581e75c97aa5f4c12d3b3062e6db81da74c15839614eb8039204383b46514d2010a02a3c8eba510b5b35864125e80709711e46082190549e70eba5bfa5fe02f19db513e37870a05ef14d7c65e8a32044299a531e81875bec42d75953405a21978ddb6a193e284121f5f2648d0f525c7a8ca3625e7d3c0ba8cacfceb66009c846f7676ca71f056391bb84715015ba100ba235ad10284431a66f9494f841e020e3f7cb9115c5380067e5c163e3a969a891d47bac102ab3c00d490e85f2bac049b5586f092be9966441159a21ebc0f16c79b22bf352c7c26d6adc0e996655f4608f85eaf3c866b760689a5013d280a196d6b023c708a8e76cd6bbe9479be521d2d055ae3515fab406b3f233c8c5d01174c5d50223cbaf5f3e794ae879404b0f3391ee1c249739f88a9125641b566a017219619c425331a23f516a8974728015c8ddc52b7bec501aa33182c07867e925cbbb017fe8fc3f1efe00d8829f50a320c561c5453518302428687bb6a2cf9e05e54e36284ed3ce09d07ee2092f79810e4ea11208e9ddf0832a8f628c3974bf2a80ae1d212e3bece1847fdf008f857a28265649600170e03c143fb17c68428f49e6484d7e219fe2b681b1adf08c474ee995995f395e28c13875fa694a98322b7cab0480b590e50a108a14d8af5a012e3c63e23592d56006fba75f1ed5fc81452bdaf19792976a2f7308f4bc17335d2a4df5fc9664b6606506e103151b99c75dc55b07fb23f79bf13a58eeae143184125e447b8ac6561a0f86732cc0daf703529ca269a5a4bf513e38e4b1715de08bd3237d54fef4411e3a6daeaace7055aab3298ae6a5351d5747865eb22e7cc2b22f6c7ec887d4ead995b35a676f4cbcb0937a19253c99b199d11066d5a29efd8aca7556028c0e6ad407adee589d6bc20161efa03988169799393cd51114d673bf1ab593b92df6f6dc59dc0eed83daca3d06de7051bd43742a16dd52b370a8b195301ceeb564ac511b3fdef93888e178280e5cd940815b8e1a7df52ec1bbe0058909e47122961b463ed6e73ee8359d06c420fe03fcea03ada3c04cc6ea205d939979d9a640e64695cd27ea10a8a60397d7119b6b1b30cc9d91cc9be78475ec1a537dd1d998977c05b65e8538a3b271c309d7bdd4c32229c5262dd700691eb4507ccb6be94b29d33310bc1bc2be2c81924f8e09a2cea055aaf11319ab99e9e4ff9d880bd7e611ecf56a4aec9ab29d69e50c88c576948c4290d52dcc0775e09927ec9fa414ab348542501726c47064c3ca3b34f8f0ef8bb6f6801e6293850b158a8907a2199b3c9fb341773c424cdded32b756aece6661b192dbf665e8597c33ccf8b98da5e731418f1a29e5b20cea388d4e1a61a3b3f66ee64663192d2f192590624307ad8dfd325133861310f6657308b02fde5afadb67bb98e5228a9732889e3c70c700033f725fe765fda503b8c3edb9b810212080bcf76e3a8b7d6fc137b1d9f2edae758eeb5375224fbff93efdf2b908704cfc52573c5494dd818c899ba8de144fabf87b2efe52643035fc9fad9c5743c457efad1cb2caceb029a6e89bf2117b25120203b21def16d510886f46cbbd536f05bef05cb7ef5df83b861cdf37526ec88aa4c06d3dbc36875b39481776dfc1af464ddf355c29e53d1ed76035038aed5f78374be7aa36a931376ec179655244f398c9efb35c4cab56190bcd97c0caf5a3cffd8526921c325da143c83b28e0843b03c81b0add5be411a07e123cf3a303b5cd5b06f745d31873dafc1002c0806f91b210e687a0b58ba13fc98da9a02831edb881af0adddac84eb2739f62c2341cd5376d865ee980a6b8390ad248008215f873635f5aad65ac4909ad482171f9f26c55b82874848f9ac6ac8d1dec49f6c4bae677b0a54f43ba8dbc31a168ad7415df2ac7079be1ddc23139eb852eb203c1fcdc883a8a3c6320ef5dd80d79824fbd0566e0b347122a36daddd05a0440d46cac12d2d6a7a664a40739f0de5df375882ad5b3b2c6d1372eae46209268163402bd77df4725ede28d1bc89d37db4c4485a086e0fa252f93e8f2203150c080ee0ee2c7ceba8a12c15aeebccc33572482d844d2bc6c408975cf3b4ddff7fd07f1a647845cc26d5a2edc465846ccfd665e62a59477f126b3a7d9b9e5d10584f44c4ea6fd0e7150fead5208a90be8554beb8c6c28c14efc08dd87debf043a822055bc962dc9fc753a4553c62f142d811fee9c0c105b43ee60c5ef495c880fb4125f456c896c91633720e18ed7159f0e67c702bbcc8b01984d1a0b7c245953af82093be2a3b48002f8c49b26b37504d9aa780c0cf392d2b1a4ccb7fc96c42cd390d23e29d6187ad03da5874ec70b57191627d07f500788daf429208f4d60c817b8d9a9490b4a93b4ac5f1a90b2dee478d092c9a61226c4fa84bd976ac7455fbb5fbbfdb308475b29494ce7aec458eb22fd84212a7a8ba43580d64278bffd05bc1ce1d0c435710c72c65eff968ba446b8695a7bba16603897b4e5f418f42150e6b2c29a2c15abef3e3cc86b1d5a9df043a97575227bfe67a83348475c11984e09b80f64180241320096cfc6c07749e2b1df8269ef57a2eab36b31d0692b46723ed4a6889198185754332ddb0cef8d23b1612e3b90a62b902b0e9739042fa4205cad924e67dfb3468b9feed7c8ffc14c3e0edc88eaddc353a3f76a33655e04c079b5c2e801c092818aedbe910055b62aa5be14c8d85a07e392a929e767601f87d13fb29dde58bae2acbf862bce29043add479fada22e43c78305065e2cc563c947478225a003f27827a9ffd2decef6e94e719d5a9ce303d4e643203334a50ca8b4868606da2e7a0d7e4a30e5922300eb9e08460b633b36237c817b1419973cb3e6c616d71d0be8b95eccbf7a580a6940fda817268ef9db5da70f739791967ed172f35be4bd1516189f40acdfa22d3b4b203161ef6d8486c5bdda637bab67889e2c24a8f414d21f70df1e3b3218b44c8699943a8754b2dee5c5a2f3d76046b58e70da8bf932810948fb650dd9cdf5d8f9947e0fb2ea2ea8cf6b9b81b1c60199fd0cfc0f3ab73e2dfd9d860b4a8bae844bd629b824fd876b38143a26bcdbd3ba669ebcd515faad665653493da5046568d7744c42316e3328a5230b61f37b002bc1dc335f82806446f4ad2d344e3130cd395024b2b6a3c656fcecd89f03ffb01b3ed5772a6e53c15f7e06c0c37305a43c8e9a4f7043d9c581156c63905ffc283c40ef068289d1271f58d8a10f234680d439e3feba3c62dea692f325a0cba55145931f7b54eae9c1f4dec0f31fbcd611eac0955f3a4ea24125b121165d5d4c07b0c31d3df228967aeab98af2888391a88a6650e655a26086bde9e131842465d842c5a60e18ab727ffb05c77ae66375277e57c6f11e904d95005fa2c65a2339872a3b71c7796f91d6421bc7c6fce3aede79bf992ca6b62f2fe48a28b4251671fa43e4025958d0af46ee16fdbe1124915c20155dade7c5ae4b1a1653427199959827540c8ebf4db7e168ea36bc3549da119233a0985ce1a83b277dc18f00b2858b000d641b1be45e2cdaa6cc117f377a9e34e89bd39b10eead1244e8b7dede0224ffe3fd606b97ccab952c2ec609dd56b5d2c87e0e1f4463598f6792d6180b97d7ddee6f435d9252223d965684028e56c1b59f85c11b2d9fb4ac4aa94cc89a837dd12ac4a8042a52823ed2292941a97e57d94380f3eef3265e9ba4c6daf799d352a57dbfbaf07ace7322880530b0a79a813e456b0ad45500aba79556bec40d686b3317911a6ee1e0a2dbb888dd7fc80ef27e3a8124a9fc8e10052e0f2610c78c6eadccaf0878e9c04a7d1250b2a8d6f188996a8afc367f83b7c85eea79f3d118193c7ca8c5f934f2393293c20478ea0add79bb0c532f058178b75019f430206aad6b7b20484e9c024318770896ef95d3c4065507e9c04df8b705a5626553cf3962d42ddfa79465bc9fece3c9b6d71f7008c05c2057ae8e7c9a3f0fafe98b2f2ac43d91db2c8fbc27d4f3cb96f6c5de5bba7809fb4c743ec1f96dec72f92aa2a848950db3b6dfbfdf0451443caab9f1dc7e06363dfccee3f326e11b9aa6cc6ab54ea9b66d465b281812402cc144403134cf29d633cf9546eb6409a5bacdd265fd0ff5660a2f338f9d5bc744ad6d658c2f299bb3c7c193c328336186c6ae8e288959fea5fba057b734cfb90c7e2706772966f33585fe94939a3152584c4a4b1a42b958919844d16fb426c517aac399b0add412b284b2a593f788bc0d47d91de2b70aa33e1961b1fe072180d4dab7aeac40998b94195054ed4f89f5b8593625ee2013f2929bcc93a40d920bef6deaad20aef3385a8bdcbc7371ef2b18acb15e082543f908277de31267300065a5edca12f2b58b934ef173817b2241a280b49969fb6f2172d617dc0c7fc2778be061963618298cebb2ad88b02328d08fd6f75bb9a1e14b6bd90d69e4ed0384ace3860f39756a279b4b2b1fc4b2377bbfc48f4a4b1e779d6688260ae4fbc9f3eddb63d7866eef8d5a2855f75cd308e1ac27d6cf19cd452dda5b292ffba75796c381a4355bccee86ac98fd430492273e625c4f16933db912ab4bba47dff57091b973d91f4dc343fc8f1b78384680c030716c3fceea5b4a1f90a956d0cefe1835f32ff250e732590d98cf7e74dc61488d613f6569141f0f7dc89d32ccd76d235a04ce3a4dbca7ee02d5b5dcf6d120fc5cd428a278bf7c27479caf94cbb0e32e710fcc3d5959157c9e5e283773dd76aaf0a6d1b612942a6b4aec04187fd6a2bf8352d9e4f56e5c43e9be84e68daf39c2285b451def3405bc5b00f4ce13da6fb67f3ea68f10c4b155c1ce2ee4a88ace075aed8c984ef717a86070a23a7af26eebb8eae8d1a870da02318635ddeda1bd93c58d6e992cd8a197ca2c87e89b32e732271640ffdc1334572b80321d771eb11540cbcec678918b118207836696f4ef7dae0e67f8100eb8bb79716c8a5260b408ce88f950df1aea000b757b1570f3cc3685ac8a03f0055630d47bd3a8e9a27fbe89cd19f4bbed0975691cc5b2c523c016bb88e2cc72481b9ad07d005da50a5cc17a3933423fed48c8643d8de74f8120f611efd3c9d22f9c865a7cb692ed2943f29fbee544c9907f5e662de3dd08aa707ca3475cbedd7c3adffad25749ec1aa6e6e1ab27eea1a07b31f5e2d823015fa5c4d4bfc9b3ce60faa70a15e17208aefa6fb800dc6c79f058cc31772f4513893e82b126f4ce129f911ae19e121fdc48991f12fa483e70173879ae448baa02e73367b9c1eafe4cc38cb212c13fe91f756f56438aff2a5d3813214af9c5a5acd6c6f51d12453b26cd6c2ff01167464f6d6c5de9e125020f87a768f7d81b6850e2201ff1f78d891e3fb45c39c77fc7315454cd06861016b8d1405b612e393b7f587182a15a221ae9c17e2fbde401a3fd15c26469e5ef211615c677cf6c7a05fb6601af8fc68a47dd1dfe608a3bd00caa4997997d83fdf1a502e32ced71ffdd6681dd4b15c645aa4dc833cd0f79770aa4ac144bfa23661c5054dbdbb6ecf2157679da0c047e8560c9e96012e55550616a240619f97fd0a86aaf8d11c7de03ca3e5d2efbfd9144e2cdea1cabe4112f3ab5bafc0031693a571f3468aacc0cecbc5b926f3a77d3cd0941118f50f167e7d8f60cdd3e4c482274419691c8c1b1987081dfe02422fa4452a075c1bab7b2dc80141c5d1800b1dd4a9b5afb2dd7318d37ca162a25fa72c4f3d61d2efbeb431072c61b5efa7cb6850dd2e538dbc80a3c9e30ee7535b45dcd786a199f1d587c59f99e7dffcf21d2f4758f90a8167fecab2b59216cf2dcea6ce082d0f245ae26dc76f730b76e6c6bb6de38c35ce683efacb13dd55e2a3ac1fa84abb993dd8f3e86cea7fc559c1c282c968b5c7ff883f5816412ef36e331d03a9b1de23093025f8db81f922843300c717e7e6aabeb5ce30545dba59709b2c7d96662eaf359f3ba13f96381e72bc144fae38c06fbbb0154f36e1d804639f7dfd8ff0cff61f4f60b694a56b29cc907e88d8c00ae6ffca7b08f4916ebf008aa7e2fb5e8ac8aa6e0b79d477a851cd394cb6f549aac2c7b39a0b5b6be46fca819b9bebbada382ccd2b33488a9d6ff23c497b70538b49b02c396cfa44e17afc6487f1efee02057b1f6ad10631e89884e93763f3c84001891e522f8c7d9b0dc2c2bcf7dd6bc3fd05e2d8eed1c2ada6c5796da48a38def25ec96a49da50b903cbd1ece43f76b65bd70d42caf4d2a6e8273507fbee33ebcadb874d1cd64eaf9eb7e605c4d5b91eb6bdd7eea956be143f304248dfad597c12c259159a4b0cfd6863a206eda5c107dfad8608fc45cf3f61606e5182ae753822942eb9a98330dbfd8a0f9ba7f9db3d8c9c229e4add97cfc257128181732dffa5c6c78db6fffad2d058f6209a96b8bd69e61dfcfc7f53118375eeb9f9bd206a071c8d44290c19a0759a4d10b6e08a5bf597398c34b4e5cd6e73e730d44de8003a47940d8d05eab85db69948f14a889f1f49e35d51b319991961e328af1e18e942c0ac3f900bd736a94aea17504a85d2d03afde1ede3908994644e1277cce83ccdc595c1a1e2808c7f0b01009ea1b0244711a7c72a07bddf4f1c3dc22a28e879099a749dceab7acd1db6b676185c2059e0dc08704378874849336cc4c971a180001fcd1578367e932b102693c2bffece4df0be8e5832efcda832c4d9a33b31718a5ff5213300e27dae1095b2044208d8ce859d196102841e433a536354d1ae0310d42eda58e9142df1eee411ce5366f6f8a2c8e06265af8df8065e012e05b4e5ac649eeaa246ec579c6bb36c24d600d3182238b47632ba49e264e43948a849aecbdd6d499cd856201a9cbb264136ab03f9ac892851d583cda6e3194c8eba893e77f8c5459731ccb9f76342bf376a9bc590129688de157b2454d498ba62822128388dba7af0d2d2760e6bef1c07aacab830d7ea594c135e56ab939091c6b2220840f02b0f110eeb11e84a8c181f63d3b95258ca064e2b2d72b15eb5b09cb0cc1d003d25832c3c42fe4ab8584ce24848d0155aa16538dbb2cd294d5e426c0625655497b06a7d9abd106c6a1cf01f87d20be67045af148f9243b7916c11325325512970e7631a01577b4fa1ea4f81fcaf54b10cd20c24154cbfdc59d808defa5de967a3eb8860735b273268be8a234085803db2c00a99d0a5c8eee25e61e384a1eee286365bc610ef460e84371984c5f3f38442c567c208668c1191b51e0b153a5e023a92a2b5b2965114c9b369904284be66bebc0d48ec3fecf3cb63e3b59b7d8787bd34bd432cb17c5240c1af29f9893b29aa6eabc52e1751ed041776916ed5d005d0d769b2dafb2125f3dacb9e59e25e5acc5272b436a46bc482a40c81f80344029b746e591e2549723716e96f87ee7a6ac9958884e0aa0abd8b9a40a53484b2518ae6066728c16d87356d6b3f83d5127a688be801169dbea85ab9f86f612c0e8fbc744390357ebd4d25c28f9d65b3090b8b1d125b4a5f325ea1c03f1aaeb2ec1e0ca36e8b76f1980d1eb10857fd557b6ad7417bc7e7584624682ea1b82b5175387b6fe333ea81fa0dd58f573f6a352b66e537d8972317fc971b658e609b195094c6bfb0d75b45a9b59ac89f122a7c8722f8a14882159e2d2dd6239f01aebdfb1a8ca3c90258aecdc40705bb88614622fdc15cc918798a1beb3e250234cc93c9b5d6696698df9475bab19e8cde596023927f748084dc8bd6e99760f1ba21e330484a9d0ca7e16f01600a956bfa14e2031695552335c940bdc0f082b18c1361904e554fc02b7db7099258b3d9068517c11b7a35bf054d450a38207e415556e73b1de589aecafd6a42f21588cf0fb7a1d869442a85e6d03a3baa9acb8dadb14006dc014f6dc1cf56a6839abcea3d8009566b27ab5fc3c80fcf42e51adb08c5fbea870b5b29c3e57af07cce911ae1c90ef6580e8df94ce0ae83fff5a6a981966da3cac3f973ac6e3a54348b2abd4d1c80e07125a9b22eb29e1e1e092477afbe780d9bc4aad8fe2d68dd853df15242af9b4a76f471b7d6da7a3a4a28dcd1de08909954eecc772772093522e31a6ca745fa398320c3489e6209ce53186cfe5fe4d67faf7f9d2be7fa333b910fb3ad15663537cca20051698bcb32654a9370a2c766b4e91ea7446d18234905c085ef7008e678ec9d68a62f2897a558b31eef28a3f39a2a4273d6b9209f6f37099389e585e6232b9fc463e02c2344afb243d79b1896bb6894314904fa9e69b7002b365f67545f629fe0e680382ce6ac795a4919ccb00d7c2cddb9aa47d431eeec84bb3cb5fb44def90a7dcef58a973d415b28ac1f8d968afee68d9d296f97710a772abb201e11a4d3da8b15dd5961e3d28d17cedcae0739e841eb90547d1e642d3cc0b9f61221ba114d9aaab60ff237e8e74843836e5614870a57ed96300a67eaee6717fce92468fb15a4b74337a68173211041ddb80d8a3186d92ef9dcbc6411110ff396454a7efa8c70fe20c1302c4a1fd29a66d02240fc6aaec7baaa3ad86ef4998079924aea7747aca4ea6098001cc8469c494f4ed2762e11b5a1d86610591bef158b29188ca4ba9ed8d81cd03a42faa40644464cd2ca7e8d2cda6cee7c33f24e10df9819deadcca14d4826946cf0efca58d6ebab789afe512a03e23a49769c6595878dc482ec5c7c5370be00bdeb695fd51a598982d8b1bb7000c26155b51df0ab80cc77de3660be454117b2a52ef80b9318065e8655aab140a3ad65f4fb034620a9f6ae7c3e4e66bdd9017c788328ca37d4fddbfea2c2f8a6ec45feb2bd0a6e7d59d284576359f4d3047d32eb082b575d9f007318d8dc7bc46a33d91376a912e0523966a2a7d6d715138438c635a8e0e46287fb78cbe154ffcc9d22f45d9215ca2046414b98b9c3023e837c87f08f8a64802a11b9edad24e571c27b73e1cac9cb727bba68e44461263549a3a820deb64e12fd35f5f0c48a7fce69b9cb32742cdb7167efb4d5752aad10442c444532c7cc894526450e114b751ad4fd684e7a9993680c2c0e794e33ffb656c7432b9796428248ab6c637338e1e4d4e5a02c9daa7f303670775496ea0c07192a25f9b484b9e60a369d91931ad91466fc0c9fe974c2562b4b34d0f8e466d276f768fd44752074c4646337582f34bea81138b30e3d302e583c9b1c08b40108ba4e4902800e53287d1112b1d20b6bde3f138cf6102cc6b5b653666f31918a0f6072d3c2b60dc3ee06a70a44f9d8b283ccb96fe03bde6578f9674b1bc9c37222a8d3c4a3575a6c395a9a40262f0ca26742a436d2f72c02f534065f965f5e61d12cf651772bb861e7f89e995661c5f17db517534daf4cafa81421fa0f1277521299216a3283c89d4137f6351ad9f96fdbda547146b39615adc945045dc24d7abdc44fd8f2f4343006cb4708334eb51254702780198814ed0889226556607893922733767c7b763b1a43c9a52f2478d04facfb02569f115ee2ae4b978316c1272d9fa461fd72958d233168600f73621a5ce8b11ccd6977112845d95631b995030cc0421c790d4e8b546095cd55b3567bef81b870dddcb90d87d4a9e3696c878689db63635b18d74068a7452a5db462c8c721151f272c1c90ff1a4c3f04b73b9421815c74375d2c0baca51785bfa2b1fec977944f1dbfc1d67d734206ac42b02f16697a05a9c070ae441a10d354a110906933107a33179970a2f81633be1f4224e7f8c030ce4903f39d9cb6992e7577832f9f853e94cc8cc9216aeff130dfdb36b462e6e08608cdfc83b2e5d0fc072410709dba730d51bf5f51ebdb6436e1ed59c15c1cb75924056ff34ee2cc8a5fa7c6143b17aa4381bd09bb831c3c91f9465b48383f2fadce7c0838dd1b9c1d99772e6cf2ff4906e33fd12167033ca4b4b6c1a437cba71f663892d4888a6d252450ea3447b41dc10270a02896f2d94eea68a2620b4665f7211c131aaec49a777cb7ee5d7cc102433077c97cc2c633de847d171fa5d51cbc967b8065e14cdd242869490ce708d3c287a35f5199acd4b8a8ec91745c3dd178a0a7f2ec333fa42d1b9fbe60a5efbe0a2f01a1b29b3a7322ca30f149debcf1505db978a7e6028c356af51a6f60e8009ade4ab5565f6d9ab7c52bb84a23e5dcb9becac8090e0436ffecc4a916654e9d64682bb694c4ebd181535fdac96b271c7846ef6465f32f82cdf8d821d5def2fb5a7cf5ef83c1a940f4df0c0c65ac49b90191f39de13bd8e3e406fa337749437756b5e62fa98674ac9198effd54153fa6bafb42550fef605ce3040b78ad18beba4eb9399687f0af5755ce81dfb355fd05b67e06a5f880cfb88900297c367a93b524d8d8b0ee8c7988e0084d35722c242c7042fd5886a1d81b3519bb49b1d5d0a0b73f5001e7d5a912b1b922ccc63dad8987019f68ab58fc90db48abfa62644fc84025e8ac966509a84271af2bb4161d6dda6f9039c041bbe902ee437ce54d4036094fa946418a3414bcca4e8bb7a3a47ea785e3d96f361c2147529a7bbe0c3a7719706b3f4f0519e959aa4113028fd2f686bbf07e2f442db85b0001072973d6191da197010476edd973aaf4ed5c042b5f790090787a2aae7a5745c424190404dd59abb717ab77a96e4b711c194f12aab6f068c05a2c0c4c6ea759a4147f743bd18316af7224970efb540521568d1f392ba8934ff1f15343017a64ced05d847e0228bb3f38f74b237c6043bccbf6bdfaf6b94aee9ff220bad548e22ad1944bf3673c0770da2c76be9d1b17d8501617fce2e17944da10fcbb9a1310af3f6d944477c0313ba19b66c1f8a0c9ecb44d0bdbaeb9d04532f1c1daba7f1dbbd9d61bacce7dc269f106276472d8f2099f552eea40406ae30107c892a16f09272618ad7373ff414bf8134e05e6f2753ef94a3a66af3ae6aec7296d0a2455fcad6aadde2885ed05bf16ea317c006d27f9130b140d3cd3840e220d83cb18100e13f4865966b2d1fc176b3dff8ea1ae21d19dbd257425c8e236e7c0b1c153d2b5e6b2d3e92915ecfe619dcf873c840a4db7f10e9df1b263a96f1f4957c991c8be9ac4363fba6c039bf97f9913f6c15f3597ec6166ea97d3fd0c38df737df2d91035e8b6e76e66f31bb2c9099d484ffb4c0f3450b6fb1e319b19b15ee6e64a64cec724358e00665c2c465eecdc17aa733ef0b3a2c48f001ce9f22c63cea55a48030c968a86ddad167674215f4c8bc43ef083781dcaa1a2d6e807ac9702b76a04cf4d715215f4c45df906f17717334726f8f3f6cec3843ba15eb08be75d2d2e29298292caf236640be8e6fd01f49fed2058648d2cacc6c083d2992e796a5497d5d1334a1cd9c19d285826cda734091708b7aabc43e14126d697047534a43a3bfef9ed1b0b8a698fddcb9f5fb3ece292cb4fe675ea8bf64b8cc40e5ef732133bb1e2cbc4181ccadf5f3816b8830de276d90fd532ed671f9d6e739a1b4c57d15cd82ed0d9b3aef7738ecfd468ce85e3787da7e926d1fca5bdf2e0dc58bf7d7f2c23330c476c131e5587f8cd4b0d28fba4c7452714bbddd0a04c21925fa3e94c6951d732d86dd7697453c0705af50f21a95481f9bc9af99e74d135d1b243bd8b4c18960076d69af3e582faee091d755e50e9f111f44cf95d7cfc5748f8606ee03154f065f0b7e67c7ea7cf918a08b6479732ad5ea72de2e982f3ed073f46078deae8ef31b5655a70171dd55f600d277b2e1e474eaea34245b82414d050088abc09c6913a7edffd797ed8a2946d82788088175e9fb1b4ce3807fd7916ce06552895b156c8d9df64475a524681f073a1c735a38ba111639af99d325435202ad8d16464233a224a81de51db791f9d64b3e42fc69d37cb0f5efcd2b46813da628d5d16c26eed4441132b71392d43163bda691ba821552b885d5a86ac847557949ea5fd3281e513ad4c9950d36f96737fa35c98d110db6866cf85272f7e1ada75b2bf97bcc4c7c4d4b5f432fb217e469a3f0eb03f47fa58e6295de2bce73635cb11adc4ef3be9b40e081c87d40f6d996c99adabfe58bc00b76adc15c35e96a571f0fde85103b1b58504fcfa5a0804ca5e371d43e83c5628929513b2f58f9ab0a131fc79395414857bd59027b94274a865a094e4ca32852fecbfdfaccb1eeac976e850383d023d879c88b398ee18e2697b20f9d503a3263028fbea6fef18e0f32d0d511435411abeae94a506c7ad2da7a3f13c3fba024de214ffa738592a4abb82ccc0dc36806a91fb9ebae89097f5771c643dad4ffea5c744e43b4e2735eb79ef96d965f5e1a1d8b6b8bcc79178e078ebe424c8e61017cc9f0f480791ecdd50fc29e7ed694123ebdae0bc92c62c704d30187b7547af6c6779b147bf3d756b75cbce4a67bfb233037df5d123078df8365cd88f560d415eab632de844b65b85c507bfc263268b645f8c4ef5205cdbe822ffca535d06b6bf896dfa40caa59e06b7e291528b7165ff94d6b4059abf18d1f950834752d3e8fffcd2a83d6bfbe4e373fff24de2d99eac8905a2ebfca0250ea8ff8df3f6818a794bb32eb51312896bf31f6cb027c2dd0635d5e014f09893eedfe0a7cca48f468b757c0534ca24fbba7029fb2123d5bc0ca08b070828ddcab78853b264afca52f04d58c3250dcac9b93a00afadf98c02175419c08366a53100fc7f05635f9a1f57acf1a861f52946ac853ffbecf6772b18319c1af8d16dc631e7d1470fd973ec9ba9f563137d5f8013d83f976a64193feaeb778fd563072f300e8fe6ac3af46c9bbd083fe34ac88a900fed93327b10e082e4b8db5dcd1803e0452f9555762de5402e85e3ed38736301858600f44e23aedb2834c6007b23d8fd62e94e73fd989280b40d3430867e8ed25e011e2d66aef8c29e6651b0a0e2871c0f50f1867f139e325d7f8ab2677dad43ddd1bb65821499e01627c28d53505a4ea5515f9a611d1490d6933f2001982c417bb58b5ada4e2d916aa16f8830d95b858528f39c12d76883fc9298da61a388c01580e6785886affd20b0d7fa88fe5c3531039e7deecac6db090c208b63ca9e3adb937aa45b2118446956ae141a8d1e28465411670e1fa7d442250862992d1d244c8358491c6f80516f7f8c61417e4e971f50b069c975c3c31556724899befa3c0ddecf9ceee3970683a5b2288d7b8cb113d2c7853153fc631ab0216ac14900778398dd45549461909924cb3c60eee9f151c360cfb0edf14f0ad3781c4f651aa173273dd869bfd4f41cfe4da02b66e2c25707a353a23901f5989822c01cd5de92bdb44698a84ce5203f295abbf032f1171d894188eb94e145a41176edf7aa66a331ea8f62983af71214fbc2286186fccdd1b270a8a2155601c11e31e45a9c6bbf52fde3a8c00d7d6aac367ab30268bdeb8b23608c5fc50646d5c4c21727b595638c2229fb07ba834a6c6ed79d1c8c3d618b34c252bb5dbc06346c44a7c1c72895aeb726bd024aa1a4de405ae5855c9310ab18bd2aa696f6180fd07da5bba0dc1286480917cf6dfb42da5868873a536c785d37800677dc9136bab022b295dfe485b5e226842273194ed3bebd5e5c78279aa761eeb0f38b55378cfe75b0f57fdb49deb7e23554be17a64fba87970c13b2610c72d65e14ae9d95ec23b99c57be100cec4c3b8a2286096c6ecbfa5f5fcc66fc4acadaebd6c9335428e0f957c8cec508a97f84241b700e0b8384fae995de0664045dfb4f47bb3f5e15b55d6d395982ebeb6ecd4f9ba5f79f74ee983f625756c0a0275f0ad897bb2130b0e2e82c2cf5e4f9c500ca0153049dc7700235684e6c66ff7f9951ae30cda9547f3a20685c4f9f9819cf6c974390a29bca20dc2d1aa8ab8f7271af57ba63e120bc5e4371de520d534dcbdcd9e3c4572fbc8a493586607b430b5816e52de480cd687eb6c231e7324fec496b17c8e6ba4d105279ef70ae3234fe095c4ccd1b3866b11e9ea895621fec67a2c932cb3598e6b1d1d3c5aa34d5e9d8488c84649e6ec1bd8f3f8562bb442958c87ea24005c70e9b5fc4bb2ef2a2bbc154147678aabd14406c8ad8074fc098c93a16f2df3340142de2c3aa973b1a3c062523eca51e95195e3c00ff7c354678929594869e17b8fb3fdd7553d02a1f25b832fff7a915c5aa121289205b1b2b15c422edeb24b2826f65df4d81a3232bf96c5c197299c6fc305dd9a4c05be4fd53ace9774439e0602830364c56489e2b4a5f8273157759969cd938d0ee0c55c4a8892eee2c623fd0e6b37969882e704d402950a1e3b0ac6795454caf80fb74aacdb017082e9b4d05052a44c5e971eabaa39cfc0d074deb662e5066bd70b8cf27332d2998c46f95b105cf26cc1396bf59b78a3701f122d33a30a40e62af7bc51437ff00d75e0481b01b85528bdf49210522f3b01a24a47535e0786f686fe0cef0a0c10dba804d897f4939f4a1c2888cfd5f99338ab1f0926d2bc474aebc12da6f84c49edef6138d713002f6161657de04429fc8e921292f65f1d5f3400173d73d611e9c1ac6fcfd270b7627f90000f9fb61596c985e64aa6a0183eeb7c0f7344a04c001110b22e022fabc5aba3edfcaae7aef2119d2f0131b0fd70807de8711989481ab482c16e289cd4c2354777000f808da821061021506b4e92b1515af0154af698b106b7f7d02c5adc2ec557791e8988c15fc4be0a51ad9de5b2c38730c09a2dcac3862c446bea45b503210a54d4e9817a2604faafe92cff0a33114020e7bcc8c6aa748c7b8e9950f21cd9859461a7581cf07078833d9e18ada3661df4654aa9eefd59ef99cd8564136f6f1ff48419a4c2b9ad313104653b3d4832dd0f94fe1211314865ba9694e12c0cc94b1d2205351c3e79da61f15b498e44c2041c470fc55d35f66006eeb923fb90a7b8ad0f1321563f37a1d2a3696d53a402671ca50dc4914d0cc6a32715f5a8b63f68db51c114b56d543c0f5458b311edc0fdf9e0d7d71b4d522d0e661e3885196aae02b180c64e63331b35158e5e360936a175012742ad2b88201dab4b4f645e4504c46956d32336af9b3a9e11f3ca15d070ffde2d55f087087337e8bb42c6fc597196be1a9fd21d6615287010b1a211bfd7d2afdc0af2ea0b6942cff2132095d6e9db15e11aee91f05ccd7511ecde462b34d3a26d67f6dcf9a2f1a99cde008d13d632bdbd0d6af1e175438082075e1f21217dbde1191349ef651655f4a2c6375b7e249fbe032b7081cffb2acc7f6c5aec3d8b00b97682b8c20c547c0dbc0464f3cd437c960460d6fe2d03e689fc3363b97b600ce185a277953eb7c809d35015ce854779e85614a6ba15238181c0e970294ae700bbc8e2385cfee8aa7bcbf1346eb3facfd0fdf73ebbad77f8c565e8afcbed5a33468993fdd1a1f4985747a51141028598459d87ec4b953b1e166ada21515cb3e07e1e62dbf4e2df06cb29b61f03104af823f00cb01ea2de7033c4c11f2a98001ffc22d986b0940814d55d93404c945bd116337270396f3723c767ce33813d6fdd793534528ccb4ae104e014db8cd7ad0edd8dbe1c20387772973b6c2ac654a4f4cfa1b1412d0b278a55751a7fb9d628b357d5524a957454f9d58706a1c6aa33fb970174456013a143ba3dabd72c9ae13fd64afa6dfac7eb862eb66e4bea6f31109463351107d7120eef99fb054cb0506afb4c2e28f366688a0e8b82ad329583622531b2862e10f3891dedfb50608036076af302288ba034789a0992b0aeff4af4515f52390d33af369ad0d91fc6110b825b3c53839213ac454d97aa4261e7c5b3454edebca5bc082dc111c0888ea816fb9585c79ba2d675a6ab4246064507b9feadb52a43e3e41381a0114746572898a58f7cef60f3e10e971ae7f9db798502340d6e4e0f62cc5bace96a3a0000e9a35405c8d128e4c132c8e5e7df082fa1148ae267608c2b87f4e4e46ffe5567dbd0d05014c638031e79c35c666a82d645d913cb866eeeb82c0d7522d4b44cbc8926793fe30dd2c751bbb3fc1a6a05726102b07b6002680a3f626b1fd2e16d8282b5f6dee81c7e0412f98cd856df53facc49ec286707ad8f4a83b288df6e313da163a0b81b31cc52fd896ed221e95e84b2ed5e936500543d10ac823161f5ea0d3e1e565de9e1694f6f3a11ff94f552d547eb67a1aa98256fc6fd4adb2872f0317480f50d7501fed312a3c26cb0387b0a47881d643718b80e482f1b5a946c13a5cab8e5f01add6584d02b59c61fe9fc41ec06da668c309d210d5e4d65d21960b78fe304e3c3efe14cca44077541916a8ba1e9d577a3347aa645d56252359ad52dbe233b52e37cc485be9f478900671599ec28b607a14a14d82d0b1cebd8b7c329fc30a056356ed90cbadb7ebf19f9ef831680fea1b41e14d15d6de416b9c7fa85b30bf1217cc13a8cb4d7736c3c1132e7712429a7060ca934890d151732f2e5c2de6b7a78cd4bd33bfee91d05772be0e29fbfde0843cabb5156fc21f51180eb3c482a9ec42e85b6d3b5a2bb4abfb63dc0fcaf902ab13bcf9d7c0fb9a0f2e7e61561a62c59e56e0e28f309875857f418dad4fc67a9c6bc7da3b894ceec402ac69f15c52657448c314cb2d3aa48677a744c037872a74deaed3244d72617a9c05368e8a13d1a78a9c427577bb8563166761a88d6af90f2a41cc6c4c40ff218e5489b4c678262c3df8e214fe9a89d03e7f40cabfbfcf116ff235e2a3c3d3795a197f52f8537d12491e0c420345d25e04add32ed440d3426264395782179a929a482f50d15177c9719e3f86b9212787076cbb240e4a04506693c73aa088d5ae0e7a4d8124c0e8c466001f61dde738b80a28f462340d0607eba5c46e6b20c2b8278708e99706bf60f5d323b0e2618cbf163483ea983aaba076071e0ebebd37e16173b16138d21e90eba08a43ccdc6a689685fef627f1ff2f152bbca78a211f802c2ec46b24cbc8ffee871a848226f8d8587c9b5af44aca7f6ce99cec8d96bce6c6e2f225b6d61fa1b031fbaf1c4677f9f514dc9cfaf234bd90e20fb1285895b1d4df267542de5044ce4287c2af8dd9c3d1f188127e292c757a578b19b20281f50f4f87e5453b3d0d7476a180c24f7b0d9d986a7ec1537c4db806de5f25b628e829222ea52e7763b0fe12a9cafa03c821a178a9e0a2e5c0d73a8ef5a87ee9f04eabbf64a8a86ffe9a5865e53d37f37cfcacaafe2c2cd461c0e983e8166b26cc8cc36a6304fb4e8f9685bd75b433de5ce23ce2f6a4ec20722be2a0e1d12ba801b957b5f67debb6d7768a2acca295b80c0dfb38612271c658b4fbedb58a1c6a50c2b9862533a0363ee94f77179f1cee6657704a4691bdd2259ca2dfc4688f2a1402eb807cbb8b12075f3077eb54b5a810378f8e1e1478d0157f4cefcb8c0fad8857355029e2ec62a210d7015b25a1acf8fb84f288361ecb1484254f9036bc0b3102c5465d45a16ca1bea6c6d9977969a047d926ca903b4b6c4fd8f8f52809ca3a3f82beaaadd02699ed2106d48c945f10bb4614a3c8a4bda4c38331d1e47c418f74c133959cc18c6318c360bc5f60f23ac280d21de2e58a7e7b3f42ccc72e01f786fed75f887b161525202ebb5481291a45bd74592cc99a0d1fd33300b9c699204ee2521aacc7f8877e8f42311a8d103ca47262573803eedca89c392351f24c4bab1fb2dce0defa4193e6c992648ac1e728d085d6e66f19b7b71f9f5fa40a503a9ad0dec29035a99868457205e515107a9e5caa1a5bc7a8f2e5e8a57614fc56e1f6a840dc0e699b4de01a32fb0f88b3b3d57001cc422f57806c0e245b49e297e031a3d0c260397b66deff559c28798dcacc050f66361addc7bef265bca2da54c52063408cd070f08a29fd6ce288d8c8c8ce8fb7382d5da0b661f5f94b21a50bb5c9d2be5f2648abae64b769e3767360541ddf33d107e7efafdd420f880b80f525103db67c057be0d14a78ea7e6cb55dbff6973519719f2f7e3944d2d7f06d11c88afccd9fd74959d6eb2d78c35b896ffd89b4cd1973e415a94fe8e8d27ef9db299af8cd3e5b2d9db4f9d29f3d98236bddb4f202a5e7d84a7b639f293862f652865f8539cfa886f1b4d976cc43f52688f12b6b3fd364e9abdfda6c446229544274c53d663ee4f67c053dbcf1925e80a4b15fded25d577fb23601e2474184c4871c59d734e8fa635065c6d271292a529459f9117cf39e794e27d29d1206b122719cc797f5e2c25e6380ee73a591b11ba4c577a54628b5e8adc6ff87aadb5d65a2ba7b156e27aadb5d65a2ba594524a691d43809b1065baaa4f29a5dbb63d0a6ce4d8be0912d83f51d56cc2478e4d37b13dadef5a529500043092404a1f640fa24d4bd983fc59459963db61d259710919c37943133e405c8003117290807e757777777777afb53e0a6ce4a8ba09aa8920d2269d761fbe04766f0add694bacb2a5775e279dd20e749df431e74a0f0fce4d0c4bf6a3e36ad1d084603d4070646280642f9d9a568de60353910feb018203247be9d09a1acd07160488cbcc80765e43b11a5a45d2904ee98bea5e51c31b7452569b5a33548bf9e404a133f447d08c678735f41373e54c9a2d678492e80902a5cbb13c6d133ae99d74772983ae9b2e250d393d9c3ef78a2cbfa33265e7bd225b946d3a383f20e89e2faba441c110456dd3ffb9670dab7407c2dd81d09656d801cd1e5f07339f93524a3becf8d613aaf4f6df291974a47006182e797225a79455573a67139d44b942a7a315e6c14a30140c6506a6e53a6463defed832345b7e0d72185d7135ae0683c160dc908846f4c3471413e386442cd429e67392d527f238612bae4655fe52c4e2388eabd15595fdffe9b4b99a57ae5681ea50a5056da74053cc58e4aa5f7bfc4cabcc53ce93c7cad5b6bfad19ab6cfb9c3bbb25fb1f248b6f972cee2359bce6e5403240609426595cb2b864713bf3a2dad6e5299fa9964ab6717aa1780a65bc292b6546431eb34fcfbf75cd7894939d29d91957398adfa837345b5ae126668f5ccd0a3e88edefe63637faf30b42eeac3a43aed4e5b4a0148d3831676de0d9520a5b0a6943cceec236e419e4a9191479c6f658f7e88d796a6fbc312b2ca32aaff6c6ccd98da154b6fdad9e42596428f20ff795fbcadd9f79fe9ea9a9f29a41aef2c73608f7e9b07bced690e7d71fe9ce6c656de88ee7c206b136945a1c0f73f3ce3ae9d76d6d90205fd99cd59ce9b09bd33688903c35edf9d106a13c9ef21984d2207467b4fd48775c95091b86fb7a77705f3971949ef23c7535be3367e8f215327702560c13ddd3ee69f7f47e77823c9f5eafe3b69f3f62e5f1f735f99efe8ed4bb776f77efa7aae3bff7512e7d913651edfb764e51fd5ee877a207c1dc223d8308aa25555991b71be05c29a5acb7459b31d259f5471644298fd4a1f267eb66d3b79152fb0f4b9dc667ea4b1a69fd478da6b4297518783fbd9fdecfdfbe8bc9d253f31b491515d9be64228fbf3713d004d43b527b76ffdb6f5bd6534c558947284f715fb747494996ee3739dfb5896a6f6fbf21e67b262ff33d6dd2e91da9dd7da7532098bb138944a8acc8f2e584f91c90cdfdef2ec463c91e477bca9506a80a5feeef9dd3bfa9018a3137c5f9b95c6e6eaf81f9c3575a1b902b1b54851f633c4a366cccc4e6221262063c858ff0147e49475e69e3b7f86d60b7a1e337f7dcfd51ce342059e8c6d509ef4b8e1f7f4a45a36c3c63e369f3864ea28c13b482fd6dfb5cecd78a31c694e2fa9bdc94528d040d42c5460d241c63ac9f0e81b5132620427dd1dbd862904795ed239652b5abd440dd15967f859f3883cb0c71a8220a1be4a00184274c50835a0dda40cbe1af624345d2f094a0e25c0ca6538fcefb22ceabf23d5145e27091a86235112917648c9f7e4e9cb04c595bdd5224580164fb4fff4da7cb3ceccf5977f80e11ecf91ba554a678ccf7ff5ea69dbe0293176b7596eff9d856a324be184f3cefbdf75a91bd17dfe771f1b5fb3ee57175a52fe98bc98bc98eca62edba6565b0389750965e4a29a594524a29a5d7524aadb5b64afadb532cdf6eff71049bee7b37d156ff4a675d77f2159317ff8dbe2df95f2b6af6fdfa76671edbbbce263b7ccbafdbde9fdf0e11ecfa57ee39c12a695899b27aac92477daa4fced375965a5b7760f98b8a3158a12a74602b9da215ac49e956b7cd0e0036ab800511f286a01921704881102b64489badb358e90d405e2b152b8bb5e7f752594c6cfae308767daa79506df2529ffe10284fcda76ae8c2f7f2e9515223114bd5c4d97f7e0d01de5d084e99f2de8e6077563aa520a871b88fdd7df79d48f4fd89a04cd5277560bf6c9be20fecf4f8814d52073d49a3d2fd612c53d5ebb1bdca1a82aa25e87509b552d4a954e9a44e88821382ac200a55c8e7c3662bada162e38657f2445b0aa982662bc20a9c10e48bc38b064d610b59a8e2892a0cdde08a23a220d403254431030627d49057c084d88615f4c07230e0a15c1364ac1456e004e7c31652450afc25078727a278c2cc0d40f8c20c0f0fdc1094022ccc64c1832cb0b0a9373ab08196a1d6c052d1d5f001ab0aaec0d5544cc51aaa102ab2286d29848a315001863d9e609d140010430e5a7110c2908fcc909f2139d8810f0e6ee0832b365ab3b193e52ea55c354bb2868d1b282216fc10010b6c80830d4f8e31d32253b47c8022085ee0420f1b803003191bdc5208d0149e0ddea33fbd128fe9a1bc92974f25af943de5d5cb35973caa7d6ca76fc0abed2fa61b2c4f8fd2fa3665ad88b26247931ddb6e931d73d77fb1f5ae543cd9f50933c784207ab9b2861b6cb206a5a7df95440f84a41f8923e2dcdf07c33de61e8b1b634ee4c13d7e9238729fbffb76848f5ff4bd808fb3806d89862d851001da9dca93be62e2491af3e5962f74e32454e89ebb7ee77522cef32ce8987370a4c7126c4e634f811ddd6cc59e02bf7e060235fec47a63d3d9ae1c1ebd1ad949539cb9e2c746d952481a66b12db7dc767274c23ac93d91473c775c355f723c9987ffa8c890c72a622177d6c39eaf3aff2a8e49a4b6a5d87f1379d4efe12ba308e52b3c44bfbd64c14f5f46c7d9bf5664edb593f3cd4e69c198ca1ada9e56cf5e79ebdcf55a5badadaa19962cf7fdad64c1eff5b71fbd4ab7a7db53913e16e5a69b288260ee1933e84bb9e33715913ca568427f4c6d4b75aac70c4963ced99dd2fd5a708a2b6ab6dcd5576aadb57ec557a4efa27e2e96ce19ddf5b353d1d796099b29fef5a59e3f9eca42421336ad9eb02c9684f26ffad933cd9bf5acc64e1f5379652754836af55adfd24929a54f7350f9d12b80ecedab8e2cce28cb483715a2aaba69d04cf1076184447acc41b365ce668a3fa783b6efee13af4c89de133b99128552259a2d73e66d9f4bf809e163e3af769fc5b93f710a899306bb53e877f75368e6e0b4c8abddd70f88df9d16c93b1d1c7d6ceb49fc24e1ed0877d5af4da938d67189ede39b1f17b830fc54a4949be7e7b6fccfc5f49fee48e2c84f99111c4e12e72ed5adfbbecfc544ee292359e6b6530572857b92c4f8ad8cae50f48451957daa6a4155a797bef2917c37855eccf93d8b72bbbf8ba207268dc445b9391808e3fcc67c94f10c9ab449bb3ffafa70afeb33e2deddb5733e6973e79f41599cb4fce30cda5668d23a92163fe2d3891b11e9abe49c47c4dcc247fcc568846b713a9dfee4dc8f90bc2df192934739f722d1f6e5bd38cd83f4fe237a243df71de805b9ccf9cd6f8a3368d2388ee3384e85e4df7123239fc5d1db233f47de4518cf891de967d0a49160e8a01f8496f488abdef478a22e9e937bd4e2678f5636379ed63b41959c449338f6b09bf42ebea32e9e7e2e262f3f92894884101f02c29138fa1171f4b147de3f9791cf39bf0eb9f3fbd82271fc50fcc42c8ab8971f69f49fe8639374a5c14c19fd8cb4e782c3bfefdb3e9238aa6cd277178b4cca5963d197b990bf21341a6d87ff21e9e79611a8013d0be4a9cf45a1688a8ca0dee7223282ba25fdc8923ed43246faa963a4cfda66d2cbf74a7f1a7553fc5df238bc085fb12fa51022b1881b872cfa51f610a18bb0324badcc7223a3efa6fd74d8ef48e29c69d1e27329a1243bbf1412d4b3e5f742921f87ef50eca6777a1c6e2291b028faae54c2a5984d267cfb9b25d516242dbc162d1e977cecfa2dbe5289387d62245178496fe5a3bc25d1238ef19e1eb349d74c8f82710c6d32fdc8a7e33718866f2a8523a1e843b1fbbc6dd157b9527ad1634fae905ef459b290bce8479f8bc8db212693fe7efe2efc5c3249bf7826b960d626d724ff7865df0be9af36c91affd017c755a6b0c35ec99561d19742d3bda50f4da148fa6b0a4b3788166f8eabc2eaa96679ac32f5c77d1ea5cf6fbfca4816efed5715481692b7df91881e08f7df2f79f9492591f4243bf2931e877b250be4a99915f2947d936869b6a46d90a7ac6f91be37d4259d151c7d6c2b233de947bc495a7a0aff20bdcc55f6311ed163ce233d9e4e3fa636f7a2509b709af4e18f5636a2493f1249243d7f78ca7ee8914824128944d21f989fcb94b12257192b93342cc99642827af6e840eafebe1bfbabb1bf19fb7b1454697fa4ffbeef4ede6900b98751c5c9d196e22a255a20195dd999abecdbd6b62a237a4ca5467a7c59d632911eef6c5b20eee32b630a488eafe8788fafcc20977d218af86a6a868f35f60d999df0b91d12498b7ed4cd3689445ae2c7262d3123f2c0123b3f491c296c8ff2e3709107381eb7d1f194bdaf6d85a48167933ee727d1469f479f45b93fd183388fcdcb7ee2051addfcd6494e72d24f699ff452b22491daf9af0e0c49df9dac2f8f8a8acca3c7dc2a2a32e9555364d106d999a75453e429dda905adcc53f6e90784ddd253244dd2a38f4d7afbf47371e1863c639eb23fd213e6298bbf21be97fca49f1f0ce973fe4cf29b59267d7ed1e79503912afb222c72e1863cf2a41f53db021922bf8c3efffc60f28f463fd26ee3a9941dfd85796aee91f69be9dd1ecaf1f80a2d8949dba4e75e9ee2786432e947eea583dbd11c8fa7aac8a32591c42b85a4615f7e5796a9c8a230f4d3fe52564655f6bfef4425fb1bed8fdbdff753cecfa5e7c27ce549a2f7232e8ebcfc488fc32f8faf640e2fbf7d0be42ba3b7ef228a4c05d66bf7f0ddfd954916dfd647c68378ca7e32fb36d423ce7a4c89f4f8243d9eb27dd51af2e8f35f99af98de6ea50dbf83266d65b6a4392179a479907e947fb4b2d11381c819742040b67d4f1cafceb6f6af28936debdc8be3e160272e840a3ab9bb704f1494999234a60c5d763041f61fb10e2969ccefea7409eba697f3697ce9bbdbdd87e0a5fb2e0ba92feceebbee71d709f56c19b4a5102c64bb9b1fd6638d3d6b583add4abb81262f1bd6e312fb7a7854128245cf1e6feceeeddfe856ba0fe2445755aae6775ea73b3da23af7ee15793cedeefde4a90eff14fd287982902c74772f84afd015d4a9eb5ea2741b1c94a02b9237bdf792ae5a889e449c5245bf8528a5ca24be5adbcf1a9d9dedede71fd9e654a287a7b6efaf38ff1375dc9fb72ad1c357c0df7e4a215799aab63f59c186bdfd9c18dfefee8828ebe9b46d23dfcf5ab789bd128a678b5c6475441a29995a909c4a5c98a04e5ec0e8444cbd6e2a3352be92dfbdef78f8538feb5483baa8ca529f9962696ca650576cb6842f9c631bd3e9e1fc90899134ec8b669a9029e1cbe6bd146cfbe1ebc66eecfef86a860cef7910bd1bcfc6532c57d9dfd9f5f470c258cd0973f83094f161178bc56221ca875dad16c6f8b073b95cae507fd8f9f884e2875d2b0cc3f03fec727242181f8a6ab55a2d7cf16147139e7c288ac562b110f5a188460b4d3e14b95c2e57e8e243918f4f58f2a1a815866178fa50949313927cc8d56ab55ad8e243114d189a3ee462b1582c2c7dc8d168e1c8879ccbe57285a40f399f99627dc2d1875cab15b6c2300cb99c10c762b1182dc4b4307ff84af80af7e12721593a97cb153e11bec22eaab23e21f6095bad10b7c2ef43fa614e580b6b61f8229c1386b7168698260c657c2e610e1e2b26430d394489d562b1586ddb176380ba73f974aeced5b97cb6fd17bfef5a5d4ed7ea5a5dabcbd9f661c0f05ed43a9a5aadd6d16cfb2f4e3a548c168bc568dbfe8989c885c8e5e372b97cb67d54097712b54439a1a82512b540512b67db3721c12db89a8826ac7d4d44b3edbb30dd1217e3685c4cc4c562b46dbf646423712ece8773712ecec5f96cfba7911ab2dde3ede15a5c0ed7e25a5c8bcbd9e1cf5318867a04676662b4582c46dbf673f71c49d7752eec835dd8855d58a4ffb5a0b88573700bb7700be798e8cdf4c6668afd9c69178a1e8e77e3c978319fe8b1240def47ac665b9a0b866d3f6b218fb8866b78c8573bbc17e3a97ae3ab2be3c70a64e7f063cdd1e1c7aab3c1af36be927af06b0e64cba5a1fc5877b0c1af359225c6831707a7cae0d4199cda1af29567836cb93c3c6ea84916fde3ab2b0314448bf98ac805d9726f6ebce0235960b87cb5cd66af19cf0cb641d4834f8f205b6e0c4dc2069f06912c2f1e7c4ae3ab8d8787d6f0d01b1e201b3c79f0690b64cb06043efd21594c1edc70706a3894854365827ce564856cd97676d030932c2e7a7cb5c9f8c8fc006db044886cd96e6e9ed8912c2438beb2b35990990b7cbff195d283ef3c902d5b8cfb6083ef3692a5c583ef31beb23cfe830634bd41b65820a0380c49961199af2c0ece0c470807247d41b6d89d9d30c424cb48c757564666a7070c1ffca904d9626f668abd59c2067fe64896fc609dd980a297c1067fc240b6d8981ebeaa3c433c3f36f81c902d1568ce4896f9e02bf1494816fa3319f844f8aae2509505ff45b6d49d9a6fc8803fc3575546882024cb7d70d461830f82ff8974cb902df50645b2d4071ffb8acec09fb2a5c6cc14fbe0834ff2b980af9dbab14bd341df580efac664e81b43d1b46d3f86f6589286500eff5e9efbf7da1fd1a078effd7b2f09c687daee6cdbeee88577b26d1b6adbb66cd29db60de7ed872e44259bcc76b3c99c36994d66bbd9f64112ae34db6266a5d937db62b6fdaf0536f100813c251e1ea06ddf1bb9249c1d50e3e0e0ec6cfbdd680bad8cbd397d5a5b999b6d5f94ada8ce6c4c9dcdeaccc66cfb9c50ae7bbc3d95078887870768db8e9b60ccb6600cce0e0e0ececef630b5b52a7373b3ed5fb13e768e75ab1ebf201da6b86d17bf999783fc9362e8a37d6690343efd61913dfab3edb33c96cc27fb803cf5cd5c651f646dfb557ba63f5446817cc5ff0baa619a5bbb354c5382431a0f5bbedae10b029a79e29c214e208a9fcee80ad7688d992dddd04cb1a7d9ac1baaa23f16bfa0981a5d7932ddd06cf1989029f6eddb6c5bc3355c63f14ed0c161db17698f8545ae3f86af6da594327c85afdbe32be327bb3e305f113fd907e42bd5dbff823ea18f663775d1d527a32a9fd992678a7d8f4555f63f99cb457d30567df75199dadec52b535b2755dbdbcfdb290ddb6e3f7eb36db7ace3b7bbd83c6f3e6db11fe64104634490c5a2ab4fe62afb18e7ac1a924727547fff3e28e32bd22795d882f47178dd9cb8833863aeb2e30c9578da7c7e9f8cae4aaeb2bf7d324cbd185fd116cb636dfbb44529b5d976f5017db24d7f9f6cdb10c53f6004dbd994b4a8cf6cfb5352fab26efa9b68777d5acceea8376772e549957d4f0865e50cf9b2fe4cd9049223fc2315a24292657a2c5f494969b8ced8a16d1f6ff473c12a9bca5cc4d0509a8cae68cd55d635e76d9ecb749c97ca986e425bfd8dd26476a7a990a7ec27575488aa244b7d5b656c5b59dbfe78b2ad1e4d355321ba7299a9b27f3a653a5542dbbee873a12a1e15df65660b0ba4bf40aec0b73fbaf763b8fa7e24b93fc2d8a3cb5c4965ea3e15bffb9b785da4dbb66defe27e2e147fdb06fb600005c8dafe35b54e204f39cdcad7d0ec098477d553e62958ae349bac523b6542d8a9aebae5ab4fc8a3f115ead1c83c9aedff09d1d504927d42734e4a29958fe5ea4a157d2953b445ca14fa72d6cdc3be9a405b86ab3f0659170b3270823f3f0bd996506c298448cc6611f1d979e3f0c1f041307cccb1c207b9c7e1639b1393d147f783a73ceff3bcd42aff49d25545f9c2ede334ce3d458fb979bc4099b870311a9d484840fca3cee7488f73dbc0cf71a33f7d2e23ee39d28fa3e7bec3a27d6e64c2719fda233fea5137b6a19a22dfa72fbd1de1c6df71e2b6bb18e00445df330cc31b8217bca0078ae38c5d5176f51cd75aeb0c7cd3e7020261f70d4fd11fdd67530f63fe2359f2d3eda11e02fc30d426398723df0bf859db0f47ce61bec2037cfadde8db31c32142b9f3f7c23d06c1c7bfc1ef72ad2fe9f79dcea3fc21e638f0479f71f860f86016c110673087a3cf8be18122f654178abe41719cdf0e70e39770e32ab7efb10499eefcddf7b998ec486dd086a7c0ef429148be26f96ffed40643ab6d4c9a3f4fd2a83736e9e9ffe02b3c463724cbc8d327806409458a142952a4489122458a142952a4489122458a14e9428af2f7af7e51fcff3f397914ea4b4afe747a93e94ba51f8d3ee7ffbef7bce7b8c7f86b7d6bff8482ea019d99b2e5dacc14c7d766b6dcd74ca12f9bd985235235c56002d36162199e94524ae1cafbf2c7b0d76cc133259423323549a48a5e2230aa0e426a3afb0af98aaf4821b59c4d1ffbdc19fd1be42bf3d236a5bb7ef55545f258833280810b5c0ba02051010a8813d0474820020f8118463cc001270d78510403168052000c2260125032840b217620e0f46212840e204c2e2d7e38408ed226c16180028c0840bad1c29207306263b5f20920003ed4e801f442951400d0d88187199c08ab523ae420a34b65000317b0001215a0c0048e9040042060c4031cd0802218b00005100193802184d8818097207400e1f2c301726c1c062800016eb4b00cc0c66a4500357c08400f2a2900a03183871d54291d72908172efbdf7defb1206e55e198ff23250f4bd3d28e2dcb7075685992c7605193278304c76effd7b77f860aefefbfae25420f50775a7ead49ceac4dd28aafbe2df981819266c5a33271045968e8d8d8d4e4a260312031da20591e1ffe785e83b860e3a3a2f26c4603c4d383971e5d06ad5cc2007c84d0d50281a17a26f183fafd7eb47068d5653c38c0c6b484989908e8d8d8d0e0a0ce60385073990ff44719abf4d6200011224083c2fd7104c261c2d23f3a3899b1a9a14f826f979bd5e3f2210d04c0a564dc80ca3914cc7c6c646e75faf1d27cc1f9f1e28f81e81515363630357101c1c7c5feb454d0e4922343f626411dfe1898f4f2c0b4233d916380e86fa603056d9546ad0e8d9b99182b19eb1f9be912b1b18f8b102b9c08f35c7022ebe178184ebf7af2cb932a2023f56190afc586726e0dee308f7a73f72150209fc488122f0230d82c08f94b6fda94f1a23fc854bae66eb013fd297037ea43c0d709f3945b83fa591abe962c08fb466013fd21b0578c9fbf421c25dfc6ac6607ef45a027ea4ac21dc274d08ef91ab59dbf1a3fb20e047ff79f9d1819c26086f812357ded2f1a30701e24777b978e9dd737e70b972d7017ef41f397e749aeda377f7c1f1e38cc3906421c9e4ca6306f871ce0af0e31422c08fb3e6b41bae23575e6bf971eeb0fc387b06f093d2cc146ac37fe6cc965cd1d6eac769b3f2e3c411807b5fc3694e0f49bf871fe550007e9c31db0795e7c08c1249481651ca8f7206801fa58cc61321573446557406a5cd14faaa1fe5ce0e3fdee0e1c71adb7f865cd11a152208c9d2a57ed461eb7092e17f5b2892657b9f5155f597a7cfc56d500c5cc00245cc960b84841e7d1b518118056213d03d66cb951da147df21a0ab8b25a0471c010d014d335bee8f1134d7e6012d07b41ad0ca992d57a7083dfa6531c0b50097025c3eb3e5d610a147df9b0c269680d810b14d7fd266cb3624841e7dcf1a7dbc438f1801fa45d3ed27089a165d6d363a5a40b45c5a39b365d3f921c745571beb007ac4395cdbe5335bb61a1c7af4ed316a8058016204a0efb4d9626f68daa696d2cc166b69ce6cb12d5e63f1da00bc668306aff48857f49805a06be8d1a965d99a99427f556554459b2d7568a6d0f7c11500570f2e159da2c75306801e338dd80c5da3abfa6acd96fa33536674556d6a664bd59929f479a0b51d744da56ba9d6d6418fa79c831eb30c8da26b36fd0ec380660badc160305a031245511445d145930f468b22caeb47d17a9c5bd4a228c2b438b708f3a1352882807ea2a06d4041b9328cf195c5f8ffff7f51145f14ff258cf81fe3c58f31f7ebff0712439cfbc51aa406a1f2d457750d4114f5fcad5f3faf9f1727272727272727ffffff27251fcc9f9c88ff2ffec9c99f9c9cbc10e73e11eb8fda44bda93595a6a6e0ffda5c9d6b737560a05028140a853a3939f99313d4e9833941a1fe4ffe4f50a847a1504030c4b9514033292aab2664869313190cd1f70bd1777759b7e6b22eebb26e8d8b92929292929212140af5285409c907832a293979d49fa0f43877494949c9cb853877894877a8137e7c7a28145028d9904c261b32399d4ea7d3e9545252f22525a7161f4cc9e984fa924795e871eed3e9743211e73e89d486dac0150487e2a0a464fa76f1fa79bd5e3f2d4c2693c964329d4ea73f9d4ca60fe6643295fce94b4e26d39b4ca6dadca6da10111afa83c614399da68d8e8d8d8d0e49a9542a954a2593c9f42653a9f4c1984aa5d39bfe64d2a5920f893877c9279605a1996c0b26d3f4dd42f4dd6dacad66636dacad86341a8d46a3d1a8542a7da9341af9604aa391e94b6f9a7ba447a3519091e844e87123944ab221994c36349273ce39e7d16834caa40f669473e9475f1ae971e6bcb3e833ae021cb7f196b360349abe49af9fd7ebf5037edff77ddf9773fe9cbfd10793bf6ff4f947f9fbbed92c28668836abc8d346c7c6c64627f43ccff33ceffb3e2f7f309fe7e5ff3e7f7a9cdbd39eb7138a737b3b3c5190c56053f8be97efceb26c8d65599665d91a11c7711cc7719ee7795cf8c1781cf7bdf79fa7c7c971a29983a933732690b903cf930dc964b2a10e638c31c61cc761f083e130f69e7b6f623c8487268b0dad393365dcc071a26fd1ebe7f57afd6cb5d65a6bc5183fc6f5fb6070ad1cd6e3ac75933fb420202f601bbaba33aad2992d1876b271faddb5d65a6b6dadb5da971f4cd5d87a7daca7b5356c0d1b3decf92c1e211f54248de93c78281975671ed60256c1f80583a5f09cd30cfe1f8cd5d84fb28b864d3f6791fde79dc15058b54df1d542913ca6ba19de09068351159517dbc8af13cfc3eeac05db3d5777e62ada220d2053f3318cae0e802d4c0c9b5e21b6698a575dd6b0b1e7ab8adc59a53eedd76d351764cb183e2e3067177c86ac8108112244881021428408112243860c1942a3d168341a8d46a3d16843860c193264884f11a09d3d45b1276950e92915aa427555f124bc196eff5757bff3177b437d37fd0d377b625fc170c83aea18767d2b5be6cf4c999fb7904d80c05b8e3dee9e1aa7a8c98b1e4bfb349fead4be22ca4ffd18d5ea9734aec8b4b24e29893d2a5357a2eab6fd86dad56db5d6befb948901b627ad76bb981375de0786019dd6a844ebd90b8bdeb1a1910040002316000028140e86430291589487b29ae30314000c769e44665a34184aa3148632086210530a18430c01003020002322541a0005f4fea0970ea8de067a9ca8e7037a4fd4e3837a4ed0f3a11e27d2f381de13f57c408f13f57c50ef097a7ea8e751eab999d61a04663651cab5761a911d98f684481d2c18483e2da1e08f722e11e30381dc908b215a380d04fc3c623937dac7d46c317315e8a7bcffe1c0c443f2c16500f1508fa3feb8eb805d950086b853bec7898f427702aca8bbfc5aea5dbf9d7f178b19885000d49669b9522cd37f8e2a33644123265492560f6b552e52df7c2d626c69703556a5e2205098a4548490f8cd22fe46370aad1854a916de56563731707c51b6200db0921d3e7935617f2a1b042b37fbae0ee108cbb8ef5c2bade46292bcfc96655880b5f40781d4be09cde4fe319b1913edfebd337ca8f526ec1437eb94d2fcfde41158f3e1f59df9827faa1257dea31b8d54b9cbc61ffc4a6a6c8bfe9244a5568687732a095dc807e34f3174a51fe45f279148c7f873d954d31476ce79f49a073a08e1941ae4517633e2c0a974b2937740d95447b77198537e5b038cc39df25f19e08b19feb7d4b34c6dfd4a79c794d7e63f89670cd8b6fd93bf8a816f935fd99798596dfd9779c620d7f65f92770c986dfc937e8a81df867f898f28d2f6a98fec2a2299a849d17186ad36db8a509ff47e2ec3e054969b1204ef0413346884fbe10f02d0deaf7bbc7d2f252899465a95a492b4694b09cad390462554927e5a2945d934d2aa2495a44f4b4a519a4eda2a6d7261913556acb2c09a15930b96acb1c49205d65931b9b1c8120b96ac618dac813288aa14de42db4a8f859c2944be8a84f83298ac0c42656ee0d6bed4192418841ad6b1658accaade00124fcaa071f09033ff44ce2c2b72dc667fb11d824ed8994d584c1ee56ee442432579dc7b12b3af9b013607dbd99ef4a0587824f10cbcc6b6d14c8aed1c38ebafe33e3e0d9c01a475de50265706c9250171c7a8514ed0bb0b376729850ab9108e00b345a15bf0dea4f9adade404fd2d681d07c617e01f44aef60963a771f409b1df58127250dbb5987f6972c551c9c45706f58c0a7c39c728932b77e2f62cd5d03a2ec4219813887ce50940f19541d92411772c3ae524fd1bbaa506cc053431fac528e49648293de142ca98815d3289ee0aaa8e037108e70722577d00b93bc56530ba49b1ae925d66d93521379499908bc523352821bf580677181168490751932b37e5e6591aa13a4e94279017984cf521c0eb97c1394910e1340a8549ba0bfa951acc85856c0b1321478b47360d7d1e0ebbd404ba3b281d07c021c81f88acf20124771a97c1689362d3869b90323474d431e72229547fd866659090a3cb23ab8d29689d5d7202dd1d341d07e210e40f4656fb00534f3050048ebb319b9d2609b916c62c5fa5167c49a65b06b5b700ab24283333837d7b964aed305be21f9b62d4385aa1e012f9063411729d798becca9059a86f132e4ddc81ab88f412210f8cac30483546c51ed405fdc07d467a73b98c04ec141b3686b543171e5a08ae1bc9a7a24370479d877e746af16404863692b766979c96f28045ad6d1be5cbdea5f94e825b46f25125b86130e034fa8e07226f4a871db7819a80de47e7f6bc546004a2b938faea638682781bb67ca360b46ac6096de2851e3775bce74bd845636a7c7543501aefe1acc0a5fd4181af4014c689572cf088128871d991d47a85eca07e6583b640b7aeb41c30396d39ae80c464b468e8da5e908224bfab60bab16903bd7ede16a93e7706582b31e0d253b7c946045ebd47fc3bcf02ae6c23dfd4bc4461b24856e830526e3b2d792386f9554b1f289c1811be115fe7d24ce3b5e1feda5a0e4eb93fe3e85d58d13f0823cc27c11276b941cd8817e2d7c4a0920ea61e7b55900dbdd4c45c028c789a45bdb12626999674a526adc79c9e0fca63babcfc85bf01abaa6d6ed1ab927b813d6df3ac7d880600051284e5ea2be68b9a8c4891befdfa7d14a62260d69875f4f9ac304f27b07ba5890500eae10c68e77eb259992a72d81ac7eade64002547db57aaa7c50fa9a80535002802beb5476daa82a69dbd7a5007445e8b0d2bcc2027d193f27227622697c64a38dc7136fcd5552bb0cf8f0f6ffe20077e9a984865ab7a2efc294258402b52c061cc40e0d1747e9021426003b0314714a90f88749e3b5de9a1fba3e2d69dd7c07e2f076b6c6dc18d675d40b6479dc581b3d2c32044824e9859751b8a75413090a3977db56df2232c773157675400a71d0d5a253b35f6b661ae4a2d4505e41c2ebbbbd58b9f2ce43526645ee0764dcb364de36d032530fb5e73062899d6cf0723b303ba2ca71864dbac434264b421a44d89e270d53aacf48f8036fdcdd0e99dc7ee9f55dee8ea36b99045ed2ccb6a27e649b991a09e60b44023c5f6cf5977a58af7c21a0f2f1d6215bc57a375937e77bf56de784fca5fd5b3b9b5aa7cbdc2b9d18df5eb35dfdc97607b9d9ec09ab846a0322d6168cdf8d08fe1a00964d53ae2333163455fb9f976a15d10f1a2e167b512b0187445f0f1aa7b7c132d03ad0cba2f6ed2fe4019190cf75e9045ec7909fa4f822e8dc0cd4911318f0d586f0795d8f92481d7426cc3d6a053d2ed44f479477e4b1a3eccbcdd471679bf95a96c9236d17fc53b3629738404dec089e3d38923b045452b8c98bc113c00c36211fca74889cf82fc8a2482df053ea190ea81c6d889a498bc5f987201eec5d12443252e1b30a3097016f16f7d08c4bd00f516df6fc8cb0066e5ad0c855ce616ad824b6cb579a819c33c2a5d627a2a88807e362f472e736b14a5651aa7c0e728a41bec0099a993f067c04b25c0e78b15a17773d4fd25c299be282003c2a2cae8c97554162f60a16640cbafc3ac631f2bcd5902f9e2215701a2e0eb00e17305a4e84550530e8445605894827e6125c1f141816fa24ba51569a14716b06762be67a14986255f6d62d610158a8445ffa14a8938179d9483aa05e2c8937827e91f94aa0c0e0bd45160f367636d7484b4971decc28b22857333531d9644b299c245991242415988b52f0ac15507be9cb3e8b3ae45011114565d505faca1b258034b35011b7e1df256132c855ed8ebdf441d359478f499331397164502a5641e329d0358d229fe576f027008047b27df1ff46a09ee0b7011e630a548dd9f74fd2c2c4c9b71b90acc951e0c1723ff0642fd637083c54fe93305e2997aec5c20bdac0b0984f06eeb52f8d32e99c3064326868fd597c89c58fa5d5e4dd0b02818e0f5c570eaf0302e45417007e3f411ed2c0489969e49b3863e0e641a8594b1012d751cf7aa3f22208281bd557216c04c932099e1a300ef02f4f88937f584f894fa9afbbb1a6f7521025b06589d6cae40831ccc99c085166962285fe9ab380ad12a27de216ab41c7aa10926a704bd548fdc439218168089a1ef6954a23ea54e3f0f07a6e0b554ff472109522a73b1fc665aa587744ac70109094ca5904cddde1834f0e59ca34ff52602a760b07682c2f45be6f2ebdc0153f15d74bb9862d9e42538369603a50a99d5df2054ee022e53a6846d787d238017470c6d7a62600084dda6f6cb26c648816470890098508df2646e98905a77b85170cc04e29c3638e84c2da9ae42d3d2d827446f66bd9a012fa3201a6ca0e54e477e754f06c900b077557b13f415de9cdfb843ba18f56e0000be051793f7f084112c923ffd42aa60260e1b8ce1605d0cff41d4cc2350f551a38d8cca0e33d0b28ee2bffa36008620d85642fe41b8ca60dba10eba6042f9ad4ce74879e5c2c84d6e8969c5d368ba0016df825f5b0ca0e50fdf8637a222b4cffe6308f08fa1213eb0b5e169595cc89b9cfc81b080c16e32f1819ed265c80257dcf7954311e2e90774a03663397bb9b30b67b10012a84ad4ca21612b651a114f3a63a98be931ae47be0c8e7877c96db326c49ae8c941b1079e9400e124a68c4e45b15a1a61c687837495e92801177a018ea0d05c2de9bd36d82526df041f4e88e62736b8d1d0a075dc6a9bb05a9057b4e30064b03f7296595b2cc94c734f32754c5393de437ac989272aeb32a39befe415094a3921e58a8d52bc8ede725f6ba28434579ae164309c20aaa2d9883cabeca66b30c34fcb4952387576458145b19ed3085f8d901a921bd40c21e660066d556a8c4c57c602443c95cb52bb8d81c80dfbffa03cf08f1c378a3f524c5e939e47d7aeb210826e4ce399d891c906158bc62218456f1c5bc8154b495ccaed9617a25b0f226d2094328f4a3608028067cab832cb281fe9181c28e47e922a703510528d9a0433a07b75e75e0e31277c95df92cc12815273001dcf2c805346f298f996f2761c19440a01f9d4ab28a2e821b78021776a58501b5618b9c3b630861636c9651eee838462f8afc67cb76ce5929339110f991e5806bd37ac1a8528f92460f5787559b006379ae256e73cd96983059c8fe76ba4c81ceec05ab3bafa7b996a13202a7bfd01487f989d0b63efe38d6e7a9984ea46c614c6468a2d8819195b20363276c1d88898c9d8207483a31b1ddf28921b8ed3ae606c44ccc2d84831053122630ac446c62e181b113b191b4237707423e21bd2b831c1de0a5caf69bafc4fccfd4d91d8613f61e4b14b95a756b109536af81523063eb75cd80766c20521a1bc5f8974b316c399dba2f9e35f6e78177b3c8af2c0731b7a2b153847832f1bf446fe539ed201a5019cc0f4ce01a80772e9c06986490257b0210361d06d2fcecc88bd2faaf6cd78dd363a5cacd3a23a9bb139e2c728853f4eb359e869ed64022e3dc2597ef761f128cfe9bb77dacb030144f0e738dc627dcfb084e032b12f9807c3896f2292da38dc93536d6118b2b4da74fe44d46d9df722870bb1be45bf860e54ef04656b890074c06166b0d9852ea382c2a4a5ef3db67409b3c238f7959e17612f64326208be81ddb9be2c93a6087b29b85b2d202cf8c5fb721a52ea0b9fe14a68d66796860215187db685f8fa2e54e5586c300fb1ef24b796ef546e6e89928dca3d355a2eabc12320887fef64c6037b6ad61c8e47edbf1eaa8bfd6611c6f976d860f0a356371e6ae2aa2fbb1212f5a011033352b9ac7ba0791ca394b952a0b20dca8d36db287d36300cbba20e449ce9d1d2520a01a0d151c17dc0ea225019b82e35fd99febdf253f64e4c6c074962b4da8bd87e123ff14d4dc87fe9857d7e5f05ad18ccf0d31e94ae8a3e55426d0a4ba7b0c613c07d108c0184a31999eb33e11dc120c934b053942fc622252e1aafbe81c15de0ba99ecd265175dbbe9b2cb2e5d76d58dbbd4d08ef25a1bf986d5b871c61e337e2ce3c71c63ec783a9ed9783ace31e5c2844623a11ccdad53a579d0f5bc5a0c13c03167680118e935881bb86ff7f9491015e85e27a8f550b9bcea5d3df7c424a2698db71e1bcd78f6b25e7660e1fb5cf6696756065e9870628fd0f391acbb3d1681708f2ae90076304448fd8134f33959bc6083fc75935bdb07353de717c85a5636cf19deed64258c2ae5d91a60e504b034ade8d668dc0cb28c82d0cb66520a6abf9adb5255907394c16c5f229a3cfd4bd8be009aedc3ad8b4fa69750a668004a683d50a75c2b6bd54438e64c30682eced33589f56b8cb660d75c68a20863d74c4d974dca4eb4a723808b4939ae9000030c187d426773a2a3c09fccda109a0535905cfb0a32954befd088807251958a62ab4e76f77f39975eb33725fae32f1234b3490ca632a25f3ce927fde89f698a12a66cdabfbab3085302fd579efc137ee4cf7b4482299be65f9ce469cb702b6c26914f70b8efe1ffac2e274c15f3f7eddf11a66cf37fb1f77f52e5f7f70f61ca9e7951b9b9a86d3d4c0992dff4e14fffb1bf0c1217a6eccc7f91b002a604c96f7ce0a7fec85fc4c70f5376e6bfa46965a1b1a2a83bc2e7301edf2402f8230a98b269ffe2c7224c09b4bf78d24ffc913f6b354959cbb861bb3715a632c96ff8e0a7ffd15fc489075376f67fa958075382e4b77cf8d37ff42f62c414a6ecec5c42b3075342d9f29b7e0cc3d4621785c5da51277ac2542e4857eac321839d7a09502e215121dd38e36b1dd6970dc25f42341e30b5acda55225afd8ed8106798fa40002702830f960a7bc054d6637f660b3e4c7d78f142bcc72562f64b18e0c8b8a6f330555e3ba7c1d4cf213eadd5886e717849b7bc78ef350266090f2de6ad39a11ea65666d741a117855243101be632aef96996b2c558ba352596d21c8513bf295ce977c8b5b7bf00fe53dd9585d9f728cee298329819807c0f1559373b0b6627b739d9eafc81d1614f27f8d00976474c1aaa9fcf69872c0642e0a91876033f5a73ec2f1e93d36df9566d292cfe66b56f831430d8af2a07b5cc4cccf8188c86725fe9096cae33461cae87b2adeb8d4812cdad45d2840b79293ee146910a52d49004b8ec89c594e2387d22e0b73891dcb4ac35d254553b8a5528ae0f10e2ce5434570a36150f6b688ace0e7181db85e6c3acebeaf5d902b3e2372b3df217e8479dbadc22cda6e514c75597e79690347c3e910f0aac628aca9472d662e496d8e7eb4120b1426bde1d637f28a2bc47f76fac9a6455cfb02aada7104027827a5262670059c88785973e84409f81226904218082384f2e829ac39ee3592f29148a6960c3427763bf19eb844a23070666e63a165b46585ffe607f46a106d6ce4b3fdca7d33cd25292088316349f80bc1301a7f0244e84bc8a568115ee367f372b40aa5305a4f8571132b5f84390e11fe96278630e0158c09e976db58a867ba8c9be41971415ff6e8114b4c1c80c69ab45a1d4d1eed3330b4d066e1555996cfe7290802334fc177ca06410887e75530a716db0fe92f61709208edfef28280f5bf32442312e580d8cdfe27d4b23b26b0f2d1636f63973a82418fc0e5a1208dedb7821fffbefe67a4953c9f9a749277f80d98ec180f8d18afeee4f08c5f560eb1a3feb1bc8d93f9fee043b85728e974cd19cbda732cec9f16f0ab6af056489c76ac90fc33d4918ea4e62fb6da3e149cb74819b1bf7fe1c9a76e479886b5ab12630c8a01d04bc4b10b9cf2063355488227a9b14212b00419ab0930f48099a26990968c97e80c0e41bab7b2444a0680bc2a5f03f10adf7e88e1991800e64321a6af489f2a7ca749615a67011c8fa73462f5044d4afa8889e1970ce1a080f3fe48f1b587744f4547acf2746da045f86a59e8f30fd1ec5f05bf659f3d0fb63c28d0e679089d33f3a92d34fa6266a17aefd8743626d9315370a1528e29e9598ed4a44207718a0cf6f26b6140ca47164cf862505d94b0518177c854e9745045b940531f81f4d317a706521c023a9fe61b36ce87bc015d7c18a2b586f2200a9190ee277b25be85b24c705f3141e3cc99bdd6546049952e4f9583cdf21e60f410342debf5426975cffe3c39aad255d8cecd6f2ba61d8127ea09f1147ae418c51f86c9eb469c5488970bb43335594e0938820f2eb4d5a73c0fc4badd92fcb40eaa657d5780a17b2d6274930dc342a98c9542349ebda10a36ef0b6157869e468e40ac5c5a8d942852d548910d48f657385234181dd8b88b344e391d3e34f737afa91563ccf91c776a3634262642ce737861b32386982e61aaea1056f88e6cc76433d07cc5c8f9a1b1434c4e0052eb37938ba5d4c867045200931f6014cbdd561b2c4a0ad0f23ce6570d9feed870bbf25a3d181f09d69043125dcb7c9a69c94b6b74d43adce1d48d276cc8891d024919f081aa33279a0efb033323d58ede85968985135024b8b895c57570c49691e06e64d70fc4a423eeba96ffefba7381cce9db1b072f1385e638d57933feae782bc210b75b76ba8ac291e15e33a3994b5de3b478a0141989e2d35754bb0c24b3ff2d2d9486e6692391e6000df476e6ed2f5baa20b214115b2b883add411a8aeef7cca07e82290febd170a977a9e01f1d642fdf22596924162c6ef9cc3a043d43462648b1ee13c272738aea5fa0d453a5c09cef8b8c677ac9d2d9097fe592e408742f1772102d2956bc1548faa6ec0316900a5fd929882095e07f0a498eaa30a83c3f77f8941628cdc26140e500896cb41dbfe85a023daf5ad8e0316df9ccb70b3a1915cf731860536ca5b1e49c1d93dc281b17097afe87ffc8028d7a63a8be813f9665bb45e6c246d362dfdc67c06836b1cc5b791ab7b930c27b67ca079632e94fb69dc86e46c04731dda40e8f5ea859c3e334c58fd20b304632da58abd6682f9e7a0e3d99f0f2659f76a465d98ed30966134cc70065c62b16beb0e9c01829cefc8901f34b4b40f98176d063be08ed0f55a69fd39fa84f271680c3d722da3b57f9339370806442f9bd8adc2494f8df73c91eaebca9a14fce8a13b727da5b8f42f9109c95923699ff931d9486a999f7725422755b04e715a28d8673c26d42c3528c535f9609cb46a82d082fbcc93bb9f2a8bf9c4e3b3317d8e46e04acce846e4be815f5769d88ccdc4c18658dcd519f4ed0d3be28791a93281d308f156b50aeca73134c8b2d9c4e5f759730e5d3716e25c7b343ce028d5c1e2b37e3dd11e82aa17c7a10ceb03113efc854e6e0c1216a4d01ba21093eae7123eeda42cd790d0b446a4c123018d09f11e60ddeaa85223a59d58c50ee78b2862f2c65fbe516873d32649332ecc40eaed9c2f0f69d66de8a5be847d53f1a2cd33c34fd97018a8385cae10fd9006e166c98b1bc820f30629e236b8f014475ee9c1a2b6f8a19028cdb83a4b067e35c201dfc9fcd07b8308ab2afbd77cd7ebfb65306e084af515dd3c76484c10cd5a085d3cd0b56424e45c41714fd483579aebb441d08c733f45009f4867e8efb63ac37a5976cc4f4f5d7559233b2abb3b9e884d7047c9404cbb85c974c936e2084d0d44fe809e05180af52bab1dc428af43e44252d373871907258e4f38e548ace53112c9d98abca439ca8370f5ed37d9e0cb97e7318436db60f0faa3d23d0a74b3c1b45fe969eb64c07d18abb786438c87209ad87947fe0142855c9c80a7168ba79bfae1d4dbe3f71e1ba492f1ec4f33e6083f3e6c74b0ad9bc0bc6979e94fa74040093f329709f35838b0dfe88262fc7ae6350ca8f9a73d5fe4c75883aa0aad33d50ed1be6897bd1840f0cdccda00ddec32fc73e44bed61282dd14accf3a984b17257611e497ca921f0d215cd39928cb05de34a4fe1a5f6aa92cde88966d9802d54930b158a96fee900f75de306f4985658b3317b115cad6297c74cd838b58a93715280fa9fbeeaaf05a84d134ff307d1b13f9dd090c3a08615ae29289ecabed8c6fbb57f5bc36e14e3f46ea1156b9da9d6951dae38d65a3f3aea2808ef8677e483a45dfb4b6a165bdca6f92cfc545674a6101879df338c3cf4e779f93679fac4501246314cab89cd1e4032190a24349152b9b2c25487a95236f9a5a73d4790ee5f1123850b37eefb032f7b990a8c352ef1592de857a7ef743f16f6abade82eab248b3fd578bc75647e41446ac41c40ccf46074d10d6a8cf882e3a40b92a0c2e97d2de4229cecb628715f7b9c0a3b24b251c9d357c0216e07e76a1a1d6d1a3e68c891d64f3430f7591c6e9941f09ce589a3745f4a2b20ee7af4039143378124c61d2bf558350e24049e6c65a9e703e54360166298e9b0142506aecf475ac9902f6815e0baf9f7241b514746a1d06ec8145a9f37f64e1e177a5212955fbd7160c6e6ae70f6eb6d113198aebc1cfe1fc65abe593a469aa02c41ba23a8f4ca3fa220411821207cc02734f0ae72ddc2976427780084f6a283286c52ba3eebfe23266bc1bb6930e7df42fd58a1b6f5d24366375e099f178ec3169921e93b1e9e4b051706d0262473955648ade2c00b939106d816bd17a281289dd9f5e952816e80d824de4ba9ab3dce3f7cd88587c492b810dff9b8c5930911c974a88a9237c63a836920def5e045ad19d783cf6f128fd0ea0f6b3da89816406ca1f34930c6e086553727dd6ce917ce7f1d2ef8749f1d0a03b31016a4181981453b0a15785ece90dc8e25b62c5588f9e068a90b1c9aa03f3b5c0dcd7bf67d109b464afd9e5b62928e3b95ec18dfaa412f40b83c25668a7e101b384fe2bad2b0e742aaf5d63450772fa12ad9bff51eeca350c8ecf823135587790215372ba333efa907edeed72c6e5d9061ad14c9bb914d2a8260c1b5d7e1785b7afea5143c4fc6ca3b25258812b102413401fa9d0929c7a6f9ce4c06c8d68856dc76893a5ac743aa645000eedac4daecd658f8c50229c5f8396f7918afe40a49a3ed22598d5ba242494671166f8ad9249c79a783e58e13ad11b0add3568fe6586c13e9b96e2e66aca71e01d16e8bfc423c9aab6b37199af2fca87c1106316cf35d1702b872b0287a6ea80479bcc7560e0a11ba8ed57dc0802273eef743ae92ee5255c98890a551c755b78de932db4640bd08125a5dd0b77880a04b80acbccca4882bf4276b83f2aedbc6c774b014c1b5191d6adf122a2922122431c8eefef545ea6b86420b700aff81b5aa2878429f6e8ea4d94a862c846fcce523ba7e005a0c2888d05184360ed9547e7d4bf7d8e69f0d05667ae84304654b03e765377fec91dc9a41a299f52456bf8a3fed341ac40ecbc8e58f781b8d41bcf126866140ba6a127b3fa0348e858e3b719e06008802ceec47d8df2a3d40b7b80af81a2a60f05da3435e3498bb39852375bb61d1d8f3a1f54b0b67674e8c83f9419a1c75741d87fa602d0e9a8b03a143a4f95c33f07bfbccde80db3d7b5eb2473016c88cc343b44b0cdcf05f63b2648a692b9e7ec518a2eac0cefe9690a78a38f7878e03fd0b6de1702d0eb73fe17bfab01f5c4f2d251cfd62f21729eb76fbf7c3a1fee91f637dc83a03500456bd03c501d73ce56414942fd5ba348de0ac38b9a123eee50c8dc9f8a5596a1d122b62430b0cced7e57548a2e3d64e2a1d68e261a9e118d5ea6a2dcea2e96b6b586763e383e02a64df6ca6526ff76a2101316aa479cbaf4081023e8f1ead510213dba206daa723d0ecc29f6f4a184be0168552ca36cfd46b14637a836c25025122d31a71d25753a6f0180e259dd5ec520d89942962a01d7aa5ee7ffcb784fdafc759740ca1351420f2153d6b3f012381febe6d47f836f97986e017123d31b1e007305a0f3d9b538c609be274bcb5df008cda2cee4c21a8a6f5349ccd8667c9d5964042329bb42622dbe5319704bf1be48db5f8a690b8a6d2bf7cac1a835b4bd578c6addfbe60e89e9ff798bbfc3ee7bd918546937aaa1aa12124d3fe43239cf7941f86add97371f48ddb45eef27b8fb59f21b734301377fea5dec71a71d00b92edc690c3c7da6760fdd0880111a0ce145e75aea84092a3034fb3555d21c1866155779c4da3512d58238e4431193ee762125a0b4cee50eaca5fc298b4bda65d06cd4271dfe35f2cf5ef0b66a1c661c616f868cd06ff6bd0ca9e676b7bc3e5e68d04dd619fe7cff2c6387beee0e0ab5f3f562a29e6a947ebbcc208c95f52dd4d78d0d3f7ed4521dada0030d3aa9b431482d894124087d652e979cef383b64adb377d5a19521bf130dc905e17e281b17d6d7c2ee30bad36913927fea135092d8edcca67a2059ce58898615854224a0d41dd98e576a55b471f258a0d6b05c9ad6b0c240a54f1496d7129b739450b59badec872a1a0b75af868ea792e8d16f66c6c07e33f13fabd34efa8316ae57be3781265115ba0db81deb129a5df871e23ff3ff8983817a3a80abaf26a0dab347cb6c721ae84d53677415eb8f3db5c08254735a17091e9dca1c20bcfbe0a31ad8867229d64f853321f32cab2efdd7b0a2e55e42b1cb8485d569850af92ffd5451dd140082748f0b9a59d130fdd839332384a307668d5a59e4cd1e4fb83f68266d906b770a81fb4a5cfaa1639d3367c7446dd30c803b87fd15f88333586e1541a56e8ddc9ca7051c01c1f053c4a6cb0470f6f0b199b4c1ab248d24691fdaba419cc91dd8987b5e49b03855053468ecfbcf557051b9fc7309dc0bb3c0059098839a4408da505a7f7d1b3baa3e7b29966bfeeb3cf7f5ceb644608d5d3b3229069e43edb59d79a6731f7cb0ba7a78c7fe32fcfc49e42284c40333ae68c8d2f7f877ab47fa7121adac00a013696c10361f774204f785359ebc180094a29dec63c7525e4344f615058af123d0286c76d0360246a9cbb2f138e83eeaa543b45febfed02e3f19cde37c032681720354560ea15c3bde261ddf138a4062c5d9964ec6629e8c6f3c2f8a3a04e66012a85b4fbc924d36fd3bf4479e85e300ba63463cdfc229bd647eb24589481eea25dc96c7fe45eafd622fe8b00398317e7c45e936949f6c0d59629fc557d405e3da778617b3ffc837cdb83c12a52df3f935930401d2f2d191153a06db5415702138fd2169582d763ae356ab7d7ea9b93c71eef30fe2e5d6da100695d96fbab46977b5feaba01dfd225592b6ee2ad2cd07fd7978b34cc977b812380678344df4402c54305dd0d4c7926897c30f3cd0abee79f1a87465c0e4de9f561254e93204df8e6a2d64744be91222e3558beae09f5906365596d65189930700087dba06f8d6b933b9135a7bf26e80d2260ff6d82904cfa7a1559d9835d8b4cd6cc079dfe7dc7ba464dc9ab18df3fcf6143e2103a9bc0770928cba23026be7deae0b6102ad8f2db62390107b027b4ea740e6052fd314c31bfd909756be533f9c9408d3eef99dfaf060a2214d19c25311230ecf78eafe60b061db45162d86624167dfde126639780073a63133573ac9c3977695e63a03c1bdceed27f0a6d56714aa25924a4da3fe9d2a362ed91c669ffcc1202892cde4e50d38a5a6721b9005da4f49b0e6fae7180bad9e80d3f7ffccc16dd9a076caf260109bad41a041f9b6230899ea4f0ce045ff0eb5941ba99cb66860f0ef736d351c197ae27eb11afbbb4f364e89e05af36520f497a3a1ba70070937b22a27d2e77b0000d296ab002a04d5c057580c51559fd094ed0197e5027e9a059fb16f298101da0872f0088a68b31e73f04a1562b51ed4245968e8142a2e1b71f23e4a9bea2656ba23a4c5bf0b7120b36e2aef626e360b5a7841cf3a46853d510a4c36f1f372c7257a8729b9235a8b66c29c091eef315dd87237b8b412d1cfc98243ca568d45b731e7c2ed0b0175ecbc0694ff931eeae2aab364103b7bceed0f0d5944983fef3b4ea79a69161c7d55e59c038eabcb22347f083907e0548cef2b1fc44883df6c39f45957895946b99586094033713987bf66114e685de5581a320bfbf766c4461ce36412ed105cbede013c40545d30ff04d23df66525028218c5f6dd59b0122864a4af0c27286163995676a7db3e05c84776eed05dc0cdd9e86181910fe9e885dc2f9eacab74aef6a17515c01d5aa7ab59d53b4af12b933a26207bd8aeab570c19ef602b13a630c1c26706abcbd68977337a93f7ac5526d4f74f971a2512472dbca6365d2ce3eebfb056aba0d1947688fa12595641656b4c4ccb8f3e837652ba62987d857a0d174a0c406174e11f9017e2e910d3e84b82fa775047f924d0c7609421e0a6949b10e3538c880fbdf8841d94c40680256aa9ead5a53988f0a4faca276c25a50a901818d25a0c50ec4a780b8330a8e61849a93315890a1896ebd2f7d2a0dc7fce0a7cda6fa0ae84f83c7bee7cef28b316ff881d0a980970174b99b521780253462ac2cd87c863c26362b22b07f4e0280db8d5c468a33e2758af2c2d810b3f04ed0b9c7d9da1f0dd6b20c60dd5421026243ac66a483c7c057790c9ad1f25d358de0d56d2e5334cb384928371327f90cc43b374065c38d5c8f9f57dd97d1d91ba31ce9fe356be07c18367cef4de49b68f317fe180ceeb7ea84624aef5c2b50d62c8d78334e652a40055e283ea47405199ae2577eb9ff69641ae51bd7c3826ccd7c27ecef2c1ce98954dc5e88dc5fa5c0bb425e629ca3a6381b26d850067d66cc80f531d9034ef4181e5ecaad8c86da9e37422fa9a6b544644ae4c71b3c2028deb771bcfbcb36cebea1d501e2ec48f62d31136ce2bc1b7718690eb0c647dc2cb857d68bbc33cc06042ff7cf97f5a3a8bd7165079813eefc2a4bbb466173e373139bae1e7db5fea7cbab68db333f533bf2c6071f05f9b0e5e9fb6bc1bc1690f1df9ba627f35c35baaddb16f1f81b3b4f8fb5a177b4acfa1308f28d4fc7e2d7170d3ad77a129994f939430832520ee644c2139803002def3c9c488f15aa27aee329dd54633ddeab14848943518eff26c0db99724a4afd4dc3530f043e766c989cefb0e14604e5708bd1a0972a6347315c88e6aa649d5a1dead00fe3b52aadcee3e4444477286b37220e4227bb691adcc8da208d525351a3b8d9971550a5898533016fcce9557ecb4ffa1e3daa8963a8eb42f4a3ab9c8b40128289fd87df1f16470c053d436fd6b2565b96751b014b0eebc571ea5da873aeb828c03b36f38c2d0f7ab90c6025a00672ddc1316f305e829037378a1cc350c83d19aaecfa14154059b8fe8b42e284c23f84a317a7d224e561c4c37a5e74107faab6595aa858ec75662dcf2878e96cdc320cbc4ca9c44175d6bf2ff7c415258c7a215622012bcd5a11eefe0c403c534cc0da14c4393a9366410220d51644246e615873380dc0d49d61d999762f34f3769fe0a4ddcb1427b8550fd7e2812ec96172b4b9b64d949fc89acdda04cd748de6c09093e40d0c25db9724a8747feeb0af75125dfe46a118b2d5a48cc6be3c805c884eec8ab5f8c9a500440b9642f6fa84bb51cf8684d08298c5c734481fae2e0ac186d208ba7c5f098172792f7e4f42bcba7552702efafe7be305624b03a26eb42c60e8459681b221a48c613cdaa14a837d3916ec88307be8d420d3b191a240a64148dee506e5da482c6b3d3019367ec7d09ccc2a18e539120fa6db5c0af734acc267725ee45e6961af858cc1f099f5ac212a37525d7c28fd33a9a627eb8d321451246dd3c926ce5d7151fdbefdde5a0e5340036999374f2aced26d2101f31322731c1b7358c443627fc473fa8842c40e426a2674a994e74e59797ec7a1dc5a8d868459caa81bf832f5fd91cce4b6976531e7d589823c69a785ab6aab7706ae758bebc8194ca159df7ddf4e146a4a9f0c9f2b0527818b0d07983dd6c896a2f63241c642d472347f2b3dd04b2dad0a284eaf27cd37adb9f9b2f686cbcfb46a51558538702a6737d1ba44f0ee44403838ddb1d1f12fd03e85f04acf1373f90e0d9e2821fd575c1cf1a245912e2b965a07a2743d47b0adbe5a3fe1c05b2aed3398b51813e621110e00dd545640bb222cceb5c83267b1c041b4e94c274c848474a44480ec993d48c08a4fe80f50efc461fb51f1c0f499e34628fa9e2c287e10e6fb05bc54c34122d7cea071a8fe63493c1b34182783e2e2e28b3c2fb65fa3b47071d29e5e093f8f16c09d4543aad09629b052e0ec3534e95992f44b4c08458d197391eb364159a3638ec3352c160c5280305b6fc7bdc4785cf2c8b1749b15068ad430099749b067d52d416917c50b8e090344f2e132901dffc8cec2b0a443955caf93535a25bda2daf4b1b951454f4a7bcbd507a025e3be535f490bb0379e1d1ac26c6b1ed3e273736b56d16eb6aae597747fb56a9dabb3afbc21a23c696bd05c101875dd0fbb876295eb3bbc2b7600e03ad293c76c32d285637eea80804e6b224d663f2f7d651c902d60c8f79320fd0426583986f3517203e4375705d26019e771818cc72bf3453c771bf021b93ebe8e891919b47fb08c3467672dc6663b243fe8469d9d931b7bdd37f71e014884b973b7a72ca1b31ed059f7018fd3112b0a9cdda7d5f3beffdf048891c62a1ef2de81c7ae016f197462033928035919e8b9f3bd957b08548eb22d8b3361954c2f9fa4a6a21ebfe1c6ae9d42b8bd2cab71d061170720525a555d9ae3ea9ecae2b20aa56c5b6b88b5c3d3f50d7b376af36f4e2e7deaabbaacdd55c0c358475f1257d0a605e05f970571ddbb9e6b8b042e5345c26101222711ff4d02b389e9d67ca406f01690ade5e6a8643934ec97c4b9aef00bc1bf1dce831d46a191f665893a2f603258340e884b644eaaa4befebf53bad4b1f7c260d0a51d1a2f9befbf22f2d2fdb990059ec9245709575f26b9fbef3866ca44945b828dd4d1dae91680a5e580619a8a9770dd32805c52c56e3387847f60b8864b64b2ac2030c7eb24d5f840ab64e7773c17274f7d2ecaca91ec3a0536f0a1c2a3dfd97de028b87b301fa440c25951c0a9dd740f74df014b917b08a2c6875b9d6311ec440c1d24882bebc2780f2fd75a8a7cb51811564fc1b02749986ba614e2b3a38686bd925ae0eb47f27a0a4467dc719947a339fcf015f367dc1de52242340f2c295c308a6e1d9ca480d25826f494103474ac112462adb60b94bb81789737668384df8cbf56ff93fb49b0b64c922553dbbf643fee7a3edb8b49e0bd7c9300b9c232135c96c175f8cd985d7d0520b56fb2aa1dac8730ce4075cb94ac36b5dc8b5c63050d18b93dd158dfa0e3832f5854bccd8b9fb00cae082d8f12527848906a067314dfdca45b728e30a7c86852f6e6cc55feec782aea58f432e8ce0949c37e9d90e6fbdddfcce8a7d8099d8488bbcb58e9f804201015bb45f69677d32aa38626bb5d3363eadbe769c24430c2da32b2b6743523b1be20404ac670dd6433b8709d7c29a89cd2369de6528e6c54b82efa90f8ebe8b49a144b854e25f8087363711189b39c67ea1e094ad1ae531e5d76f7c901afdb71d64026ff9b0e70ff270bde66c9569dc1bd228326dcd79dcd5814c2c621f476d59f01e2b7cd359c15a007b1bdb675b8c790c0d31f9d9b93945bbd1d24465a0a9b05d49a68bc3536125d181b212c2e28a861a1161169eef41833e5945b075721087347b756b6c3e4f711d3680100335bf45144d01700fcfe1f6b77f7b98396dea6a355268acbc9ceedd6b3906f88bddc296446d14e3f94f9c47fd6d7828fe387b7a3ced6445ae36e858866e5a345177d2567b50c8089d56ea476b9b78768f4fc68a2c9df42f7c3581ce10a80b63ec6d82ba2b0cbc34b1f594e852a6ae83983328a06245e295b0b8d34250fe54216441201add4a77567ea97ca32c834c2dcd91d11c443f9968604940fc61469806bdd88fb5ab1528d9feac47074334c90fe54b739bb9771053744633d12daa97b27769bf2dbc3617110196d80b1124cffcb4b164264a6783b22446ad31ef8098d92981c54dd9e4254a32210d31770ff49354065243e8431e1a77f595bb29ca8bcf829dff00b39c1250698f2b01de9d9af31ed7f44404b1f21982e06cb30618676e41dda64a90ebb8fca6e43d4b293563cac312cfeffa0b49122b8fba0aaee3247c2b0c7d3db96368a3b2daff04f6888108f3b23b8220f1c824885c94df2ce49a8e93ac0504368164cdbe47a0962326bfa0bea69892f1dbebf74364e7b2a66671d7f31942ce83ca557998f79baa1be5289b65956d6ec47e77f1b48800d24baf89ca4a8a27d0d9d63596f06c20be5b0fe99b1696ed7ff1642dc71717f4acff6dacf13f38031f2c0ac794d00c5708838322ff3667333948513f595dce4f3a6ecb6916d36010c9089cf477c29468d6cfd4ab91a1ac9bf25db50e4962a1991053ae2fc55ca95b04829be0ea125d966449b72a5d5b2efded44e7aca74067c0986dc2f30eb0dfdfc6a8e440411bb7ab8a9c1ebf2ce7ca68da42a1f81e2554e24b9566620bb14c4c9b94b05cdb24945d70a54b959642064dbd17761831b086bf23fd815be16b196383570e71a7f29f5c1f45bc65af43c0030cfb3ef86ce2c693de236aa91eb2c331ceb1fcc5d164e807994e0b7612a4912e3f3c5b93d58610c51674698c7da2c4b677c3d8ea6cd53dae8c3fb6ea731a9f76064e817aadfb724b9dc7940ed6293dde5cb5093c740ac0a8cda1f605944b88f58b3b4a0a0c22c0695221d33b3e3fdaa532129c0ed29fd32b010d23dac4648d524375dfc3e5759bc99415c2a07fa31658dc1e6b3361da808bdc9083d1710582122f820cba2c43d88244b16576f46029e05b808fa53a26f6e49696e5baf9bac71512d6a69e041568890140cfc4e227cfd303c984ffcbb15bd5f447733b82da7a0fe1b41546536bb7d70c6c5ac7b8503f7d9ed05376e66bf2f1cb89cd53eb8e262d67de184fbacf6801337b3c79eabe95a838fa36436455f5198f53ef8c1a8e235106e4d91d2b89f6d9f7025b3576a0a9bdd074eb8cd760f38f1563f52c996dc03475ccd2c2c34857d813d53a064e2d47275a6389c7c69d654c69b29da8921b2c9396bc48de6e05e739d69c3f8e7083ffb2653e4d2c064a1ee26720573392007eb82f4895415e394992214ab5950ed2a41863f9e79f1ece3f3229d7cc733e57def9935c5d70920a74ee01211997d225292ee9e7d9667fa9e982742d0753f3969c34f140cb75695cd17d52acc1e6436fe5e1d1b14fe252260fe8c5981c167c950a0c7f352650b3efd1022da6c877bfe411f2f86d637c4cb0c986230c2da100185a140d646c4e11c4081b0771ce9916b1224f6c7669354125d3ec59122892dff99e964ad83d65d2520701d0b9c64ebf5d409fab4c37e4727f275b1e8e83e2885917fb7138df07448bf8177cd74fa6e131449ae8dc61c714db500cf8e555d2b7674860e99e3ddfe454709e77a9d0074d3c0b28d5c290c05a81d30f39f74c04b944d15e31854e995c8cf56e35e53425c8644edb23caa3d176ab6cffbbf5f6e2c8088e6c31ba05a30c58c0f41eedf3ce310c5a10870f4a92193805bc7e10a1acbbfbe9087bc7f96713624d4096ab898bba72ac31bc80c0195d9a2f4e2671b328e53decd3ace9b9b0a381d0e556a1d67dce61149f8c96ae65d9ee6e8f8ea27e15a7f0dbfa97299e6b497e1575639a8254a627533ed5ae85a72b9084fdbb6092db598c38dfa94c7db71f473553ea1df17fff8af2d40e70724446fa8d48e45b6d9adfa18f76c5f98f4d2b5577c6ff0847b3d59dd5b16f80c5d019cdcd296fcbfdcbce8d9aef2c22bd65e9083abadaf1dd4ec9347d987f3b4aaa3712279dd58e3924c4dd9a9b08d52cdfce88f0b425537e972d148411171adfff85ad71a105abef0386bc319e688907fc5f6b389669c89613090e2e80bd7e610390ee617af6a6074966d812642fe9eebfb147cd8fc58b3151e3a27b49e87cb93f71938ff984e4838f74a23d0041bdd8d61caac199eb3d28b61ae7e6d19be2081bb07b4799c1c00bf26c7a7f2f27196b865d747fa0becdbf035da94013a43c261aeea0e8d233ff77c302241019ef9bdf199c960d368a2dafb0bee4f5c7516f6e1c7fd1161c509122761c97f965e10940345694b574680d94368a1c4837e907a2e658969b3bf59e27f28aac4ac9a47692ef6097951a70d35863a55dfa9aed1fbe981f0711338d9e1dff59c672070e6380a1d01106b369b17a870e502f143af0ee7222fd021818fb61bd4dc83d0faebe59b981a23e57d59464882b62c2a41593f48c2fb33d2b356852175d8dc01f17097bac34bf41662a1152c553a80fa6fc4c303a27e8d25c612387f29ade21f76f499638ad7f5bb31f1576a9c9ed0380fb281968032e87aaa99571b6bad614dbf1d7152bf362b2b4cf7287d7ddb89fc83d5c2c71a7deb36fa3908a768664c8498e8348e0a566425f5fbe1d04027795ad5bdc9ea32f7d9d651844cb94e09c31897f34ca88825544a0a8a822cf4a12d4c812991eb99faeda06112633c53df9968cd74931823b0761c2bcb0689d35e870ee3e092065dda3a7f773b9a6751aab42adc14137dde2e5c9cb0c8b5c7024782869bc348b0f9548cdceee1ca8e8e7f3912703fa0f387f5c4aae985f9fba23471b094d4592010722b2701af8f67a07634e6481d59a818df7805b12262dfe1e3275005bf9308593974c3eb88b579759bfc7ae5e9c3d964f30d6f92174258e66b1f861095544131c92b3d2f62976001bd721f71091002c0ba853e9f2cf4eb11c3316389d37c3dbc5589516e5f6f16743d205539674241c9169d725df1a326a111aeb350b68c6bafa46f1766d621ab9f2069ff40419456682a5f31d9250418c6a1c434e291ac3279c03ea8c45768e7663bbf6053741f07df2d029e09d91469d98ab9e0fe0073607b6ff8145d1457f2ce99b4ddffa3b26e9962bf070deb16728ceb8e7a6e698fbb6200fbe9576e2116afbcdcfa3ae023ceccad1f764f37049503a188ff175d611629c212f4c311203c0e2438336e660e65d05c6d1a106c2cf3cc17d56441b74fbae0bc8c699578544805813649b103c100a95f8ffe07b568e100827d1c182c2754ea10342c5a0ad6b0502b0f4d0d70fdf484bdf3979d458a03853b440a7fa0f81c444f9287c69c3bc3a30f46672643c5252f48678302b02eef5a0b15ad183e1e6330f37a2c27a7677da456389be488c1d6d4cc94ebd18e1eb36a988d121db0505009a3eda427db21f98de1925ca977101c7c8f9d493accc7968901958ae0faaeec982f686c694caeeaee2ec8adbb373a6a1df043fadc600e25c62c1722b3421f9436e60d6f250b6e1d3ff450e861c4452609ee440c4bf02125be23e39d5e7402fa3bf0400f932e8dd96b3f77f54e4c78f8240f01fff25da04acdab81d49fe0a14a004e138583a15e9f03774395343d3d9715fd99ff60a89791aa238a4d58bd719cf59e8ad325cea1a48dba869653585cd4dcb55d44ac11954e983d0c30d1e7650df4c3c5928f0629cecd18917b5951ee9a7a432ba10a320afb4eecb577451d2deae4cbd83b3dc74da8b10a4da34e3215550c68eb6edea965493b48404a71b512c90d7c29e55ac9103f8d662ac4a8a25acbd416f6c449d7c5961f0aeded282977029a06b781fb35c1ce3e7399041d81b312053a2988ace98357a2ed4429e0eb59aa8efdc037401e07ad0f30cb4e6df7e6b59c43c70cb365286f8fe7c04724a331b78eeda118aa213c23987a01521462024c3ea0065241d69d144ac1386e6e094d141755a9a37e6f2e6bde1cb84a844a80662b7c6225b34bcdead32cd7b4dae63c6633e6fc1dac881449f080044eca275403b155bb2b5a939dbe814180001245bef27834d5cb39eb1ce9ea9f1ec5defb4b4c157846d62a4712ac40ab7e1421f8ededdc3c96e389744ca9e419cce6f652c8d38f2a8c0e39726ee0b0f8d0e2d7793de8a80f79769ec46a9b57acbd83b6289923a67efb34b3b6eafc542a6189a003fe83093e805f40915009388e1879b44a3cd4e0e11e918223cba31f102879dd427b59a5fe1ee1db306171d077ceb7e07be9c9a993a0aec9de07ea6cdb22ad24bcca1f8ecdc1ebc5599fc9d6b5920bdf2301453c81edebc541faa7a1bc254ed771196274e6cde5565fad333ef3467098cc02eb11087fa0ffb54b1d3088ca4984a945c09c266b73349dba39e7030d3f7e08d5966aac10f9dd900ce81a20e7793a65f721711ec84ce331f5194d6521cdf52ca9bde54a6d05dfdeba87cd8f2ca9a6cc2a344c9c19c926785a233a123d539362831d9c0737007c8bb7ac328693717125cb024b764c97a6457fb0fbb5e4544cf1eac0c3e57c32800f43d8e460eab407c8bacf1f40fc09d9023c32dc1cdc889ea0a86900bd118eb859b7de912a2ea813bd1ef851b914c1b3a977b1ea3a7936577a6ac076fad336937322e5e977b97b612ec4d6bd2fce0ecb1dd81a0abe0ea2c101f13f4d49801102342f591333e166bd4df8a05441aed5b4d5e7122c53116d5c88d6ad4426afb93a35bbe7df4b188832a480a81e21fec59b263a3d81ca1eeb922d65a1d7ca89ee7d3755a4e0d29bb2e3d970ee8ee80ef3902cb0a5678417e4ca82e2821847e9174021589697f70ca38a0151cd015a526e4b2807b0e31b70c6423255fc4bb3a923e8ecd158b2d53c7ef36c631a06b6b40875c02e9c1c4929e1ab16e268aa360dafc6fa29f8e2f03b7afd94a23d810bc3ec23a540a94243aa115eb1f3fb67431da9025184bbd9bb1aa1afbff9552679171f5a0ffcd012f8454888c3c812b06898c358519ea0a14616baf9764852659999b0e7e83bb9ac94ecd7306f332c0690f40b1d73f5f6a00acda766903fd115e311134d3dd28b0cf303c16fd0467aa1b1a0db8e3b70277f8954507362874685b8564d80e01ed28880ee3636e61f709169b0812915517ff052dff463c18c26d0ebcca5f314b722b8c0490cefdd46ac93e62637781bef8e5cf8839d69e222d3b0661000046ac12bc8d0302d24cfb8b55cb45e8e9807a89ced9c5b95b1d39bd454af076dd2e57c6acf24842ece4ef90aa0564792b31a7f45f1d411bbed3757479aa4362025f0f4137f1b108b84ce17890127bb60f22e1b0ba4f6edf422cbf6a46877aea3fd4c82c929bc015feb78a2f171e815e8c0d9dc2f72006d0956ce3ace9270d29da23212e87c576baf8905c88b8c86789408b3117d25a7219bd96ac588a5ebb9d30835a272b514a1a888d2858259f38cef745c6495d3248b21502f0c42f4b52dafde246d3e01ae19074366b4d6e6ceaf1376933bdadca019c1baa9f14a63524581dc78b1f6d92578b5ff58c533b2b62a8acb52446b5cb3f48a229d2e7a234891a55ca05f045c9b12ca2a1923152b60a895941474e9a9778da3a308c7825d9cd486cf1e83af48067e2c7d18a03aa1be717008c93fcdfac962e7725905a360a50053213990d8caa11202767bb8962b162204242a22e254cb2d8b9aaa0bad36b3825edf0ba79e6a464e76a1d33dc8893e97cb5d7f9c03a8f4931055ab051ba11fc179a2af418871b52a822b6f82a67fc50fbad1aaca73f6bfdc0db79fb759e892f7257cf16255c660a087e57f0c71c2d8f02dd26f5c6d0d5f82b4ad82123a02cd179c5d6b98c0e459403c05b1e68bf88e3415d09fdb2f9dd5d5af8bbc542b0ad90cc625b4705ac91315ae07f7bd6e110fd4259cdb615a1a90656107468169698530a384669754c78ce5bf57f9fd7a870668c23d6190e6acc09cd5d23093f1ccf8d397ea67fcaeb607dab2f384bf13299266aebc4f8d6f15b445b393d804032174260a57bb5b06d9847fc299fe56b716e4765028c2314345763c476400be367031edcb3aa1b9445fb4cadb2ff2acb3e13c680fd11323af102b4bc60516c476b6915c9d5b092b8e3d4d6a98a83aca0561f83f6e0c60d88f4ce473b66968e485924bd6a1ac8546bf75306b20a1817ef10cd0423437db411f1c5ad5050c68a4b66ec358ef02a240d9962ab3423a2352cb7bb3c52255ef1a4e155d37ec4e597884c285ae4667f73b1914f1e8f3f9eddc67b9c98ae9f31afb0ae5007ece6533c00ad536b05e80c3142d64b376814aebb79d85242902328cf0d58e48b85e7f930937834cc64e1454d14861fec4d30876cfbb089805a72f4fc1c8db29ff6b47e2b3c415cd8e86423d3cab991c6b8d00298d3afa27a5f73bc2245412a479b8cc5c1ff10d8e6861da7db4c3c70cb62f16781c089a16febc2e71dc530e1b27358dd23c6a959ed8dbb7562825b96d07a49c21c9e0718ded5584dc5b369ad7e5119b31384a065cb610540c88f1d5d55bd0e465c35c121b66cb29f8fbf0d9276abaa1e0b6489cb0fd49668c990f7ebb15717baba6367cd944573987e78fd2eabc2f45003008e0447489b046c1f68dfa04c53713f8560153bb89bdfe48f900faa6a8648e8f80b390f2b29a5fe3568cf4df7d748e42ff52856c1651d115377f2dfe47011eac51da9c86b99cdd29c00cd432c14095a3fdd1362776b4d276602bb3829dcb4f645b72a4a9cd194c68da205342db3c09f01d8d3f73f0fded3e84bf9862ec1091a0a672f811a22affb0fde647a74b841057fcdca65eb79349c883f1972c902f236e21771492d2d8a0c26b0cb4af1e3688d207f328c20108176432243c0a5ae3ca4ac3e4f59f79cf242e4262c9e0c17a727777eaa230c2139f4e31f819c84adc7954d449d858d9dd1dab119b4eb499e5c483165267d70b6a946154e1d311a04aa2ec75f2d410a29fdb65d99d46e1808b9f5a04d0cd33a773a105fa29b3c0d2290c945d5e37f5e49aa1781e57bdb3d99f2196172c3c8d6a7af17b057dec786ce8635d82d418a9b1b7f4775207f9024299d7f7fec6ae98684635b7551abf24b18724b8aac065f16cb2ec58556deeda5984d09152628f76c6a26422e168582ea7b402d5e31408af4e59de2666839a32c3d40e514823e244c084ee13bdbeb4c5ed8fd96365bfe805da29e0633cb1ab464d556d8b50bf7be02af06af60df72f408240dcde94f82329e502ef27d263613767344fad7a75d8916b28ad46d1cb49bb49ff1c4619e631111ace6851a00b9e867be13ca61ac0e068785a89f74e547d8fcfa45773294ce712bba64d8094303411010cc94290e4ae993f5998c919aa21130efaf373e8231db827021e40ce33df80cc21d999e82526efe3fe257dfaafb4564ad07abd3dd338d055728ee24d6a7cece41241983bba9c51518965f2704376fc466316aaa5d291b3cefb91dbbbb996d670802995604607438ff4820ca2a246a0a483939f9364ebea9bc80ec6a5e662dc909086a8512787e5048b296e7cdb63b037b5690b7d74db44dd383edc370704aa02ba1eb2685e505815271d4985942aabd2fd650cd421c9df55d618cbffc1b5e1d35c1266c4f6e8cf611b7c4658be5876f5fe1e8487007ec401d73f7891f387bb56956530596ab0b3ecd4e940b490cddc519345d45beb2af8ab258410228dec4df6de72ef56064806ac069367fa34aa6134fb5064bb15694a44a0cdd21968969802354bb3340b0894851765e3b17dda1704746fcb911de4c3b337b2cf87f6c916c92259fa44ea03a174a627db5bda8ad71b1d8cd19aa815d097c9d0e4ec9142b2a5421ab4317e54c6e4994ecc27cc9ee9435da8103aa4411c13357f5ab265c9face39afcd89633f63ce3c7fa32a9ee2a9669f261b8f79e7f5fb6bce6ccb3eb7ecbb27cd8684f02e9a9892d93e5e1fe4f9855a7d8a9766fbe8b72dc79b3cd1645b666827d0af1664fb30468cf135a22ed6d501fb821f31428147440e2f11c838e5c41a604044c9d8434cddafb058de6c98fa0b4273ff47f7fe3c4db4f25d974b0b4b4897ec8fcc3092edc3159048b6a794524aa9a4b4fe4a4a4b37defdcdaf6c5f8d342a76a5e9d30f99b5cf645b65b2ad49b2ad47b265d59a6cbffae2e58cea4eb671c6d69f2dbb60b6675f1099b52fbccf9ec1d040f84a7221b98e5c17be5ca2c91ec31708a2c97ec35708a48a107c0d0972f3fc621ac7445d44ba64dfba349e0d8e4eca5544b6c79b8dce1988299beda94f9f66626a8e7a5aac2555bef08794ed3fba8cbbe106190dca1b1a94b141ca93eda90ecda8b562df342665d4c23bc94d4f90edc32df76b44d113c49205bd5317a681dcb17331633a48106e1ccac8b7971925b1207bda6a75b4a5615dbf6c3ab4635f109939d607fac2eaa3fb1a46c3f183cb111bf95344a6755a606aa60f257271bff0d87ebf203267bf361bd9b52b67b846ffe28b75b5d87f34f25e3f2f986cdf2f9b8efab51109e36a89267b8a2f96064097bff7915dabd1306de405f442baf62a38b97dc3740052dc9ec3588a0f6cfb38298bbad0b4a0b1b0d9e8cfc7f6f54df6b50da826a4b949f7da0784ce1ed29d3cfd32b52bf250466ded4a973ac66b8d78ecb3939681f068a22e96b5d65a0bb2b760c6ae0ef9f90591f97e5e83f63d6f2f1eae8194a00a3b78e209254f709fdc27f779797924cff77fe0653c985c917db871f36d970669c442b97a3f5ed8f31e742a756689de66df3ecaf16ee6ea62df6af5c30fb45b3a269cab986ec5549db595c8f4dbb6639eab55abb3d21b511dd3f2bc917cfb907f8e39942d2fb2fc5a4816c36964ce603af0c2d9833d9c39d32726d7f6992e3a584e9fb41dce8998eabc77dd351c7add376d304cb369905e9e4677e3dccc154b976c56397889a79f2c8d0a9d3e8b7886f034d2a58ee9dcdb8d6973d327ecc370fad4539b2f3124595863efd03ba786be988e99ab9fe93373664facb1b5fe696627e7a64693c951ca541a693025d3c903cfc7a43ee49be58198d2ce9dfbb4cfdb78f4651ffbec6950f6fce68f8f17b64fa6f4f4b3a74f24f99092a4ec997a4a442cd1a3e01e91e95f5e90e99b06995ea67732a5f46addd22797889d666c3e49a6f41a9630546ee02f568c421ecbb64ec73448bfe196d199a8a6b3e2ded1f1a691eca0d34f23624a3b0d270cfed16529f395f21a8685f73704438924d357d64e9f405f8c8e99a8f9d2257a3a5fbcd17cf9ed984c7b76385fee7cb10dd27bf35dede84f1d74f041ca315f3f5faf83d6226bcbd54d908964d3a8010954e02931f2f5ec1acd7e0e38a27a441b72284329d35a317dc437ea69bdaca7312b8d09815fef71454c7108fa9a524a29a535405146a6322e2ae715af0ca28f4aa86073dd8e68057ed58941bf8e02023d5f18e81908fbaeab3c7a49ad40b3040f2dc96711df88190bb37ca373b4e18019d9078e1939da833e7fc5527c668222f418bdd87de278318da6781af38db59b601438f446cfd93b1cba90b30f888c98fb50fec38c3c3fb0c70e7235238da6fb8959b4bc50b258240e2c48fc985658e58eafa18c899b0d0cfac2941c57f3f3f2bc67815506e2fe9012d3438ecf6e0c1ae5a4341e05013b4c94bc97156d48a07910f788516d72ad9737f532a6ce8052fa14cac8135b9cc8d8226a0790168fd2600a8b17bf94ace48487a4ca473c2ff18df8193f3f3fda60f76ba4124992f8cd17583cd0491da324f5d7a3c12ab3dc21bc291e8e547cb14b275fecd20d3234190dde4943ef9a325e7d7da105f2fcb42bf2c2104c41d97680b9c6bdf7de5b818bb51b8a8f4aa6709377c0a206edd79321d0b36b144228f128a594524a8fd0aab4d6d75a6bad94d2955a6bad95d6fa5a6b3dadb5d6fa5a6badb52261b68fcf0e3e3c999e877eee6cca29cce410cc4aa62093e9293d18a3374951b040490962947a4a78f3f431fa145e7a90be07ce3cc292254b962c59b264c992254b962c599203b3a7c7c3b9c3a300d76aa20ef0d12206f87a7c231e5f01be2a7aa81d7b86615a841661054f050538982910ed3f200084e6901699a8027cf2a54bf5d743f185dea8fb68117ad06f34d12fb41c068266ed936692b0eddaf6499afc436659134df517ff903c1963515282571f73488bd0227d02f5e9a54f1174d1c6c344ca8cdd5b7b149b8e7b7b77dc5b12103a894420883c87d887b61af61a0e83c876cae47ab10f33a35a79103302e58a16af6c7b9a6dbfe6681982233c410a4dbbb6b6f190dd12a75b87a729b517882a31b56ac2ea5ecf1b8d6ecb58e45ebbc4bb802c82c6284990e92f24d94a4ff6132fb9258b5ccd90a8c109d62fd6d0a841f95e11c16271606e9c9675ddb6cdacd3581ca76d1b97711cc7655cc771dd31eee3382ec3b287ddb36d7bc6bdc3346ed3b09a2fa63c1487cc1c7765e5b699751a4be3b2adebb68ccbb88cd3ae245dddebe564e56aada00ae2b2db6cc3f419eedc982a11537127a4349b8ee7cadd7becbea39cc6691df77befe5de94cbbe65df34f9c9cd6b97bb5dd669bff7765e77b1aebbc7befb8ea3db9cb2cbb44a2b474120109761da71f7d3eec6719f5a97659d9669d9b5675a0a8e1f5c8ed8c89f2232add30253337d28914e9bdcc67dd933ab6db85ee2fa0cd39f5c94755dd7a1300979d889c8044517f2b0aefb82709327a6b4e9c4ec993e54081d42e906388de3b8cf47a6619bb36e6edc5de1b6544cad701ba7715adc384dd3348d8ba9ecdb404c7130946e80e3b2adb2b24de3362ee3b699751a6beb384debb62ccbb22ddbb62dcb3a2cdbb0ec5b876199a671dc330d5f99db64cd64dd00f78ccbb4142a6edf6d2a52685cc7e16f985ec33567180899753cd7770d440e322a6d1368c7eff38b1d8e17efe97798a8fb4996da026537bb17e479d8c7723f4aaf5716fbb1449a258db2b9b0eb07439d30270c9dd365ce39e79c73ce39e79c73ce39e7acf3ded08046c9213d56a25c922e595cca8ffa345291e2272293a3085d7697521e870e3d10b043a33e4d6e3ce4c4e1e22deee2cba141392790169ff2c5b3daa7f649dfb556d904cffe46fae21ac64eb18b577c10e81cdede61ee1eee4237c1282ec2263fc1a2a748f11156f11578d402ffb0c00f79857bbd110a7e711246398b6758e60fb320e1824587e3e9b4c5de2b6b1be60f3b896c67ba649ffd7a331998b32f6c1630b7c0316b2b7e40203bb6f1d03ea7f6155a8b162f70d7d8dcb8c0b388972ed9cb06c4524c51dbd6b6c098d6e26614dc35b86d70df344ee7a8c0ad9302f7ce096e11eefe992b3c591ab4eff064cd96065d84cc21441afcf02ca24bf61a9e466ef40ce83547c6742b46b696ded21cc668a2946e3dd3204d07bc50e6ec3021d7778ed4913bb5566f925a44842ca684d78c468d50a3d68c2835100ac72c592ca6b0c783a46aeb470e3ba5d7d5574bece953df3ede203463ffd1652cbb33b22cfbcd7046f7de3b59b79bb8ddc4ed266e37715f23aa9bb8daefcd361e5c9675e7de65daed1cb0e59365f4d33dbd93ed35cdc3b4af6bb2b9f1c8beb601bd6f1ab4ade1c8ae2bcb70cc3646323093f429669b3b39f3a626db996c1feda7cbbd3df88f469e375db27d4cc1f183cb91eed6e9ee6e71d8475bda77d09781b49a06b383be20326fb75b8ed62eedf2c294c8f469b067f234681b8784f0c28b75b95c20c8f6574b6f3a409f8d2f6d459accf3b26cf698106990ce79ee1808d4df3eb377f7fbd8fccd7ebffd6ebfd9bb5ed2ed9976ec8921f9851c95506127afc08b3a2001916c068d62ee17a6cf7a1a94f26edbbca1c1e6b11f59ac5655ccd9c41b8ffe6e9813eb30ee8dbd3f179b8e79ee0b2273f785ddb7b7d878cc63d9e9b4e52865ea0dc1c33dd3340d5a1cf62f7d4434d9376e23a28a7dc5cde1de70b340aad863b891682394bed874c84fb24020d01017d68a67f2803008049a3c9307e402949dc3f5a0962ed91fb9583356ec4b372cf79bdb67109ae77f74395eeb5f38dd331a255d70ee0ee56eeedf7834d87d5d1db06f898086081b1ca993e272c446fe1491699d16989ae9438970b8c55623932cf393ac1074d912235dc07f34f2bcd92f3159bab8481797f930fbbc2669d3d1cfbeb0fb4299adc6e1fa79b1e45b749383308683dc4cbfe1205ea6cffa067bd84c64d2c603f4cea4d6357dc23aa662b667b1e900bd3f7d84e62fd644f58bc76d17e1098568b237c1d389a8628f024b8c47de17dedb7d5b1f2459546c3afad8e4e9977e89a69ed605a3e982962ee5508b275f2e24b344236746325e122447b02b5f2aabc14ad20e84b6d423b9dedb6d1a76d55bafd5a66157adb7d65a2b928aa422a9489080e09c586dc1adac58aab5031175c1802fc8b51e31428147048c08648c79a92d7d225dd7f50b5bdd3b64c807ca9714359451c8f5b2d5b54a9e0b471ec9552639c288a8ba7ea4ca4b4c955e6fbb37dbda87d993abb88a5f3813d5adf9235595c58b2cd7cf05b382b1a391e7ddeb7919a599da0eac03d6810980c3bbcaf539300e7c03dbc035700e780018079c310d2c001c000c007c0356e1177068634e70686710da1884d605372e1009030e690a727d0c1c522372bd098714895c1f43bd0a0e290c72fd0a0ee90c72bd0c38a435c8f533e090de20d7d38043aa24d7cbc0215522d7d78043ba44ae3fe190fa20d7a370488190eb67e0900a21d7db8043ca44ae4fe1903691eb411c5224e47a1770489590eb5bc02ce0903a91eb61e09046814e21d72ae40ae334c3c00fa97c69cd9b2b8b545db40a51659324b9c24f4c6553882a1b13f344aea7f5340a516565a44abdcc925c4f7b620af47aea44a550c815634254d9991927ecc4d4a584a8b234344bd089290d0951656b6a929013535d1351656d6c8e90abc74454d99b9b22e41a124254591c1c22e46a0284a8b2393941c8f5b426a644afa73e882aab2355ea757e90eb6889a8b23b4a4495e5511255b6e70651657d58bc925e515e4f6362cac5777ac0b3835c73907d7090eb690da2cafecc20aaee0a065175599288aacb922a4962eac5eb5f4f8fc4548bd75398985af11f1bac68c02283cc7a414ce1d75314201155b745aa5423318542255952a56eafa729882abb922a959e20aa2a4baad4b720d323725da920d7672df00b5f815b1c055ef16d3bc6f7192efdc3190c30c4886132c510838acaca8a0c32cc30030d34c89051430da7130a3563860d36a440175a608185e317fe02ff2ef08ba360172c2ec2a39b60d143d8e4de350d84b1634cff61d0e58b7db5b7b7bf5630c070ad92c4889124c6648a9189210699968a4a6b66656586460619686a6698a1c686061a6c6e64c8b8c1a9a1069c9cd329470785d2d999316327d75b1e1b6c78d8f5b627e503bedefeb8b06ae1f5978585a70e5a1f177e720b2b165872fd65a5c0f8f0eb2b2b8505e3df5978857158b3fd87432cdbc3c0e196ed53300b383cc9f62d601770d822db8338854316b2bd0d78060e4dd91e854319b2fd09873564fb1a706843b697814300647b1aec67c0615492ed65c0615422dbafe0302e91ed5570187d90ed63c0261c462164fb18388c4c647b1870189bc8d6de68b247b1027bd164df028ba2c9fe053c8a26fb639468b27f811f4df62e704a34d9a360309aec49384634d9b3c02bd1643fc23266dc104df6214c239aec3d9c030e1da2c9fec23d4078071ea2c9be847b88261bb11388058e5660a3d6cf4c56c951c9133639bbb4cc522ba913c0e3d18a908d95b2501b80c7a31573482cd5ec71121151bd8358aa870183443231e92cafb424cd03a1178b8ecb48ae2f31c10be79022a7d0ae724c699d910ea1f848a6759274955f782beb7ade68f4574148067354f2b393b3d831b2a675f13dce9416c0150f5db8e8e1c824a43bd843ca845c4f63264803e3e18cfae2e1e807bff0baf085b7852ff4bc940fc6178ebe6f0e9943ee2d0b64d5ff454b9bb6ab2f045ba0cc7021877635b2ab192461249aea33cc6a2191eb2b0bcccf7b4639b9bec6094b5cc9a8065e7deb25e4018f3ec9cd4f929c92a3929f2199523a736f9f68e5149a8a2dc7cc59f77bad2e16fa7263ca88986a41ec23e22993aadb52a40e691bb40c726de9178d521aca971dd9e99c94ce8d448f49d8ef69013ed2c3793373e6cee80be78fe8f7d91591eebdc93d98b18b2e8672492c568c2686596a2fe9de25cbbefeb648957469c99b76c3bb8e61d8439748c35d961ae634bc6958d370a6619086310d5f0d5b0d5f1aae1aa61a9e59c3ad6199bf180daedcf8d0dd2a422d5ecc31d7afd49a3813656ec8b546fb8cda0fb469d8cd72785dab9713ec25d64b239b0bf1279b8d6ca465b7bdd9a039997e61ca0f29d9cb17eeb224124da077f9c29ccf85b79a2d5f5883d1f285b3d992e50b837440f9c2980c962f7cbbc8cd17b63f974d3d52f385698e2610cd179ef98768029d46e39829d1043a912d4729d7642cb61ab4488345843a70f27a091353295e2f938829eef554080c44ba92aa392355eaabcf0872bdf4037366952bcaa623bba5b7945a7a91680afc4392e8edb16714936a485a9d35157ba1b95613458b74a9fe5e4ffb4ebf10a42fa2651c16da76d06bde96835e2391e85753138462efb61ad847a29f0e50d218b9f2a5412338a4f5b3a6510778953f06781831a2622c8571499657c8f2a1178e1e104bf2f6dba1c159b9bad58040839a74094db29cf30a3994794eb9edc06e2746e3ce7943e4455303fa44ca71730d65ae3cf4c0a274054f5e21b74b4a839a7c4602dd850492421a6c22a6640d264e867b34985dc30fa3aa8b902af2d7a5bc4c1253a0dfeb79a3112679e6bd9e1767172155d245fbc296dc7b640cfb82c0617bc4c0f60a0481c3768a4317a95a2263973dc89d41589099553081ed31cf1edbb71dc318f689430aacb2fd9c19080287384bb206596a7d8a1567f2b0caf18d796890e2cc20b4860185214030c410430c018221401082107020ca96f641b22295cdcd1a1d9bc6e62625e5a014e545afd278dd46c8b2e8f12b3466a986bc1ea44ad54e54dda30ce18689a6233536366753bb3866a11ada3bfaeb793d904b4495199a50e8d9c530afc60b65cb4617a9e06834e79c55b6224e4bcda7c8147c62ca0b4f2eba167aecd349c827e413f209ddc73b8d0edd0b79a150e8f1a3a2df066b0f96d8f14e60a6dc018fd045cfa49006ef0c2430b5eb42ef42ef42f69de854742af286e0a14091354cc3c0843e5b47f4b09590eb3ba771fa24ca1aa7036d3a445de84e1f6fd594d5d4a5e96663e6133c7366a2d13e853a6deef40905cff5460f0981e3855da48bc406bb562b66b644d8ebbaf6f2ccdb76c3c76db06edb8dd027fa4a4c78a2779f48345bad295b53b65088be4e0ad1709cd192ad99eb670ccc6cd5702a916342ef62626ad311fa687761ba1ba6fbc2a82342b1d238383831316573fde4e993e8f553e6cef4ec70c6c464214dc3354287b9dd33149a8665bfa093682431736a58e6cce67b63661fa22974cde6420be4d04751295e43f79e02cb58ea34ef2bbaee219665a87b085ff1a08d877df78669d164179b5c2f0289b61c5e76a2754edf64275a8783dc1cba3751b386a6cb6c31c193a5d3e04e97a4aa9b88e9e9234423e47af275a8c58b3d6362ea8aa9a9d3a86e1e9fbc62358ccb8c4971926f566ac0995ca74c34d5cf980fc4842e7aec93e80baf8f096e982348640bcb992bcb1d4453bd5422aad4d398a84ed25ee89ee763b61aac325f8909afca3c63fa44ea0e84e6b04f28ea6cf5a9611aac2928394260606a6612371ea53c43427892a66a76e3213a6dc9993ed16bd3213afdc9c917fa383910321fa17b7d371155ddabc9eb27ab751a27a642afde611a6684937f5627b866efe4f5343298987b4f7ef2939f3c0433112e31e1d5ebd8e7e7430404084fc332cb9f3edd8f74afbd92ee773265be196382634e18737c88a67a8b97a084869931132585b072c3f814e11919c59ccc96f1a472dc69e6b6af01d1542fb3948929d06703fb80903994e600832ca6cc99c4beeddb1e778b76bb747777777777777777777777777777bfc5b424162b462a529c884c5084bc8edbb40c845df86a1b0fd98d72172813039947b91e2b9441ed9c9f735e73b68c9d233abad7c52fee5fb885a6d9a3dceb55127631c22b4e599068710d1c073c5fa69196f1921cc9f5c5c319855c653c6f346a997fe16ca13c6c997f2198b31196f905cab78dc768743a3a1d8d5c9058ac9844a8052273385f22a657360abe9976ab6770d3744ddba8c07d9302374ee7b44ef3744ffbf4cf5c4d96c9c2b3054f970685608c27915944cbb878fdd927f96ac48b6ddcc34435a07b946bd75b6cdb21b79669b0355f24ab6560aa7d3893c82f7db25fac1b0ffb9e2f46a20e6bed376445f7755dd405a54731437060080e7472477f346a6de4695205fd4c7a3ff0425a841689a64a63962f51a53ec543b177c59b81ba565db2aba8425d6c29d621b9d63320aaac0ba44ab5ef610151656310835ced79504054d919ec908018848cddde00f63d62eabafd0ecdb65a35620eb27d0e31e5dd3e876e0f0001646b6f83e8f635a0b2bd0c1968c8f62b31c5224725db9ba2cae6e8c090ed4b516575ec59882abb638fa3caf2c48829d2edc19842b97d4a4cb978d1f322dbb7882adb63bf22aaac8f8a6c7f1255f627145577851253bffd28a65adc5e14532b6eefc5148adb2daa2e8b3d165597655fa3eab6cc6c5951a5de5e8ba9edf637a6620a3fe5bdf1b0d4d24f2a5f6ce4b8c7789222c5637ce185c7a8523dc61b6e788c0000c0630c40001ea30004f01869d0788c393f461c70788c0318c063cc21871a8fb1868dc768e3c663bcf11871e0c841001d3aa878d879c763ccf11809f018753c461d1e557cc74b3803e1ef180669f87a8735131c1a61d159e0d14998c55130e92e30ca5f60173f7ef116f829187f070e25ab85c572573f3e3d3c3b3a393837363534332d9998243388419855a8e40c7785450dd5cc0c00000028e31400003014080584c2d178204a439d8e0f14800c7fae54684c1b49b42cc7711042861063000000000000000000c80c6d00c7522080af9225bc55081bad444de53926bbaf896c9734692cbde52adf29c99825e52ff9a8f0c8d11ba235a77af1f2e495527249975119b6e76996c8c314c710069c6a7d41c9913a7521a2612298e9c81c184ec25b3b98e86999150846a43e1b7efd009d93c5734befcc2c61bffe6159ee9e70d49aba17ba64cb79c66441b241cdb77290418a3f840d731aab8fe6e879caa2008fe7944a1ab90dbb80fd89b5df53eb4f1d099ea5938f64e39f372016afef4d293b932297b9be825785bb83d48b66711448dcf4a1af1eafd7442679647db550f4266015e72515888d4fb8d9cdbeba9e9763af683f671ac2be641de938c62d930d59dfd98a45e910f9a3930bf0053d866b893434bca9ccb1bde903360bf3e82e82b824e53d61b2c5b58dfa7231379d67e84716b590e56e7354ca5f8a2fd037cca2c4f3b6a9f35f8adc18a8675322c738868cc04692c787bd453c9f16a87b9b026aadea6a6b23fc200669af31436c1d6c285006b561725271311a859be0ba9c073846144115a74d3b06a78d5a78ac25b072dff49e0eb999f2ff51763141a8b9bd1c8e117bc5ae9ee1aeb195a3ddad48af5970a767bdad827b49e8a19cdeb87b0bf206716f2f65fa63f9a6259f133b30795620c6c1ef729aa80e58528149064271aeb7945d4825ba7af3032095237c9c3951d8fd427cfd62e944b41a1f780ec8cc0fd1ee4752afeef5f2abfc95886e3fff082c3f4b06e485490dd9ef2127a16681e0a015e8c70e767dbb09e99694c305250cccf11ad1659fff79267806837802f8ba86dd03bf553ebcc9c28778f67c0bbd90466082688365fc8e936fa3f48b9c5de486fbf0f2011371cb8e2ee57a54765dae27adc031d9dac670e436baf4895c5d7e7bbc5245a482ddbb09c7685bbb4cd19ea2f78317d1a34f53df033e7cfbc7b68c1a9ecb74a9f189be279d30007a04254ea07234df599c8a0d569d18ca8a6d82a1f1f5aad8bbb38d082cb3fff115640f0b590ab67cf33f7204f62e470eed562470509d9e936cdbab663fe986e95553407bc433217bcb1fab837a1ee61a9288497712abf743c04a02d33fcf00925d3c00a138be9e081be50f30f68b8f3d04566f2b28ef2a46d910bfbbfa86e061b045cc962ed23273c070f7d46285e16a177f4ae3feb0890b1e0cdffff05dca16daba9f5aa936f0cb6f3537c143121b9c7520f98dcba215b34cf3a17772c0c20196bac29644385d294a934a83c94c766c56242faede4c30a270aa6e304fdf4882a94807b2c1cec983d7c5741ba63758b8e82db24063bf1b0b20e09cdde0547b87445109e28ed80cbceb1a2917686ac28ddb8615614170e4140ee90216cba457c026d6b129121d7cfbe789714931edbeea4266ac6235730c3932d3bf468492b71dda0b48563811a90b8920cc08517c760cc0fba91094729e22035a15cb308c40a42765f0faa9f03caf8f91ebc2e7794ab666e85b33b73c97b14e3a59b27e089e3b63634ac251a1c0e414bc57cb63308a8fd48210317b92d286a4a8a624ff89b6ffe5dbe11cfd5dc8d14793ff7b5abc46b76f246f4a952e079f50b7c1b6e913e9e31dd2be57da1d9c1046791d178865269ced199878f6738bad76cd99591ea76ddca7880fd669394a0ec4e9bb637c3028a3743b683dcb033cd288711004e120a6557bf77950d050f6a12613cb69d2c0d3bd064fbc754746f006a09c36aa1de203785470aa0307a2f5bdd06b2d408866b045cae72c96ee24884d6c4cc454919584ba6f38b7997e4d8e488fd9d2e8edb4f6900d39991c629a664a1061fc38c49ca3e308aa599d2328f383fc4ff316394a2f29ebc7379e4984c34fac91ef541fd57f5420b2ff9bd731535b861769e589ae277c28eb2c1bf9a7e9b27c847a29ee38992af10cdc59735a885c7a1b3d9539f22101ffde1a84bf15c20f78e00699e7057454cf0876e9edaf37a59b26456ea2daa718696d3987560bdc00073fdd4a1f32eeb9584123d1fc8bacb6b77a3c220f2ff48bf7be60eefddd8840733467322726302226863971ff351ff9f43937ec4df68c7a73455d8e3c25992d7011651899f32089716c0695796ab35adaa2c1f1e9e1719c8008775788e94772369fb8574e8d6b48e1397b746f3596e5a58b26d75a11056dbd309518ec225f6d50d9d99a403defa49accdb2bc405661c20558dec73b907221172c609807cbf97d0bdf0cc4a909dbc7012a7086b4604646851990678dc36f1d9b08c18d4ceadad9df46d698a4faf384517fe271ba76127b3737e67eba368582028a24024af4cf48c0a2925605329718cd76caa687a820e4ea7bfa614354b21c130826a091722c8a7fa7acc2622ec825be180a893eee4087a2d8d13763fb005c5970f9054794109c12390cfa6dbc3820dd41b21f96b83f927d52436709a1f4b268b0c9fa4e64d140dea0aae94a61ecee2a6fd0af11635dd99300a47a1b21bb5a11b98b2934a68a188f5232f44cc32682c36568b091fab814bb9a43cfee8fb37381ea6a57b21214ecaf3642169262714a4ddd2f0ce6ec6eb523de91cbfd29de64ca4744254ac6d35da28e4dcda0e5c00082c949bc4c6133df55043b29f9007445d373e38788730750f1a801d0b7812c70198ab5459b0e9180f424a15061b9f580ce2e278f8b9c4f04375ca781e2ed3ad2ed0671ac799b593c84934a877e41607aa5ab3be9bb8900ab6642fc19f8e25d29bec635461c5741c138894a59eeb51582c817ec5fa77b0d09ca0108e52b6b2023520ff49a0ccb38d51eeb40df99263622b226c5dfd17f514278e894610c5b4c6093e1382f66cff0faafc3eddec766e9906f9edfb1fccc174ed5536eb3ca6d9043f6746804a7bba80da9e09e2ffa567114967959ba48fa4aa2a58530d3e3ed0531ba114ec3a21f6166bf73acacf579bcbb58a5fb4cad9af87d52fbc857db4367d7a0d4b639277d74bb7e6a5794f02b944fd9dfebe74a0884295166fcf60c892f2cbeac10b3921aa3cce154a6c1a1bd3f108d055c8a6a5c399dedc0d8a3020f74e4009f45941e4a2192e5544aaf0cd25be0b5ecf424693c2057101ff3eafbae31520e4e64772c08ced432adeb47b31ec9b6e3dbe79c21f7478721a907a1a61173034b0065228b1ee7c076524c3daae122399236a947b1d17aa3237b972edf9441404ab0db41276118ff7637f0a0a476eb081563d64aac969c18a14332ff0ab6a55a50bb76cab9a01a81e204d5d1779581a3decd375f92b7b70b9f1bea38e4818e4bd948845603dfb00f553164bb533d2cb587828210bf1b01db26d6c3d6cbb8d0e7e34c7ac1eb68da5d8b50e9ac62e4de0f71a7dee0865d650aa90516792f7be4fbff091b426b765554f3b0bbd6f989ee6b8ae8f734ee2a5dbc0a0f5ab13a988b909f088472306989d4f7c1bc5949c5023ddd8301f46723197cb56c951faaf84d47e79ba2bd025091cdaf91f0dd348bb53b260c4ba743735fa2531b993f76fd808dac89ac4e04ac47745b8df45ace16700db84d3c9900aad093b03d87908fb53b7bf821f58783dd78f7336a128856fe96791e88d252b9a07b9416b61eef70e1b88d0250636ae96a699490a24c58f894e8944a42ceca47d5c39160082c0b37b4bc067070262b283a713d8f9c5ab69192ac6b50932ee589c6ab9d85b6402943067873a54c78f8f9cc2441bfecfa8e4800cd45c3271ade0d84856f5d20dc1a3f703bde9c69abc985f98fbadd3638426e1e9a08f1b8a33573a548174808dbafffe7cfdec2d3dfe2901819fe677f460f7a088fa093e9c9ac6cd001c909512c31e33d083f7a89bd0758cfe089fdf73cd51a20299da29978334706e6708f02f89908685c1565233e339e637810def394acafc86b82803b4fa1400c901479652aed8d1a8bbf9883a323a12a98eda8785298e99b2668a0d80494153ae1c8a720bae2b21332d523780196492159479328d32a2b2d5f6f8b960a1dc843a4f2bf18274c615b02efb1a0cc755e483e32a5329aa49ce30c71f0442f2d8bedb84147b22bc0998e3a7b261adf3d2b14d188e45120263d9533179fa1720438a3314082dc47de4616a1fa22d23658250341e9aa415dbde6a366dd68ae2a957d845eec237ea6e7f6817a08745ea59ff37f891cd70db8d7f6c9303fa1c76eadb0156a7b081b4da1fcfa9fb2f37ed4b863e06573cf26bd50da6bb4dc65995de90a09c70f0d724cd99720268a2f9e821bf210ee33e72d60a0ac272fba79cee3606868404090a18d3cad297d61ad17ab39c6eec3683827c1c7482dc0c1a23a90ff10d4db7f7cfb07f327bf46d9b9f5a153c8bc72321ccba28fe8c03e22d82b54aa51286db43dedd644a04f17ff7e2b50fac586feadcb38277cf2b124ab71476768897fefb4c0fe8ef11d92c8b1a27a748b99676270ebe97eb9f347def992bdbf89156c525e659afa735707595848a06d2a7e85fbe4568e0262dea669c0f83cf1d1f1b01665adcad363f118efd37171e77d721da829e33eeba0872be53284f01b65fe81d4f1bdc10f6f5cffb7712aa755175dc106035db6cdec09a7765515ff0b7a5fb5897214c399292713b41115395f0929972038f98d8db1f74c8e60456fd42a397281f91485140188f8680509e21e498056e0eed92060a3d4c87742f02f7a12850d0fe5fdde2b1054a83621d06894560be84263ae0d71152848430271e8b38da1a37e01a53f115263cf47b2cd0c31dca3d236a8fa9fca98d4c3de930465489ad5eb4078dc808c1aca52026466a3e575c926f2a7733aab98beabb7f80e005179f7b16657e66c9206512bc9152019f877c4cf58a3892831ffe2a31160987396ae2ab491a873d9c57bb860be6a114873dcb2c9de76750d9e3ed1dd97a54ff9847d2715b05ff4b7bec4c24837d8ff430f508a029fd8e1fc9e87d5f43da26fd5b049274e903550c39216510520d1697adcd4591c80f756aaf23913d3b3405a71d85efe0ffc03f05cff73dceed89dcc052b3976f9416af684fb20296ae10d929dd595d39a9b3cf958d292f2b9d1d227b79a9814e31ca8a8f294a166ee708244c590aa55e93c2a0774452ee8ac56b82832bcafaebb75a952cd9b0fca6924bca94312d993ec6a7644c781662242faece1d77d31d613b4bef9655bb72e27775e8f152302f9774ebf63c8f98831a6708e0c887f606820f3d9c494e1bf927ad30d6f23509a72a4c0b0b8b9e555d83eb888f48498f8cb19fbf8f8ba1a88f68c6903e1f0d437ac40b8afcf97f24e2238c4884cf6f20111f413d227c6e8ec037db604a8da7ad99e966ccd284be68195c62fabd95c88d28a79d253da3220b2f57dae8b494702ee2e505d2e6dcb1f36c084c480f0ef6b265728ccc25eb8e3b1600a43f3d012438dabb040a1aa396c890686dab3dbdf41ecdf817b6fa9d2f60d4ec24bd1e3d43ed8ab5035b4a2bec29faf009d348ac7c886c35788cd4ee6fe66155e28d292d72755778ee4c82f7b2bdde0d2586bad93349923eb3eb41fc3ba0837d320d8ad02ffa04aad642e784a83a0b1123b07258b5e1d0bab4564a621b3fd6023911d96587d48a11406e30b46b880b870957c5a5090220e234cb3cbf49f810212e126440d33f32bef7231bc7569571bc5be42236931130bf4abfe2fd339ced4577d989e3326e613cc6d632e4304742243650ab7ef5fc291db2df066ba5d5ed645298761c22adce8f5b9e583c81cf3e3b1f4c2c40b410e881025ee29db826693f52aee9b172b8e42fd15c348cd595477d5398d4d138b1d5b850fe24f6fcc33b323815e7ebedb7832a4359907a40559b25de92c4bb1bf2fd99ed4c8c7f5bd46e2397b099b9f0e915d470093f9e59a898f84d604265c9a353e7948c557de07d0291ad0579d23af332ee4d2b761975805b239d6dd02d0441ca17187e2dcd9fc789d6fb87fb60c38a99abcf9b02e8fe3164b74edbf7e56a1f1cbe2f67ef79c52e89231ac428738a59fce9884ec1206d70708ec5c6a7a2161b347c455e66fe741a529d757ff604c322eab342043614e572f67b17440f9dfd5a9ae8dff1a2439e8cba3a5e960467eedc4adc6aff9971492f15376b72019d5dabb65a3c06d69793668e4259869bec024cb650c1961c2393ff8a25b2467d46e9d584a8d9477a3e380f5544cd113145dab4b1df366eb29beda3df06e2f466e1faf90dd64656b2aced311409fb5bb74fd3a803028a02a9e0056d179b9a01c33c12d848631a2e0dba97d731c3673ab836dd0e31aeda607fd27fbcdc63d2d61e8af2228d15738e79a56df646ed13e7c422c2c856746b0462d39d6426f2e3c79c7b71a4c6a0b034dbb2273f26e641e5e4b4c4a06d4c03bb4f47135ea70f55024fd746ba9db4b040c8e13dc14684f2ecfce98d085134034ed021b0bbc85baf5f1d93c6c0d07a038a686142b666ec7626de38733137c96d11c7ac67207d6cef5989c476f28c380829b67d2d5540da8d77f5b67ef9ec048a17ccd11f59b09f1529b0df87656dbb92a0926a22b337f38fcbf9a7c1f8dc47833e49dc36620d76a540aa97d3f73b4f7fbb5fc6c61b278c6b52dcd7684c60af4eaa9b8812956e338a443a8a8823112e0e547cdf578c44a163f1109a380e75f98553606906f50a78353210e354de44e80f30eaaf5066fb008fd192fcb207dd9825f6d911e00464387ecab628928321c331d2ffb869780f121d13f521da9f580f92fe693420ee9e560b79bf09dd907498d40d61ef74176941f4de6a2dbd2e19d52d9bb0bca8de333bbe2989fe97a7c0d4d7172620333b5898aa28e193ee71108a4b1d41063a91ac9c4ee2e63670f52affaeb653d03499264b9bdf6750dfa16dfeb8f2e71700ba0215e35f8822ef6cfd5d438f30c0fbe575433f380678a3af1d1d74d40890b34684c70d093f28a8f86d2326e0a2edae3be2cc3ca30ac6f63c21a9ed176424c1d4e586988c2879401987560c6281ab3b99b4c7d590987d380768017bc521eacedb10dacc859630ddb4fa19c7d366993a8269b3c8daaef163104a5b37ffe24a9ab81a3eb129b1c6963156b1dfaed80cd9efd4a75d145deba74f1ed3c4c0a72e67fd131187c40f859b289439e99532ebf62b9a5305005e15332d940b2bb5fa5e4e842eca12359653dc100d371b12386577d5d80c4ccdab32029db05c2e595938580cd07858d795d702da8a4b0224e158e7ac2a2c19b2715e56ca240b298c047fa56763529a20d92be0227dc631aabc96167a477acbb3a66a0e7e5119d26731e07d33130dfbed79df9de271157d2c2bbe7278b59c6a6c7087c7ee568ba638e06b0657b43af8d230515c207a6eb580d170faea7c1e28db04323bd5eef73683811ccdae0e41c818eec7a008b9c38abc83166e66b773c236e0aaf440323d21b0cf0360e841878c3d4a011a96b6a1a7ec85502969d29537e014e158cc580deb63c845a58a71ec250a548baf8bac90a6d567b79e1264dc0283b301603025c47fa389702de0f8ac476e4f4429e8e6561e431b191d1a140b419cb976b83c283dc1ca8de47f91b068d57d5a882d25d7ae229585d27f33df8a693db1645428fc3bc6b33288bc65e1a9b6438e85b4ca18e91f43472dceca670205da2d282ce990369a9664798bfc07667fa7256fcade6381dd287e1e367ce1eb9ae26b3fd24b78d6c8661a772180fff4741a768ca563ec4b59a4afcdbd26de44b7dde844522b6c3a04b940616506749aab8521e48a944f58ae6ed13a2d3150383ee8fbd1c6ff6a246c743a16917d6a19bc2a91a0081152f73a5d1ba8b00fd69f802f005a46a9c94fb5eb8b98d24e0f5d40bee91f84780c1785e5a41bfe0ed4fb9cdfdd783a66413b00426a72302904a78fc8bac5a03c323f3a5bc00b3d238ada068fcce35330b5ab082b8ba695a3d90fde72c62b3d7d7ad032485eb9078a86a8c0be521dd8081bf4f0b75eb501d9d7e37e6970cc5e11b8c1e5d74f4d86f74e66d9dd0c31024cd9a7ea7c6dfcdc5139b660c8564aefa8208d8076a3414a36172b0b164f9b1c994464100fe0ceda92f9b78087278127209f7e550ba649b16bb0d2e2172646786fa5dfb5fe73222f8c2a2eec4e39baaeeff2853c2b526ae32c6a7abe5f99c171e4989a67634ae18b34f8318d36a95325d42504d3bb126c5861c5c3e088d8a3c0e8987122c3f8c0faa9aeff5035740685bf752f105db520719119afc1857ab1ac4a0e6c89634457eeebd3ecc2fcf66558b039de769ace9b74e1484881e9510517d1454410374f9762109845cf2721eee2e9820f7776ed740b95685523da2b084d6d4453321bb2630ca4d4860c3df03d884c81f85e5c7aabcd4b575f9f2f6b50f9702427ac13f17cf4b4293f523cb2f08584331097ec0bee76f39cdda27b226bc9c34ae77484d7e8ca4bde91f38950e49e6070766b797e2ee49f89028c0c5be4699a35018d588d55b5cb35cdc343386123c9063f9c112018a8e8463469860159fd2b6d0fe1122f0ed41fe5612706dd5b39b84ac7c983deb90582ed8afc7a5a18f6dcc4ecf7747e5680c72c00c6bb9164acc7082132a6bd1918307de830662f8496398b96ceb845015279420b8823b96e034253bbbacb643eb9f805e6b9767ac334e65b6d62fe235573054ea789cdd7ac17c0929c3e3211f7b8960cd2586b0244bf4284227132b2d22a3614c19b1c88f8dbeb86c8fb1142cc9d5d41f4a63b20e0aeb71f6667990f75d3ab07b8eb8e87ddd96d87aa5634a743305570e972a48d0687faa7d4baa1bbc53009cb2604e3651c79d6b3f1239dc405bf59efd17ad12b8c6ad15223f76f07a5006f75f8f8290cf116dba10e75696b9211ae35a729c4d04dd225cf0351dcb0017d9ceb05c57506c09e02b10491dd08e8d41e9f667c1f9cd1caeecbbd8a16a6ac6dba5e0aec98a6e12241826c329afde2e6f66a80f4881229778650ba79ad395fd753ccd51e12bffec18da714c1b56b99c607c4964f10048db39a956e43615205a3e3306bdb9915fcad154caba25b663763bfa7236d21e6e48656da3f83e20ee20eefd006e881fb4e2bb19388507c1d78e3c55228605ac53d95cf1d67e060cdc30ed2da5f073f1d2fda2b58fac4202d3b7a4bd12e0ed2a65ffe8c3f422a7aba913996af08dcc0299ca8a924e08640e3b4ddb3c1be81ae68938cc84bc2614767f48a96fc1b2ea4487cab0a8f0f8ca7d885abb15c61bb9be8b7d043b33774ddfc69e934ba5fc44eeb884e1704c2566f1289f217f6e123df7d82089c09400e70033fa43ac4042300b97dd3eb9080223671ed5da39b87509e38498108be03a3721cf952b2b96e2f0bf0d7be01e00e36ec4a2524146cabeeef53f7a6f40c90af14c5c870c92fffaa394705bc9654a59b86afcc8a7165459cf22ee0b90a0432ada220f21f3af89eed2f86e8503b626a17f15ac0e72bdd3d6cab40fe72520f8da3414ecb3d88a80f3491b22841f496d8b85d9e54c1d10609cf36d658a3c54611f3ccca7fd4e2475c68fc5891bea7b1aae814ceedd42124088b9bee0da7d3123618cdd8abcf407a7d876061fc722d8f57ec8b6542d69fba8612d0d88ac567dd40d390ed507e66fac0834ca9c64cbe4c1c678c2788362b61f120ab70b2965946a0e25b37b50b9b130d138392d327f7e14c953e19993ec1069890aaaa2d366cdc42bf89a8a0f2282ae3e86722409da81f64da2d122e3896a4d0a241c81040362746bf445f45c3803516e99740f6ff0d2bff66045286552ce2fe751c51d3b1242130ac1cd208d333b0b71ce7d7c6ff79708e4d723a7dfde5010531315ec3b44dd82a63ac9f77de9fb133fdff112c91f8f8dd024e6b4c2593a331352e0cc93b40d9f489824c2c9b495efcc12e974d029cdb0f14e8ce5816d9211bfb5f2b7cb3259579c7b3df512bd0535f1d4b85f03db8f4186361bc124c2e3bc18828c98266eb4e021953f004c7d8c8f3e72ad8fa7510c849a61900d9bfb4578bb171497ba08d7cce85848ef5fdb295287463bada0526a659c0434343fad5548e30167c81c98a708ef0a71af85787469eb3178b78c4ba827a1341d18c95c2b1673be5b2bb79d8ec5262d033ddea16ac05a75c8d71c89957a82754b6193128170265d8547726481a7919b35ef9768a30f918a8d884238d3a07313cce46b33cf326ff0ceac23cb41a6ee961f7b241a8f00a7e0aac337c22bc4d13ca5061ef86aafa088ddac579bd38eb480663a7477dc83216595ffb643ff063a2bc984bf59e8d91923502ae39fb7df1f4c9857a2e0586d6915080f96a18d347d1fa15ef79cdec727ad7e3ac5790c259c9936aad76262be021e950a6da9f9444e88c859343d7b758b1a064f2763166faa12182e31a691fdfe1ad824b1ca05bba03e477295c1ff5f70aec6fc22a5491654dd48ee5f5f85174de4b3effad8db62bcc50a349ed5d3946c37f6fd96b1ce680242c5adbe757cf9a5bd729cdccc413704baa95372cefb5732a73d5b4c16bf20743846bc7a67b2bd30e1c7a234848d887b525e08ee687954e9a9ef514c5b11e91dfc428a157c0216b56937224f39500b00c4af489a64be2ee5f30e25018ddd1745ac50a42f2ce2ef6b548935f580bc8763ef7296043cb032bf69a791447545bc5292421675f15aebf7766308f01d1258e3dcbf0bac2889cecea2092b22f9a4a6405135c2df287450fa9b6d686f964e47cd9919c486e7cd2f63e0b1e5e59957ef140151069d4970ef6d553c9130998dc14e40264be79a49339211e675cdd4af3b4aeea98a4bb9bd8f3b82fd780948e0e629d46df3b275eb051eb1b90eff9568c71835a2b5282ae82f455bf769c6cdee6eb96fd578d860f34bb9b8529d932d157af2a3c358c68eadb2ea4ac2a9a376cd1d4eee4a6afd14dc4b6cf196ef4dc4de3d0edd24068c54ecf299c91279855b3316ce17eafddb44e71c20cfa597b6ccca19d555e5bf923348ed82e8ad2d685198ff90cdde8e5905a1f00aff5c938b0d9b3e2c1d2e2a327b241b4e43254ddd13886e30c0c123207145ed86942a8cbeb9db8f03a83643ae471f47d7bc33a1107942368e6606682798cb012515f312bfab1baf1fad84cfd9e2e336e6e1556b12eb803656413281c515301fd78818e2059949488637349a037bc86c0f4af2f1f4d0a4777fc0b7e0abbb6d724ace292992bd5366d8ceb458cfaf1431e0dc20238ff0e89d6796ec2a68d581205340516e117524c517b835ee83766e44ab81bb17bce48691faf52d3c6fd033d6997ed988b6e8b776b3bc002ceb33162444eb5041b149f0ba3f4f88078e2d6051bd780cbacfc2c33ed57d4c904bee128aacf5ca049009433142a5d62a7b2169b3510ace6d3d30b6fe658b9bbe4f666557aaf189a04170cd0e6ac510a6df54e7c2f1f6c2af5d8451fbaf7750dfcf035e3b3442364a82580234589e011940bfe190809710e8d144171f5d981f384064516d6756a07e1718a6dea8acbd3338ccfc887ba56d6fa419773c3783251eee9106af40cb72c107928a28159aaff4371cea784798c7a92c3872728957fc4a1373d4357f8993b3c859a213d0f2376b9e8e27eafd3c4276f28f6292eb02d41ba2175d93734a013885bb4337a1d744f19c0cea856b0e634db93bc807209ddb513314a375caac36ffc7fca43c7efcbd59e4fb5327a6283b72b04f12a3df57e7f2041462f7ac1b3d33a46ed945c3678b2f533d0d7d17c603112c44af37433682725ef593411039065e00a86ae21f32748944c7b182da5f7ef562fd88439183d0067c9f8bbdf8dfb88f5769b0f26ff821eb99466422f930199f0b9715ca9e20d77b168250ee9d5a2abbbf5ee55325ceb57e34ef10a1dc3bad0df80f15e85fa663e8cfbc505a6f0aba03643f9b05ed7f8dae576e9dee1bde58224df7365f17870f72c7002dd502890aef07d557b7d2e3c8bd1a38da116e26a4f6dfd47f68b4bed6ee8b67b5dafbdf0b20df63bf4a76a26041e3ab2631e71ea88b59af870eb15d11f6a616bad54191de4144682d861bb61ec09f3a0ffd86814e53705caf7342ccb5d10db02e5515f8ab9b746ff9b401c21cf065e7bf596ed46ac6abafc2ed20c07f1e8dd5ab2d0b578ccb6b7d29882f5945948b0afc8b22728ad2d915ef3edd546d97f3d9dcc5070f6558e74e3048888a1534650fbc80f98b45794ebea5696a75db2d9a9d741dd5e6b367186cdb6f46de59fbda6c212c5bdf66baa3beb1cfa772166d3dd9fc9bf63cbca3c97fc146bed3e6b725e547192a4479a6047e73259198f73c0bfb9eeb77d84a16953ea50d3d720e9d076cb8d249359fd00c4196fdf9f5304836c4f3058b3b7c01371154a36a1e52804d695e8061447aab5ade5e30912f49f87b998d19062dbcf41d11bd3f7f355498185c72f57492a614dd63838f48a5f2a15f80bcf5099f0e08bd0c0a2a4cf7bd27a114e54e02b0d8a782c9805519c8aea1549d5b40dbfb1674d0b030f6cd397d963d5b099ef8d88d4ee8f4de6eed1ee02a3d5443ee0b1ef32d350fb45a2a0216fccfefdafaf9b4489ef72ff796a8cbff027d3acd7c5a125d4d01378a41df3f6c57aa47f9ffdb1fca78b0d953fcd15eee81310889e9b5ebe13c2c46bd99fd8cc017ada266f28bbda05c068f6b832c5b0b4c6340e955bdfda9ea27e02211b59872331a93b518503e2d8414c1f510a7aed8e58f1e4bd64ece33e8003882e09fc7c9f5bfccda79bc718fe802bf7f57958202bd4fd27f8f992bcd7b9bfb42b22ffcde9e0a20d8e6dd5584874b0bb8a00741e566e2108d9198612f7bc2edac5ec4af6efb7cd045f6b5e4cff79b5bfc6134a6e6addfd0c20c7a14520b524e63cb868b5cdf7956cecd2790121329e3b6882ab448616b4fca36a3ca1f79ae8bb9f7a6260366793f8194633f5f436abd0975ae7a0c771533b3aabb32e4f77492848a23d3303eef596762b65a29e284ff4fab0200f06a34f133944c5510753df386c5c833ead6b8103394d58c3036a685808bad22c82680bac8e3d6c674738fc4e22915d1ea0441a7f4a0603e7a7275963132c8a08fa6f5a34147509ee94afdec10fe2ad508b483c110e345079621f46ea85f7b61703eda5c75094e3147d5afba1b4b64f05464ec5895fe38e473bb024702f6b941f464e8eb589a9c0e0a16f8158ce6a4dc85a016f4b00ee52cb5f15a31d1a49c3daf04be7181116edbea18bfbda2a406f2fc72a384a900e0ac5751795621bac2eab817ffa2e6599d58f8009f2955de63674005bf94776bdb528ef3814eb84ce094dc2820c9ae83b10e5e9099fc66be08557fb1796f3500e94cbf3c4e515067cda9d3dd713250f54a0160a401a56b0c5caa6831e8f897e045b4e106d45eeef6a6f4fea9f561de1d0b5fe4923173d6dcb6a676f07b439b5c97fb379b230d01619123b9044e6936205d39b803ec2b55f4017fbc3fb68b052e31a2b051416b256a20808443b5b3971cfe7ad8e15998e093a12d3b1a09483964ac9d2ea39f1ed0734993bf34e739bc8dd4e3959ff7576b6c3d8601327ff3d0da013eaf52135608577b81b6126d81416b19fe161d984f6c249e5c303193edba3540b52029279708bc05b4c490ca362a5350d625348a17e62125305445afcef194480cbaa831653eda7293d8ee827f585444dc209c40be6d64e049ac28d7a7f4815e8945ae84c25ec14daba002241251b173da3fd39426564eaa7a350eb713ab841da781d5ef9b6fbaab9888de3a847f2f79ab56d83c2585bfa33b2bcdf12766b46b84789d48a413fe218786e5c4515c0e460764404e3e141c8f961d4a6a1c2359195b30d8b99d3983671453cf5d14d44550a8841e04478ae753fb2a3f21d03357618f7a053a80259ed53ae9930726d741606db63715fa4633c6b0507c773e16af8d243a336c377aab1d9adb3abb65122760b13a7c8b63bb212f03ccdcf0d4b528851641ad4afd9da0be54617970842b9cf02b0c242876bc508a9a210682f1d6130499b75a5f8f8573874bc28d311f9baf85a2c14c6e6733121c8ee1d531a4902326fba1ad1d4e19e191897507d867523627235fe5a7bccaf82aa5c5eb8126ab30d731da2f1cb362a16acfb2bbb03aa9167b74a1454dd779cc83c7a1f71264b75a3579daf011d25c50732ac7c358c5d291fc3a52e6cf36825e01d8dfdb4ae02899a32c78c04111b8544b851713f43161bb7040f356d56aa22451d530a5c444818bd6c5f18cb902456b6ba183e74670337807cd753258d6cd74f71c04a9a031187932dfc0ce9ba2ad80299e396ce90e64a0669b6ffd1fd41e200228f16458dc0c328c6061d49d29641fe4a29226dcdfb2dc19547bfaccd0472b8695ab526104e34bafa846ed182f227bc6bde74d0f46a2cadd77f435cdd5e60b706b342e64153fefe7c70a35dc77f982e1dd34115ea24353041f3d389bcc1f34d795c4aebca3028a3e88c401732a1fb454f126807cd15ccca941e9c85ce33adb6610f802b6d6075343e325c2547b670d9b57a3a4fa873d6b53d8b587c86cc69efb5ea30132b03b7c08349e0d1f5913a7e4c37944690e9739a66adb74dcdac779301b6c9185e9a502167a4c66d33482f8f10901ca7580dffbee4421218c84d9674581a82b28e9578652a37602869dda87d931a0d907a49b88100c3975969270dccee915103f7421367acaf1852fd0e30c9b4472ca4797951819a0aed0cbc3b9d37ad0b26f73f0ef057498176d55c0c1dbe8074215db4886d84d8738d28edc52a7200ad7b91d3fa241f526541a610acd189f87453a4996602f41b921bfe0490bea02f9680412401053c52e0cf3ff96f96915aaee460651d710567a02933db718972a79323ecfa92cc6d8d361a8d806f81931ad8b16092675bf0e62f4113c6c7c23f4c03751c24ecf26114139383e8268168ab1e58cc4fe1e91040e9ee88b9851cd757e1a5895ef8c465e94ebfb934e7681448ea5fac5cf503e410b709deb98c77c6f2aa0c134cb41cdb261c21cdae430d90315c01cc64120caa4cc04146c9c4cc599858c59848fbd3400e28e46cfaaf3c92be7e24ee852c4437fe63332e00c39d60078e72e42b68c4e38aee20a431d4a4548661bdf5a856abb058efaf56dcc43ad094f3552cfde6e6eac98f981314f60beab63dd3413d213ed323eba884485e9ec00d8e00f29996e91a2ca2f93cca0cb31a3c20ce34a2741a455616b75c3d3da10d0865a77f663f0885fafb752abc6a1411ec39ad9c775cf2c5edfcc3235f8a01710ae28d68fd4beb4edf992395e5882180fb62559416f43c8f807ec8715ba74faa7f041607f828c41658fa4fb7501ac580f81f1c5c70e967162ac39959f2e9bd0697f56d626f4359dd425b969429467a0fc075a7d2c24754111625e922dd18f8686b3c290ddfbf7113b025deae432da7efd8f7420ef79ff80115dfb903bd594188afb4b38a5a60858bc7e9ae9873cc8751038f211b9640095147a37b1cacbf4e69eb4155147003e1ef79e37e752e7f80b737fcae0e4dd1ec178fd64aad8b4ea2026708fff27f00df1cc6c8afcc320c2cd503d0157e7359fa3732a857d2927309c6b2c7d1e4b1c1f4afc10d9f09b3765a57f354ef4fb21334f0f3462596312862a0189029ba6cca706010ab5e08f18c5c7016e00535a603bac458eb1df20b301aa496f7ad1c7d61839c818c58201633ac51d7c9df2496b4021802cf992443bd654025413e55538979ca0a9827cd3a6510f3205d202c69ce4bb1ec73738f094b2d9d47f0607ad13e6173ddc2ad8eeac58cd5d132758fb2c77159453ec64280b90ef0090895b6a9548313e00e73619230b31b3ce0c12c55a3a1cfb9441c8b215473d39aefa28c662fe82651d139d27d31974a9c4fb98036113dff67cbd4913cf773bf34a56ece4c1a0e1bf28bf89580a0fd6a7a768b067a661423be7b5e3531754c27cbb107543d8f27b17b7d100bd209c2861280f37276c348926fbbea054cf7c7c366661c4ebe3f5d241fcdb3994f2dee62d0a159c70a1a1dc008ebd41ba1083ec2de8e737734b2bfde6887f6705885bd3a4001acbfe12ab098ac432044aab13e1432cd4bf32bb64aa58c3c0309b01be7764d944538504e290b6d444a31785380ad48cbb1ff9bd0a48dcc51110ec07f67617c6c32230079e973fbdefa74867357fa5396f9b66ca6bdf801e56e29354dae12c8cc6677a490d38a3bf8a97fead9a204847b7cfff6d6d757ab8dfe3b1cfacf780b5efffc1bef060522f15f5e5994b6cdf40b2a6a83d7786aeb0656d0a654cc9804e8a1c5d435a003966ced5000194e01b40b0663f64c125c7d1ec8fc95e87c8c793b2e19b078b7d51aee3ee1fda579e88ad61302ce950404968ce9ec78f6c86dbe180c01b1a999d621077755c51df1c78a71e09323af7139aa6307c7698847d73be0d8215a80d2f25d46dbd5586b7176c45c4af613ee249229f625e3e02a65aaf024f4450925b1abf9c38c4888209cef6360b5a8494ab60d84593af397d11ce9d2b7d9e6cc81e9f202d9a46f0555713b5fa5a0b7f495d0994ef91d270f86069ab0a05ba11aa9d9f10b66a58f8b2730a11bb0f0378133128127a688c0c5e821b0856c29846fbce969890246557ff20310680e2d83ed02c60ae36c887004520a7c4342e4ab8206e6bc6cb05fe9e97bea5f457831129aa2a38bf0bc12878e18e3711e414d086ce314979850d8f8f17dff9da74dca0cc4be8d1e48f0803372328b16bf03d4cf9b3b9fd58ad6ad657ba7a86ed59cade8c2e5a26a8a6903da82139dea0c95b7d83a77cd121281021ad37f32ecc74069a2bcf670f213d679a73bfbc46251ed7bae70fd18c65525e45447fc20539eb83087f6141243843add558eb080b509643b21d1e986acd5c740dc7f346cabee96b9cda5fef9c51368b1302c1382544a879689da9c5ef4b2dfcd6aad1f1efe9e1f0b202534112baf81e66314914041eec9031959cdf1cb5dec3bd69ab71de48177c3889b1d6c0b5598c14902c90daac004f8b6dd96f8a4b5b8bbfa36c124abbf48755a857a09d1284eb1702b90b95b77dfe651aba593077b2a37c50b7409624d11540179f744a1294ec8764d5df51181346b7cfbe15b161490b387f852bf2e6e5d84225bf1fe9815f5f32d512776d392cf988fdb662c38ee7a0da119ef44e3ed5b21c7247fa0abae9f296fe5132f51cb56768653f849a52ea9b33c5c85603be5fc42c0cf536dfe2bcfc5d8ae2ec6d306c81f5a3d9732ed6b693102cffe57e6726562626fb23cd23ec16fe34ffa97af7b28e0b51ba7717c855e40ec5d0e9ca9add810e6154ab4b56663e5a940e809cd2da4ad49a77b99854b9e7514c36cc62223a20b7574d5629e820454f1ac4b68e0251bab893d8af038451e3226c0b9ec82179158ff7e60115bacca74575622b4cbb75fb2b5f1b0330ad5201019182ecf91128f405224bd00c3b45faf73b706f173811a74af9c58a49b7a2be24bd63da41f4eef288a43b0323d8f2f4dec815951e9724af53585c793bc6c2d3c79c7c6fad2309f5d06073632dec2053b1a6d683b63cdc833c664ea4f87f3d80f4f8a07124ae5d3806350a9e54561e6a5676ba2e74ddb34446b931eff8c44279cd2ae47f03e4005d49a3e40f6cb893b9d1a5c972a074d84af322862400871ca57cc054444179d9d05d006654fd029a6fa557ef4311386053c79abc5509749b6bf56c1d36b7c56dd99b74188be239908a647cf5e40bce1732bff0d44d92bd34600a756a050f9cdc11de36ce5c179c2b4b7c91850b019912bf7a1c7af46aa03c89b44365003c680d5baf0e98b33603578eb910ac83a6b499216787ce221a20b1f389fb050c36c7716fa5531172b6276e1c5b7b238b9b5b1b79121a8a3f7dd2b132a6d10c1674ae2f33a9206f564bda0638fbdf7dc0c12278b122e2f4a2abb0003ce028099600c4f935fc8e0520642ae8c9d5bc5461eaff5b0812edec5f8e16b68d708c01926eb53b0391fee3f197d2baa8c95408185060550aa72ccaa2f07da3f66a5982f02e2ba259edfd82b0f1ac37c7689b5e20e1ab6f219fee80d9f8c608487e6de3b68b40844411d34d48e6c90071b0d5c80a20165a26eaa0df1b40456103c798055c42ed705598a73ce72b16d50b8a74d421aeb4cf4eb513e270c4ce49dc426f974f50baaf74fe2776d646a7646b9a9a092d53c6684b601fe9e23d76755b163755291050ef6d9357bbd64df9c011ef2efa0bc1eb675742a6ad278490d0952f6e51e9d59478640d2e5420d283f8718663f5eb3765d26ad729ac186c52b10885883df0c05fa1e1f2d9885285a0f31c879d4830343e8638932c61d9a9b1e755836bf55b0270935daca5384f9f0664be32c333178170ae09393801648d731a14ae01262368efdc9db5a38c52efc358aa263488aba74f46b3058c2b8c63825dc04fa6e9ddfc513b98d3b44b7a5125cbcdd89e9a493e0d5d7cfe6cf208147f4c1a567de44dafcc374582b33b63ad591f93e1da184491dd34323131b0287c0591052b96f2724f786b247d0f2e84ef06b9eb3ec84ddbf007ff2a4050778bae8042822c2cca4f6960185d5f17706dc0dd0cf4392b829edf5f58066b06754c080acbf940dc245c180c3a24fe050458122cb86b0443a5c3cfd23d09d3fa8fb20921ca39224cee76c30761695472e486197c57c0d5f015dea8a2b6ef28a4ab2634dfad931cf542f3e714562734c61530be4755b5ee94a3bef2fea740127a12735652dad01429a27f43ab181f5ba3b2de00aaaf2175cdd253e1506cd94796a1ed9ddd91f77f6208d6d289d201b550fafc784e4db20af02b1ad7b9ab1d5211ef1de21c8dabbe8a07354e5df88ffb397dc1a33a35e67ce364b73788da56c9257f072c24faf20f7eec7274441ab255746108234cf4c2046cbb1238be01fd8f7091142ebc747dfde7e006dc5791d9b96d260daa023749c7203d97ec3618eb267415b80eae631ab8bb34bc285977bce8d2ca8754c9797ab24961d2b514337d8d53f2c0ad9c7fc57301bfaa06a77e13a28472bb10d719d3f4be902e86537fa60c277c4816d8a09d9c940863a5df4df47bd6aea08882a81d6ff8c7972bc43a191f3b37634453b9cbddb9b10b32b557104f042d0804f9402e364bff0e8fdc54b7c2e41d6bb2cf5110cb2088b71f8ff7f913da2a94cf452ab87e0af09741fdec670e552de82c514018ed6730440bdb51837c95c386a87783c34b8e8e45c7153e6dcc09d47d6b31f24455e8d06f8859e9648c60d682d153787467cfeebbbb0ef65c3131cdc4d948ffa2540a523fd5809a934f202849f67eae4258b862491543dc186d92523f57fcc7172fac45d13ea4fef75021c2a5474ed29dda5e4343d0b244d2d1a76d6987a591409b4e2368b27ecf408c2c75bd451571dbbfb2e06822b0da97fede35a07c4c9c3e0907f32d9bb370ca68b0c9a3bcc79ded755d83b0c1275ff014ce3229f88acc320abdf2685f479fad2e75ad36793f5f4191d66d69238fd2256de8c6f93be8ae220a2b88c5dccbf095e7ea1ca47a4b879c2d34150ea20dd17d87e5c78a03905343249ef57246c888c477c04a4bbcd7d3d779cd41c1777f223fda0720cb3398cfd10b83bb6e1c30822b2d68500c18e8ac48becdeaddb3b2dbaa21b787d4601dd3f754883340000e444fc21382a44b3f124230d5b812ac28347eef707f711804ec676f360416a36058cb5c96ebb1991acb4e1da8aa2999a19bc63296bf2744794ddbce3d8bffd1983229c1d9c24ae5bc290114ff3be4cdbd03aa3d29fd869cc713eb03cd1b4453374940f637536a49999447b55e9e11d8fdaffd283a0d4d078667ae816588470e9338b4cebfe7824e191e7f0df80ca7f13df5b63dd5ef96f411b3904e3a2e743cc51e9b1b9b0fd9b5d9ec121e7a93ac2bfc63b140c32bbb89bec79e3965b1362006e24c56fef19322967662eb5b9f87dcba0cdbe14c6bf64f1f6b83fbc2fa739e35218e0993e9aeb80bf511c9dcdabb62a27924ce5cc706c3eac16be38744a46a953338b2f0359c8ac9b4d6ca5a0d3037b5e1d281477fa0ab533840650ee9cff12cfef0bd0d2c8485539d4a55ac31a942038182e9d77f7f711f9b792ec03cf7d1ed63cd8e78712495279b5750773e7b3f8aac20d0097f5dda53f18e5e616b0d4930051fb2729a1b046bc6c0a732f8d6dd85723c0d8440bca9253a3c2940f75e4e1e32ca9d062631c83d3deff680ad766bef9ffb2e7193d7544691b67e6a071d635a2267673a62a673a11d66ac192836e84ea0aa2b7632750b2328504bd92451555ec73f39b6b766238336df17e97db764f32d3d2f215cd3ff079e677488012eb643b4ffc9c832300444393103bb974d946a9ba930df48beb29dad8578be8880617f3f00250be0d631490aa5684d150373159485c5c5f963fd5ccb57bca3794755ccc65c6173085b4ebc4fec276453212968c3fc8bb400ec6af6048bb882048af06937acc8ee07ff0aeaccb76471d70d11619bfe393f4b71daea63d38986245b985d772c64fb8f906ac913ba50f9c8d1d0387651cdcc2538fd9ec16f5b0949cefa4b4f0a4dd4021b0426453596345ee61711efc93ebceb4b3b67d47ae1bedab861563b448b4c6300e5ce234ccbbfd570e18156779e71d605bd3fb0b6840142c7e51064b70385d6dd7204bf15e6775db993807615e56aa99f471a10fe5e92ad5a4549fa1461819933d8baadc48e56ade8bf7e4a4ea6d71fec0ba5e1012043e94407feca5ced1961e3ef763e7e403a4587c982b1033698f2b6bafb940211c72b8d65754d38f13121e428fe29370f72236086477ad78e1384b9eca7142c1a8daff3a6e2596d4206720da8e9b501f71dfd938b1ffd40efd2a9751cd1ea10bd0a0fb0945ce57648d68e738f72dce8a2b2d01fd1aeefb9652c11b521b574da961975418b6b69cb9494db043ddab31555ce0897821e600e717765c33522bfccca9903c19efefc3a080cca3a0f4ff2f0c5cb0f4140f655c1774c23ddbfe3d7f25e3fbea50adbc77de831e463db7b96cc65726be8344aabcab0e8a91ff8f10cce342f181648abe15ae2fee8e449d9ebcde585c1e54178f3073f881b5c847371d2b55308b039e40711c4190c1336380ce6d8710c8b06b2ed11dece1ca0fb76030b6499d8e45fc8fa7bbc13a4f71216b76ef050422e9fa901767c7bc97800312fd1d82dad5886056c136354439550de0d36024086b3dc8528a332e56618f28d0e6889a84dc31d4ceb5b5c1baee71040c792d86f58a608e22a5fc79233351252cf327def88d16a11de529881a9b5775b6c061f49247af68cc8fdb5eb1b5340a852efca79e39bc30bba78add0df49e488f0fea3d51af0feb3d91de1fe83db11e1fd07302bd3ed473623d3fa817fe8d70015cab039a7ada805820cec24a074dbd1637e8db2b83ba36d027488e20d5e308beae2660f82c9090be1dadefd38f240f9e9db1f153fcdf5349c70528244f940012e4c29bd2a3679ba79217cfb4d9b2ef08848899434812b2f7de446e29934c4906a108080890073cd880244aeca22a8c47e4fcf3c492294fdc7eb7b7eb5e00a5f3ce6be71b2891ddeeaeab81a4c90f28a872650b196c2c4de1850c134a284dd143b295420c26576e574a29a54b799530e18005e72584f51bb158fe21458e1ad6bfa5611bc0a3bfff037f0a70c321e9012155c4346e370c8e22503bb84290a8a63f6c4984d0eae377108556e091500563ff84066030362c24ba9c12cb1d884072859c32368c4f22481985b03c0f685853092588d030b9a161b9f24b2959729d25d11d893a04db7523c99c84b3d1c6105a983ad4dac2f4f171e2ee6339830e8e48971d8719743658ede3ed4868812f832e64e84eb06b580dcfefaf7dfdb476bfba5bb5af5756f48ad2f768217e75fcfe694fbf2bab9fdf15ef1f7f75df60bf8ce2e4371f71bd839ddf244c50489caa46cd3170213b33b315363e162a2845c145183264c02813a7560003374c90e012c6cd1157e4eb151d943dbdc5f06b893b51b384f31a803368c0e276bfa28cd1c4ad8086d96d37633e3f05c32097bafefa9c60e7d2df364cd24927c882df22b35d10b526405148a8ce48926aa2399de0494dc2c2b5ae6cb5c2afc5cdcd913d764a9fd648bfd86f6904f12f8a40f225047f10295d826101ae8c6d6085200ddbd2b06194aaa10c185a5cf927e8703054a266922e5f1f93a6e9fadc38c6055f5c0358246090783952759fd25c9e5d8ec27acf8a61de1c71c60b1cc448a15af9708226283386c0e286d8593356feeaa3788a67484c5fd60891860c6dd0c4e99133c6d2b75fd4561a4bb4cfd9af9972b07ce95be1d1dead8ff16ba47f7ff8b7152431566b432eb24cb09e59cc6216b33e2c4227e8d51a67313e6c8867e0b7c0b75c2ba51188a35774d47db143946cd84c2d7be7eb4e2e7eacd73efaf19514482b4e9c38f7b9ced3b4197ff5130ce373cfc9cefbe4d758645ec97173ceba581ef3d4307e1992dce88404cefde04627245097b1303779f73756fb4751fbd57332e9cea4293751554f697a4645354bf354f551667ffc56af11798188bc128c112cd2390ec8f2248c1b9d6498c2b32e367e61a4e2aad85904b2816711883fa78c65a5a9a4c4c4cc542b7f9c7a85f66a317623acd619cf629c857fc37a14a9ae8c3db38cc34d3b372435f972ea6818bbcf95eef973ac366ee340a3ed7d0373f8d42b4adfa303e9171be61f247dce863c094edfc1fa4876a7d5dd3522314e9c38695cff16fc56d088fef4417f3ac83f2618f3a94370fc832fd9929c8e4c695918a77232626689f3d719d8dce834039a04dce8340396db4e34c8eecb89062cb7bbb9568e0ada034295305d7eaebdaeda87d957cc49903f47902fe5468a9b4e073d89cdf86bd2a785618bfcf8fed303e23fbd11e41b4dd0829593ae6c249d0d511c71060cd23445618401bc305285d39b30a6fc90c21b2c4038b1060a0a59114d42a8a08c2c090b2f8650218a61a10a8e1526807892040f5e040a667c4102ca862356f0e40535375071048d18ce88c253d0451070acb8e269862fa8549031482166c105142e40a451c3b40513152480a429cb17305fe264f10508072a6e0843090f52ae48410707aca4008397308aa82269ca114978216208282772d84245c914153e38f2c311355232486d21828c1411569694686a83830a114a0c1459105e88c8b2c587401ae2043224692203032da050408ca5a732b6b00163cabb2001214615306ea8a0d2848c0a0b18f3a68b163c51d1851b59d0135f9e805aa2cb1a30b0aca0c1d2992a284c8001a5831000b0028c0c6da2e8012a88146258220a131534747144155c5a600514497ec8a10a064d56088a1f39f092a20548c4e042050c2ebe05055254d218424c0a6644c4a0d2e6ca130d462869d9820549ba2083ca155108a1420d4faa8cd9e2044f904122080ac880258b2d9638d13206016160b93244162347040184d3165862e00515a62e5e5400c09b2454ac30419c24315936587304124b901155c6970a6411668d0bd2f05085112c3b4e67c060c3a50c324f149da93244941aa09466b8125ec1c30a7c0083260635a480a444061c22ae5062a58a211c0538e03c6103103e84810ad3fd8ea73adb7666f0d065072d9698a2a647f8baab2c5e1007cc9724b210d1c3dddd7fb8ee5ee7e7e3fe802c6450c060420c0b989c9a2cb915272867dc70e2431247b840c19229ef14c393fb373a41c1c2094a1431c926723181a82e9600238a8b2f667c30e3c4142a8c880367872154d8f134460c383cf12107a71ed2c8aedc50c6892c905ca1428cc2cd114a34ed10c68c35ce43bce2c90565d84851a60552f494616202198098b2051967f22933c514a82e5610058d1ef1630a4eacc06e7ec65881154b584c31f5822698297e54418c982885b41c5d277b1773b44f6b1db4baab2bc13874997dae0fd786757314f452e50d2996bfb9a59b1c267568686888abaf9fcbdfe5ea1fe65c663133357247c3fc1d8538e55004f28ebc4204f20dd860c3a130a2b92e877ca0030f441060fc81bfff5124a2ef492ca8e6caeb9f635698fbcb3bb8eef4c80c367669ac6134d2f70eba1da5f4230a11e80413d8b0bb2b46c24a9c44031bc04004c104fe803ea56fe9903481c65ef42315d766e0ab55a4aabfaaa0376c3e472239a9e09479f3a689372e576ea561dc50dad40febc3efca1dc9fabccfa261ebd414dd9e822b304639b5ea33604b354c8a80044dff888024ac3226d1e24a1108ca862e356625bd542c97f9fd690c147d7e8f221271cfcf7d445adb177660c8dee491e0be35b9a63da77d3e73305226bdf44f939435a1245fc87b57f224fd23a756dee4b319b6e7e05f3baeb4b4f26fbee2bd8493d441550a79a09c925346530db34f567ebcaea583384a55deb43368b68773d991348c05e724ada561ec4a11888d3499f4d24146f257cf2f651dd40426127912bf51306497922b77a986b1d4a6fc8c1936ecda8a94925407f1c829d8546c989f712d2ee322fef0bfa0967199cfb8fc47e4992924532f36520d4b4db1e4b0ad5c2d3c6b1898867153c39849fce15f555ea20a39b8503f605897336e9ad5b7b5d6aaa3617247c3a4d720514a59e5b681213fa016c531745cf90171834f83afe7e3f9b8ff74befb6c4ef82d507a45736a5a97a3f3f68b77dac8b1dfb09d0f632cc1b008bdf67da258bef6873200c3a1d80e18c65e6008bb21eb5a384069efebc6732ed7bbe6f3f6357e6ceffa6e998deff8026d3c0e30b4b2a7fa4c4b2db5d4520bfc0e5c7290ab6c50d90ed211b25dabb531c2ae4eecea0ce93c7b453a9dd4b55adb810e0edd30269babf1fdf84bdff535dff9f1bdf1f1adf1fd88b7f536be78739e9b5dbceefdd85aeffae8d7f8b8b5883ffd5fdc7e1d30ac64bca18a40fdcec60d5751c964526883d7e0c3da23fbf0d5df4b52680350835a415ee201c3d70d3bb0c8bcb6c87213a744eb73be9eef1b163677655a50828a3241942185972b5e082926d0224394186a60cd8cd5be7a1f1196521699cc3df5cb7df752264db989aa7a4a33a39a499e9afd132c8aa594fcd5e788bc70354e5eadca55fff68545e8d5406ee2ab31952290ae54b9a20a1d7e4083872718c841083654634cc1c407ce9baa85e2134b494949469a8d16d913a64a32e686ade676bb714ae2e58612895c72c9b20e72bacd3385aa04505748c98c68a1664d8f4ea1082869aac8987803a7477f53f5779a213d4b3d8eb4d3311670d1470a94943152ce4caffbc1b7c626c4f890d4834eb19d04bae740ba6491aeeb6a5fc37a698cce0a8f5cb7d6187f5660eca13daddac70854b5a37be4ba73c710d7a66ad663d3f1b0da334cdc8903b8b5befac31d9767a6c34c4ec1abcbc58f659618b903d8b113c7f6eca8377a310323965fcddd3b3a2435bbbc41ce5c3940f9c40bbbf13330629b9b59b692a258b9eeeefeba614413d5c8f61e1dee596e38745f3d63703112c55967bfff9cfdde11cd9a3802ed0b34d63451064d932d63a25461460a1410d1c41764bab489646801861733a67428630a49cb15a92c4ddc5459ea32e64b14d306083763b0592343982f566c806345490a6250831354886982818f335b9ad4c045952553585ac060b3458c23d2940963441962d874d1c3130a5220065406b2a491240822aa64a862228837606ea0810728353b64315305144730d9a10566f830830112125ebe585a326bf2e58d143c2c59c2e5cd0bc26862892c6da214416b5a40d2e66929ca940bb288542c10e38d132931f040450999041306155792a431050592113d3cb1f1a24a0f4d7849020b075928c07b320176cd4dcca576fe1a3d4cf952f6741e9a6dab885f59c41f88a3ebd58b70b3574eb0b9b9db997bba4f8f605c6b2de49e2e9925b717f41d0c27bf4bfef4aaf9d1ebe8d56eba1f31f7286b7dbdc009d28f8f62324b8b893e7f68a08c2e1be33b681b268bc8eb3fa34b1ae5ec33e6fc413f82e15cba51fa17bf460f363c9a4773e97a8c3d264e173899b061779fcec92ca8524a194197525ceda09d178e1bfeec365c3574726c8be575dcb6aa1a9d2e9bdf775e19b082fa8d64c3c048b2bd281ccfae32173edde973d5a646416ff797d47dba9be93238e919ecbc2e8e5bbf17f5aed81bd7c6ad5fadde95d8eeeeeeeeeedfe6ee7ea373775f551ff3a50442826bf429a0ef5ec1a8b1b3c60cbacbd8943d123ea7524570b58332989aac1d94c1ce7d5d1cf56a33fe8420f046a89dfc5c97ab9dfc6a5c6ed5c94fe7721bc775f2b397eb3816eb72ac4e7edee55a9dfcbacbd94e7edce5723af96d97abd1695fec21bfd5e56a74f2ab977375f2d32e6783c3c1e1e8e4e7977b753b5dcf0e4f062c097a04f29f24982db3a0f4d60fe7dd7eb2e673b32a09f3a74baed5fb62049adf7ddc1168fef679049abffa2ebdf3e937c1d8b07a1d648f650f5cb4c04ad3a6eda0d5f3ecaca6d55f7940e8afbe7a2368bfd264055d7b9e40bc11fc35309ceff37dd2395d42c1712dd7e1b2711dabd5aca353c36d546f18fbb8b85f5c9ab9c19d4ea78beddfe9579c32827b7a74b658d6e1c23a5c6c98808b3e21cfed79f49cdf95ed392e5ad52885648ff8b1fbedb747ea315f5b45a158fcf1bed983dbbe212ec81feda9b8418b77d150384cb9da8eab758fe8f918228578496a1ad357c209f2477b0e220b6e747a82e6ce20512b540d6dc0e90635577b1d1dd45afb1029c44a55d69e80a504261f2e48210e1c22851e267fb4a794ce15939333554aae6e3ac358acfb0db4f267689b45b4cab16c967c1b0c4fb8ac24c6c61eb107d562435288fb2dfcda7343be880bddd465178650e0354d607d0b7c817b1658e58f07beb07d07be14da5e7b9814e25e0dd328a5b3cee8fcae706fbf21f923b9efd508d03e7a25c4e48f86c586dc5f9086695f6badaa433a288c5445b4201d14dafb392088a8de341cdc840c26c66e30d958ff68cf7d0c22853850d39ed3945a882669cf4b53aef6ecc50a83994949da132cd7899a1bb296abb1ec6a3f3f075c81131432142668b11a38d8f7a148b26f1c996106a56e336c372b7152146ed641f1a5fcef8940f25faf57adf6f5c3f522c25783082459e81bf6f468496ccfe51ef25ffcf29fa8b04e4e96aaec1aa6446906d7228a2a89c104928a6ad6581b255d6ded2c16f953b380423936a4031cda428b392591e2cef99d6b4eed6a9144e9fc9c28f9fcbcd1a909d55dfd50a9e4976eec76a39311196ee823b7b0f546a724342ebf908f2653f227defaf5f40f3fdfb8d1c9c8194d92dcf0d5682a1763fc18dfdd3dc6d9710c235657ddc69c477fc1e2c72a7fdabaf69b07448ef0b36aee6037bbe58bce9e1ef3282accd97a130d8d135786b9f239af484e217d18c095bf7945d20316b4698ab3658d1459f408b2a899e20353122d3ef4e86e0713c6527777b743018557f956cd755a42e24a26345cf9114ac2c2684154d5143a38b18306945230450d0f3f50597124d62c4929a54be94337ec969081c286ae080f35c8ae086088d4550ad377fad12341a3715eda183676bd11e098a31437c371774bd9fda33d1fdd7e5b4a8f537677fb953c3eea8dbec4c5b882cb2f5e1eb2c1d011c2fa73dd52babb7ae6a41466b5ba715bd8e5dcbd87d5e970b1f4599e8fd5ede1d2e96cb13a5c727274745ceae8e8e8bc5a9782e105dc29a560f86376e3ea0a2ec6866e85e5b01fbe6a58efd95f3606791061cdbd3ac23cf816eba3d703e3acb4e3bc07749d06dbbe59e9af3ef975a80ee95829d3a4763dd574cf5d6b8bab8e8b41ade72fe2ae76dc71afb655739168e3589edd581eb76d5f8b8b44abcde3beab57d471de77997f933f8f5c3d67173b76dc5980cbe1e76a3133c72ef0c1285f14465f0ac557f8bad4eb3eeedb3eaac99fe1cea5af7d473baef4392fef0092a334a6872bdfbd4a9d73eafd5f67d8d6e473a55356d662fab8942ed79dab0fedf6d9cbd335e7f394f279b4e4332ad76afa31ecf1597df872b9cff6758064db6aaddd57df7d56bedb8b1ec16e4bf9b93c82dd1d282f88b8ed75d792096eeeaf99999b89047932454418724a723454a41b73d415f1c0100bc6d55418937b949d199d753ec56b0e6bd1ebce2ccc3192436774a60115a2e7328843c62561430da870c834a0a2333ac3218331b973dad7ef5cb81cf7914160bda7c4867c85b86efdc9712c66666666e6efbee9baf50b4fb8b5d3de7bef2b83b0bdd7018966803093e572200f1021ae6bc460e82222e354dd0d3c9a5137ec408e6d45a0c9f23a6eeb408d40f33bb08a40f323687fc8abcd1f5e5df7c40ad966cec44cacb4c45a4c13725a3c29634366e2136891060536f4aad27855ccc44c695eb2384155b39e1e1e26a058215436e361420049686c189bdd8ecd7a04901454c5d49383977c5aabbd71f8c26530ac3f9f58be2eb442dbaeb9f06541cf71e5c74b3b6052287677cf4fd77df9dc3999ee0aec0f86afbbc45ac2ba96b8fd5d9b353172c8dc1d8ad71cd6a2911c275608952161c32d6a8b8a443d54966384ca78665ed8500049b32b80a49ebb4551d916c533cb218b8383a9eb9a6a888be3c0edbbbb3d8f1ec2b7b33b4d15725d76a25821db8cc5840de3368b55705db659a7f4f2c1861d95d2eda8866cb34e0907d33cc3836d76eba5dff1e5beebc0f0689b41b17cb9ee30c7598b7ceb6ab56510daf862cbb191831512a7aed19cc2865bd4eddfa222514c8c0d6dd8588a44b1db944efd28c0e56d895b3fb4f1c5fc6297c1c7e24a63c30ed2dc0e62d7c652046a1b4bb7350a761ecc38a662a494fd469201add5479f703a83c033c2cb38716e64dd8eb162b1310681af7c03ec883c31deede57b1a11a45017f56d5fcf8b7edc0d5c0d767ecd91ff52c87b290f1085bcbb0f61205c1921c05fa70e183b148363e76b565207dd0a21f5f077f7399b58fc0b5d39d5231191fabcfa1adbbbb8b7d1fd0d2222dee360fdabf53bf633584520fafd197c75e7f5511cdfbcf1b90dd7d73558070c2debebbeed5b7db55ed7fce3f8b44476437afb69bdaeb59e88afb8fe2d1211e9e7b8efef58fd5e2422729d1589885c8f444468ebe308449ff57504a2ef7d3202d1ef3eff6604a2bf7d3402d15f7d5a04a25f3fed5b45200ac61d9e316819b9b8a69368d374725a2caf03c11adaf0e8e8cea76c2983165c7d46fe527e12a55b82081d149d6a90bafd0fe820e6da75e50b91999d9500d68705f09deb39fe1c85aafce9f7aeb23fae62315808ebc0f0397013c1a54f6bac542c4117fdd09ddfc1f9d29d32b3df091e75d7c94c298f8c01e5d163f418638cee1e638cdeb034de69f2e9cfa9b9a651f0a8bbf3ab26a53182ae4d6845a54bff5a5f2f5b411a935378f41863f418dddddddd1db4a25d6070dc13257feefcf1c79f56b76de33ccf9352e674d67349d9ddddddb2372a74645ccbb2778db13b76ecd831ce1839c6d76cecc831be4e11d17a54968297c51c3687bbd8dd52b66cd93272dcc969c37523497e00d7c5beb863e022171b8b74bc8495c1ee8b972fd68b0dbb59f90397b511cc625d5687086b85b0117ce90c613516ed7670b033976f5dbe43ab5e11cb6e57b7596b86fb584ae92e5dbafceee62b5ce4963e5b54ebb42434ad565647d5252e36d792ec6a297d524dea7491dc59e1384e82a1656eafc8ddfad046a037823502f9471df10b637352a7d53badd3748ab0b5d6ae6259753a32ab53840debd59159aed39159aeeb74bad8f85d04bda239edeb599d8ecc86f67a6df9b460fea3c7da9c9cc9e9e8c418298d34d2487d7ad439c2b10e1096257773338356a4c03949515344531818dcb0d214563a338605ee15c60c3aa04230db6664b46cb32494b0cc6474206189534e53e29415cbdf1d2014411495c139a2329f46723245def8a4841bd78d4e5092a8373e1d11e5644bce8d4e50b4cc392318c7885fb99e0f0a4eb3f13c9af376a26660f2e49348bbe9cd6e3437c8e59a5eaf5a59d6c4b2d6cb8f9b8accb0652d8b9a1333618cdc661951d4e206d90ff99b6421d2652f4d1dc4ccb20ef2c2c28c0de96032d4410cf28c4095305d6eeb38af88fbeef3fea3d6b55aad0ea25a694aa6d446298dd72d254cb79999ff475fd63c0850254c1e09fef2fd3d9ef287ffecf2e9e0bea1b6dc626630f474cc96eddefb7e1dd57bddce7bafc8d3220a3d19b7e3e5b8468d1af22516db545a9448b4009645a21a1f85b53f39e6868662b12b613c3d1fda0d5e8221f773e8c51f573e1300a83f2000c74610356554e27f10fb800040393ce8e00716236ac37130b8793161ef10cce4d7c881a50cd3524a29cd50a7be863a7535ee5ea4e6f458afe92815c492d0fc6e823b2cb06c3cf0a07b07db55195dde0e838b5555d786181bdadb45a22f56c990a5a2144ff507a59191e1341a6c34348c3855d1c24e54d85c9e1b9daa30b9de8d4e559074cec5539c6a82a2b2fe825b718c31c6186bb8ba46f2dd844eea31297bb7e4f19faf813ef8824a431d9330ff1ef3d33e2abd7acc4ffbf94925db63be045b90f78a08e6d34fa9f698df9e099c94d463be44923d91b0c20a2cb0f0e951a5907f9457e2cbda0d80f095ffc51f7b2a4347d571f9e398101070f9636d80931ccc343d81a58c24c8c4d853b5e96ae25afd0a0c7908795da3d58bf0fc5f031af645ad011d2442037ed2e7ea156d200f7501f4867dcf65d7aba76a93b694425ed7483ed2fd86b94ffd62e7d341d29b55ab5158665d97a3614dc150763afaa7630d8b5e510e9f1072b8eb700ae1e698c923bce4de6ddf71140c37bed2a95318af9cae4009bb9dd7eabab55bba5bb7da5ef341e16a91835b67124ec5552b0f5f62258f79020a1ee475575ff8721748e5e564e39407394187b9c6a5bd9df35d07511b3d94f34b2a1d726d3a3f7da8df06289f3e39a66192a9841955575dbddc90a953e57de4f758ec02d661d679fe960ec86e6ccef74a4a923bc831217351c5a1b5d65a0d8c02a34ad0b45707668030b383e512aedca821830db98a4d8f8b4afe74947c6ad8042553c3a49516ba0182107ffa7b5c32bd646aa87ea6927287084204e207532291cbb0a1a2aaa092428840fc892544200986d5ca9d558b1bae6a587f0e5646754ec4a8e853e4b20b97b59e2622843daf69472f0d04325d90de73f98b21ecf6eaaf9473d6e90ef200e1f147baeea0bbec113b9f5c60297946d07e6a600326330a5d910e7aa1832a23d9d1813b1ad67d7b3d69076e600368d55c08a3d4102ab1ea1f068bc58656b26a3564b5f2d5bfd1fc8625a943585b76c474d0e9c31a0472684a49aefc1795252e89f46ea78a0d7dae7d1733f3774e867cd55990737ebec7dce21c90e1b09e87749fdbfabc48e5dd37c397562da8edd8a1699a4f4f13195cdc6fd84e15cbbf238b0d2592db0f874dec1d3bee04976e18a93a898bfaecd77590e17415cb495509ba724d5b813d4839055d7bf5d45a573d48d5fa9ae370429078828e2027d41fb55afb02a76e3b0f3f92fc7846e0d004e6f1d1970eddf67cac2e27e930f534e59c73ce598f8678e4235df948377e8c1f5aaf88412bc1d087a5d41fab3b94a3431d627b8f759dab729d943dfdd3ec71e0ab0cfbdbf60edad7ad462e3bdbfd9c3d127c1d61bb86c58eb8773858beee5af44bbdd69a0647398dfb31bd22ed6dc4f9a3a12b64e81ab1d6fd77d3f3e11569cf0919baa108d7c803c3a1ebbdff0674bb50c7ed3e74ddcec6ed34b85d006e67856c78cfbd8d2fe7e3aff1f1b7f859cfaecb60e8bdb7bef0c301dcfe29c9b8f3e9739fdfed8b577b214337da9e337cadf5b78fedc6b92799b7f87760a4dcf4224ee3a66bdab7bdf5d33a084cd0bd76520a190303d87e4e722fbf1efed83dbb94b85e5b78f5dad315a594993257cdf5f26d7bf68ab698b6bdf6ab0d8c9c57b4e2557da7226af5fe311816b9b2f2e5f7c26afc77d5d9add6289ffee9dfbe9764f0bdb04b347430e46f7b8e3b28ec065a704363437faf9f517f91c6dda5405cfaf7db88d8e5569ae62ff0d5b4e7d1ee40369752735daebed71a61ab2277e511b602226f5d316ce5976b956082083de70e1e0dd3c193276f0085331a0afdd3af81216562431e1d3b44b82197d0b07e13a4eb46af2848e7d6a53c725d0a86dcc595200f101e1f9ea116fc1af10e399dbe06b6e03782a09454ba9c1281e14a1a7b59574e13552d275eaffee9ed4317aef602f76af2eae1aed2d7dd3e2397af9ed56ae555d0e78a75594dd334d09370da470d8c9aa6f99340a475e77791a86acc6fba0f394e8ae5f11e293e8d7db9c53382f7ac678121eb3d16eb0bbd1ff1769f7c4e364884e3f8e8d5c7dbd42ba254bcdc9d1b9da4545daeebba4ffee643f3bef047bc4647fddecff74021fdb3887a5fdcdef37e38581bc6fdf6c9db7d2c14719918294c37de7837fa469bf4b6efb46dfb7ae571aec360e4d6e7fad52bb7fdf6c50a64235023794cdbb8aef41a89b6a7bfda2251f7f4b948e4bd17895a4f9f1589ecd36f45a29ca76f2391ced3cf8944359ebe0e83505db0c8e487d3c811683ed732024d9f54ab35c09c0824bf5f27c77eac0824bff57911483eebf33e2e02c9efbe6d552390fc950e7f2035902da8c3920c8e8d58a91b76ddc749363a511973f949e01a29e9ce475ae2fab3c0e3ce478a40d168823c232ce0fa2fe0867de506bfc1eddf200467dd7e162cebf6b338981fc6186344e238b7bf1006233d3972942cf91ec78d78802ce0f6b310673782314eecf638b53078e84f5a9975c458c98d83f67e70702b4884835b9fdbba1889a60f7b8970958fbf4498ea560681198436c26dcf7974b2a6b7ba0881f9dbcb6ff5dbe71b7bfef50be1460fc8fcb0a5f723845b412221dcfa9ce5ada5b340d0b705aacdb6823e0f10faf3a95c3d0701faabe75bbf90e3dc1ae7aec0f9f56b5ddae28ba4311b21938ae21ecdf0134ce7083c3b59e570aad8c10c942a7a7ab15dc37838ed203543da3d597f233a5fd3420dac1da199a8048ef6543909d1d808000040019314000020100a8885229148301c2782547d14000d7f9242724e9b0a84498ec32886829031c4186088210018438c199b991100f9d2e0966d7b80bf87620cf1ca882827bae51464d18a9364808a6c8feeea19badcbf01025721092335a1a0c3a936588296b992a3afefdab4f9ed77634a0d9dfec9c5369ff8d122c1b9953b11e4297091d14df5578527a5f10332d7999c6cd65837838a85bc0c470e32b7abcbe1e530b5e86a9c7cc6d6afa301402dd1fdc328d085057f7a089410e92fc54cb3bfa371ff511258975f54f6e81de66928b1b9d3698c9dbb1f18cf17cdb88ff58ca3c4ac52727b21ceb3ce70fda463e45a68ac7abf223a78d7547c7aac9da2d2330c3c44c821413dfd1f9925923900a60ef2d05cd2996ed33d3e9dc4259d47b450672e11d26b90aae9c7e966b29086d68ba1ae0e30e64170ec39e8d078603985ccd191b0aac929c2fd63f85776ef87c0024ea528007afb730bc10061ea3b324523758a8435757ea655a414ecc77b9d44cdc2a515ecab091f4c9e4a7f69a0fc29749a5ac18c9e10c09dc3a90d6a322ac22d4943cf3f087acf34d386264ea1f04600f11665351edf5ec9783ea1a197035de640ca1b63e492b2e31391645e8f470f643920ab2ca94750979ddd40bdc12bc91d773365f656750d137d02d260cd01da065e9e482348115933e3bea5f6e5d965e2ebea4faf9c6d2b292bd4e072d3f4d956dbc84431680f876bfc4554f944915f469903fa59a38b1e4cc2ce5d1417250fe936d4dd9a0bb6458b1378f2c670601bf2a72774de07441b5e2044d7991c260049ac8afdaa9bd68bb56daec75dff0a9aa4882aa47ceac05de874085dee94c1a08bf125ec73202eb7481027d626dcce337271255d2bd069ae4795ffb4cd6e4bc5725c9a79044e7485e5798972187789685e55770caf92d69bbab57504ffc7fd8e66b9d47c7c25dd5afacf366fc7a6680f942ee42a3d885b4e71e9544b34f4dc5a7a75b58ed8971f37c2ff7223c33d4fd9b899a9af5f410112cdca39cb9f5225297a7a598d86aa8a5b59a54d95c82de52f98ccf708b905f4a929ca5fd40c554c51a404375c572ff71d2c7f959f5b7d6d2db3136673489276b16ee04efbdf69128ddc8ed22c9fdf7fee8b261cd43184a106292b84a1df8fd44218de3b0b9a8296ddcedb8e2d7982810d407818d908c8364283d2ba35ac69c33df41a103a8cdb28a083b0d10eb2243d69423547501a32ca2dc86802bf99766db955d07c7cf41bb4c15d476d9c22d3920810a619c411bab78a3e703b0d288321609f5ad88adc2fee4c8af6347db640b17cfa84f5fc98a4d37eb708c37778144563287184a1e0add8ef536f037e8ec0544d872b326d9525e9a856292e25844826f41e64eff95b4663c3a13fd964c7a2e3fbc97b27720e701b1b8ce0c50653c8dc20d6db12426163a69cd9602c038c5a991b2539f6c0994a3378fd0c9859f4e6617c8ec1b76593baf31c4ca65baf3690d35f538bc108cba63a156c77ad1b6b7d8492729523886dbd0bfd4b17a58db646aff58d129f4881774b7eebbb9cf033161a649332bfa11b1412c13b1518346da0f033e45e4760a4d5d4749f8031d676b059e1b198a164f7e3aa6f88029197c372d2f00d481aeacf3949185294f43e967158f76c12d1c2f2855fc92bf1113018c20680b8ee8194368c54fc87c480d15809dcefc4c79c36c80c65c88869318697e634fb2a7245ec1da81d537c5500b181b461b6f9d6a3eba62cefae4a12708e227a12d4086f362c9dddacadb28c1545f5e90b2a579a44f1c6cd19da8b99e53cc1380113836bd4d809dd517231864d37448e35f0ced48b223629eb3623e1858b86485ace7e7e445ed98778b17670fab3edceefdb468dc4ee73051e5ed5773a0a78b9f879f9c3279b6ed7504a613948f51199b60af50b18c4b359d8e365bc39e6c091f73f225a489d2290b120399a418dae3ab1801ec19530c58ee40a8c111e51d09e7c241b598045f52780e6f8f255d019f78b38fa582cc69595b56269591e0ce04656601a1869f792009631f917f18e9911c74622e421a31a854d9edd2180fd118a29b5a535827f6a998a7aad84823d62bb1227b8f03c4dbbb61e70054cabd2c2ce5a3c994a0e2ea746a9afb72da53776e8cb2008b57ad94c2b606215c750a399f886db6bb94ace603efeea2d649bf885dec950ae5dbe2af09af0e47a52e4d774f17070685215c5a171cd8b54428cec9ad4c6e2920bcaf4bb6030939978ebe478577a9a06049cb03addf8a2fd7dd032b4c539a67bc23cb53bab896363f500c7969a9ff0662eaebf68c11537059f28fc0ab46aa3906a25de1a20d75e3cbe3cffa292105b0d8d62c71c75e57509c87c654feb186d6d5d161134cd3a9771b7dcac7b7b3b02083bcca3e94d9d584c056684b07de9c7463a177ae687d89d7c163ac664692de60a2d857c0ba365ef1910b86a3c0902de74dbefd52c0805230602b72392d1b1e81bb2ea60be6f6d929f3b168b41daaa53538de4a4989d930296965dfde1d467a3af1fa78ee3d5e38f6d2327b9fd6b0e9c562de6fed670969ab95c2314d8131e620c59b650b28ef1ce0f3c1ebcaa98952905a36457fb14aa2333e034521f9b38e051e86ca3508ca511c15d5cd4d1353e779a68e7c71ffb7137c4b0bc8a52c2740c4d6f98133b03e3224ab802470dceb5a66d1a6017c91d449ba1af23d99e70342cc0e5696fab5ae7091a0a74b6e7881143aa85c57bbc1a02ba6f9cb009b4a299b5fc38c1f14f355ac5960747d429cc80374a06ac659e6a6c74ab09120b0221ef37cf48b0e0ea097e7fad34bfc2a9bbad4421d3c4f1ea4352f12baa18e67e82f74bce60d764608099f8a11c8d63e334482671078f66583410effb00ceeefb59170ebf41eff3194ce84717ae83c6baca9d4d853eff0625f3fe8ad5df517094403b96e6e4920f5257060f0a212ca9a774efb0ab5564a1852c239ac233263fcf10bd8b2c83ab69222347ff70e78f4f2576dcac78ddcc06bfacb120802c612815d99e987d97bc3fd8c293992910b87bd8935ee4e136971d14396a26aa3a07c2547a86395b511f1003845234b4b90568d2201333db964088686e6df7fcb4530e29c3c3e9bb24d7f009188121579839ce239665a85930c1ad9e3bed35d41c0b7f40d0226ade65cffe87bd645d5f46e11e9a4bd9c6aef66f6d2d0cb7ec7c19810fe56f3543db8c6f29f655b8a57dfd0556652152dd554ad1d24f79f3bdd93348cbd8669d604dbd3657c3a229d768d1deb25ef7edde15ae2a4dbb93b8d5fad316273459c9befc742b4a4cb8a221b51bb67516a575064215db504e686441a1f1ba88719dece7931b4545b80c93ed25d651ae8bd0e3eb4140957998135f27699822aa15699086428df1d2594ff8c13a64c4312c1133350f2076bd724b14ffcbb4bfa17e0ba0184590c3b07cb6a0b33ea01591624f064ee9478627ba4a8787d826d85f06213a691f0b821959f3c5cd52322ca4e202909203a5756a0cea3d8dc917859e4783c6a8495bd1e87109fe866500400611ccc642f0991e86d00d5e78a11513313cabe5c178d90563428deb404bcb3b65e167f226ced9288d53dd753d82532f82d03a3c32d2e6c81dd1619b6a3e1b7ccfa6a66af97211e1be24a9c95bc56c4f348adeaf3ea4b784af25218f4712df57121fd7e312157a1b9aaecbfbdd92ace2b839231e77d914b53283817971a00a6da0e6d0b2c0420e5324cc15173ee5f8355081b4fd59db3bdf489fe6162e49c511bda21675738145c8b983e4482423df301bd19ec2a2f6d4197b8ad515a8804e8bb94c116db1119544a73d5b551833d5a412c8c8eab0b749bb6329a1ee8b6acb9ee6a759a4299f54d4d94f1049e090473c7c09d967b42ec455e7faa2f7107420fec90cc596109ee7c040ce2633e6d4a878ba75d75704ee6abe5483eda009df6cbb247b67a204163e8391ca606b5097231a57eb1dd7cb9f1a1086ba13fa7a3fec9cc42ed37d1cf25fddfd7a98e8b50570eb1c83ada4b75cedbd21aec1fd9a8aed53a2fe133350d6fcec562b0ee414a3e5b5a2d9a997db169a3b39fe759bb439f38c8fbf4bea07a8492eead2f39d8a02e105f885563abe73f6184fa28e5f8a83c101d00a5e75cd3f9b55686f0c4174890d2f050ad8e7eacbc653fbfaa52381c7e29be85d2291998199d4a13e74f7f57efa769522d01492ae606a997eca384d0d0bb0d62db5e3ed285e9e11a1c94a1d589456e0ec73d105364d2d67cc2a6d85aa6294ab659c2ccf6155191ec5424a9b6e8ce3ae796151fe805e672438fce84b018204801a5518ae67ada80992379ffc3b46964e7f14e1c2c558463f42fc6e34bb4726945eb29157d1f09e95b3de00808806ca27bee687f389b17c0714d2ee5ac65563797b60c0e8149a72634e75aeafcb1c62daac716e844a83a1d990b9511b0601c85b7f9d8469e62466156ef4bf295b508a6d1c7711254c60f6a51bb38f72292901913ba0b3544cf4884ef42f368fd338f8c1e70ea5455fa203856a221205b69ff20af0ca87778a2f16ca4bc1809d5e42ec1474966204e66bee960fa1dcb7c903489609f250e6d63780905614a381d5efe4ac68b1b8feae78b856884bb04865324706d76da797ff2a2b452b779768c24d55066d64be553f5e948ba11af955af1d89b4a1281c46d71704f7f28ec3d475220aec5708f6c354a0c6a27c0c8fa3d36d329fd096496645070d233cc4a73d395788e569aa8cc857b82e7a5903ba9b43fe0caa153d20ae2e80c96b11f082a1d268c07f3397fb4f126b30e68bcb26c010f540926ed85a7984a5843d79d8c4c31732aa01ba874df778fdd21cacec4187aa816395d4d9ab2c38f162880626db55cfb0fb6fd62934e4759743175594deaae680e8c7000cc3204b0316712d6534b113db47aeb08c4c33ae5c29db42b916cd2bdd627d33f8dca67cb390cfa80a0e6aae8503322c44fd949b5369299e3c2b7baaea149dbf08ce3f8268c3f2c63f02fbea714a15e5efe2484b61384124c2d30c1c99fe328467a6e8b2196737f644af829b6ef1e170e9b44d49809ba8d17ef7f4185027d3dfd627ee873b0bb41dec9149d9635ed6834648c5563466488a935016b13a23f21df1c0129e58fc1984ad951261f057c9d1296d0a23dccc7fe260d87c55b74978e53ebde0f3259a550825245cf9ba89b295bcc6f0319dcd6b244ff020fefa49d5287854655c8e63abe002817694d7f5c61a308b495e46d2ae73ae2d812b0633ff74728f7841f0b1011a1dfc7cd7ef5adafe9b9a496343bb7d423042cb1f50257f2a5b5964680ad5197134b10c8fc0804fcabff15d8ebf2870eec7da007a5b6be1bec3d12f38a5b09ff477140d0b5d132c517a35e7d1899d34d788610ac3c1e733d42a76fc3574cb6c9600e2357c4f3610a1fdfede6c5413bca649d378e71fbcfbffc487ca37db036c929f6e03400d438b1f1280867ab3b2250bc21460bfa65893145e9c74e6cead59238bb254af859951d8bd442437773038d8cf160991dfe97afd6d4fb797a9737200c9d34a9b2609c6b710f25722f19ff28af12640bac93fe4d05e1111445d72eb1b93e5c6a688c95f066979a3289fafa1c59d89c25c4bdcb3bd6c538d0c5295d11c7e8c0cd9adc498ec1fb9ad30522449d5e9af42252a55c43952dd561a68542fb367d234fef6f01f57999fe8fff7c8dd4b552a882a688d8e3e53acbf2d9444df2ec8a6b70a7f52e85f458479afbe4c3746bf2c95cd125fe1406e16956d00c0591f4185cf08db9d23cccca2899dab6bfb40b1f81545bf27c49cfa782e8ba6323761878df1f98f2b80bef95fe6c393371f65cab8f9ff7e2fff4fad466764be759e35d0f7143030b5b118e4816464509ca23c5bf55648464db3f2410203cc16f96c368ad24c3f21572d4c10f69532fc3461d404ee93e8634a703648c04849de2570cea61d0e37d30dec7093a41116761014036b63d3f83c212d05f768a57124960f9df9a7dece8be551ef6178d2a02f41a286b6712ad7e0f9e0b7ba9256346ec0bf7d24398f68e78f8d9f7d4fd2935d146425323bb35b05a1197b2b425fcf2937189bc5f67c09249b380cee0a2b1e1c76bfe8fddda5c48051b3603b5419ef5ef4ee50660a39a0101f18175ae86cbbfa146a74c1de8de64d0c63100efa83975a1338492fb1f77c5a0e268aaf5e9f44b645efdddd6903fe3bfde48a261d2f9723b016f70e5b42467e3ab7266df895ae31c7b330771267ae1037b523fe408e2192a6907fb5fea6efbb098f049b7c7183ff10ff790cc9d2522065b65e279aeb219aa7d38b21eb4efcfc5df805817ab5e9d7b471d6507a2e4f032f19ec0bc316d4685bdc364c1687d587c492cb7086747c9f8f6f85f6272f73548689fbbbdb20cbb3ef9bafe1568b7750566a529f698e4d8661749fd125880c3ed1c0a6f931b43f3dc43ddf822aab6e80b106740d1aa236ad2d1a41d709913f07d6664aa0171d17849ddc0a8b0ea71cc66cae39f3dfcc6b88a36f046b923ec6d1fdfd265c4b448677caba57d3bc5fb2ef9b64d30431ed362343926e0fc3f84793a8eb38f469cc5c934dd81ac296cd740cc84056958a4d85645dd93056b77eb0ba062bd412d67d7b87bd12ec9908b83ad6f0474b12dc2f20ced09360d304c08deeddc94f13639f414b65047c4afa691b95f6b730efd60c0f7726d1750f406a99165209dca46a99531ae2905c218f7df7701b64526e1b5e839f638e07b0cd220039c7808af900566975d2dae3381d1c6c9f3af2b3e605ebe2506bd839b42b25109ac962c1a5637c2dbf26faf722d0253e9cbe248b6ec43cc00858b394a2c9f2bad9c0e7dad6b21a54131ad9ba842ae0f5bf4db2a837fc84510b3eddd02d1567f149494af95ab605290f4c5947990cf0a5dc318c8aa06efd562fd5681d0ae6f08e73255560f06a3354b2a2235c68adebd53f3d91f39a9501a73adaae06225ecd56946681c1ece46224b65bd95ad0b8485dcef550cc634c1809446364dca7b515552c7890a348bb38a32f403e3741474adcdee6269dcd849230a4e32932cef491dbd8572adf9dd507a830c10f5b4de8f05e315eb32511d562306f557a13484b56eb780ce04d0876b9ad6e2afd832179fcfcf06b506c8d8412503371267071d85909de8bb147153061453ec8d7f575c2e9d1512d0bd93136900eddbe59be86107a6c328c6e96b263725108d96d857814cc1a05d58e2c263a3cf159c3f6a7c14d818a2706287c6c855388960a99ba2847572ca6209185fa5126151a588786fc099d5c6358fb900b274f90a1b0232eaf39431dbe07b029a571d7ac175edc9c16b8b9c3c57996450c3072c1d98781bc68feb2165f2251b33f68eab9f4e3bbf5c379aa001ca31fe3961fe03f856948fce8aa2be1f885c508b80fdf509d73b38f39f0b6ddd6079c747e1ed347ef81d15c952d997905aca7545489221195dd376364458d9e89eb198567b31d20ca5136f549428d15149135a36a635c55ec08cf109f3ccf13d5a012f4e780b46bacf1550d041a0ef1f2206cf49c004211404824d62a54a6441931766ceccdf42845bfb0bca5ce7fa97caee1221da9df7e8c7915895e58d60fbba2881bb2a2b66d2742eef504c4eaefd84cc0c34f9da5873e0e1a86fabbd734f7c2d0174c1a255dcc50264616b0771ed4837640b9600220204bc4551e14a2732d627cba0536c54d8c140dab85d0b8d58955186d0599f3dad3697e555ce03bfbb370d73e1713254217c8d0c00a0b81f777079c553104eb9d116cf4047905cc22bcf7f51da3f3a99ea8cb8b9553a62a1b59da438c774f8657bfc11417d2b34098077d70fb65e428a529a8f77a8242608c3df4fa5d83a34f4ef36abc5ed9e2f42fb26af3746793778cd562a65a38fd8980fcdacefae26161feeb656c8640fe8b3a50faaf71a0fe3f4b1fdcf85b44943b623e41fa09310941f8cc21d9d109c75039740c901e834d88cfb9191ea2db4ff701f9205a8242b3ced88b81ade9fa72892dea24e3598c566c7b288dfed7268acf94db899a4c909f833468ed0445ff87baabb1159cea2b1f21030f3a216df134235d9c1c9401ead39653e0c3fb08512730d30741c8758dcb9c0484866c7cf4dfafaebd09e08ff131294bd6ee0fde71d3f40c82966b9ed134ece91c75aa6047e0016eed8268a451d9ef6cf002337b46f1b7fe1bba7f4309c444a03c82ad4948f984af393ab0c64794143bd89095748f8edb8e0ba6f5fd15430617583e87b054db8202719475641cebac41116971656cc2cd282407f63e078ffc87f6f505a8963891e77991bc672d166384f37033d0b9d9268037ee20a1948dcaadf9ed59b1e920a3e13c5d117a21dcc571d70caf4a922fe3e766e072c2b9e21f0b74b04e5e39b22289aadf6c65ac32551423327755b3776b86eaf51a47036a0f4c6da9673252eda3dbc45c5262580e0baf9b1c5385f14945dc24120acfa98c14567634bd33d4d8aaf8bf37f6014624d5bd504ba70a0b2d8ca282af2c367cfd5b48ae431c3ac5c817ac3674022db9a66b0353588048f257736d37d4310eeddf4b3109915c32d4d049999a4ab290e9e574aa4bd86d55e86eb6cb230ac6da9548219de19a4c59876b1b3cb57e7c43a7db25164d6f989cdf1bc6f6790da69b3579a07e95163e186a0c0406191f4b723f970aa7449073a814879d3c2107a393f4b8d3a5590bf7c53eef20d2f887ebc475d48422d2d1d7c4a0b1602edfc2cbfb67e269c805844f5f674d4b61209f810f24aa74b08a8b95e7baef2369348a25e62e3595bde3ba2e2c42fecb765144b75c9737b411dc7c97853711efc48479074c3ac5ec8614d99580b4245494c74f67c38a90b6a0c28a9cd288a57ba18f42113a33bd75661add9a63bef68d9017a27fa7bf33b500413af0032ad1df94346f014303749d1c2bc18d830399cfcadc39ba6cb7be439f034ebd4e70f96d1e1abbd91554c4b5d0e7a27f897b66f914edd89b9712f4a73fa0f8095e4c5f9bbeb8cf1d38bd6b40c143bcd850cb8b59a07498b162fb5192bf2f7cdd7541c43cbf1fdb85f78986df00790380fa8797184c09c5e47e510fe72d4a691ac220e517def0d132947c4e3fcef90cc6ff6827a5d7f9503712409da406589756cb5403eb042b5514fcaa1c26378dc5578b55d5ea39bcf881e6d072f70bf37313142c26b75576ae333b1396be2b4ab08889cfd8bb73a6dab57700821d132ebb032c59a6794ce14da889d5d34c991e1138acd9ceaca2866b2b33c6526ab6b86323367e314702538b939cff0a753643c999cd5276601aaea3d40198d0172f6c7105e4355ca92b8059289457a0ec639009cd4a3d2b6e72d23e73e76b3c30908cc95720dc109dea83777956d1325d3f3ee63bd1db5e23883c5908025d1e2428b2641608a30c88415753be784777f235344084e83ad08bbb9a899e7b3d66b73b6ae7a210e86f1886a88ce6c4d6067e9d65ec4e756bfa94e8793efab25761560a5974ca6698600b1f8759dcef24478608a620122b899f26fcbb8a4269404b30855fec8b0598ddb314342428895003aa2cbd07816bfc001ff64e6b69f77d596346dee52773d58a1eef5062e8023657fa09a6064ee291364d1d3b81fb35065788509128422ff1fa9304605a059d30810415740abdee4e720fd4caea53328e97ca1928414e6afc954b079bf2498d6d0b9e65952aba76b2f18097f70e0b3cb83aaa0c8e8e7c963c49c498378a7c7a361cc71012355924bf7208514611cb8e9f836be8794f0dcd1b2dab37798d596a79ce9fe531ff6cfae4a552c7a5cbd51730231d63c6810a5f5b531ebea804aa128c770d6c5461247564b9988ce88f34d55b99b709000e3470be8733d4ffcb56091f220c451cc5fe8e275614e98618c2be276ece15895256f3a30a52f4080e35c2b0ed33b392a9825eb46608119b0ca0c250720d4950860b44b6fc70382a5824017e9ff1a7691316d405929cfb7c1967fd9061370a185ed8b7d9a04c958ceb752d863c3b7551c718df2a341ee13d0209e77de0d5f07acc830ca80b488244f19b58e9e6e489febdcfcfc32df44ccc1d9db57763f9bd4c4fce2a58a7f82de8a172224a8ba99b2c786749bdb06cfd19a49917a7bda14178ad2e70353378a289b9607471dd334b0a482b162d0cc3e64c64ec750ee952c6850d34968cc6e372ca0e2c12019dddbb05a42ea3865581122ee032482dd1b0bc562a2dd8981af201ec970e95dc4f08d7d4d6f49dbc1660c6e1705b621a8821fccb38391e90243946115b8d932b5f041483c4a8bf71250480a78488e4564cde6cce93c6c3bb9b3573885333c1c0253048d3dd73aefc3a5a0d7b5675b5f10bc74760a7d2a97b42202cedd29cd06003fc1e11957d5c7e46c165e8ac3338f610fefc82533c807c272fa32ae98ef26a2ddbc2889eb8532b38106c9e0243948e2ea28cbcd8b8f914db1ab34466b38db065130e64e5050dc45117cb4b7e1c3040a8e0e1f220a71597bd812de11c8116e06653fe98877806accc10f71585bf36c315cc9c2b7f33cfdc9c3ef8619329419082d206d34c79c4b7dc0e39910fcc31066c6e7ae376e71cc35aeba410cb22aaf12d2dca69b78af4c83da63e671d9507e89d35c747fb912cb285345a16a0b342d50d347c2c914079432323be310f373b33f9d1361563683f9b0500119543fd5c3307c0314733a46611fb6a256cb981a69fd3856cce57ed5328d07d5a1008e0ade13ebc9a64f08bd8f6aeb08b711e9c461a3a178ffbbbbee039e069c99ba20c5836fb1c7012422b6f2d6b74405fc0bc6709a42bc13e86ba8a20dbe3713f52eb014ca701bbeef4a0b891d0ddd2d7c1af20b7a9aa7e1f3acf4e2fe481a1691aae25b3b6e583e94b60d3a27fd79dd76a645e25302f87c40c916239db8b4716d7c2ffde5dc711ea13612feed637d31eabefc7fc163f1f9bcc285498eff66835e36af518e8d180215ecedb76d8fa0f11a67013735c3bdf6aceae9aec3105e99df212354d82a557d12cdcec248fb3db5ee88fcf2eb2eb1dc185ae8d264610f09a50e341db7f7ab7317ab0bae69870e23afefcb6872ab78006241bf10e3646bdda9a08d9592e891ba77629c8557cc64a9c185723da2d0f6d115b9f35440f589543c5a1c9a0a3689d42aa3dd551a48ec3bd06fe0dcbce18e15f8f82864ae9079e833ebb4547d57ef61e4e84aed93840be9d38b4ae8be687c1bce5c8671b3b0e889c640621f7e432236f4c689ca64c2d39a7254f45b030991bd623f054a5886dd470177540bed13af51aac6785bf18cf687f310d13bbecdb59d2e14f528c7891746e1c3036c7bdfcac68c16e1b8dc8a91f20dc85f4111b451849db18f0f10b38c184e69fb64afea8dffcec79f26b91701984336b4b031328298ac14096b59f53aa5357033eb9263066c91b5d98df69897c9d6ccf9fea5e2ed702efe902753389839c06a9f65791a3c41107ed5be1b30a48f48d3961fc1948641c0668a35e7a003e59860752c4cd9058518339e198c3ac40402871d3c440c40e92c8d0bb935f407b118ed400b80c2008d12884ab40c5f6a3a2d5c866a3cf35bd61988e25491865308c61d21ba28fe4fd32cbb1c9aa062fefd97b166a4685b749e61c13b8c1e82195299b56d1b442201cf5d7ef3f915cc20a7f1de1d140469ab273a1c795f4489b89865693f0f2691494eeeb91de93069b6979c71e40e430063056c373f9ef1f55ec10d1a696ba168e9ee28dade51ad9f5ab5f8fd18ff36fcc0684c4256fddf9bf1e1d7551c1fdad26fda83a750bd2e370cc566a3b775635d7f049989954b171b03f48ab5b1e33f2f1552165bb790d146458c99d54ce38c65f18723abef30558c0d063ca7aad694460d628059063b16315492a9231095b94be6ecf348bbf948e47809f6fc2583a382374139650653da3598369522028511f890411e229ad5f3ee6a1292f22a08dfbed0568ca04267c0228904f3410a47cb1b1368a55fb296a7fd8ab2c49f14ae4a45450eefce5326c5a1630e6e14f179c3f4928acfbea5fc7f8a803ea264ac5d67fcdc176dee0f0d63f2d330d0664b11a74311488d83d552d1777f23b604acb3dc8adf54e4a9b49be72f572df4011e9e63edbb7da60022f291104a009e4cded9b362a16dc0b9d8bb72c447349b6c82d56285dc961c524757dcd4821d136b2ccef38f09b994d88d4e2ba9ec23b3f4a24c53e016c5deb0dabb305597c1342a701f8db137acd393eaab07cec87fa80b251d78b18dbaf904aeac4afec8ca8a2c15302ff9a1e83bcfcd9e5ede83586e3dd05cadd78ac4c3f5e2fce8b20e9ce9546c19d0c51893989895000e56dfb03ef37556966829be310b0ecae3ba4e25c55ce8c04ae0eb843b9c1484fa0c0b9226a2710fbf7a5fb9ae4bc20755b2890973603bcfc629037d35c7776f6a28940cacb2f96bc1a9df949b094a90d7c9fedc4e28c6fbb4498c552975b6f58b63e2b3bbdfeb9841170823a8899ce7f23560f81b8aa64f70f429f0e4f3822f324d8623de9b27d4969a74d55ec643139143a0ead3829e5da5525ceb24fb6f498aefaa0f75901b5f1d20e6aa877847600d04057321d1aa74071d231b731f6b4f8325ffb37e14be380172e0bcae1bc35e4a2dc22aab569017ecb3098381f7f16f636b6e6a5b59e85fefbd648ea8a2f5e501a95295320319acdabb13fd6648da3490d745bcf93e00561c950ce6866ff8eb015e71551021feabef0429dc4b2003758de2a88257622a6aa73381aa16d6ff35d63edc9e1e57a62a059ab69e767ed0e62bb6475338d5876c4c6d52e6d307088f1cfc9ebca9b942f987ab8fc06fa7ca68e34bb2d714402998f7fbc39273bc25a17550debddb338970e59e36543a4adc3ea2be41fceb5b46681a72ebe486186fb60f501ece2f655662647064845a6dcc9bfd3d372f0c40f8823e42464c7d5e2d60cb945461013bb5ea04bb23f797e82c617a5d4d2223fe7e6f8f09d82eb45368c2ce18a7021f8a0f7cc91899e8d8105c9cee3f83426c3b2002cd293931651d9c9157428089c847cd52ca6b69352e29ac6b010ba3e78708be0ae5bf7ad0d974f0f572d72a0983498767a65fc4b24a299bb0ec4b4d5a15095f58d0119d20ece2fc17a63cef07d237152ded77a788d0b1f271035b88822a18ae72a7f2d389ca2eeb12c1b3d459856c6b23226a79a0a47c338448e37889b3cfd701124d33bcae87006299db4b1b9a5a510f8d309819aea31ec24a5460fc6d8a64f62ccff5767d9cec1cbc8932ea55f511cf668dc1c5d43734c701b416ef1d774ff35cbc3ab88f8c3d9601393cdaa071b61d131651175c342c3d82e6a8aeb598ed80cccf61540cf9f38ca342aa0cd401d8186af6fd71142ae91d2fbcf1081f961628781b96217f4f5135c09f6f5b38c99bf94d711e9fead64ed2d1f09fea19d75bc170f323a9d3022b1a34a82b71714a6418462a6f08c22a38d8535c3bc6230fa15781eba2c926ec6faeaaa2b2fd6052742ecb5c14c09941c8f9bdb362917c85bb1c43e3135996361063184639224027851dc500c461ee6d490580350f9c47be189cf4fc8207c5a88a1b9387bed77b4b442cbb23585989196bb75d91e13b66e2490223fc5598b356ceb2ee703ba5e61cc1153fc637b6c7340acce40220bf6afa51d05daff981ee3667b03cbe633256bbdfb1821247d356c276f32fcfdf7a7ad0aeccd444b63c2cad2edb35bb10e1f1bb727fc9bb0ee0aff55b1034b68d2ac88a08c8207804043b1018ec785df47a51c10f8fcd9b59a68295e0216a32b6a6ba9e07b17a0ff081c433ea8a9b8d113ac3ed8f30ffe38a96ea068ef3fa850c405c98a14d4126fcba1715e051da43df2f58b93771e4933f12b71421736773a1cea5b9e5428f2cbe94a89b697588d34633310406617f217293a52b45eea1dfd20063d102b69ec69dbe3ae510d1087556f043d18873fe5703e944012ef206afe6972febe612cb780cdeb03333985d29101b08a40891ef4705af5024de5943618cc1c38a492f5fa5bc42098c877a650be4acb6c68a53236fe729201209398f338d6ff0c4743e590dc80ec734101e64296d65bec59f216ce2072d681de7a4b008b1ede67be3edfb450c36bdca9aa13bd80b03579c463327e7bc87dc7a227f942be91f042e21ef6108d00fb1e1a325803fb07ad9a7c8d76a7922068b5736a7f64af448ddc93aa779963d7b138d6082b8bc641311b0fa02a46becbda8832924f08019988d423a30e0297ca9da1c5da4048e1a09e8dfb74fad3824b9413a3a2ed794042311074c81ea6e80230a57fb2afeff0eceac7f17b8a9581304b412634d1c448866e3acd0c8044f4767cbbbcc51bd65edf29832ea0d858c11cdd0a625de38b430a6e084eedfe7b187c15fd0a0005c455a887771aaeb7688eb731f32ae65f8e13f12540c8beac9232c8de322f2bb22ee19e356fa241d228bfed7d54d41887e1ebbaa697232e2695c2dd9e6ea631a7102d2a562148322c4af66c03e10ecc0c5df709c014ec07677ace687612b867775678bc0ac2dfbc3ddcd722637838b49af2a2184bfba7221af3db33fd015815638d6bc19fd6a8beb146a3a5654696aea76448e89cc06c4dd677866ab9dd4b568e4c41e81bf695ab4d40b1422906442e10ff2c6e1e10850f6c41a1ad087202065388ebcecb2add9c48332dcfd7c248f335190630e6b967ac6ab4b36c8a6a810032c42fed9f1c8fac16984377f3f294eeeb9b2895743aca2e7defe6dddee9fbf1fb883bbb6809d9af0c61617790f36a2172f7a2244416df10147ea817ad838f0591e37ed4d03891991d856f656491be096c1933e37ee8432ae1be3600c40d68b3bb290ad576db4587aa10e4fbbbc420874e2c12625d0689d0681998442d2d9be4232965f77bf0b58cda5ae8286e87b8f2d885437eefae21899257c688d3e0de7c4711efd832657460984a0c11c65f69046188fcfceeaf1e59b0f832779667f687df9eefe457a89cbe915db14510945f50f7e365d3ccf0c23aef2bc676dffe22c1868d30f37ca963402fd6b483b4edfd3424267c1d3976f5a0db4316112b1218223ab75d8c013c84b52a8782471e0f583e8cafa7687f661ad1b4369985d5f5f837672a45e0d8111e959fc0c31377e06507faff0a01cea18a968561f4a51e996bd3ab3a68c77c630c31a1014776463db8df50317ffb2dcce5ff2150c46920281022b7366e44471ff8fecdc1189ae0ab9aed2ba9d822cf9ac2b927b50f66f48aade429e0621afc8044c1afc061e23a60df3f80b5b1afcac28a4a686dbceee0a89b4d550178e4ece51537a5c812670efbcdf50d1468520a765fc9c7f3d45010617b6b5999e48d2ace2675c1f819084bf17fc8af6e2e42ae2a645f225f068cb00644e07a7263297bb4a28be317194a0fdce1204ecf7085137ebca053cb10a2c1c2b3716519ac2130a6a84f891edaa2ef17a83201df48be717240e6756d8e1950c1b86ce0b4d911dd36305184fe64345258267e70495704210d4d441449279a18b313420b5d1430d2893028970f2592fceaf48e28d2c96653275a79e644a1c5bef802590a4d691d02c75754e29e5cdb6ffcf2b20ef0bf372769fb56e38ddb974280fa99703d07265300630c4e01eb07299b97c1e60d7d17ff2e7033b45b7ce2bdc00fed950444e15a213507b4b835b562cc43ee3e742fcdc2266015e330873605d06e01c7464d909dfba424c60621c734620b283371249b5775ef45c1d731f95f8288c44939968618488168e9016c7329ae6ef4f1208fa480a6c6030872ffbf40e2ec196088adf6608473576b533788fba0a2e7531d5aaa0723d3ecc4f8261879f5aa31a3b60a8a824c6cc95a0106c7fe1948b20243126db5004140f611e8f4ac762b6784cb1789fef7a714fc1ac4dd86a645a63b5d83b69960c99be4c3299bc064d6e41eaa0641bb05b2df9f5c2bfc3a30d9cb2a81b74085ea37d395e6346ca14b4b6d09797aeab96cb4997c8e63681fdc31a978f20aaeb084f93c524403ebf32b860a3d9634c747110ba0be2a93e86e38f73bafe6f97eaf61c4e72d20879d829071e2c68cf478319645b20d1cd48990ebbe7ed6cc4fb6c86cac19c99643273d8226dbe756b78b4e47e1d050fba986991a89c0baded0d2d4722ccd51f0b2b384056ac0ebebdcd4e26d4e6c99b9f1a3d3f03a0873d5ff3c7a43fdbdb57ac3ff85761e8312cb8e81263672d633a495840ef76d7914c68f5481c93a202d75afee48fd98cd176036bf423b83824e5177c164690c706d55b3e95ce69e8fc942f477fef7fa83de7f88956b1a84aa706ac272af7999dceddc3c2f5443b6c7780fda4b8ee00f576590b8add6b4e841caea576b80a588fd6d4ad99e252c09e07c8c5d5e1363b2439d19edf337011cc38bb620cf49ebc1a6a8c22f0811513e655c048792dc64f21e3692574eff4006037b5cf5bd0bd8317d15aa884d0596fbe295c0336d138ad63903c3c3e6cf7876e701cd911d0641d203dde38950032c62a64d12fb52b999ec62ddf3f2618ebb1b701d48b7c741834a876b7c3a6a986246bb5a7f01a7952dca7b0e2c35b50b0e551f44f309b4225e98eda0aea7649b79c1d4dec675212d8f62be35d6eba0184709e6330bda2634efee5715611bd0ee2ccf86a6b8b226323df6a668ffb22f5068cac531376463f5020a158d983c4822c859d9457cba005b94b3eb12852acb801ed91e658880cd20f4ddb4347c146c280cb54ea5688f0e0b71019b83661e1bcaf53a7700b9048582f20ef8ad93a0d579ce691f78530964c51d7cf1d61038597b62b55ab0fe5c051223db485f250a970f3600c384418f8f4c9cb5d196d801191b8ada728182e42685e253d5f26ce0458fb757a9cb4bf3b4f71ee03cd3c81c4f2a88e1afa053f13d4394aeeca31dcfbc2dca14acbadcd2f2dc551413a221bffd715881df9dd0b1234ae919af16ff1ae18e0c3fad36f9670c85b5130fa86b70142054499d177d4dee0eb506453b319921f2955ee4c99e8006f338b0d6f4049a13c04e7f2442da35c11fb54ccabe779c1d6863cda51152b70a8950b3015f421a6ea7d270dd2c7a1e565efc3f4c122e18ead44e4dee531e094b049bf75a8a97b3ac76af4635cdca89270fcdf6b0a1e2c9c3b73444347e9f0c2f64518ab5b957deaf0f1663df2de333b8162a9a215a75c12dc8c511c93e8af972ef9821004e8639984f3eb685aa762028ebee7258212d198c0812e31ae113becfb43de7996d992b973d1c7488518b6d30e7f804cbb3d1984aa18f1d31ae4c09f1241bfd36f0446dba22d8f2ff7619a0946f01a88edb2af3e0ec5f0841f4f905775b97255c3975aba928af4347a0fdb426130cbd3a8be545b72bcfd4e830f78a45d8578da8347ee2c6fb3d89a0bf4526c74138f32f0b02a72d8326684a4ec003f7d80080cc7888d3c1bbbd46d6031f9b343d8b3f4ae5624db7373e38bf2c545fb7578c4b284d7f6793aa76f538b907745f85eea150c787957e2dac823d0d315bdf59aef71c07cc2a6ac0e64c5934e4a00f833cddef4512991a762b833ea3dc090b714a889c298e993694a388ad55fb833b315b112d985e9b77618fbcd0bba17cf8dcd0f705f762485b100a7067b174580a3eff1dd56791889f632c733d90846cf8781b2c00540634257e0b9498945a704ae0d7ee0c1474282c59f9c1d8cddb97fd6091de26e48e89dcca34e75019a2cd82766998a46cd5056217d2f1ec14c1f1a66d35d7cc3653f6aa4bb957f43b2d28cc4cd32187604c9f295aa04fd038a302b5aacabf079424dc698c0fea55919bd93cfd860eb0207baa0eda1531fadfe0bcd38845342bc69035829ecdbc61733e26e941c844680baea6cedf0953b795d55e57d16c006de2b6a55e13febe70304c118c48afd83a77c36f578e83bd90b376e9c109b8fe2634d69333f5b7dcf74a5b68bedd9284131d3c1fef82fe8cf505fb86ee1d008f0a0b9b7352e1f1c28448e64d671f54930fe805cb52367326344d846ba474d332a74f5d36596e1470dfc4078c1bc042d816f48d234b2d29ef02d4efcd4b68a07359bfecb58443d1c5d3312f8b7cb093057f813eaf251cec4145dc2aa65d6ee17229d4d839cf897eef40eb6b85b8970cb9f80242839635a57d10bffefd8b72211a3e14120c7913feba9e0a8d157bdff538ab9c6b17b4c0e15a8e9b61b84f0c5a7cd87b4047219aa5e5f2420d838f2de7275b934293d36eed7b30c6ad5e8c2f2b8cfda3eeb59b3685787b761e7e6b538b5f6b34fa179c1b2ee6bb4166736951fb6a269945c782f37b83353ee859c2ba2c7d01d1b6e61ad001beb1016b04f4cffcaedb06f9986dde62266fc5fd3cb12584b17c9dcda7046facda4a21ead7a7b37d4477fb49169aa24aa0931992974bdfbf1cc1537b1ef439d2e0a763bd1c91a2141f8b5e8e6f0d1c89d4f346ff93ee1564342b430ea68e3254ed312bed718fe263a2d01569c977102f7f408923b0427e5d8052191b022346974d9fda0169aa1c7a75d0cf8d8fc97aa1c4953ab52adfc286f7015b82633abb05c9368367493ec1aa5fe0e00e8e5f067c1691602ebcb1e32a4b003af59aeb05e9fa5ec905c50eea23185c493dee81240940b480bbf7d8b836b0f52de9c9c241111168b05ebd061968d22e5d335323e3406ad14e990182b772a9e97ae72a8d6db19a4aa9d098fda5d277f0cd935e3e025b9c07c90bde7176e987a0463ffa405ceb1f083a9b2bb773f33d6cfa6fe3d2696cfe88cf7668f9c5afa71df1bb75bf35f8b59b116bd2e60f1a1fc3116ade6ec7b8b3ebf636b2d1fa1acd26ecfea01b4cccaee6ed0093dff1f2b7dbb241a5d8f45c4c63393eae72eabeb3ca33fbabb05679cb5c7fadc06a0ac577e79b26edd3cd1f8e808e36f087ded9dbbfbb2517621f5c179278d989c1709c15baf5051e890f0d88f24523f9ee98c676cb289316d05a211c51f37628c4eff4f9bb4b8d1dbb914cd8466b5334028dd9cf14bd039072a2dd91deda4c7e7a4c34fd7c59a364a27a880f74c92c8af51576f27002c621c07de88aeeb015f28af2e0335caacff5d90156791be9834befc82543485c731529e75b7f15a39cd28e9703aceb142aa2064d701bb0b2f71d9c97182f8d5c0b4a9f96eda611807005f18260654470c6034d3d6d0a263406d132557732bbb02526c9d1ef6a3a8efe249a6ada2ae69e2988ef46d553a573b17994d2b9fa3c4eb466ac4e19d2efb6b68f7f648dde834d2557740b889b1bfc2cbde94249e6c3ba552d06155ed24be09c20a310e89e7a8999d7f4313e2b001fc351dad9cc81000959289762bc76750bb88c6357c7e1815a3eed994d564fff6b2b3aa00b91ac69d1b0ab4592de720c9db3d5f0a6fb818c350fdaaf3c509fc428f4961920aa474aaeafe90ec2d1ab850019e83ddc14d0961b5742c6a0e93c93d197ccbdba42474b8b17a5a7ba5b465d311f013ccfade23d07f4d6db33bdfa007a7186ab8f9075a127c5533618d1286dbc4391a9b2e2eaeac9a1bc41f26c4ac6c25bd6ffacb24816431836d51462675b5323e4d900dbcf144248336571b5a519702aa54c55fdf827b314516019cae05446084b2c1a89e1b9fa02687ed7f3710ad5af3aa89826c09430eb6199ade3a7fc9a64a8daf07bf1f259c7e3ff52c6373d6806bad5446b9229e94da4f66f5547aac7b20295a1e0fde63b71453c065251461423fb6920c1c4b22b2c4526ec1dc743886791e7c35826d3d871821332757e70e265f685fdd8c259de0556b01d4834d1d365126d765e6e0d3842551f81731d139a81725eed6f5367680e73adf134d29401c0d97a729cd85cd7c8c4763a12b63a3714ccb5b4c3740d3469725c97f25147d0ef6e75e3d7b4568b55519a2a94092edfedb4e292d9ee74491eeb24057ac8f9b10fb18adba71410ec7af4d0e71016d118f6c9468f737d8a447d70d89151c460645561b40394d605b74573179d27a4270828a2f0b4335345f5e0de95718739999127b2f59140d115250a90196aa2e656160225262a6e69a5a0c8a4e0aaac128a9a14aec2aaa0c809c55584d59904ec23e870e341f70193c53704da9520ae9ed547dbf724ffa29cd4478abb76a4bee9b0344c98069940a47ab8f61c6c3f14b6d9211910dcc3321919301497f778aa92962f9c62e3a2617abaf904a0a4b92ec9271859971e335a4831134a5a897ba0b49027ebed285314292bd72ebcfc838b7dee86449bfe18af38c3b645d0e8b3a09237974f1ee83551c9b21b4ad684c98a0aedc6150f3c96c0c45e429f1e6810d10c8cb92d0adcd2818f229fdb54457fdb3bba0ce4c28381bebe2f4e95ba236d43a65d496e3e5036262ef8af27556a9ba87b10c1ec14059c1ddd655a9306883a3ef765b86cc7194f6b9f8ac4eceb91c742858cd06dc0927300a018797d90bd2488458341bfae8974470c330731abb7f19ea41221d18b67a0e308113380c2103ad32b4c423f3e45da9a70cc331b47a6528ed18fdf70a235fb8fc611c2036fd5c1478cf136e459541b583f3dbad5fe24e57464179ce34dcf59e5b7b8e19038e805b70323de9441f126c3fb735f93cf0926a8e030af2c39c1850df11e727e3c99e17404d6e2fcbb7586b029d514b93163a6eb9333029545d96bd0bf0e776ad80ca3211ea0e5dff86f1469126667043d215a751fdfbbc007ccc4951137ef0815527184b099205a634400a567c02b641850d1a74c1ef26b5ec5b5cce2d6761351a9e2dac4301f45faf654e0c69c00161d674564eab2b8f1b852780f1d13b2b077e4d8634276c936898e9309a103fbc0de02ce68079453281a138027a925ae0db64ec2045ec28b92d43a241e96eca770f78845fcadc035a5cfb5daac514aa48c81b45ceb2c71a44812a93f1a2e6fade9ad417c414b045d2d772190b738ed033465f78d969d979f9e64aaad59dec6215ea1e50c1540dfedd3aff73f2f508bbdb7ae1d811a4ff7c27d7f8fe947e46bc564042548c3775c0c75077e833731921a9fcc5e34508488a7c9e2c6e6bce91ace3c3f2794f5930bab94b2fe3444a2cc46f15f4d4213e78ac06f8103063595d291033543c296ea85cd02762854f53cd3ee090336861a9caba32e1276c6bad34b47ba20983a23651918e4f879dcb234b0dd48b75c2c83e1d8c704b76af81caaae88397cabacb0a9f2e9945d16ea7ed3275ca69bcb2fbc63354388816e1f39bf518b91aa8c0bfd536c5aab6fae4237a8360e50d7a7d521ac02c4ccdb742594aebd3126bf088a21490559cd8042e4d064b005e0275388273075349f9fd4ebc7e07323761094c363c660bff6c196cc81b61ba0dbce42db7cc3be78385bcec67d587bea8c82f8b80c46e7c3eba0a6ef17a4794d599aea1f27637de12ea384d50c4d81db9be759b5da551a014d84398a686f0a8d342544596ffc0193c23e11c1635a249c0d51e8686606f7a690199221ae2d5bc4d09882832ec13925f85e087a944a59511bc55d47c9d9e9ce193a62b5e323d2259eb0bc216eb2ecc55f4ff8be7306cf1d010addf6c9663d0c9ba50362494141cce4ad093146af1388ffef4e202a5a9d526e005ddac2346e2186f74ed0a735956293968f26fb96637d39a1a6111dc0be4f5c269950ea9a48b517054282f0fb9fa511c9f0a7f68a5ec000eb891d9c6aa34036f9f956d938b770ee9da52c0c354467993e8bc8f2a36c4fc0cdb713eacc7e2ebe5dc89675e0f28c03a7804e02cc6b14b332d438fb84b3d905ccc339ad0be0227b49da8ffcdc82db6529140bac6db6cc72c3f88c557fe1e1e38a4c2160428b16c7d9fe3b02f1937d0467d9b3a9e4a274195e1a42cf30297abcea7c31bfc0a9dd00810ea892229ec0a1a536aef95b8bdaad28081fe36ef58468b5a947991d7379c9b02702613e05a614f5b2963a0ba25f62af17fa973488da43974f9458c524dde8b847a14779653d1f8a74cd6dce0d938ecf30055ca210b47f1d5bddcadee206a82ce5852343767ac014aaa17f992494debe25a1e7cefaad09aa6c0d71c1663bf78102631cb01720501909d099d8c61f69888ee82f521efd015ba2f4338f05d79d694790533657fe62df82b76c5e3f34555f9b2f0388959eed41dbee63cde7829eed34938b7cea7e5ea05721dff8736fe868d0eaa79eb20ec7cb0c40d6a0d8dc4d3564675852570e119ac7d5c3e6263f4b6634850c63e241af1c1a095c0d4fb66ebc9074091c20aa1e71a78b962d0045581559738cd80f035c03a7b7f04a4f7e2566faebae7d8d05ab4fab526033d6e7b680eb06952c52fbdb5ea0efee01b94e9ef0aaec20b5cc383e79851af3eef1384219122d5f64992c7e0688242bd339ee2634302f8372d24e07cac434d5048972f91b5edd8cf1ebc8bf592b849b28f2cb28cc53e7c58c28034934eb3209a557c65f877c519c61c0e1f846a91f5bc59354facba84c538b4644891fdfd7f201690bc408524f42a18cdeef077454b5666c9f73db1947d315b6704cbc03749b869f38cbfd172f23508722bb45022e4d2d19e3473b78ce8d8e7c76f6bf2469b91bfedf7d434366dec9cf446cd7290a477a6051049b9b3a2d46ca6ce6106f380c42aaac2546dee4220de8025969ee4127e03e33db4c750ad03c4eb47d0d09d00b3c291b78f5ba8c43f22aeaede4c608809258d8404834e39fb0b0a65325a7bc7952642a0832599078e493ec2cc06660aa3b209ebf3e6be44735f01486b19ecd421c99c9db0c8bc9326fe912751b93659e966df19f2f612ae60c45b30ae292977d367f113de79923af9c830616cc85182911151cee510f6cfc829299aa30d54d4e1dd864e5365506f34674402bd2ced601227389e688ba5956fafa4c23a2afb174429f836650d6257d8da882b62547ce502adbec9dd3ec2b57b4d1deff2705d250ba7151c148794a88d3d622ac66735dbe9854f69834ab15353ec0a964ed807ca344d36f3a653022dcbbae47f6bfffbb138295dcf295d0bfd48c4ddfab0cfb26503411ee88df07a211104ea46c096ab10c75fb7f92b716206bd604e2da40007b826934753d087f6cd1437305f6a4f3242c7c1037e18c9dbb18f8a986807b1201008519b2e928f23eef5cdbc136241ffb90e3dc1c3861d0b85d0c39d954c91be06dd811ba8a729ca33dd2442d380fc20493822d271e08b1d6078b58f284e13737f4d309234d72e6d7fa95e6e1710102744c75ec0f461c2a95d3a0a5901c1dc2b1c0b77456ec957fb1eb6cceec0de6af21f41200a60f96b564df7d8d866800e91a6710762ffc503c0a8563e419f370470806691e3425877195eeffd460f8616a6db49f344119e9d42cf51066baf2ca66276026e7ffe5e12675e4997a4cd8c7e8cd651c42c93171459053dae1c018fe5ead70ad33bab5b8de79ef610539b72f40c3aa1a36ecc4e6c5eff02706d6b8591b397efff9356660bd4807e7e550e5a3f01fcd1ceb045baf9f801753857c184b8e148f455d5249e83624674dd200a9ba1a2fb75687180b664884a179b4789ccbfe706823eb946f52923df072291c3b3b2401589f1debed268add0dc325285ede61d13c563bac7f436152f1cbd22890f82c8a46e990b3e2d3f83d211cf51e5ef9840058d93e6a3e7c326c1600d1611e37c01c6c371cc1c29144e2417cc74470d8e30e17054339ba0bc471016fca136828e8bb4b08566c25f9fee85345986f082ebdf5a09c34fc9d75f56974e207b1b515d4d6b18d1f1e80c006181508762035a080cc99761c841efae19dd4d64da264d051270ac7fd81dd99859b649b2372dd2f690402c73a9a963d028c63c9284d99c12c9da83042ee40dd5a34d742ee56be3c194041f1470040c51d395fd8c175dcd99b2ce28edde0c7e0d70da0bb2e5ee4a050b578eaa81dbf6dc41ae0b5b2e746ac183cfef5321ae295c5b6a779341a0959b2f83f289269c5b53f1ad7f9894e3be87400e0caac44495b05d3dbda2f9d34f5db7e5dd1d8f9b8aa1bb6d2b266f96fa9ecf798c2ed357ae93a542fe034f72aae4aa91ca5e3f62935ed202ce95416706f5edc7a0f105263c9d2a3391307bf922dcc8b976a404d5076bd9d2c204bf3e91e4be997f0bab2612900243432e61b61215dc69aaaa13b8e33809448830ffb59564086c2d064a53be483cd4b28cdf8505d1a6417342641cb243c6873c251cdd9c1c5a2ea9115ea133815435248a15459c6d145671d27988e5ec0fddcea6cb52fe9fe3c8a8dfcf85538e37fcea54564b72bda0a8a42ff3c42e1b7ed2091c8d1aef7085d92981b0fa4222b46f79a30e0c3cd688746dd05c2c4c72066be4f5450fc0dfc4465a57c8b315d43534d22cca73c6761ff9bba1ee8774bb6d76c2e682c101a538c93e774f73a84a8a7a85dea60e57ff3443121f3317198a4d5a4365f674d2632a4f0540294ef755e6b6818593337858ab791bd8b6e54ab6db0c4792f4aec1a247db3c0899e631690f53fb097a910187f7ed716b162e46c5d173de79a653e0b06ba9bdadfa43a224b7062b78fa6b4f3842002c0c9df9d8300c9b6b54f21a220f963312bd44cb0a3bfef9e79d21e3de39e9fb34653b01e7da5a8561303f826192fc9d6b0b46645cc376241c965282484a9f3ce99ab394ef3cc0980a67711099da8d9474bd8e21adba8a976cd2f06c738c5c6176f77b34b3cf6a73d0ef2fff82997fc88fdbd96f72a952a1f3e4dbf1e464763952d407a198ebf0501184cc938b8465a5069562069869830b198f5786fdab6868085b370b817e2a217572ac859e83f497b84ea0a0128e313a49f2f868fb8d9f3079f6412b81eef22db75a6afffdc6f6f70059f6c07ce988318633c84919a600b725a67f324816c5788ff5ec524c4428fea728b45f5a7802f99b2dda7a250c5c44b81c6053e8d7d8193cb8495b419e70835676f716ac7bb407649242b925661e43a289aba3e441ec9c5bad564c899e6245291603a1808b4c20ed52682fa9c71ab164b46c14c31c687d9a4ce9e3dfb0f054b906f11b135953815ba488134207e5f03781f778874ca5d2dc24add28b70aaabde8203a22cbee7c14d14fc21e5dc529d129803d0affca1931d01c83dca398b2e8a010cc84a98c260c3ad750d18f7f5e8baabf579fa39184b040458921610be7498403afb0a575c59805a8fc53c3006d2ab15e78718b6d5fc876c55b6752cfc6418b08893daa92e0ecc55d76feb897a4a20fa80c9a0be8327f82295d87704028c26e04f58fceb999f8149b886c0dbc060e7600410a5dec8f1bfad7be3a628de3e8fe782dfb9bd10fe898e4adeb3155dfae1359abff85f06d70001d9403076c80f1210b481c68b1c21593668bb91b494a5928c277c47ce152bdc88cb25930033c203cc7e971ccc35c52767de00d87455cc10c507aa8b2bc2f4a10ba0c741b516923ee6ef19df9f27d7beb81a03cc285562a0aaa17b35e2838a3eae64f531903823600c3edd8abac92a2cbf9e2cfc8612e5f91b35a5a61029cc1761c5c78497c7428531c4d02f271e0d040f6a4d13659135a75009f05b0073d6daab224f7c1cb17c4a004ddcced62a9d9920892158a07784c9e48ac9fca26c22143d827a38d0b918361ef3b13cf9e4d113e836e61e8c8a1ea2234b7998a06f1b8bd47ceb02577240d84037dcd8dacbfb5f1d5048ae484b243b780d0b74a614ed5e8a42602783339ad3563593d6ddee1015ea05b405f4e99c8472431c1584e80077d2187844140e4c4c27b8cdcef7965332ebb80962ccd133e70bd0b206ceb24a059137e1f70d997bd344cfb4dab0d96cb64e5c3af00f5e867ab01860503f1c110ab3e5b92e71363e0efe38b94b806508a5a3e017d36c09dc4aa2999665c604e25bfbc07b2d7134ad7d700a886fcd3a99f822f3d7a615d03a217761ba117a67194069dd614fd3a6c3e711fae51172e56032566f9eda875088caaf9d5a082f2285f5ab33117b5b6f5af2c1254e20cc710f59fede2bb1cfa9f86ca83a8f04194fb8300e22cba368e9886388c5d4b868648a7a21a5dde2ffa720388b4d40b44a63be63a3ae0082a569ba1b8829d07a8d9b383c1b112a666cad768a053b534926768837cb5dcc2286543493af91e75be416b9a1c22f50645c902cc9194f42800598f688a992bfc048f4626cd3416c34b307a007bd4959075e095fd6e2d585a968cd687ab075a8a45146ba7cdf5df4e54c83ab383d4a68d065805ff7261d4626adbc3d843470fed256819d17e569577ce68a7895a4e37ce9715a7eaa1f25c0a0239510a7a566d4a80dbb9b69eb608877bc217fc5d06fae05fef7e077e0e842821c899f310a9cab9bb057ee37f1c38b9d090fdc281f720401c3750adf941e107c0a20a9eaa0dd9931be6f4415026b7f1ab738a3733d2ccccfcdfc0b879c096fe22448b5b856738903b553837083ab06c8b3f00fe9f17a293f41ca6ed3fd5bafcb03311928d80330217e54331c5761ed1a4e735c457a544ffd829fa461a4cb6223c61d3d2bb06a55833271dda29433fb3e5da3502fe3cc0a0e18036d1917c2f2e56cd0ba121bbfb8b2f8b5d468c0e172b8367575514ec556d4843713a7ced5a9ad98415ee2eb95352494e5c5677cc7a974992bb868c3bd12d8973ec9185452a3025d2628ed1f6d633586826f423d3f08ed938b6776ec4ee6d4a2e152c032e68a457012a4db9ab99245e4246fd0b045d9d60aa3ef217bc89fc2ea4f007ba5948f51429fb10853766dcde2663b6b36ec02a4d270434103235771a241bf23aa5d8d448cd66127b092ef4120d87b759868eb326f1e11a678239e75452cd01b08992e30ec501174be5abc4edf83fd8a493fcd83805a12892e857c0608d7b29f5b97afc7434c73ef72c65911d5f6767ab75a70d61be36daa18f15c33f1b46b587f185a72e2426aabd9b2eaec28e247fb8e7e777bcc29d02d8c068ce5c73167cc99176a62f9e52307537ff2c3d3c3c85425ff7fe563b3868761ab238d4060dd30497353fc16bc7cb999f7f8efe7b90d96d0c037837e8e88e103f1e64dd4bbcc7112fb85308be8dacaf7c1a7d1757484d0832f20440d78f5ad3df97364f74439087353238ecbcb5a163fe7eb7d438d2503684862a9339c97e7a4d4eb4443103b9b6e42cadb8ca915d1ed10473a85d2c80c572d8e5fd4cedb5a6f2fec1583fff552db41e3c838cac5f7753374587726b8908ef82b8d5c375b38b59d40c6e948bcfc5326f2dfdb28369a4f15e34fd26b8cfe9f74d8407c8160974cec92f5ac806423e08b64bc487073618c48970fb752bd84f9aa0e20cb4486a70d36a8ec5e1b6e8aff462a5666b24834e70cfc85b441d9ff702ddd0ad0a21723b1c083d94e6ff4a32c7fac713bbc8f644942d422958b3ae4b52052a443ae68fdd0682fb77893e9a12197a84b58ff0887be1621116b6ca2f9417433ee99efaa001be62b5106258ac8dfa083f07e6d29d23d559d7f134e7cdb8e559a913a107051267eb0b580016f4d12c4c6748a2796eec2bbd6f158d8c1f13827a03a802a71f740bb978be7388e43ccd33278580a3b7836ff74b873b89954fc91221f5bde535ee86346182d3db46ae60eb4566fd9d4648baffd401e9101c55be6d8896f70c4b5a864f5cc1518e76ef6333dd9d114b029bed9382e996576d376ca364621f7399b4f5c6118876fe863fffc207fe4a4004ac3a59576615f05dec6db2ffb407c268d1aeac0b53fe47607d0279b028fd3b6df03beeeac03a5bdf45d6ad6a5bfbd159bfad3b85e13728761a8177be5d039fefddcaff03a3fead8245faf821c3e7cb510fd31c5a3434ae714920ca7c87344c5b6f61de217f136770ec1bd4854c4793f4815579e08a7d44a3800f0716229912dbe501988c7913f243b450a855811a2282bee930c4fa1d9fad4b95e60a10a8bb5bbf2bf167a30ab57b0ae72b6227bbe7aa07fa12a375f555e9d40191cc0e6160d46ee52604808a6cfdff3f68dc3bb17a8c9a257722e9f19cc027b181b4e3dee729151b7802f8152228ebd7a0d50e000723947ca01ec98f9e7c9d4a86cc3f9de6b5890ad5106339a9d2c3fadb598339fe0604419b02ae0548a03ba0b92eb540236144c7d11cdd014d078ec86e766ce2fb0515557d014c24a3a676de6a537f303126a68b538c74803397684940daaaf9708fe4dac14f74443f688f5d8e93b98ccfb0a1b41045f46a6fd35fc347e903c4f470e0be2dcb1b389458490fe8d396f7d78180a3fb31523f7559491c249dc9f247af4f8feed3182937100032342a8d53a6b0da58dbe4c9f06f711798cd648d836f859ceced34fad9debb37878f6059a63610c4ca27988438819ddd749eeb01a5fb9831ee1f468075375a35b78bfef0bdd401a459c4b706f5df376d6d6ff914ef7a812c3caf004cfac2f6213ecbec548f2258c06973efd0142884178931ee9b03dd624c1899466b76074b172030e8c4775268e9df7bd951a1e23fc76a0399c9210d434fedf33e762c5373a30d7c9dabc6f4e3e4657893bf435cd4dac85a036a9059d624e31fd69465cb91f4f134e6a0ef3e97d7cc0c8598e7d228f00fa76d309762a66efa8e58ee4ef266b8b21174be415d952b312e10d6e4674898e1cf906d80cf77c452b27a14eca6d2d94c6f5fb35cd0bac568b9fd68da404ce3675e512fced6cf7eab2998d114d8bc0a84a9f087be1a88bae6b3594f66c598c8760678132130ebbe746bdaa59919c445f48f39757e71acd320feaa25c68e6e75e5e92b4aee84a84c67d9961fc8eb1ec3a347b94a5bbe75d0bdb58edb201735a6b953af03a6e7cbae7c6a1025979e1921d6326e42bb0fba02e37f5c2b88fbd202a731070536237f4e1db96688f8ccfb1b41958efb2cab993a63cfb22e5c572f768003ff3e08c16f352a9ca56dcad829091edc68d8328acbc11471aed938e3b4c3282024d2eae42ab1c1664394d35bced12b4adb07b71d9a985264c392215bd1f5498c7a8a02863f12c99d903bcff43c749e3d23c18e937ff48f749d0fdd458541832bcd06f4d0548d15c1fd711bd96b8e8b26e665c7dd47eade80396157386ee8f6592ebf7431ec13db9c07dae8171809d7111c27f8495ec4a39fd240408ebda62a75c3d91f32b4228d94370068c8a8f45a87b2d126b69924db8ee7894c7bc4e3e2c7660f6f0e66907046a1958ca8fc6e9abfca1c87bdd4ce6ba7671ae2ed05e009f36aaf90a42f81f12f5d2e7091488844aa9c15434b0212f1752655315560c17e88e764a06c75df4c6298078785e7f80485bb7b7e6fc76272f9e0a136bce5c19be1c2e7843b68a089901aa583fc1323b664f3810a6b2fc4999e220645c120a6a6687b6fd3f8ddb24b3743f979f783a1edf94955f847f7f5fcc690b539492cc9a5b105a3434f1cb3abf84663b4672205aa1e0114d48d731cf45d4a1336c4ba50d5fd8960228d9d0ded26d307fef38135dbb1077d200a70a86ef4d1ca51317cce4cc566a88a5015c0021bd35422be272a0a4338736114e4b7b6a1059036b48e525ef018ae0d4dadc35fbc3931f99b36f4b21b7adcf1c2ed52b445cbd569d9a99878a937009d7f90f8a157bec7df466d3fb8e0073d03978c99de8133c5c23c097e8fe2be40a946bb0800d822435904e811eca1f3f6ad1470dd7f35363b95ebaab44b68f651f60ac5a96453465846ce7d3c7083cf1633aeeed01228cb1fbee83a6dc788c0233bdc71013bf605c37c3cb55259258ff038e88d4b7fed663661374a9f1873930af777f1955887c7761213ebf0e25822ac6778bd179e4b1a252b0deb3f0098c04323500203eded723c662775ad22bcefa66ca693e2a529024f5d0745a8e63a5fe9149dc9693670680eca2c0f66b99a756a041b306cbb63ee216be8a9872654bf445280660a08252193ad8fa1d99624d9bcd30706d22d957dd401d62c97aa29d11011b03fa2a130c6fb29f20f541f2b7d1e0ee9c8a7a86e7596932d545e798ea7f9a000da078ca5208b03c82855bd916d8d0e1fb1d3c1e52ceaa7da8650eb4f975f550299ac5910e998f9a35191099baba9d57d2867ec0449472be8b3f1ab872ed958579a43257d35ac58a97d892a86106e0f754a3208700f9050fa310d719a07ff8877f38e739aff99d151cd5edebfde8ce51c404a692acdd0942a6ad9caba2e5489f6786f6289906f307c919efc2b944e3fd3a7701bec18279f21d06cf00891a35f24bb2e2dc6a1859311ed3ddb1a8f8a5427999f55437436d607b5cf52499175a9467c5352cb1177442449668a371fd46379ad3f8c1acb94fa10a1b3de6e6f6c2033bf18ca5cf6e2bef8a6c9058c3203a29b2d9b99f7f751e37c504b50df1fb983abbaf0bdc96a54e52fb3b1d14fd850a61fe34ad1cde2f07adc507c5d615379f1b72833f5a41224cc6b5d43a32fe324d075dd40d26058f0256b8687f81419623d66578a2ec112a90a12d4cbbc8800f8c06a5bf3d81c5da549b58e731b7f5037af7b54030941cb6223ba9f3f78a6331a792bed5f528244c58644e0e1909c13e4a05a62fc8080c94f53a05e9083fac51f6cef47d1a7d8f7d792b7188008b1b1c11955477729d55038b951d6ee2e59f2e964bf4eb1ee47a4cec04be04e71a104d53a726b48ffbfbe71c76af40ed9ad9a840539f64155887c3ce9999ce11f4e040d3ec220155089c492c4e7acc3498e5660c94b67a6f7a5b54cf57371fba7b3536c456d32eae568e208d300c017773bfd85bc982fb577a1db88c1b371727d09a944f04db70903cd83779e41704b9873b2e69a5f5ed584791de0f1aa3a173181e2ae6a2d2181af62d34e31478e9a7e98c5fa5c5fdd3197b676468b95ee683019283cd74ef452896ed0b408e668447c92bf3083ee2034a802dacdf15d5d4014564d07f9891bf2f04800b275490c305f1af1b0c8b53941277fa8d4b94f076d1b6043c7f5e5f9999df89d1b302ac251767d07d8ffd66734f31c60f9bc3a04f1b70783fd813a37b8a2df93acbed427bffe88b5b6f7967bcb949294297005cb05f0051d4ece0dee291ad751aeeb76b8f295c40ea757a587a2baba28ba9754c92a159b4d31c96df33a4dfe8ba371d37cba49377fe27bd2aeb3d4ca8eeb28d7c51d5e9d775d17ddbdbddbf8bbaeeb883a8c53f24ca56a7dc59e614acf4fe7ee55c98b87fd7f7ce8f2c4e1629c0f072455d27235f0e91627e38aa4aa065cc359c12a1f8f5f98c1b35c6769d86e3ccbc9bac519f5aa48d67049526505d7705cb04a1ac51a78256d07c61dd886b49c51b7585c92ac892f8e0bae893b38a32b6de7451ef104341205bc4ac1a1dd33ed5ab077c3f9ffae777bfdc7d7ffe36c379e8d3b70acc19bda346961b869b6e3b4ff89af89f372e32b95aab5bf5388787998d2d3bda4089c3a71e3c1c6e118b6dde6eeefeeeeceff1615ffffa5bbdb96dba1944915f790ae75bb6b21734c47772ddc05b24380ba71db628c42984cb9054599acc1e9eeeeeeeeeeeeeef68f31c6ffcec2bb249616bc64d48dde9ad6ddb0ea6d5c740ce3f2dc354d93c9598ac832d0adb5d61a43d71f5d59758074a4aa7db420ef0528c748fb48fe48b626ac5746b266b33c3d3eb1093465d307cb9d42dda23cb49483f2c0bad5752157d2cec093430f0f1f1f5e9009e4093165dc167649426ab42ecaa369b3b442afa0719ca8dbf252ae2593352d934888f25c69298fac1142b6da47eb7c105c4ac677afe709d736aa6d59d0d662b413b81f22f5064377e0feea9f524a893c8cdaa59b46e4afc34cbeeca298ade3eab89472cefd46b98d46e19276b8f295c887a257b3f451682fa92abdac468ee3382afee70a3ae4fda95d8e6e5468dab4ee41bea343ca583b167036529582549d78aacbe6b224c91a14e52c0ddb4d675d15474ed97432817a256b269154c9de82fb0bb621ed046a275cd33f6095ec2d6ad076706b42b148576a38dc09458b1aad6b42b91c05e0f219fc2569a486025ec92f3825a9a56da49640c85ac308dcb7acbd5ab0574be2562cf0a516ead590ba25b90ddc47923592556ee5747de07e0b7ebbfe825b9d95b6b7e02ee54abd6b9a6986515e11dcb711c4d96eb8907b45c16d8a1aadcc41b63ae6c337de02f190f9302262c3721ba95bda4bae5ef205843a2355d2b258b16ed1995c494b0404457674250542d1a55d1869afee90ca34f9d224678356e238ed45ca5501989b4238638303a0db4e925c4722091048a2caacba38a642015838c04f5753b6bb9ce40728d71ba2ca8648e6965e37e043a2ba6ca3d7b08d8154dfbfd8dd56dede7ee852397e0a72b923524a29ade8342436df8afc8b63a4942c3c1dd946298574110097532d63aa5b2cc962c2d461e418d9318cc3b1dbe1575bc6ff51f0f7523d59dd4ac1aa6e87365dd4fb265c6eae51843a23579235a4b68d766eb24626ce207278637bd97e0c37ed67933dffe2d0631c23ed86447b52266b9e6ff4cb8d56ce644b12114181727404841b65179265517d11dcf61ebe01b6f4e826978e98e33dffffffffffffffffffffffffffffffffffffffffffffffffffffffdedfddfdef1a1235dafeffd79488b29ddf6ed34397bbb534dcbd795c8816e1f98cd6d2f818a3f7b669ac624bab78ebedeeb40abe1f769bac61e1699ecb9c8c85cb40d870c71bf8e083542131efc0423ec4626cd1c174628ecc7575776f45180032869999b9bbbbb951603ee14d983fe4acb41f7254db0f255c577777733ed022df1112be588dcb3760ae8b9999bd11a6d7ddec24f494dd8ad438dffb638c51de58438d2a3606528db6bbbb636cb1bd9c56667c96657c2ecc2c31509e6bf354aa8539060c944b0fcb2cdd2e1e3333cbf0802e5bf931152eba19ef73fae134c33bc16085c68b8aa551afabbbbbdb6b4a087a9e53752e873827185c577777cfb9b577bbb72235482841e575c7d7e5c8d239a64ff0c184520eb69caa45babb39c6ff046f2b52a3edcfa9eeee8e8217638b53901aadeb792e5bfaa403aa1217b7dddb04b0971dae2bea6c383a57d2580ca31c184f104f5093264d524f9ec02887241f28f6b18ff5ca27c621c54e44c42a8c063bd745578c8843a854ae87d2eee626a7511bada6596abd9483862e8e27c8882c7c6ad3b1a040321ae14b3ae975b76bb196a51c9ba6195104c9dbe164b0ebfa1e5912c748fb1dd183e4131414141414e4ef53ebd9d7430bc49d4f7fcdb1701f9e202f1e3675dc1dcdb5afee76f204c9a24ee33abad915685c37e218a3265c9354af5838c00b2a28a13579d93a909127887982be1a6ab41f0d35c6681e5f96f69554cd3d86ff448d9bf78de09be1dbf1c9f0c550a3fd5e5f14c18b2eb820c2690835daa4962d603411c22908355a20fcc0073d40e2c10e74703aaad16aa1cac284a01c1845c1e20a28272b02e09daa1040b700022035235058a0c0d8d68c97aa5565ed088a9c5091333513648a3ea75bdbc39ef4141d7972655c8999ba654ff0a53dc6bee9538e11252400dcd28f0dc96325d88654428a4026ac542759d31252605752a4cd53601b525b8f51241fe2b21d8aae8c32a5c21fb30cd9953eb5a75baa5e756bab7181553c6a58784196e3051850aacbb2ccc539e19cb04cf6aab6d205ae198155d2ca367e61c500a6d739406f8fc0352f74abf2ea85c0ee6e19b933cdb068aea0ab71630f174de03352a3edc008b2bd3025c3c244903fa9aa749321e5cc8cb528a8a44a258f2498b2dddaf8c8500ec794592a550f6248b1a8e3811ec9c752f8d8b589750fdb1fa3174b5ba7e44a7ece5bd0b85b4dd95ea130535556d557740ce35a41ba51dbb81fbaf2a384b402dbfedb5fee045f2e920a66c870ef68430ac531961b65db0e65d4c84801070ebec1514617d423ae6bf5efd3ad69f9663edf7cd1170da9b1c6a49438b0fd1eee4897f3e448979312834addd9ec8d28e37e0efc383e8728236fd4b4e721575c102e08c7235bcfe373a69d3e5ee7797c0e11c7f3f03dbc0e9fd33fccdb666aa5f0f4e48468964baa417cc0fe0457b2fd1e8ce379441999c2d3add7912b695fe775528cbc1159e34a299252843ac109b9f275b8240af4411ef63e9e47c4f13dde873fc1eba4c43cc8e9157d70fc88eb8a2699fbf8b8ec3a54891e2edbe781715023514676a9073f25a439e79cf4892b2910456224e2a04758465ad904c748eba24a5c693ba4b15311b1d3ab6ff0eed6ada9bdf59efcec608fdc49613df7391c8d71cc86c4a7b0983061c262c2844984b1ec0a875b91875c492b7df070de402b457737ac87ec4adb52c6379ec88d9f477284648bcaa80c4a7551242edac46dc21483a4b20f4d2f3a932b8ae44a4b91c89a169d5199b3a9a3d861797b2c876fb8752547641646aeba05632d8c889e98e3ddbb1c9e63826ffd3ffe9b9cc52996a75b26cbf67b9e88918f3d8c6f74d6c6956c5dc63738cb1d7d62e37b2217d2a28e52cd46fa7259d6b8b458dae15405dfc8c71ec903f54ae676f83e3f6ab49ee57a38f926903172eadbb6efeb81a846cba72635da1814ee54a1d332c8acdbfd09acdb4def24458d964f4335da93508df684831abd1313ef34abd19e9678a71bd4e89d94d4684fb21aedc906355a8ee2f34e505496d3132d30eed62d9622e59d6a00a3e5440317efe4448d33bc13d08b779a010def94c47a271980de0949e89d9a18c13b3101e39d8ed4f04e31124e4bd468b7bbb12e65b2f24e4a98e09d9238c13b1941c13b1589f14e4800c03bfdc878271f96773ac286c77c8375d976365826ad873a71777677777777ef52a9f0ada5e1eefe3eeefd2ffda393a0a7e6ddadcde69cb2fdb559cf3967cf9edd9c737afb12eedc2173ccff7777ef9054d6a36d7c24ead04641658363a49da50bc4cb624d6d1b00c7942e10af0d129b0d84e14a36c852254778a28e4ae518f9489ce0945cf972797825edb6559e21277852848ed4088363529e8cdcb9c9c3f7a69d27040f8c07d6ea84e0e1a9cee3415e0f3592e33ee0cf651b23293ed8325252876c7f0a7e9d83912362ebee342f96da3ae8f7857044cc6eba4f9f3e478040ca8f109c092356bbef876046d6dce4b6d33cf2ec5e7306d9ea72e870023108563a3b977244671991a6d6eecccccccc5d0ab8ed695590f26fbbbc9d2e1fae106788632359ad727b3337c749dd4cbbd9096a6e5590dbf469b539e7b41f458c45e9ff52b814b2631251fe9c433f243b32e13ede030b642df5c42d1568ecaeab4ecd264a4dd96288a32055dc10735437294a503b1bc82a6a8909195413911d4184081104e63d417ae82982cc10440f7a8031a27e53c426d553129f2471a27e45482e766208c28711049103abf47292206a08835002976805902b2293ea97930079720590a0bb417143cb55b15000168a006142c2a0a65c4e02c4880a840524f88a00240551809040faa8d58b2b6a0b163da49686a492243f925c57f522c90f24ea4e921f43aeabca1924f901a4d69ae4070a6aaa7ea9243f469004e683ebaa433d7553d23ef54b2252514b3d4ea4962e278105b144455d4e0223c1953f9525c986aa45eaab2a14808503d494ed8aaaac1acd66b3d96cc6840913264c9870b36f1cdb940c59b35190bf9dce823673bac0ba34286523572eb0ae87305215a4eae1c4ff5f1aa1838728709038c1c112321431801c4c6083155ff4c0210a1a783126a7231e4590a10b26848e7e80ccb04309901738d0e06505caa150c17cd54bb1666c522072ef93917239091050dca68117c3818b9999999979d37cfe4fd79a9999d66e8eb9ce24e57602fa0dd568bf99bbbbb7bbbb83d3dfddbfef64d3ee4e9f74eeee1eba6fdf911a6d77d409333377a3f785b6512ec6d8a4f34aa6949aaa757b3b6b4ac9050ed04dc5050980565be94c2556923be5dc63ae12a31bd73917d53d0cea643c14e8e69534d72c4b6e9a974c1e644ad182a2a4bd756ba34373f3a4cade95f7c61ebdae631762c42a62a1b8c4ab89321654784166c2026e5b5e3d777f03dc6dba645a299bff11083d8cdab41cf48202b845dd6918614d60b208932a2611b681205290acfa795b0ba374772fb510de8e91aaa8b5710a1bbd9bbfd882075138e5abc0b769d35fb5b2600a0665bdc00ce090bfb892b7b892a35c298536fdfb25eb5669dd2debcd5a5794ade0dd18030b1893947f9d8e9a5069a21b87d93f126bc372eeeede319b4b34ce574e5fa434729d572a791d4797f85862c4019f4a2b701786252ca89667f94a2e4820b45a0b9a6dad2546aaa2c2d67b5a41dd0e460c8db5f20161d85097afe40205beefb412c3a59f3addb4d9d555ba6b2aa5b8c8d0628c81291895d5cd4040ddb65aa3b6844c3159191eead2a06ec62c79321411ba28db9f5d2cd5ca823694001dba384a6725cfc01472afaa17c25430704c1253f32adfd80860c338b8c559695918c7b42d976d84758b0b61e0265c110683540555186c06b8a6c319a99aa95e46969c69630b36e56e71960353bd22e22ab3dd361bd60a8441bf0a7c14b5ba6cd32d8e0e6dda7c2f9998f53c59631a61bd929e4a85b012ee4718ba35005e49cb4a22ce50514441773bb4e11869bf246cbaee5293775dd630ea7226190b10d9da7c8f3b88407ce3e5b2cee6c465bba5eaec26b4089439383aeafea943aa5695b537c4000644b0c0e27d6aa95a55d612f98af888f87ab48d725d4f6ca360bce922175337fdd3757747284c58a964b27b781cfd24f133c26ca6c34c87d94c9b4343433fff0f245572f683b7cfbc7bd645d7dddfdf5e58cf42d336bafd88e05fae06bedc0864c76cc76c6868289594f453b37ca3cd94dff4e410191a1aa241a51211a2ed981189724444488c51ce1891de616868e847889fd96c369bcd7eea309b433ff483fbb74f79f43fbe63b664674a9ffd337dc72c06a5aa9262f2baee87b3ac6994eb381d2a437528c5f415290d75f253b063b663b663f6bde01b02859b82114fb8916fc418a3f709f1b9e06bc127e4e3f9763e167c2bf8827c417c40be1f1fec03e2fba1bb873e157c3e3e1fbe147c3d3e9d0f05df093e137c3cbe1ebe127c3c74f7eccbf976f874f848f0e5f0e1f0ddf0d9c0524ba23ef5757a25ade3f85c498bbe47a747e73f9f1e2983b78c4926ac54edee2323114a54ea718b03fa8072361d0ea85b2c0001b180457571441c51932640409e94dab65a5329bb42f72dc140451e031223040505057dcfb75b16e298233ea9ea3112ad8c31cecf833cdc993f3f0c57dad20840303a2a1e4ec573fabea65d9f4e27afe32c4521a17e804a6a39a2a5a725d6d204aba295615d322ed6a572d9546d0172212a99b416d40f5048a8a496235a7a5a9a6889c94025b9a09262a09260a0925049a8a416a02b2d8c0b51c985a8c5aa203596528e16ad8b25032c61296199ae05847da51c6e57aaa89185c69752ee0c7008b71cb8633b10036f35b05d0c68002584224239e14c3297282e452828a828b4b3b5be18a18eb6995c4996ac4617350acd641c83128a386894b08c131411cd922b2d277465cecb247389828a8282424db2ce246b932cc52433c94cb2251ca3843593aaa3ede83e092f672919c06f0baa9443b32ad1dd743b7007c672e04e0d4bc19d177086215a2c0ddbcd0eed8b2fbeb81902031aa8b7b30da362a4a2850ad2ca9095b8e2b3528455d146199654ac31aec46e8ca8590c856a80a6995cbd4903d2e209235943e304ab244d4e920a52b7687858194283b3c2d32d9a18568a74b1e2236b66861093b92e152415247b5d2a4825152415a41e2a48a995d8951646a8080a6a1671b0ae8882fa429a29745d367084584b584a5eac24a423a32222d6ac2564c938860419360d4ce2e1a92d2fb6850377606c07eed480a9215150624c7ad58071b7da4945c6312e4557baecba6ce4b09eb08cb4238036706cbc7a950404a9425a01595058451cc31262cdacb8d2a2a0441c2c254b220aca0c59321264a82e934ca548d6b86d1d97a2ad6b6179210d50afa41f79d2c77a7660493cd840c382b54b799db515a4d101697038c6d2f4e09c4b6303d3c4c0335ca09d23b09f2422847a25ed0b0da3238e61e98007529c64a7528e1d1ba39463c7da181cb8632d057754688038f66686f5a3888312451969699154fd806ba815ac62f1a36e51a33e825bdc0ef7703d52f54d700d67848cbd499c0f158a384c4f4419152bf47224bbb8bd80342d200d129a180aa4f1218a38688eb00cb582c6c82d9235343faca269e24acb1212cd9cc01923a36ed1c4c0ab1d9e49bab06ecdf48057461cdd1e593393839e2b2344f5e3ca1e57f270258d0dd428e7ca5832d6ec898883c58415647aa28634af1723d08863a4e9e5e88b3c3535a3822fb7439025eb95b429208b0864599065d42b69bfd20a32770b594245f505a401d29001d2084de02c819163a2a501d65e45af8319a1a4852f4635bc17f07624d000fdf5ba6930c6e5c09d17dbbd845bd712605c0edca161298d707b7999317fd572bb979719f367b8bf20bd18c9587962a2104301b05d0d7419ef45bbdae6a1502c3f5fb3bfd9d7260b4b0e972297227f9f2e453eff745a595951a92f46d2a69472984a284175b15e8caeb4ac2259239b09b188648dab026df238c554a26991916598b85bf3ea74b8c808f4e87eeb1cb8ff27206ab41e9ddde74ec7ec77b656a493de47856d217687afd2bce9a6c9684e9502ad75e933ddeda6e00e6737b0e9d65c683313c5ccd3f7a9d9ccccd8cc1431332711ff36f859fcb74177f7ff307b1a4aa526b57ddba17603bf65c338d83bd46a60b7ed4e859cac4637d1cbb2864b18a2ba52574a1822d42e7916bcc2d40a191646965ce4eb86b3559e2e05745cb6da06ce4083cd0d0d35bb4d70b314c4b1b9d92c07ce40c376b3591c9b1b6a3bf7f72da42b1c2dcd4e9b5d49b655417660b31ac83754b32a74831748dd8ea5046837032917d06e871478cd828063371e98d6039aad975da20b872f68e1f52235eea06307f8bbf3901881622cc6622cc622a59452d125179a6e9a6f2517de76b8b577a81d5182df38ce6e6f39ca6d94d334d7268fc3dc27cc7dc2dc27c7713bdc141f468e71ab5d8e6e53f88f86c5c60d78000bdd9a40af607800d76480526a350a4e40da882333c035110756495b14777835846d48db816ec51c59531383a044624023837825a3939c213cb0188b3118cfd387c99af9f329b57108b7e80ea59bd62914806ff48c879a4f9190c776223bb2bf3a97ed6a2bdd5daafa49943deb99ec9ef5acbd673df3ee9efdec20346e52ebe9ffce3c9bd989f4ee666666fe28f3d2a0195d6a9135ced4a17357c7bbbba5101d5bd7eb35ef5f2eb5105fafcb29f6888e61da4a295f06758ef8fda173cbc8edf37fccdc67019b33a8940c9bcb69e766060002100083160000200c0a060482c1304d03414bb5031400105d863c6e6038190823498ee328888220888218648c21c4208308320a11510d0006fc95527c1cfca1932aa5647a00254f0843b0651607b8ef5cdad1f8dd8de36ce92b0f9804fe73c0b0e6915a0827cb4b830d4e288c243cde880282a07ad13ec6969e18e131c09fefd9f9f98e4fe831fd1df17e79942f0a2b067bac886d287e82888882318123570b8cfe05bae3cf0a0939cf725e442c73abb42047da94d542edd38e6d0195c98b494e2c9c3f9c5831202c42fd0693fe170f14600381c5304007825108580c0045e0e70c7efd420ccc7e7dfb3c6b6f1c0a50fd909dec21240d98a68fd17dc6361182598c3ac4325e9046d75af161e8d4807500e80a1889ec85bc40d791cd9e3abf17d2d4089f6ab7b4a9787ad2d77004177bbef54d93bb5f023c55938e1d2a87593225ca155f07013cfda95337bccc0a1d751d5fc271bd0302af151adbf19770b8c5042c20bb66c6cedb689e7b1bd896b3ec51be88c9fb4ef764f2162ddf01c6cc44a3b4b04feb192a97daf83da7f9c6c13231b69c9e0d21ade7c2c741100040488b062cb1cf4e46ae8ef6d6b2b84b606547cf5ba91b7711179213735138848730a009ca2a114672287cbc4b67e08431109ef77f6107040793a8208b443cff68d608b6451a1dd0065227cfb87d23568d38a2461926ebd7a0466235fb413bb4342165b1e1010159a7463631b480a6b99b3c35df8b665477114310a8ac8a699bfbf4e7431fc2938bfe01480ab9f39f943282e654c2502f4c4e6ea87446b03a0fee662ebfa28843bd534b085a720a8f5b28a06a2bcd88b011526332be6e235488e4aaf7372a08454dda58b86b5debfca2cecbd3cf0e7e19b2fb330b18163e865be8903e33d920bce73450eb8c4b350315a7752f98f13a289d3d9c16528b8b0dea95a1391fcd8bca5e6f73ff0cbf756c09046dd3900e22c3cd4b18520dcd29b20b04384713360395c7fea3f373050abb99a1f74a951a30b58fc806617fb0a9146f33b2f9ab5bac545f33451a048c3244356763e1d0266a60bc694370385c987f96f0d02c0b5dbe3107fb7fa5562f589df162b3b22c17f38f3c2bee8110ea04ed16016ea2641ea8bfe066f6dc8f61715be3b85ae07019084c6590461a58492c76531b5ebbc514457fe5da9e18e3440844d7c6c36b9705463ecde9d571369e4d45dc701a4caa48176801c023be0d235ba252ec553314ac04cb886f5005c6b6f7ed52512f58000390729bdfb6a03c447e6218ac50991ab380de8a615e943a2348bdf39879d22a23df4028bc8a00d009462bdc21fe152532ba100c16339601f30f0418d63627512126bcaf2a52d5f75bd88f21458e7b29b488372feb1e13a67a99cb07e3863a5e90f401a5ae00bdf5d0050014aa8c03289bc732845e292a0cfad2085288f5080c9b31738f0fc9d9b8e712091198a653be3614c137636a5ddc6d75dded523655f3b15542b50a01db4c84fd1e682bb88076659b7004158a6ea3d7a159bf8cbb3a5569dd190cf8916d2e22ea71d8de0d5b00d2726be84cfb050e186aa838a496b35bb1bafdc57a07b22c990fc7dc495046a9a56dc96c5587019210a38d7656c5d7921f3a6ec01a492385d94307c57575731d4cf6e812a7624099f72b40137fb7d82cb5f09c9ae070bf095218a5e8543cbf0d2b02698e1fa520471005158b03ae2a476935c735db9feafe0b5642a5509c207c2ca8a4f7ea22702c3c0652ff48f0434f9f0f20aba52247a0642f82ee1312841705649d86bd13759fc083e381800f00267735e221a412ecdce7a2191d4861d34ac3ad9c8df35878141a5c96f4f78eee9fefe2250bd2e60d9cf85a61910c7e56b9137f5ef6bd2b6d27d01d2dc4f6e23a2d1e4fe680c0adf4e0fa0e4f59a8d4c2f7e3faad898cfda6c339e3c10f5da2ba7ed55978509f0e02102e863779e3a728bc37a38b551130239ce547487615a3f0409a07363d80022476e8bdd0b53f53f511794b62ba1d4b89f0c06b8a0280416e758c4f151bc8e3a36317755ef3452707f38ad6b80a6768043b6af093ae6f8fc583b6ad00e212a31143168e6ef6d59400dcef18bec04334ff932432b8b2f2198a135dcc6d0061b3eed72d8a3ffbca7210415a9b850bf6f2d2b1ea8a4655b4ab01885fca3e21bd34bbc9e94ae9eb7b32dbb66de7d411e34d05a010f4af2c2890299f408e5e067e62025350c81c06cf631c48ad5d70e53567ce722a23edf14d11facb840cf34a84f6476862b2ff6d75fc3be37df714a105d87ab8a12e920830e613b5c1016f705faaf2c59fce221684aeb6090ad9c83105a819bd3053d202a31b01800d3c23690fb2ecb126059f95a18d4d6b4d9c96e8a24af38b32b4ba03fbdc0ce32bc7224d2b2d35edcd40cadd73ac68b8e3a368c41ba14b2d6ea080b5e755b88bba4016be31a944be3a69f46501611bc8ab132bf44965387a26a6449b3e6d750ae18483c0a7e2531cb42eb4e5a552631427aff65a1a220be858b32836dd86dfa9ef561042f64436b2a1938955f2951229a0c27180c67526280134446cbabcfc8301fe05aa18d6b23c5035124ef17854e982cad178ef12c37d09ee9eb23654c9428b9b01fab58840a1fc0aaa91fe6be65027e6ee764147cce4e32848e201e2721530d3458453a3a90c34389fb769d9ce863f19b8800a304ec02c8708846076696dd014e58999411e10e07e8550f696dd87ec6d94f6cd8c6a272c9ddea0a83687f0e477322577e34f66cf7ee533d703c47acfbe80e747bb9d9d995ccfa360de67f049a7f1e949e8be59448b76918bda4c164a49cd9b8d944f77d2b60d75d09d6fe4c9f8f2fabe3ae1b7f53a8d23e381543b236abcf754f7de5c7011c931a16ee8034b26653d7c4377bd050010fb020f3f83315658da4b1f98dfcb865b7f24c5bbc8021d0f700df55d89da774e4a5370c624468502cc23fc0aa0aad2b2ae9151bfeff844fd4e5c85bc0948ddc47d59eb5b5aa2a469ddc84decadd1ae982c3e51f8f167438ca23af85fed5ce370b5414e5fc1f8c4ab1b29258e5868c5c3da8e555a42dbe10aa374813dff39b69c77543f205cbe0c14ccbaeb9b722989a5894b2c618cab60b1dc9f5eeec9f18904f3be1b85c42423fcb79c0e7fc90492ca0c50fd70f102c69b209b3c08824cbfa294f05941ae29e903918353dfa012bd4ea28ac7f19679a5fbd49c66374773e2f66151969c94fe2af25012d3c53ac0880c2a0768229b11af349e8e169b84c2df30f47fb12428f58c27846f518f2f8e05fb810b483d58b4d1b0996e9f9805c7be1353e36be3302e218403a4b5a4fc614348839bcb91b9f0d5a4319ee7b4cd2d6f14108657b7959d0b185575bed5160ab42dcb9d3fe1e472099f38a9e807c314ba297c53dc568b5e38f8f19f23aaf4eb7c633796af6f67ffc8d7f70eb1ec6776e9d541bfbbd821a70311fb3d0be2e56b70cb0beb2a85f0380162e3413902a6215e1466c657efc6b539040fe2db8f30a89b1a51a1bdb8d0a409c5ccc4ea6ac510a1177cdd2b33e101c7c9e85cbca830c80d83cee910c6c147c578f6075ce59a2f419229e4a468d0fe3b351127f73f2ee32968e9efe434e0c788ea20702bf494242cd5597a7092b81be1ab38651186780786515e5be56e98f2a8fe5bb14ad179e876b5c7288ab31aaafbe2ec87ccd1e374bd0a42ba3bdb60714dd6e0c89773ec442af79c7e5a363c8d0a6046e4f4119200aeaa79c1e798285eab6bef8524877a92db94c51c31b55a891c7a9623a6d987a191e6e20efaec7099d7f397a4ce922c876d3bb726860566a9052694ed02936594c3b824ba7aa7815106a89dfc2b40d2ffd6715cba412c620f6cc24e98cc9a4ab478550bf47358fe338a6b753c8a8aa63a9eaea8eac88289e1e7987db4c90e7b29a9b477642cfeb2aa56980a15bae0b4a5f202a3e7b570e63ace12e551a7cc761ec3948294a31dc53d06f55a19025a14d8a4b4259811fc6194bbb78a2e3083841250f042da2ab0bd375052c448de45c1f2dce770e73dc3dfeace028077d366f7a05022f66a8f69048a944c48d054ec16276c41e925f1958236f29a0de6111317e47470ae6cd981477158921b0a2c90d2dea1f8f8923738a7b0fc7542a289885f71ee7f6e92c260ddf000f69adcd1b4cb0ed486cbe5dbc4551de3e088a823aeb19a2b7341a7809edbc318c39816c0229d15af810c046762b521132492de3c83636a20baf30da4a7f64986d11a6320dc7102e99f0b65ec9e91731f3177e4bc46cc51457cab44da2aaa0b21e2a14a50bc6a2a65aac6c7a4f8d9786f78dd52c55664416cf651a1ab9bcccaf1e30133f2a7d6c4eb0bb9fbaa2cbeee13179142b9b9af36170a303c4677f47843cf002f7f31d23723ac09335c2286d7d4cf54990b2b2c2c71ac0577bf00bf6fbfb66d21bac5d75c3a83283c754b2ad8c2a825737e93ea19a601dbd91de472e08cb90c1e34959acf5f4331d1f82e7691527dd7ec46504789caf74c7ff03a97fbd9420a85ae16bcd0a9b1d3ded47f8024c0020375b05970e4d2cfd2cdd8ced9aaa7514f8350721977a16fd83dd00d024cb213952a6ff1476da030ecd696899b44bcb763e8b5a958d0b5bf16798be43fb19a79322b09f2104fa52840b4a3006665669f6a3f4276e9568c042a1e7646cfcc489b183918e519d5f1b8e58cac95fc7488bb8a4be81e429481cba776ddb69e195300ed90c7d5e82d02fa24209d19615f4f75d69714b5676e81db5bf06c0c8c06f1a11508bfc3208e4e5506d755a15576827b84ee7035f8dfb15c14b1b030c417d7db7f60fd494a55b64ce7b5b0de3aa635e43a11cee4747a976688bf8012aad3848398e8bc592a72dc05a272d8daadd490729706ffaa9794e8ef0193457b1e90dcdc9cb17f7b4265ad8e146a41777fa9410fbd21a19ca474c6a79fc012408b711324d9c1424f74b79d23ad260d6edb09f72c04221bba5b9a5ae546b7ddcf530db26f60555fcdb91b048d6321bf43e15bdb862dd8d63e52be1158e86b065e1b402a472221c3d6997b14bbda2b0d984eb97d8b94611e5080f998bf3f21aebcb9d559a27db5704064df9e4babca91ceebec256e38b630c04ffac9f219dcffc836283d6580381c05a56d8264ea35f1656d9d6ac65fb6019ba960aea4cf16dd269082a26b2b575a389ff3324a367bde12b5c0140e6aaa263c19dacf5669c1c6cfa286e530111585a932628291be8e0ec6ea06b97bf5697327310d8e208f289ea9b4d12d643b8145a3239f337e5b527d7c5ec29b6b5b26e74128ae544b31721fd7e334d665d4b28e1fb730ba6e670a7c17d0407b8066e6d6b410951f5ceebfc9b2cddfc308bbb44f3859d3840591ee535b6741d98b0c09644512951397ce95a07a398ac50e8b6cdc56a5f58ffa89d07120d398d12d1c35c94baba9366121b65145f7d81c7432a8c2e3a5325966084674ede8643a3bc4b830f8e9ece81c9ebe6a2083fcd8cb17c1ae5e8b69f8c8ed6b9af1652774fc61fa25d64c979ef64f66813b5405c4d7f608c582b7e283f0b178ae92a621d231c2c081dbf2bed7aa2c188cbdc64e34fe1f0b03711d4d9b86a47c5a8ee4e62bbf3923204553048cafb37e374b3d910fc5ef31d94c8fcc04c5f504f360d57b0190449a9098082a58094e7a704a321322e226d2e01aa4b6638c5ff53e9cfd75f7f51d925c9429b706322ca2b4a4166842a8d03873cb04b8966d8027ac9a2326302a1c4202017d93d60a19fa81b6cb997d0763c79bd200bf3c402425fe0ba0790570829897227d8f399e27f12a27cb9df21ffbcc7271d13fe6a3058311641798c21ae5dc10d87678f89c8d43859022fb36a0ae3d8de1cbaf49f502d98be9e06928e7cac0e1142c5cf2a5932ccf2effd762001760618b8a5ce0a3f6d09965c52ff339b73f762e7ee1ac45259c5d4d33ca93812fa96534c7071527209e2597154c3dea3c9fd321fb9ce267be13100a5cc03c0f848690b7df7a69586c7c23fd0e6032cb52cabf0ddb251c42b12a8448bc6cab69cce121af090e906acb5255d3473a4715f96d194b80c55ff72ad900762a6143a39a6e6ddfc583090c90cab13cefa352a98fa793b2f2b58da598abea4678384b5a6c8f12670d88a6042df03e793775a30e76d8a14c153e5dab2f9a84c21ab33b72b375b76bf05a29e91feca0a2fa7cd208e8205a581145492c7fdcb128f79edb4585d01602f940218acfb63681919a1bcf4c7bf917c80ce723d19b18a66ad042cd11c6db559c850fdfac7b71db9f47643031d7d23980c1881ea4e260b84c2b80ba0367565e377de4c2f9c2c10255f8be1fa72819f55443ac77ff1066ad0b6d3014ee2a5afa36393a2c9dc86e70d061767e454b05c8d5145d9cb0206ccb155b37e2d34471113602cba2aa073daad6ad6139f5490ea6908b585f5e2c898006a9fa8f8ff4645e7907a1d18d4d12d80652d926f5ef4b592efb2454c795c7f577a4c7c33693c8d1ac7a15ef1f8baa2aa3b0b8246502eafc742fafd37cbb6ea23fe2bb15983efe850f8950d8eb80f5b99cfed027ba4dc3daebf107ccdbaee84c9aa10209ec25bb3713c53605da4a7ea704e22bd4fc94656d18f3965d371b81c922bbfbe2a1e40819275a41d063d09310414a04477a287ddadad4c38f90f5372989b8ee52ce64c6c111215c7c8e33e064f420f245d2191cfe287539e4cb42d43968ad703ac5c980eb412f66cce0eced84edbe20de10e2975a112c3fa80ebecf6adccceffc4330bc8acf9a58e250da2413d21b2795a9d8d6a5fc52ca44a41878931b53ac32ecd6d55fe6e3b50493f8584633cb88d61ef2be59dc555aba45279f94652b281569ab44ce9b272d2ed92c6937f7fe96111d4cd062edcc3947fbee4aa0f60b0cab0264429bc27b1ec36599264df7c4408a40a76294374c2e2c2f6af202fda9db222852949333273ec1f9868aae2be056823a3c1c8069c445e6745b6aea4ee0bea523e1587a4869be5d49e2927e7b7a73a8b02f2d0e4eaedf38352a14a3e6dd822aaf10c64eeb93ca77e4b6e29596a90b5d3a96c19dab5f65b365e84fe70c0b2f1d53b7f80875e507f34351dd9a323a34053caf8d1be2b21d120a62337a4b4d1b019e0a853e3f3d22a97a10d794e4e3e9814dac874541e2d3dfe9b9c6ec62a5ebce782fe6a69793bc6ddfe9195a082d17080d8842aec95f0969a870380a1278b8f4b340de30a56a2a594fce59e5c8a097ce71433a8bda89f0f8bee1431e8489a5ce016a0da78c82680a45238cc17754aa2a13d6ecb58616b45a5323c020f3caadbe710931d17a48664d6dda35a254810c0557999f47fbaec34990a84a3ce1919ca26aa825f6f9ba3bed912e6de27a2e4557327e25a5a3201b15e37fa9a07bb879ea6c9a60977260e359bf3c4672aa215c9cab124dc4715a8aee7458a46fa8cd514b711929fe95c3d2bbedd9ed4c5fae5b8ca927a8640873e5c63addb17e7464a832738cad9f88ba6450958938e37c14027b4b0480ad7a92000abaa6e820ace299d8a226b9dacd366dba9b117f511e3d4c6432ad963313af25737402a04df29af183f92eaff7cbbe4d93548df47ebdeb6fbe300bb86b7443ac98a8063c3bd9d042e8cd5cb0a5d39d068b8e700a6ab46822778fcc2914fbfa8681f45eae3aa35184ec4b8915895447709fbe6c184ae766ceaea9d90a9688ef9629d0ec49ef6bb5b286e166f92904d2d94b47d508871ec5e8977560f1f5bfbac04c49ed3ed2648c12101de136a8ee1bdbc6bb6a6aeb040ae2a1e728e5f2e408ba1bc4ffb61c47b65cfcafdca7e8740bae094714ebf196f793a5a6b1e6d03be87492863642b751bd41bc6e444107afc1aadc08098967f1ff66ff78b0887ac768b51829c6a148a480f1c17cdb688e26d4cc59a90a5803da3c0afe7f2e20b6b8c5fc95ddb869436da02b7e91e683dd7b3242291d3c588e1971916abd19daa44c42e76eec43cfd0434a81a6093e89024f039af88b146807d24a6a15f5b2fe0204ca4861ccb9b113e3f4ffbd6da765cdb19d1e3aef5a8c3c685d917634016b0a9b27ad0d6f44e0e1dcb70c9ca2796bb50c6adc99b2a892e0ef7f355e10f56740c276590638b3d65e2a63b55016aac2d0e045706ff940a923c642084fc8642b547c558eaab85703f2f013ec86f8a6447b8a11fe4a65aaf8274e0c56744cacf10972bd52461398a95275c67eb21e51cc0ff5b40f2d07434ef513bcfc7dd3e3f5a39586ba5bb9103a79f28b89549ac619dc6d4c326812ae6f5b5bb265b455b1aa4e3d86238012e8fb5631850b26e3e2a40b12af7015bb5ac2accb5078c360385be42d85f0eb616ab0ed29a2b0e62bf35c799ffa4d3a8b0781187a8d4d06196feab4e4f54dd3e24f885647430be6a8078ca9b77ca90aa4f87357033fc5a08fc362ef144820418444f8794968346d615c8b3155b07bf7010f718ca050ecf3cb5154142836f69b081d8b2ea3f2b4f48b9822126efe0a24a8a2d5c16b6fae0b6b902991b101d455c69d16babf43b3160e640af25103542ab11c11dba87548d4da4817eb28830a8a2fcdd88c21c8665d334869f98e7465e865832ee718665354f6fd8874d08f88f6aafff15da03b95d33fc585d296de7b37957a4600d36fb6a3cf34454b06bc11b9fd952b7e5606a7d008d28c6ca1eecca68d90dac526d7a59988117c140957ea76d60162b6ef00551324b52e7b06216edfa920b30b32ef2a67bc5a0e19ae1929ef8b1613db73e545623053cba721722c4eae1e39c5285bd729e5e7b9a95ccc051d37ec5b24563d69e46e036f5e255b0528eea08447fa6a1b240fc6ffb7ca936b888c7cfb1afa64c9cf5d994fb4ef113b13c8b421d3037318c687515d00b4a6a7fd06807224a9eb6235cb720a1a019ffe9f1c143c401d3803d9ca15ac1c953e07fa77802d04c01853a7da2f2e796ea04338766d90b335c2d1e6208c9939b0ea4400be823570fe9d3c86dc94e4e595e5d2e5394d6ff54cc27f31c7cfeddfc0fb301ccfcf9943c5a836349680c05b7ec531e54074ee30251cb1a2883860ad8d9c4106cd8cc84d1b874033a3fa1ca7ae02b8d46e0c4503738c0747a076ac351a6e0440be565732587eb552fed23248e33c72163e575a46bdacec8a55d27f6bf107536d63edbd7e939511e0f17a27ff037e00cd14aa48093658a337bc080e227c8858d7673e8037c1536ae0db14bb7378d0c9ba40b5b182270ac3014094308eeda526c6a187aea8ff5284e94814071ba13486d6ef02d2dc9514d22d4875ea4394a8daaa0ab37c2046ff378a844349ba619fa67cadd8868a0921602564031d09bb5ebea8cdfd03ddcf5275378f6a5794635853ac7d7569cadc7d4c7f301240bc365ca40f3fc5a8b9e9392fce9ec10e1dd8284bea9355083fbbb873db1171ed59a3a52ef69c240ffc950bba918a4a6710801c0592df1c8fac3fad66e6b76a91a25199e142e0cf0592c3289cf07637b63879f7eae6d44a67b2144632c0c4d2b2208c14da16bb7a67f68671eb47041e672934b4ac8db367f5b08e35526d49eeed700ed516b9c1192cb191dc784150b528f05c0dc3db6ee010f2bfb1c45e12a6179ac1ba5745c740e19879090d95f02f51ba9a9429e84fe54a6f077bd24c8ad896967e43c632b21029a8f7c4ed0a5cb67856a0cbe37d6989a5a594c8a4121256460d0b20d4711bd3f88493de605172612cc362e0909ee206fb49443e21cee37fac62060ad65ca5850499731eb5f63ff55ff65cd2166149ba536357250373ea52e5d5495dc837114495dcfaed54094ebe25653359e02bcd64d56a52655e17e40b1c3325b4d7c080ab26cf19d6b69ad8e2aa14172f49a0a95c08cab47d9b98519dd274fc1350aa56f56e2208b1806cd253a14d89dd2de01ea9e43e8ceb8ba08490371af6491847bac5e1da763dac6fecd97d196f57090aca8ca112650ecba0b54f39815d1f925dec5d28c6d505f5589f08e4a2298dcec335b8ca179fcecfd5cf0a60d985d2f5e1f143bf03f074b08eb6f83e22ae879f2a26b95e322893c9726ed3fcd23a232efa9e9981ceabdce59fc193c8d36d5f33c252413a62dab828e3e81127f19ea5752e242b51ce04a8f09310045a61f1e8fb145c8df154fc04d4e986b9b70514ce8931ee5d86e23dc90b4358ed27bc553656b641a1a1f2241aaec1e4ba8595c727ed71d80192bf8f5392be68cdcb126969dac9c726b7a5d32b844faded3eafb24ba1390c535c76beb094eadfd3eb7c0336087011c13eb4f084bda017c8a9b2521d884e5a229a4885843a690debb8e46f41355462e864663fab89f5051c9f557e7472fdce2a3dfdfb962250844b4e51d7eb870e9d95a23a4a73b03b05314e4615bc0b8d17f44874d9ab156f8725b73336a387ef4e5b1f34c95fe0158e4c01e099e1d4a4bf0785e4fcb40157ac40d35b075cfcf3bfe79423b78f2b192d9229b045e122ed40ee1d5652897f75c1636dfc5a3d7cfdcdeec5f6edd4bfa6edf30fdc2fc8714fa2138a774a3f822b32b950297c02ad87917c283c115d258093cc79bc172cdb0f3602f65b52aa317f8b102af09aca2d9445a83083785acb460743ecc467a01c911086f70bdfcd139102fa2e46ac8d4f9dea40cd1cf050bac96dd9f05db7811c935810af9ccefdda08edbd0505b7102c2717daa89b21514e9a1674634375ad1e756c0e23427154e81ff2ecc5637bbe436f2a27fe80a68654eaf925625bbd59ea555a2d2709289de1998fbb6c21029f0d8caf8e9c663665cf37917e7ffe5296a139a4d412d96880f81b784225d754cfea44e29bf9af69c4b4fec927c0b62925db3c4d00ef63cfda3cc535987caed4d366726f2485058e6f69bc7aaaab9143fcfc33013fad601cab8d5cc09123a10a7072213119790e7311ab480f486ff9be7e9cbc51714c7befd8d2c05a5a50cab2a8bf9c39f5e50d903940c64f575ffaea780aea81801af5a71403ade992e37facd503e84de819c3576e2b0974b25f886fba1ac291114ab6ce9911dfc5f12b805a3769670ba157e35605ecb6a46a82bffed7afad5ffcde57dc23191b34afec357e7aba5ace8fa8673d4ab9ba60214d3e965b66addd6158a2323de11bed2f02f04fe481e16bdf50f9186e0344fc510b4e3b075c8a205a722292a1a798b4cd432202c1cd9d23f78a519e95357476cb7ab4cc0a8818d25ba1a58ef1c01882c5cafcaee589aa890ede905360a13704827d86d028773d228b14cb5def068cd2bf66a71fb2e3c892b486c21eb0eab6e6a763d4a620771d99b41553b33b209369b01e3d76a6f558a5c35d334927a3a94904489757cd7dd4b1b0b1556e6e47778b5b41e6ad382b0fc6c3d5d0ac6a4a294ab4b5975d30f92f8bc2b86893b57da5d0c3d42d266a875264804707e2a5c5ce27eeea7c97b68d15510fcb99294d48eeb1132b8e06ed1bcff987ae5d5ae0658520f83cfcc91a039199ad48a7ae4af9f3fe11ddbd8c078ce5b4b23f07af35ef47297be3678b51439d0f4cb50c3f18b977cb98f04b7453c60cb2f7c488cf813a3d7e08644f0db8adfd3e87a160edd62ce5198565d38cbf1de656119a69b485fbd413bfe453e5dbcc08e4c889d3a9464a5460323fe25b2f550d2badc0f0982c6d85973aa11fd6ec44ca65a7f608dd61de09f2dc5bcb92c65b6bab149b476da38b438c5ede4b73deaec433a15de2c54fc421114216448d8f00170ad1fe365c56f57198abca44d184d4022c227d1ecae7172f984e8cf1017dfd4e4c27be1ce96c0d12b23bf1c8cab6f87d4cff74965b451162a9a2751e3662b962529fbe8e91209c1bb31a5f42dd429f70e31f5f5c77be6d2163d05a8d7b7cfb57d94daa47312de81ca1dc5fd1f7cbbb1e84899e735c524d9add72e5b4e8c451c94a67bed192ac731fd9fdfea458a7e30884e26914f96682b01735b113747d2c6b17480374f7dfaeb700804a0e8f176140ef6c20a1cc3abf74f0e41f9513c37d3c9c89541fdc022bab45537708184deee6950afd9a0bcb90b92eb387fa4850df1c9c87bac92a708936386aeedf436e5d7552404d3a48602d50cd0d1d303b845cfde3175cd85f4090871e4ab4b8ecbfb557455221ea5dc1c7cbd3c1a94026b9945137a15a7569f3b3d0c0d01cf507c3f5e769506b9453a12ed2f4fb64d572dcddc8d10f6966dae136b5e1600d2ca0071e031ea7f69c1d021d404ab08829485c834b97443ec4925a9ce69a38c24912058dd6799b82f8fe1cc28ca816c937fe93846ebaaf693da10b9d89ab520b5c1892898b65821fe2d3e44618c83f8cdd55a4711fe7eafc1307ff6b01845160c120d2574185c232fc1c1c3c0ec228aabab7417a561b2646fb29dd506f83d6e349f169cbf13f6f7e05d805ac6688b35454ac0ac0fee7b5fc9bf40499f51bcde1b8e6786fdd80fc6c4008c87152bf76486e2f3a2b2314b22fde68ddb7cb9994b72985042225811a1f48b1192f21852b7176c8cd6f7d57e70a4ad7215632df1f8e0dd9af0f915f5c7fa3e428d5745e1292d31969203703379989233e8b44f542c73ffc18ba9343ef0cd6283e6aeadb215d20688e77aa01c3f4024482214c24a81ecb503cc57aa10e94851cb5f605be62cf8c510f170e81a88a40264c9d283f528566b264a655196122de27f8b80ceb8f1c399b09143674bc21a047c83666ef475dbb99e7af24bf1cc3f38e242b00b6622c81e2a368cd35ecc14d81937464ad6804750e30fbdddc107488f63fa53802bde833b140ae65d7775dfd7ff9d13e88c0c67b5695cd0c89820eeb94ca69f825c41761394017ae7b37203250cea8892afe953904908c841b84fb8146ded12692ea7de1f7b482a6c2cadc0ee1fe9693d1cdd011471d64fa3a01dec690498bb1d6b882b5e5a5ef6dc089bd504dc3e2474ce9c43bb8bb4a8b8cfe1b1707162469d2657d388f33100e63fbc27772a38acdbbba23a79a5bd51d779e890164e8f42456b2759f80a2ce8963feae6e25082ac11b9a70ca384c20132475ad01139460cb482b0dcf00ecdb6dc38387feccc7179fb48984d1681df67a05a2b3214148a811f31841f3be6b1e03a2ce232df3f0fe402858514663f0b08980f6c80d278ab9253099c6f60dd585b7c01d73a718b6e06bdb2cf83b18e7312d0fe1ad84094042f807e354dbab388ee5bb603700ff196e45bc3d72333574df5b1688292e2162b625ebe6204c53cdbf593a304883ca2c1b911a08ceb3da638ec42c54555811b4b515609ba5a5fdf11c5a55f511606da9f1b4d58cc2df1b0c246844478da87dab912953840ab435b2b89cc8924d2252762a083b16548269e2b45dfb959a2ddce16d3fe02d2dcc61d8ba328c466bc06473ea631fbeca4e64fbccee17ac3c80422b5a7a93f829b2caf1b50315b5aca495a4f059ba2e7185682275bb1b35f7e0884236a4d8e7aa94747fa542dc7323550ee74bbc7cde425c218cb37d20335014820823909f476295e41f30b781fc7cf29d597a6d4ef53efcc8ebe2e7ec4c5363a1a1b9d330705bc0ade260a47ac6d2b2fbb9ad83cff922681b3b2edfa5b3601142c4b35536fe33367161a1e318e86f9fc51236e575ed718addb05695f9cf1b00d1c078a38155225673b0d7aab689b3c46d3ccdadfa91ec2b1af3344e43b3817f392c3411319e6c660ffd65899d6d615f863ccd697452a5be32a47821230dca706aecb6cd859a068e22ae2f83fb957275997aec63ee0d1f12a7d0bbc41057854b8689fc85efd24a91e32fcf8a0ee5fb20df3be03ba9f9ec1fe24047d02caceef800c008e65a46d35a91712b7f4c25734f11a56dd632f90cd2c7b6ebd74c4ae0473a8841520dcc88c27f6c2324808257a76ad04bc79255e7ec770d122786598f8f2da41f68a9c86daa85b033bdf306fff426e287b55fad3b0310f96fb864994918bc900c6c4e5699146fb8a0484694085c0259fbab23f191a60e9a45101558970fa41c3669f12ad1ea8e8eb1cf50391862029dc39eab31d9e8cc035f4fed0fd1d88b9f32ecf8b4ec4618930d8f3242b2d87c6d458dc51ac8f321a006935f3dfe901194f8ad4b0a81c05e66a92aa4ad7cb76cea36e5a4857221fb9c157045cb872355963edc4888396fe718dba0ac1226bccf59bb1c9f7e6fe2c68b7bcfb27970cd1749238448e421c97e9e27ba2161fabb2042ad491f9a735df909d815858cb50ff9efd433fbf6019e9488b7730162a7365dbddd6c6d20b1785a192caee2e658974f8ec1e1d9ba7cd056f6a29c06aef24f7e913158394082858eddd6515602764af8feab436bd8a8341d6018f71d6d30802047323c3a551b079c129dfae36a3e54c736565e9045e95ee34e33aa7119acabfb902cce0f1f3f1314e39c2a74543f83f66750ecfae7087a6f196247181e3d41d06ac1763c0b8511a4f6933fa1a75c96bda06607b4a59c65ad4440b902fe4828b69513398efcdaccd6f8c7d26f78fa4c7c62772b629d7fe067e1a33b9cc2fa50eb4bebb1a0ee3d977e861ce8159b12681be23e6c9b3a58dd57b76fe3127ef7fb56b7779f0ec9c766833917c35872d2c581a38b3291237e0f00d75c5ce012f64392dc8d784eb12200f602ed5b0e54a1be8b5a0da958453a467fcdde958e3a2519bc19895b0e46eb58f4f55698bee96e243ff6268a453615138b1c2b2a5ed7f603a64f6e3da0263e5547c4749c2ca7b63d37c7717542c1c9339956f7ae81f24a94483c8dbb3158ce86c2b9b400934941d3073bc3a843a1f09cd85d57d7146694d4fb87781bd72d6523b7015fbcc52038e0d902e9192d77dbe4600510a01baea65631614d905b56aa3cc609228bfe20d8a2ee3d60db276cbf838a7db9d28da9eb939dfbff79f98b46818f379480d2427d74eed7bd78c3ae89e4e9d083fcaaa3596d69870407215d0c6ce15cdc265e07b6190a35410de11129815004454a9e89fc645e07876911e7d8b24a9ab8ce55daa4bbf4f0b08c1821d4862ad7205e7a5a6f569b410bc8c4b965b85a8ec5d0ab53a98456e240f9238e898981023e039cf73820d53db879ef7beec1e7c7dd23bb30ca1eacff1582219f951a89f46ba8df472a1d02b3ff5fa33c9c348ff1cfc3e258305c99dcba96ad28623f860535c53ef77328d8903c7a0eb41429d2148d0a295d8a521ea408c65b1898b69e947f69c87f14131a2d6541434b14e46fabe8683d054a33108f8d4fc828e53851da66679990013fd7541470e4bb5269a6dcfc26afa8f479cdade8893638f22a938749e0c73ddd9c1518d5d5c14ab105550f9ccee0f6821c5cda278f21a222c33a2a972b24bc7434cc143e97ca7d0edb430a2151cf27650e70e988263c945cfc7d13c0d33bb90b5e7f1c4e90d26a5efc184448f65cdbbb248063eaeec994a1ed588ae9c8ea580cd22791787aaf937ae3c6d49d2aeff406c3a6a77ae1e6fe26d961fbec863c50f53a839ae23948a214890800c93ffe2a1b05bd7b0c0e2e7b18b535315ed0c34f83d05231f3c126748c9634acafa66518e6a780c369ed4da38eedb2b33b8ffaba619e76230ed29e62c6d21e9c2f736a9f0ccb70215ca90e14bbfb1dde2f7518c6f1825039a0daeac027442790f8fb702722493ecf66f146634ef9d9e50ff1bc8b45eef50c7ba6661f0a9cfe039f25ce1705546a9817e331073b4bd1d8d7a83c49e25390205a647e2a01ec9bb747d597ce3990ae3de38c44191347f4a31aa96f32bca739a4760d6d86cf4b7b39fa6a2c90a4779f2aa3160bfc445d2ee8724c1d1201a42728f8bdf1621de056b86e9161cc6913a7cda61c8769ca34f131e51f280d68c9f5e323cfd926d11ea52b244fb5b1379ef7404e2846d3426558dd364f4b638d18864b6cfc13b3321a6a2c5353a0cdd9da2da255c16c537c9c29200a5d1e30388138297412dc1202bda4210a4f0cb15df2407fbacbd1253792da7e4ac4f7a6dd8bded502cdb1098a5f3d0250066da49d6b4f42fc469728c94e089ccd9858d3355cbb0640c0102825db9f98bd8a47500dbd506e45dc8c06a4c2b766965f1c22f8876fd8da38056d703534446bc0c68ac7539f8c0b5392eb3f460d4a6eaeb275352bc5a25acd3b6900df52b8a4544d3c5fa8c236f6626aea81db89d8a9365fecb39e1afea8ae4d29a9d866433c64776da764f66f3e92b8c2019330ffa83f44977625aa704ae2a92752becb498af1d6df625ee6108873b20fa378db86674e1ad170fe68841a66350d45d30cc54a56267d322c15cf302da8124424c2ab9566916ed1cd1cda043606df1f7b961250a46f944b163ca43d076595f022ad2dd0b4b7be7bb192a031337157a7ab295c15591714035798ba27601009e49c290bc2939e5370078eaff1438242bcc85212ac4a77e700f6710993fa5b65d7c02c1eb586aab3962f783a0720fb3a74c46f317c81581646d5a577cda21f758c988e742c1c4eb31858f8714c1831e4b72a38abda0311c8a74e4a7fc9722bb1825b3d42b31c1b29cd310326c7551f000c86ce7ba6db4f8a4a254d5913a7a3cee7ab115095fe86572fc8c779c7645c14565306ff36e650976a24a0dc28b7ecacaaacfd23dab25049cb1f08c715b81b80e6bb2c5060272842924208a13cf2ab3d61519da2901cda0b8ffdc0b8d42d2c707f14d9fb3a5dd79583a80693589bd8ac2cfbedcc291e174802020986c6400612155982c1285a2db95d39f5529c9ebe41eac4fc2afde7d430f9c27301e9f30d5c80975a7ab55cb5dd26e66b32056fedaf18e6ed7bcabcb4acdaa753413b18a50d7ada08ab84dd57cd24cb0e4252ad35107c94591820e6501c49db23ff3057ec424db07f1f5728bb5ea5f03a1c9e71737147db91342db1bd7ff337be6eb942b6f26456ae1f56a1c7b6d47272c55326fa4cde1a8107d564f9a0b3b6bd572798ddd84aa2f748c93d701e4359cb03a887934899e3eda44e4744722ca4da978414e478fa27489d5cf1a4ec50793992e75c0ad2b8ca0a3c88a52417dee44588d8634ad37060533a3005cf1db2752ef697dc76d81a953baf1cd3d7056abafb2a84879764fa559fd3e52407dc907759ff6255cf4ba3ea71d2c437f325277df70faef756ac9cb86b03af39ea96834f113114b568ad840982faf4761f7d1a5e402eee33010157460e71dbdebfdfd8825614d35e7862e8004709e7a85d65f25f9ad5e34a8472727c2fc1e095a13c2e9a7cd6650b81ccfb8516a840f508b43b3936e1656efd343298061329c2622e56917deeb030d114013a74f85678bfb9f520a3438597610eec49dc7ab04fbacd0ba33495b6c8529bb2f0e25fb5fb79cb1c8cec218aa9c52a59a1f056fed507a8b33fd257d10a0cde36ef9487f59a5d8051bca1e8ca63a47ac7a4710c140cbd5703eba6c216ed8f93a8dd16a4aa6fe0575dca106dd69b79663ed01c7d78dbdd71df06a5e0bee8613eb2568e46563995e6392842a84dd06324596e80b6d8acab744c5861eea5463d6c62d05da24ff07124e6454cd8b67c9a89f944bba7b1d1ffb2972c473b25180048240f7707ba0b97dd70f9f31d84645628f0ae813fc77bd330c5fa452212b2b774a333e812f4b18fe6801f7151c786a6975ebf5974bc745902531d07641e8128e3f23bf91d073bbed6c2ffbb45afe022ae55583936738294865da0bddaada6494a1fee7266755421afa9f27518a27066232e7e50a8ff057dceb212ae12b2077b6e554cc22502445f7b99aee2302a0e3924f643958f78e3fd8f47d6bffaea7fc40e61c3e0bdacde1fcb744aa1e1c38b2f6ff200c9d4872400f6356132038219ed4734c958aec4e0d80c0c1fc05676ee305de7941de5d0756fa2ec188260af293366d19cdaef3752a258e39641224e68f600b16c2b4f09063becfba79e1b78a6ea229336deefd10c7896ae4657db6c409b4b914aded0e3d30b9ad0bc72b47512275799bab0e1247ea6aa3a0b7b321ed1ec169740585768c88dc5d62e344b05eb57b0b8f5ccaa157f8dd3a0bef30204a4ea7d22f38044a48e546be37ef888ec56e48ee856eee845e66e46a1f51975eef171b88327ce13314146d020d9ccb9e7a2a64886d772300a265d3909de34c6fb93654379cb951a44428cad208d351977927b90fbf0199ce16fb4ba4080e01ab194fe04526e6ae8f47adfa7f4be6a79eba7a8d5995fd16783f2d5f468190036e0ca12cd4767cb8daa0711928bc3a8854d21a9e988d993670754512eaf4a634222dc8e2115798a12d50792b8d7943ea9becae311fd85a8b391e454251968090f0726e871344ee682749a2011f119434145e1261e0dc2aa53556e6c892218c6c0b74a679aa19b879b149d56b3babc34c97ef53786152ebfd007878accee37e9bc06f43dfede84e37d8089329eb74e2176feadb7018b495baab94e3501401b983029599293c25974c5be4a528e584e010929818230b42fc4cd309aa4a16f6d23a0c20fea0494f144e133d4f3cba6cb127c8388f26b413a211cc3979e239d870ec84e3dc0ffe3e015844c84e9f77d726c7b13354afeeccccb33734e1f5c38f891537b7a8318887781f773de5ddf59b25b0d501ff186d7fbbedd87075424313a32252c3a1a2d51657638306a9a38741d46a0f407b789406efb8b67aca7a93011ca05d2084260c0878023c190036d4870af90b166ff4196a00556021ff86618d640ba5a72c3ac9520d4ad67f053ccd876890b01e2b58a9108e06057297067e768c36b0b21864b3f5531a98fefeff6f50db1ffe01dfd860db9e946e6276ee422373375052fe058f03cd7a9f87bd0bfec6bd8c4accdcad71e89857282f42c3567166aceae70215d59835c5bfbef7f93509f4ea2ab1160232e8d1c4308059366c34b53c72e2ee5b5b49f3f50dfbe28284efd1ab213587a63a7272c4113b379cf729a6a65b67638debc8ea1bbe0925711afbeec32a3b999513960151084c6040ae2329ec31a7545363742e955cb21580f5fcc2b49e416d587ec9b6cbc486e484155328eed39ce1790ebe7b032882b3f04e308be7c3b5a34a3be501ead7ea3c066c3cc0817873d9a7a5d862250d185671ea03e68be7109c965f4e5d82d31f75a0a961e18675a3b39130e7f12178b28b54a0cdb6a8960577e101d8a3e433fcbe5db1c39cfaafe23f419ab049829250a7b002579e3d3642442052bf2b6357e8c099da60a476a4c43b5d65849d980c895320dc871bc32a5a8a5fe4e254b85984803cbfcc8ecb7a100c4125223aa713e654b80a756abc29041675356c0cc0c70f6dcba11381aefa2c71a9a6652e120ae9432b89af335c7f82463f5d5781844478f05f47e279e446cf985b93672881c99bab05811cde4d0c7d52d0d6242633cdb32927564e2b5af5a5a7874518a275b12d34704c9f0107397bede671e944ef7bb5aedf232868b34161daae22ed05fe566808324940e93d10faf2e033ae0bb83aa0aae7099cdb0fbb40bbec2ac6c86292a2a135a969aa0177d7e719d7e866b0178ef2b5d9a8537f3bd9dab1660b7a1929044538c88bf6418464beb553e2e04bc937e859dffbc6af6d8d25ac50cd2dd76695077f3b15bd02cc1988b420b4c58a9545c6454749141e88819f40644c3aab54bb988c6b5909dec3068dc9e2610c66d144a43cbc61d5ea8d1036c0ec0dbaca117eac6f22f05118c389e6bdc562b36b62e3501e2b5dd1c88b0d993c6eebe23ce983dd4abf47f25e1dcf0d950ce19df0b85cadda41c427208045d2bff1a9ba06f4a607d822d582fa6bba1d549bdfdb5da0dfcf653a1c5a09cc930146b57bf01ba0d1c637c5e2eb92734b030de00c1803cc1deaf6c4822966207d0d1190bf07ea8d48508e23f34ce8d431a9d65346416289ce62c5690e8fd7183120289a821e61e4c563ffbd54434e2f54079f19447c3c1be943ffa00a4441a6e088a966b03f89c597d1b0f119d23c402583e0a0fc6cfcf983418e9b8e5a3e8cc5d8b7d556bf2cf9aad95caae5ba81ca308c10da7ee2d739093050ae4706061ff495297c01f13295f51fa70e1e3dc912a8f40e15060b87b9875de3d813831330c4a84278bbfe2ddbd985ef5586c59fb4aac171dddfd90f929ec73c86e000cb4c85dc99651dc23700ecdcaf4617938c8881b9f5ad6d17678b42e5367a9d95eb76907632598b36a23443052cde884f1e7a4d528c211e0870ad1f72bbc4ad72faafc8d102842f340402ef946f4ce172c34c986a9b6dc908858086ab5862046d27f526d0acaf184520173bb016c9c0235d524e4a5613bc3d922258571a2c3b6896b89e2439c3d46f78715ccdea040ada11ece0af0af4a4e4a90cdb33ed3ebbb43bfa2f1b9d9a44078804637633ee68c74e62b2e658c1a3f53e766ce56eda15cd9207a050584457cf4b47624fd0ff80bc50caf3102bd00023bc1179f8b0b34bf186e4e572afd42f810f6722b1223f87be7d030ce405302d5c6d605442b45397c07667128723198e5378f04c93051de504e871122a6e320b26a1c7226251f19185176b1de604a1a63d0d72eb5323f3d4efdf7275ee588fe1d086cffc837cae5e94d59d18c54c8bd11694147d2a7d99d83cf0ce96aff79edcb853ed8f50b665a4a28ab1912a60459408da0bba0f0ded5fbe14159fd88209894806bbc3509a808b2d6bdc08b58a4cfef490d0dba1aec4e663be0e29c621b0c0f57985a43f8738626e426ee8f144bfd47b7583b7583e0f659f1aef4ae3a19f2bea1ff2c7accb72d5a9718cce4ffc924b659ad3c663a8aedfbf98445b17cf2e422f426972ae5640a018d54c8b4e73c49b8a91174790b2c5caa6e920675c91381720f72caafcd72951aadac213defaaf6cb9990527eb61614b8fff4cb978571a89c7acb78c5839e14cc03612c5857b89071a29e660f9ad27e498e64a6647c7b90dfec059c6b9c0125c5634ddafac6683f061a8a2bed29a428762f39d32a3d291eba2a33031cc82673fb2d4024606a6314e9541eaa4542ed5fc1056d3c862fcab7ef6d0882e0898602050b73c4e0d800d70c3fad771c2b6a408fdf2585a0d13c36de25327d98d38238c21e33ab71e5fef9c4d71107864631484a89094f20f5864e9b12e2d03e0431fa553d5f9197ad70549f8201c484684949dba7907cb9ab48fad87a1131d446928f2dfa1e17cb30e0e9772b9c3dcec1cc6de9ea63dcd8f9c1f4de5fa95bbe5a9802adf26c245ad44747ac9f2df322498078c80e670770cb68b796a85f0fbdf6290b0a85147ebb703b83a192328a65b30d7bfc4ee8ba4f1a13746ba40ada1591430696783d9d9d060b0d3bc7e54249228910692011647848333b86dcbac755e3ecc5fd026cfdd5e5b9eef66dce99096cf7879d064f446cbb87e17c84bea6863abe02b774a8430d81980898899507b1931f4773b537b128d8dca91dfbda1ab7616382e7079f7fb9e50cb2f38f548fe2d5cdc42b64b75917d0242641ea829741b22b6891cc6e56d0de01914951ec1612757d2c4178ff5f321efa983deda6fb851080d12128fa53d54aec1abfca2168106d17e38ca1d5508b48f4eebd6b00ca897af36b0be102871659d1c803579cb3d5222e635eeb3ecbd2c1068c934650830574c6f8c3900671a6344d4d605da8e9f693ee85f86ab3a9c257088942dd4fe504b8179ce741ab928770eb327f3c2d29af6c1a189bb41d74409475650c7975047441777e0d96868458ebc92ac65a9a884668f8de038ab4e34a473fe30a68e10de68512e4cda90f4fb86c83a5ee2a61bb1b4c0852d91fdb62ead420162a916259a34bae2cf28796d5ab2dd3208b2329aaaf68191258789d93f12797510a279aa1d7a33b0c9cdd40445583ba3aebfbc70e53568e90742d621154440d4a8154637237204a900a1dd03a56fae0c9886d6f15c96dcc0a4328d4ddfffdc9607aa551c8956d2dbe89e62d98516a46781740a95b9c724d93a2a7b42bb9133fe832c9a0c3b56f0c5fe0f091f694dcb20f8392ac12bb1c38d04fb7960aaf998c6104d1a518e3153f84c3dd4796d02b7df9787f7f5492e4e9da688d8000241b054fadafa7e522ccb30a627dc49318346fbf8827f7b6d41fbc3d3b1d1310603d7e1a381d667f2340018c0dfb53f49f037dc3a341c73af8720d9c1832d64c34bea85504e07fa04cd12862288126eab349f029cad1a54645f1eb6f8348dbd7fc919d7259203c2010cd799634a96fe6d94ebca5e3d1a1f2abeb2c1ec371cfe9168f12370a4750c46e2395b33d8c4701e050027101dabe768bab8c0029aba52f0f66d013e76e234ac047687640444272afa0415407d19382d4ce83ca4e149aa340363168cba0263494024a02466d5f4092595507559bcffa3810bf85f6c18383ba8aaf50b72bc890878178960dea2ac8fcb014c05a89a7f86c794bb61a3cc0c15d54067786b027cea8e5eed5fee6be27586dafb3bb4f466f030547ed8f2d25b663169d5967fe76fbdfff524a2953f6060707af062bd6b6c1020b20205b3608ccceb23d809758a2b30082b0871bb6e44d984478132a4378132bb0246f82b4ef8609e14d94fb6ed8116f2205f82630923761c49b5015f126566f8275e44d04c1c89b08df84b887fa8dd934d8110a10b3ef86e136ec16ad0cc76531642f90d120ab410603590c4c2eb3e1c2789abb575cd602990b64333ccd95dd9e46062e630197bd781a93cb6ce0395b2cc7b55578ce96428e6b9748ae8df34ee1250f81d9f399739db219321cfaddb29e6b73b7a8ed3e7165b86c867fc96cf8cf81e1a21c1b031a7110901d48bf7bc50e1fbc3b8bf578f4ee588c500649c3bcc1a37d909d8de4356bcd0a1f5cac48ef2cf6c2a32a6888f1a8c0dd59ac8547797c4db05f7c5383c44e12354a76d63bab39e2d1bb6d1d0464176d9ad82d06648a1fbe892d913790939fc035b4986e377fe1ff321a3af25810bf6c781327bbe19b82cc0559b0df2d4660c49c24019e27308a28ead222ad572d3d12b95c3226143b3c1f2febbcc353b1c3376416e9989856ab05c3c7153d138a154150a8d8dd481a4c0deaf5bb614176fdaa4230e09d29b9331a075250b1db3b3a2b2854106083420000208bd59c60819148c364fc72f920d4d5b5aa8f1417d8920846b991e202f296f7de4b7e49846c0159a67425914d963e7e9718731442e43d5b6e99089be5627a2155a832d5133ca19cecd7bdd046698fbbc5ce6921ad542a954af553a95c8654d9260327838b177c403d74dca8a1f0f5696c2e43bf755df7c86d824f337331b3cd6af8d5e4a25709505d718e47f5c2a4df6d8384afb9bb8597f86e11cb69d92f47081949727b9aab83b7bca8ce98ba7361ed7ee30be77969c1ecb387d487b1f772e155bbbdc024aa377ae178ac880f00929719799b9733a6de7a407d40d3b187d70bf77aa81e8d1eda437b2f1c5fa1f008d3830102e36bc5d0b2b5702d1acc15951492d8ea810102d383f1b56268d95a34b470268c6f05c6a702e34b81f191607c228cafd5531a55b504a2c6b1b45bb84a5085c94a6d85c70a6fa5b702649be48aef372a5598a804576a2b3c56782b40567a2c2b3573a5b6b2525359a9a5acd4566abe0e2c4bd4f8537fc01f6e051e61ddc633a6aa2570456ae136f216798e35a276a8025449523afd544b5440955525891a749b2eab906a03c42f21f5696c8ca82429a202bc339b2147fadda59edbe9a75a329e7ef8f4339d7ee4e977fa9d7e479ec688d045551555a24a608e6f91e7ce5de23915e7b1518e1bef16be2611e46197faa09242128328bdf5e4a722bfd82f099b2227eb9dd90c39719b1e1b5b10dfd8c8e001b7c3373632f860e322bd339b17822927c11e27c1e08d208d2089d2eb2b94d3e6f6537fc01f4e1f3172b3d5624d8217bd2b29549e317555cf1a7005962a91e7f81e79ee2cb59ceb4ad64e9ee2273fe0af6745e26b70b29bcc26e391bd90ebd3c48031a124568b13337264557f2a10f81b4f9b1f114e562c156b9fb88dee69704fc3a2d11343864761f45f10500f9b0a54f198ba3a396d6e2a8b9563ed12cfa156dcb6735a48422420290989b4967628e94abcd20eb1446e1a594a5bb8cbd07ddd316543559922099192908024a15e3b21ada51d4a3b4a3c91b492564c5a4da4955c512bae949e4e9bdbaaaebfa1f5b7aa5c3a36ad2c1e0b9654bb650554ad56fc05e65c5ba32a6654f1cf59893ca7daa3aa65a53a592e432aa0baae405508a804f853b158ab75fda9424025bf150a97a11ac115c5e9a703921653d7f5a70a0195fc60a36a665489259a51a51af1705cf1cf6919459e5bedd20ad8692e2b12527de9e11b598affc547ae78885feb10505d57a02a045402fcad4340755d81aa105009f0b70efdd475fda9424025bf75e8a7aeeb4f15022af99dac2e43173dfdd475fda9424025bf7024d22afe392d37f34a808794ae9695cc72128fea177e96d78b5e98bd392a3cf76f3d83e764afa8ecdf5a86fed1391409fd91b81d11fc5a1f12f4373978a379f8d7efdce36fb40fb987fe3bebf819b94b8dda20d15c9dc786b85bec1cd6fe1df338a49fe9658f6fedbd39e7dcf5c98742872922151725f765429173d96112362d344142aa0367da6298bd0824a5c88554baa369149231189e83d99adb009fc6a6894dd066b55172d15be4e753718ec765b70873ce24fd6e9b23bee6c298addd2296c3dae710214144fab5a93dcd6db1cedf28c7252609248da68773cc4bfbaed3f4f45b048982d26a9d9ce7dc2dc21c1e9e163bc7b55bc47264760caa03ba437190501eaa04babe6a2f162246b1272f1b4d0d19d87d2e1e0be20370b70c8f09f1b2bb63782ce86dee0e61786cc52f9d739e31dfcbee76019e501d501ce88e84ea80f25025d0f5c5e25513511ecadb28ef04e58d50decb4653433e696ac03a12bf4e221d0a0a46c1a42dc2a4303ec0f45a2eb46aad5beb85aa85c54c31b570a8ae345a81f1012685e9b55c68d5f08d4d0bad174d5ab73b430109698d0ef4c6a661ca206304638a9f0a1854d854bc50715361830a9c0a9d8a1a8fde1d862469f21d1e7ec1f0b39d246fbbb31da08a172a6e36fccd8e12ffc2373b2b7ea9d0a9a8c1337777dd7ba261c0a5eff05c43b66979ecf6343b4976802b56ec2871ba321a03172e56dc5ec692af10698961b9b609b0ede23c2ed4452628c3c45573e170ed5c3b5c3cd70faed4e57301f1e8dd6148922ad72f2623b4a11c0643f2b2bb5d38ccc8dbdc3daae170afac4bb60a65645c3d57cd55d3e172b95c2e97cbe572b95ca31399d60a5d900e0683cdccd0d09cb7f3c5893b819cbd1388d3771271fe4ee09964e55c49bb54ee94f3c5793b71270e9fb895137702397b2710a7ef24e2fc9d494ee049c265ca8c0945cb9e49893a34ab2555122153645a2c1dab066bc73ac252594958409612acd5a5e6c28254b9d8c290244d736f140dfba585b857777ad0fbeef07c3c2db26ab074ac9d8ab5636d9a49aa9cac1deb084b65256101594ab05617162e35171bcc08254b0291c47e415b75d26240e6e9a4c57a904a2db6eecb6ed139da39eb1362f609261572b7fb04176e234ce12cd894d2c55314b92b2d9b25c54f09407e7a74045049294977056df3b6b3c28e3c0d8bd0455b2c4c150269adcc8422d72aa53cf1c43db5b28c995ed307b3673231832c2c586a2c31b0d858702c343c7a771892244bcfee8601c258883b62e46b84801755b2c282176d72d19a6da73e684590fb4abd206930d5aa3b1f84ccf4ce6246cc1ebe89ddf8994b82cc1e90d9eb61f674983d5dcfd3d89898c13b8bd1606131a3d7ee2c26e3d118709dc5c642030b6eb3f4c08c20b30e05958899bbaccd1dbe69914288c9ec149e6be556ca57b2286b250ca5ad9ca1bc953de5cfa37787a1aa2c753ca0917ec370a6a75f0e3b62063773f2191b7ecdf0ccd46041d8106c8529e130e0d324e91766e461422398fa342d90295f79d25c29272d3664c782fa0dcf944f3c53be9245592b61286de50ce5adec297fd05206884aa5a974b753fa2447ccc71c1bf235363391d1bb51430c1832d880c82738987aaec005e1fa155378eed4bf4ed3b533bb68305508393383c258122163b3d9b837692525410a966a9474251ca55d89c7bf4a3c5ceadd1290922faf768ade3636e46b7e4f5344bda81027d27d4fd3434a42485fef2c16f42829886f6232fe15ebb93a8d145405633afadd61500ce262b560a9460dfdce62311ee511e3e19b189026bd06098fde6d83a94860457c8d2a24de8c27dc656f1787c1945c740de2d77579934e4d1f9d30a08b08326f1aac3c82ccfb84a49254abb63869e61b140470636214b928869bf865636208300ec0249e2b7ab231665281d4f5995d3a0b6fed8b5a9be22c5fa3ea76a7002285cf0023e6345d3c31623ed355dc3e8dcb558a98c3ba8ae78c989bf003e8879e143b52f0643f807ee8e977a7e0a5d8a1c3d3d1a163039d1d3a3de8dc4007073a3c7472e8d040a7063a3ce8ec746ee8cc4007870e0f1d1e7ef8f8f1a3dfad93eaf0a0c303003a36e8e07478e8f074763f723f0e3062feea327a04755ee8dc623270c17eb7ce4de745b7f5177a0a3a0cdd4557415f418fa1f37414f416dd855eeb2df41374163d86eec2f780f13d5cd0efeeb7ee428f417662c909608fa1db7aed532552200270901840efc491132ada6930b5d7e0203100f5c4119c1fce109c1fe010c1298203049c217088c0118213048e0f7084c0f1e104e1f40007081c227084c011c231a2df8da3e2088143440c87070e0f87089c1f8e0fe7071c14630acfc9d8ad673d62bca7c1c1f138bb1bd3f1afbb55578f0d890501f5dba3dfbdd3c5703872f4d88d1d3af4188defe9b1181f93e161f4bb676c329ac394f03577b7384cc52b2c086bf23477bff0991a6c897ef709a8a0de8a1ebe49f1c3af4b9bf5c0dde0fadd38bb3bdbe15d1c1c3fdbd9f1688ae762604bfe756148fe75f7ce8e9fc18e3c7a673075651a514e2c96164b8a272994cee24c37a331cbe1696635663acc6cc860b6c39dcd98dd30c361967b9a3bebd17c2663e633fb59f1d90ee3cb36bd6c94d3996be121083b0b0f01d9ed66f19773969be598d5a0df3ddbe562760bcfbdeccc73b6302766b366b97fddcd32dbe15f778b6232f4bb6141980a03c26a421f6f16036fc45d331b96edf07ba6c32cb39e74364317c04c05154c28f4d6615570e9a41012b5599b0653595c7cc5ffa227fbe48f5fa9adf96f2e8eb88a1d8e9ffd5ff269ec09db1ac5521cc5b90a620246cccfbec288f9ee6289e762ce14510123e62f2e978ef91a1477e9342615483dbb7491866666660666b3d579012303c673a7f09c6b93ce18fed875923b6778c2093422dd80f18413685604e1adf0ade8cda0f41e008111f3544fe1399916614e6bb7b60bb7ed1c9915bc8b66263f5bb1a3866f54ecf00bc7cf56f8b022ddf1331534a8c05dfdc3dfecf0d8e1ed68207eb613862469ea9aaee95affa09efec57a2a0b8f09e131df4583a42c8c766a6bce820c8721812d61f14b2cb1c4123c2d768e2a0739e79208c6ff4bb1216611fecbf545b3499b4626513489a6d16432654e92999b287f6242452251d6b91c738a8acaca8a5d491953a69531c564a698a659a6504cf384344d13659e4ca6699674f9e671881209bf177dfb38b0bcc71985d622d168148624520d8cf11645711c4d18e31316618cf188370a6f144642e24d9a5098c1262727229108052535a29872ce5a8435c61ae3aba26255b4de755c96292356c1ae52aaed384414499cb1c61a6bac31c65a63adc53c662d128db4168d3aa5c37b348eca9234d5300c47dd6a656e20096ff175e4688bf78e5a6bad75f8eb78639cd2e11209a9353691a612a506a4cefb44629c31499ee08c31ce592412894438637cde7df9b374107f73fb82a485fdce5a77a34029afdfcc83b0c744e0eb768f46a49d160219c1b34046dce87693aea0048aa8d11f08c950a791fd8bf8e90f8444a8d3ccfe4886f493fe40487a19d8c16f074276e063073b9ea603367c03693713f22ffaa3c6ae3bc0478d5a905e901e803c15208247440e226610f1826e77d8015f105faf3f908fe7a381af4610a0a05eb77b0ce205c9a0db957e7d1ce871034a8fd01fa847adff0efb03a549baa83f50eaeb9608dc04e4dda28b71680625ee0ecf0842ce41c8e61c821079a0453c30e540a47570ca3112f90873e841f340ca4239e840e650430e3066bc1073e00967f08c3f489842209846d4d07844b8a2518456ed2669f868f8e879861f248d1cb99cc1098d19399430f5732b730a8a1152c61f3456b092aed0b095846029eda025ab74c1bcf2c161a503ea8af0744172cfee21d38ed08554c24b8e1f328cd8ba19ba1a2c4e0783e43925cf50c7736be586c2989c90c9e7b96d811467901949be71886b24f9524540c7d1c748f6ff91cb11e666e4ecceb9c8b53055d61007551462c320137cfc88c1929ceef206b09de843ea7ee050439fc16e1c5c8cfaffc08167e8c70dc09f4ff7e386f4c70dbc1ece409a7e4ea8b15bd7edb96ac1103086b8f5071aa206042574dd1f0808c16ecf0688aea118e40305c1fd8182e8fa0305c1f5db1f28480b7aa93f5010186ec075da68f70a43e8d0fb030d31a3932900f980627f205f91106f06e073fcfc0292bcb33c9af68617fd7b73944cc69ef76a24b3486b91de48a05c889077cf68d9c769a67c3216314779202d1a84df625c8e1790b4fcfdfea891d680d4f931c6196392111263bc35296b7ebbde404a7f537680cdfcd4dfd48f10f12be1853e461036e7c78f818f838ff54e880e4218d1389cff451a8f447cf711cff64b247dc32352f8223cca91bf69ba168eb0e8492e885ae71c84ce3908fdff347edffd380731e7c78f310a58c8638c0216f218e39edf57e31d44bbedee4d8cb6ddbaf626c26db77d6ceb96c5a31bb7f0b35bbbe86da21bea5182f35d5ea789dd6ed2db2d8ef8eeda926ef41bdac21a1ff95884610b3b253db74bda85d7a55f1bbe1915b909e194f48c86fa1d35f1d169da054fd72ecaa36db989c5d12fc09097d0efc67f8e7ee3bc7388826d7b408eab7ef78ffdeed535f1af3137193710f96f44db3e8ad7fbf55992244ee1be1e05bdbfc4fbbe5628fc9e417fdffc3bf39ce20c3ff541ce38bc9bc4afdf3dee36414eb8f33d777844396f349653e8272edfb9007ee111c77b1381fc9c70db70c0688b4820327db450a4ca67aeb44dab0d1fd860c70da7700293c0c62f31b2825f2d4774a2f8d50389451e5f0e820dbd45ad335940d2de77025fce81dfb9b3996a057b6fc7fb9eda04f8e61c44b12482b218e36b6168d13e88f088fe9b047c13e17e55e3740d77c6dadfc2e2da3f5af1780c26d9d602ae66cb46fe46d7f02bab6fe284e3d122437ea67717ddf1a89099e65df4871408df452fca0989daaf7fb1122965b7d8392e7ad35c5db57f5f8b538a3128be79d1577401913ac8ce8626155cfac9fe135714e372fa9d889c54d40bd40d45030a87cafd0bd5835fa8dd455138562a5ca2782b825c1d9648272277160b52f14d4c464f3da9374eea4945bd40dd5034a070a81caa078503b543f1fadd237d92a24232a1c8b9443b2123377e3d74a03143062e2643ec859d2db96289634d4fe14b01441892e44a15aa56a158abdd99e6419d7066d5a280a4697a82922a553097e1a933b7653a1911d94f7644a6ca96c880b2a08c890a0035153b15381ebd3bb5c3cd5ad17b415a2dd3c974329d4c27d3a9643a1911d94f7644a6ca96c8803226b220006afdee90a744969165c43ca6a7f0dc19b35b842e1c066c11cb719dfa876f6674c19e15f79bb9a9e4c4bc40d2c2de32c29caed3053cd9a84b54a94c287227e69cef544c48ec172bb2d11cce0210fdee58d0d7f44e3c08508c54c70d1a326c35c115860c2e5ea8d520e15f3543bd068947ef86a92a4ab803e3bf09d4cdd6f0ebb6ee4b35b7ce1bebfe258c7b288930446bc79c8768ad75369d6670c218f300c502838837c63afc92595afbdc3e4ada2f0acf1357f3db4998c746de2d760e0bbb448e0d6c7b0e475d7fb81fefac45e10e47278955ec8d8c7ddd7dbf46b4433e7af15fa22d6345a97f89b6c8025dafc0bbdea2c8bec5a791d681f82d5249255ca224a608e143d2afa853e0a2a21de2589a568925614892b6c68464346d55554352a9440af745c5d5641a4f23a9248ea35822997c6c943dbd80b48fb239b456abd56a2cac90add1ed0f0d2f601095dc7df7dda8552f7a42e404258598acbfc270861b432f89a3c9348ab5d2ae91762ddc281ca0a82d504fc810df90f895535488b0f648911b2ae8e6268b4aeaf66facfa2f247f433af775a1d3ec124ad82561786edf0aea84328d2811552285a89108a55128140a9531eada009c90a9e89a396bb709bafe2e92776653d86c6d4bbfbbbcf6714c5b73bb0844fece1b9f2b1edf47dcc561fee5d1bb4ff6ee9a7f599cd5d7dc7d5723209db57e7e32020ea43501b617cf20ede6c1b5145c7b1379df941c69714d06a2ca0de168edbf45fa77c657e506d26efbffffaf5a21ec777fa05fdf68f7ffffffffffffffffffffffffffffffffffffffffb24d26936994c9d80767d107e7920fce3e38fbe0ec83b30fce3e3c954aa5522e1f9c4b3e38fbe0ec83b30fce3e38fb9ca6699aae8c7d7026f9e0ec83b30fce3e38fbc0b0582c96cbcbcbde9c9f301906065f0b83fae0ec83b30fce3e38fbb438e7270c4cab151323e3ca2e17bed68566ec83b30fce3e38fbc4a03e38fbe0ec2323e342d1d7cb041360337966065f3b8366ec83b38f0bf5415fa318f4fffffffffffffffffffffffffffffffffffffffff3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3fff3f3f3f3f3fff3f3f3f3fff3f3f3fff3f383b18ff8ff6fdf06f15b16672dc25a340a499944c2d7924421a9248e791cf1b5e35a1a4d27149949125f4b9ec813945499cb125f5baec1a126c155f3e8da9aaad9fadd293c2efadd2ab61518fd6ef3c6925958f0b52c355e8e1e783b1fe90e03b11056828158c54378c5ea0d07a306dc6d46cfeda277f7faddd7c70dd2efc6bd4ccbd927ca2211be5694d38bde40d2f20d4f2ea2288aa5daedb9babbbbbc9bdede9af67c3f15ef6ad757abd56ab5fb53816b90b4dbed76bb5dad56abd56a2f2727272731e51abcb56bbba53ddf4f4dd3344dd3dbed76bbddb0babb3dbbdd6eb7d3ed78e9ed85384dd334bddd6eb7db6eb7dbed763be506322695da9ef5d99f6a81699aa6e9ed76bbdd6e585d55555583b7766df77671a3344dd334bddd6eb7db0dab2a56b94aa55ab1582e2e2f2f1bc5de425c8fee02699aa6699ade6eb7dbcdf67cf6a702d3344dd3f476bbdd6e38df5e36e7e70903d38ac93131f8da98137ca37b80bfe2605ed775bda5a6c5d91eabb33bcb4bd334cde999539813a6d58a89919171a11945f1b528190b532053b3b75e0045f736cd350492abb96bd696d7d3e7d379cd79c5796db546ab7b74fd6e9919323af4bb5dba8b5ace42464d2aa039fadd2f930ab6eb9d09d90413f0b5268427d50a2412747c6a54378187bcbede835ff846f7fe379eb4b074d248d3f4f9748ff6d174cca9ffcf204dd77767291ac8fdca3445b724c911cea296d538ef3c023b144446622fcefa57a629ba25498e44235c228525bc0221e1688b56c818af400849e402a9a4c5d1f42bd31cc5d32d49522ca146fdf7681461aef97d9a7cda9c45329fe8cff8febf2589a517a2f8d95a6badb5566babadb5d65a6badb5b6248a56dbd174b2daa2acb6d65a6bb515599454aa2cadb6226badb6a5b5565b91b57a8bda8ab44561b51559cb62378bb5d66eabc36a6bb5b5da5acb72b1dacac06a6badcd7777c0daba3d47914d098a1735323960b44567095410b039a26d7344a76dcc196d5bcee111ed16a10372cee86cc1029523da3747444d006f8c39edea641a0e7bc41a3dd6d6b8d97d77d8de7d5f2a32448b7bf67eb7d662bc51829034b38b1d6f9cb3ed9cbdba05d01b6ff3ade8beeceabeb099046937cd1c95525e188a763520d9ffbdfbe39328870474bbcb21c8fb765f6cedbeed10ff667b712e8990b414743a1a9544c890442a954471244f27148a8ca1a0a0a0a452652ec3949c12b64ab234cb5549246fd1debf38b4a33eb3b8b23b268231d952eac8ab92c86a65d2211d41b2582e2e2f2f2614019a79a804cbdad169e9d00800004000e3170000200c0886236196a641107bc80714000e537a525852582c10c882d11cc56110c46010638c21c018620c21862154732700868559b5b3201a75f7b59a2d0e44b4b25c1ac971e0cb5fd40f41f1e6d2a81d7dce2389573d4a8dc1013143e345a907d358014a4cb8e48de22c6e26d827e66c4fa65b7de2eb801824ea3792734cf0c2986a495bb2f50caa4062422ac21a8c28ebde7108931ae877cad883705c03a39b78b62f91cb38f29f6e037171efb2bda099b81390f5b10ff10ccd9d994076eddb8d90b55b061306e93d0069a4cddabb96feba2d895fdd45c699f8def61f6b2f9a7931a626b208db588084c62c68278534521d5bcab59c7cc45c8c9733a2d2f69c9bdf2a3b85274cb61fb22355e4ae62b614b5cebbb7492b6ef9764bc12f65ffd022a150b23cac4e708a4e046cb470e4f9ac01ee508e60278c2efe849cec74ba5414e6be0eea99ec27643bbad067803ea6675c0b60fbf4fbd29885c1d8a4ee5ec39b27dcef696b614dd166a4cf42d9a53989035d8d02523938e4fc81f26db64a9631b0034f4b50a028351ecbb387783a040388343c3f83fa83c9a179f567f86afeaf745212735dcd8b3c5bf1c0c0410d451ef3958620054e393d32955cb3963b735ebda8a30077c34daecbd368ba6a1f2b8e11875ed30cee1d41da278b5b0fd9c617b8fbd822fd58ecae453ac35fa27c1dc2ff6eddaa596bdee3580e061bd2e9ce7c0f8dacbd0bc52728b0a274e6eb4e11d2795f732ec0549ce849fb8b897581ddaa9a8c0f4d9a4758f9da62524efdd88acc07bc46a43ac59d362be40501d93de404285e5ef3861c4336771206ba50369b9c2be49d5a3649a11d35ec0411bd8e395943c10e9604d189c0432d3bfbc55cac0b509ca7b38a0b30ef400ccf397be620f90862bae4ec290c291bd6d1bbfe3ebf3889a2eeed342c8e1b454515556dc3c04c57ee004975bd6dc753eb48d9079c4c962b80622102605ff2f4acdbd30c3d3889e8561f891709d456f1a270ec7a481035b5a2d8bb35cc1014394cfba0d60618e84e34e85bf4ca50d034be5209dc4493a7449ada558f2718f2f1cedabac4fc9a1a18e5b5ed633395043b5d8dd42498a61563b1c27c2a5728e639689b15ab0b02a4de641e433c532630015c5bba366f289718b4997394054d45cc71aa031d5d13d21ad4904613228f706f93287dbb036e031411dfff4b28baf9a25df6b75a31eb1fa2deffd289dafc602b6c11b05635fadb48d4178a89d83dc841fc390db698c8a49b398c548bb3b45d3f52d80ed6de3977f31d70d0f03a53d4b89dc00c2e25792340521dd7c4e922079f987cb81786acbaa101037e6ad7bf78091e26f06ed604739be72e53d94afba808269e63447580466f1044058dd71fd2fd98c5983a6bca2654d6c4d2e0269f0cb442b1a3a87b12b715892912b00326997110a8e82045e701d9366bb34e35af6b0d2fdadc51a61f0c360c26a177d995a6aa8919ed418d00f8d51ce50fe8f206c61627f4c5389759c9e2aa830c812520d72b110bd5f2a7a3d556790b665d6d3d0ab877033e29fd88893bfa41d1fb45554894147a212fde40b8c8724ae1845abb087906dfb59381b5065f063e329ab4eeb8c445f0c0248bcc36b624c4d86b10b6dc8e50a3671f13ab0210e9bf700128c48462b76639db90a0c0c193e3da255bb4e3904ce3357816bd68ad6317310880ae6e239e3a8d037a1c138b506882004f9e2f89c22f21b39d545860a0b59d71f0b19e5d23dd6c8941d99974a3340cfca92ad12e9fa263da7183d91b1c053cc6103b745922c4626e1a424bd67b0ffbf7dbee8b102745df909842b76eaddd41fa981ae96a3e73d5d44857d399abe699abe68d7435cd5c3599b96b9eb96a5673d73473a979e6ae79e65af3cc5553cdbda699abe6997bcd33574d33f7bac936cca0da7c4e308a487bb238e435d9a71503fb938648f640bb7d069dcbe6e790116ee8d455937b6f113764aa1593abf7f87a8b65dc0b71a3fd3674bce499e86e5e641fc1574c2ebd47dcd029574deedee3eb2db64139602b33f43f0d91ae81f6fb087ec5e4ee2d820d99b26a72e92d5e8f720fafc3ff6eeee24f73af77c1a5df864eb16272f716c1864e5d35b9f61eef77b10e6bdb513c2f697228ef72ad84d9fb1de20fca6c1fc1564deebdc5eb7d72943143e922dc859cded5369f618abd699b127dbaaa0782bbb66eed5d3ca6d14f43a46bb114a8ed7a5beccaa54a792af44dbabb14d939fa89ed537962e0d6b4c6db489bbe4d6bb86fdafc69dafcd1f4c67bd3e6afa6cf9fa699bf4dafbf4d3b7f9b367f9a7efe346dfe367dfd6ddafc69faf9d3b4f9d3b4f3a7693fb04fd57d1613bdd51cd1187559546fcefde63251fdfa234a53a38bba69adbfaa6b2d2e7aab39a2b1ff929a70a77f5d2eaa5f7f446934facac4bbc7aa577f8ad252f4cad4b8bfce1075e32d7d33ed665d1dd40d9026c6143dce6aacd034ef43cd19b8f812988d69f8d3395e7fa853d99318350109c9bb3ec07f72003ad0426f51e62ec1d2fc239ff8954185c193ec1d6b6daab09fa32c2cf9c5ad1ab6ba955b41043774ff82f88d5311c2cdda9f03f76202a5a2d09eac395ffef15506c067ad83a63af0a81749dbf8c5ad182cbab508eaf38bb4bbfa7192d3cabd543ecb4db4baa0453e53ad4e4d8e69775e698bed83aa60452c5996a74fb74bf3fea6dc7b16d1cd4219300344f11f4173350324c49bf7abd7a7cf489fc5c625ecc40e0c2813c76489702b31376cff1e835984262b1e463113d7527b4181bfa9c410d37c5e331135c95815fb7c10a73828afa628c2ab7b032586c39dcfa02db57eb44a211891d684038ca64dad65d97a49ee85d1f3aad48d5e89bb81a1d5050a13fbdf251c96cbc973cfaf566a96fd5b6bb3c75127dee05fa1e9ef62290cd08a3b006c73efedc5a83d869d01ba0c0ba620b1415c0ce860e60e8617c7a84076bc7b9b2d71e06a74119c7edbe4dd66f3e6ef206c9d63be1ae6ddfc6b7dad676a576cd4bea7f8d71fd5845767b5ac51416b831f7c4559d44203f75da31679e5a17cad43e09033d9daf9809509ab439704e9c4b53c2dc82d731900d1b8c63a0ba0037771019b29f804513fb29837239eac4f0f4cf50e4a1a5d0d5d04c72f9b79b3f12f0b298a7cbee4dbaeaa6c94e9dbdb506e3b3ab59d45c04ddedc28de93a382d31e6ae9236fb941bf9cf2306cb25f7f3993efbaba8ce0974560efc1b222f1e8fbadfa262100ffa2aca0d86f389bfc144e64ca832462a58488ba2510445f50b9f6432901f1e016f71faaf43f4e6143172be90c79b3c8c08031853dd9e43830c75aeaac026de6cd266fe06290e88a3323756f8d6d3e60967b12b2991c3d0959aed4638b72a0225c54b305149fdf07efd5d8c54f2148a45ff042b22c3791b17810f1b8c459cba32b8c7a69cc0dc8f861d6592109cabc327b3950076ae87faa1b73cb1f2f40032ca32e5a4b33e366962c20dec274881ce2b5c7e69828b728e540c5de674d18ba185d00b75f36dcdb0e96c51a558164a3910411b622ec0008cd66cb4ade5d616695e61e46baac82e13775752b6291cbbfa1b674a34892954be63695bbff5eacf69b9e280451f8c077496122217d23fe9d71b8d0d1debf6101dd26f72adfd67886b1c686326b04359b3839127eb38384b96a4f8945c1faf6e5ef7e22454191ce4e5928ef10882b258f447266ca4379b9f772b8cfde590bb061bd463533a3c5690df4346c2de4d922055a8c8fdd3f7ec3b9962960b41ff225286a5836ea9a16aecda4190ee0650d8211d4ef2134a537c1dafae22689c8906b1456e1dcca82940b0b1b442334373dfbf63a7d7933ec3890df109d7028a43325110ec01bd539edb6175ef3a5fd287fdad1b712ea890c71657f79b2f430b7cd6a025f83bff43cd7aad8cc98d4ab179449036668693edf7032f987d8a1f05e3f4e27c005463445c495b9e1c20f63947ac7cf1961dfa4a9dc1eff4f7055784b033e9087d1bf241083c2e6dbc68d4e1b8fb6e423f63a5574281a24f344db71bb188d9b1f39f1c23aca33c31b5215f259884dbf98265115eb8721a3c1af285a460ffbb74df4c6e419b7ee9924e587b0df0803c7428c4b22ed34f4d0bd4781a1e3ca0fa66d91e9b5c523bc49133c8d58bd96c0f98a13ca28077bf92a52249d8f495729d6995d4e89605ed9d96aa360d07d92190a323a2647c7c126dc706b9bfda08c4a5a7878bf8e587e07a70fd3e6e19e5ff41b01c8866e75b32cf5b353fb682b8ec77080d5548e7d8c58b733564aef1c08961d3a32eb85b8904733079878434404e404d72ec1c0ccdbf60d679ebda8fbfb2cd46d7d0d6ce89c9fe3fae21f2c0d182e277984bffadaeffb1e6ec6f0e44aecafde5a57ecae29af8eb04eedf00faa7b1d078929499b425dcc17f67da3e3a431b5e07d4eea56e4163195e5e7647d48515a6922afd1c32d27c731372e7d27be09827c94e53561c3af098ee756c692cdfec98efba55922c29fa97ead647156dacec53c4b0d462fef5322e3475b3f1ffe54123b410b455ef37b712c180c3b83ccf9b3a741d7a32511c8627912d377634e9544525579fef03c3d72539fbc6fcb2ff7314c593c8eb013f69b0a14db4574d44c14d9d456b4b27f20ad6b8b627b958cd35d8a712242fd90913ab4880686d0a53e46d1570c74432b6462f48d53ca8429dd140860c4036abb7c4a35dce56b50bc826a0355f4b705aef252ac5070ba8694845080cd6b83cd8da57128ba6f06cda7301a8dd32f31af59990cb9a98d2e11d95ae2ec5f57471905a5b2334df6412e88ddb836d4df72182bc77e2fbe8514e883645feca0a7f134eed25a0d79e7697fb531b961c78750f374df0375d97f72e067180b11fb707f2f8603e31fe9b8bb917dc95331bc34a69f35b32463da4a33ff67a2ae5e2fef45c0589dceb960be78591b83ab42fa12814de3413a090854c1b2364c2aa1bde3db81d7dce816d4814e316af5920150fb1e3f6511812bb1195a73e29dc5e736dc0ce40e42683d78346f1abba6a4e274faba988bdfa8d90c2b2d968b530c4a2aec94c42e65db0cab15e0ee472eb05fdae3e7fd2680c1ea650938dd0ce22a4354a8bf9b4178921adb0ae77db81ff0eb5c05a76ac5ccc01269e60a340272a1744b5279d968ed33c7b1258525cf0a4579fd0cf274289348c9f81ad9b7e5c05926a22da9d7949939614bbf4cf469cc84a0a44d5c1c0e9f804ecb4d5aeb0ab989cd603af19dccb9ad5dcd0efad7842b97a1c6aefef1966230f9ce749e4fe47cd3a3dd3b1b1ae8791cb8ef6e182634bb703f49d66e3c72370d8497a08473f45a64bb01aab1f3fdc7ce0a2abca42ea52d5366f52a7424707c8c578be6067059951c75d2061057de42764b3b613a9da2a7dea46bf4354b23c42090b1519bac75d7709f047d93b6261808848858646fc2cd3a5c85a4af743fc343fb9d724d18699704b77059b18c69e5a7d6c47ed6c4270fd90241738233ae5873326c7e59e4782f4fc325313f7eff0c3794e12d4c07fb257d95c796806b9b90aebc654bc481f78544257d277612f63c51b31ec6e238bd1a57b421388c4da68b83413d4a5544c500726b7fb9333db8d2d41c2eaf324ba57da854406ce1eaaea9c6a46af1348b5d109d64fb0c99d5e99ed822295bae7ec54643bca3885bc71b877593f443315d0d3f253c72f76ffe0ddcf7a264db0b8a962210c81672b23a980a1e1b47768f5e4589da63ace047f251ba9243c9d1c0004b11536e6924e48b447c5841d75fc8b82ca4b93e3de03866ec444d110dbd6f81e275aac4551c50d9c8662c0e2a9d3e15a933460e81b9e61f43b107c44b17045dd7588baca67fb9f8c38caee4b3b6496d37a086e00f31e23d2e7abaff81baec3d39f03fc628af75c3074cc5e15dfe48e7c902e10257fd4b03138eb9c0bcd4eb2a7c24455a87529bc65e6e88220ede57e5aa9a727946940aa7900bc8aa18c8da498b80f61085d70ade2735bfff2f63a9e4c4a2b7d5d3410ef46080f25f9c373eacadeb4dd5460e806578851e16592de3a519aa3bf69333d5933582b0941e15b94943b08a32a40575b2b690196a95a49c8a68620476f301dbaec19f973ef8d137c7fbba47e15d4964dc9f9045f467e24d1d9a57c113b37af65f2b2eed87221e4089ee47398b974f3210bbab20b7bcccc6698d52f4f1191900d26309cf4f353cd6ca81b77e0117cbb0643556461523422320b5932895ae37ea12d6a318a83faff35e37511f2d71a6d07163e1d0c9ca9c5d1834b649ad9c18911ad178b12f37e3de4661dbfe23e3476419bf586970e6a648ac73517a9a046c4894f7b9f6c038e16f377bc5ca896370710ff2e3236bd16fb682173e1115789aa11feee9083ca686c159ad65960f3ed386b8e6bfb48935249d7d47f7a526472006b9194d3c3a1d825778f4ad2f28fcec60c9f02de27858b85199e9b589dbfb0802ee1439b4640b11018a17b276b1eae603a2de9108513b1f33b31e4245d83c8216221ec06cf0d249cb77427970077fce5f41998c2c76142789668c3fa8dff0ccd9b30a66754a6670a85c44d00252e1dd051dcd66824ca07e00fc816bfbf5bf34484da47ae3e3d26f07bc38019f6f11ecd87c0b76e6bde1c29c76a239ba29ea966aa75bf38170fb71802fb3b630ae9d35bb9da331935f9faef05f542693662e6501df97a2e1c7a1b4c876ab61df945ba1e1bcca4f0579e8e0c0611ab8a49e4e05924461bc3d8c2be8459aa78fcfd2f47777861ab8fd31a03c1879fd5e89f6288b4384766287fca865c7f74358b25b0643f38cb0732d6b7cec7bfd1fb1586f70fc59f0e990cf49bf02fd38ebcde5475492b400e061029f71563ce70bf260033010c1ffa486a61f6c84bb33e95d675b566d4e608942a397e9a9da4b90d9eee0930832c173fca5877bb9c6a0b71d93202cf4b8c8323d091d6d704797f22a4df2d0983a64bd54c121dc7fec92c96140e969c405e5f48307c6b9a768ad1104c240827c2d0f03e82b25da40073a1aeecb4802105afc3dd91c146119573fc5bf685269ec9450eaf947fb1a39b61abebfff010ee9f6fd4df0da743903fc4ffaf1d8e8ac22d678e827bf2a45f98bd1379d5cbce2c939e38145084014ee003b2b04debec5e0fefe292d8f85d8794a619f62e86ac067727fffa6dcccaae74e090e5694bf40eb465a64820c218f8cdca0b9682cefea2d9599ad555d1602376b6dc789e7aac7febac6b463f66d383200ad65003cbd4d732116e023a357f1d9da50c536ac18edea40f3de72ce860e040458433a00677ada40e5c17502434b41ce00b85fdabd0109b530b09b83f3f2056916cbf3266528564a9d9a837c8a3ac6674a2a1582fd6be0e9af76bc29e6619192a6f556141c1353deef31d28a14755057b0d68a4dfd3bae33407a6de075c4eaad41090025ecd8432a81632c0211c02105bd3a15b05cd1054f64f5e70f08fa6db25dcc507ae28962f39d60a2759b1d7e978927da37b5195e7cc08738c9b47160c86ce564a1b31ceff2a43d9a970175cec2a03b2bb3446a44f01f58c1079fe5d4cb93b1b114e746e7db526a1bd513694c9ed9486d7b20339798267113e47a96e593b550a436f46a4ac181cf83e7e4d2ce04b2a1f5856aa2f14e9cdd3e7c88a5a6eea4a80405da3c326eefc84da76a68d35c97ff7efef4bd40ae4a9f8a08cd597b09ee72782cc4c0f02438ebe2c10b2232c1cd84bc69388e821f3916e0b82ec64fa43e95c38d9d849884290eedecbae98afd4d2e1534fa5757166c649c3180ca940898d249076a621a7da50e7aa9c41d1aa2a7aa556241a5f725d119ddb85039789100aa9b2e98f3781a0e3909a00a2ba4aa49a3ae8d84a8801e06cd4e68bd4aca2f68bd4abfce750f71c9b199ccb732c260a3b62ad478d6e37d799d5d472166d2521d8a6361747b54abffe6bfe69979a9bbe69795425121b2d0289e10478ce74c903cca37f0debc36c26957665d15ca86077980d41b866bccc523ee1fac751372a870b08eb8a9757e5462435fa55732ef0d9dd644691ea57e8a41a933e710febb713750ff32265610ccadc74ab98448bcda8755febc61b203fb40347015cc3136e1e664c2d7f10592dc11f4444281e2ed905888451963c5e9287d6f1ab64630ad8cace6587c6f45c4370344099445e8c69d6f7a267d6991e6726cd27c3b7e5e7e640e20b9987f507c8a3a426dc6de055b49c453ccece23b640afa292ec4a20e846be5c9d3b1e1287329f1b3e7b10ee5679d1d82d1c1381e40871932ed278c003b17e050ef3529292753cc9d697b842fa17b2da9250a4ae29c6ac78e3edd44fd0a5c9ccf32601b063e8f654451953871b653f960f5ce44a0fbddd6e31433ddebfb336bfc657f036325f6c8b0f3aec5472fc2eea38f8c15d0b2bf0082338b2541e2661acd24415e60dc7866264783d12667ee6e3003f121815351aa7d01536c686e1ef2b5e72dc728d53544a6b6c2dd04865927487aee48d6eb75b4c3d183d23a2574aa156a762a9988cf9e60cd128c3b9455a327885bf37d08375b02d412f0b1fa1c7acaaa8c6bc5764b51915fd8bd22a189a3ddd08037c4f7db0a808d360168e40dc04cc906a19131dd1ac290be16ff0a0756f579dabca5e45ac5184eb34589777ae8d3d2411818e461c498f18e2cb890c60de3f0449b5e0684789c17f8dccb07cb02e341b92bb3d1dde5163cf54430d29081667acbb3c23995e0398797c35fbce94b822a3a532f5c03b94827a8e392cba44a5e8209fe3db4102d632b5ae638bbdb3e70679725f8dd85be0dbddd2b3a7a74e3d4907dc39bb804717422f5a2c874012df1aee8d50bd2936e540c459ad2443a998679df1447a29b44d710f4933c985d1e3adc7344b0d91e2239a58c77a6097ca772ce4a22000856305850062100e2f060dc1d0b127da8a8dca76f37588e86f260a3af0f6003b5f77189ebb081609a9453c44b5501ddef3f2100920b1691164b1d8fc8d502144b481d67a102dca94f4446e2cc50ba0eaad0ea23078263882d2c8363f4c3c448bcacbe73c3a230a00b0f8548344bfcf5e14bcd7f71b6af63c55f27b94beca35d257a829fb0fca35649343c30a0a849b7aefcb98dbc12648dbde94775e220bb525adb826f329018eb4fc660f7848ae4e27ad942b64007c16f038f7e28dc83f4cf8c50d1fe3ca34bf0dcc2c49b1d25fb03e02b9b3e7ae4a4d8ec726ddb36cfdfd68b29a66bca28acc0d70d96d97d053a56d86dfcb3123bf130d308f1fbaf73f69da43931bb1edd0f40f23f05c101d8efdd001bcb2480950bbed259cf2f974ae17ab0995cfeaee0b3c49dbfbfb87b343960949652e0e9ba2b454de766f51d28fafb8263e99d7dd1ea95e598ad32ea1cbe68ea7b2961d9754029fc5ede02b35455984736a47c19db3911617236c4a267d0f6e9cd6dcbcc6cbd9ca708fdcd27328dfbe45ed359f211e28001611271e88f80ed4e442db39a759b7e2b412940f8b1bdef46ea2f746029e9e9b30c4a88b9e861be4dba467605a14a0964752451d6430f29f01af804dd7a220d6d2609bad1b50e541cd2ad5cfa14309bc981140322209dd9c813829bb4c86c19738dfaf45275e59bafcbbe0fd7e59b40f4633a1769154e5af2b5e7bbdf5381011a1d09912b124ce0782e06e10c8e4c8060d9f679ff7f80b0a52d20f2d98d4e83a3658560bfaba8b4c4522147e846b3a1f01bae7a1add79563e0869f008cc9ae8d7ad1fc3f19450fdde41c8afbebf95bfb45f5a24ecb638d92e08f40c29671445071e8cb1f724fc723cc4768eb76b6bb8464bbad8f71b6fc7f29665a95beaa57b8c7005082557482cd888ef11d7af82adb3839e854e1581d86601f5eb858a866487993f869717da6de289eccbacc09b9caa65f7dd262bf821ec35f3110f4672f6294722c28152d874ad2fb48f65a4d139d434c32b8ba3243b2b43fbcd03bfb13451206611e9220b5fc69819cfcb839e21aedaa8c652285dc8f081915ffbb06c89f05a72b44048f2c0f0d45ea8ae20aae88508b1287926c918b9c4e4a1795c7d4c2c5088711c43f6dcf928b640f58ed0317c700724a8e34df5c0ac91637df98b9117a06156a51b56e7e44fbb82ba49767cf0dd66aeb7e443f34ccda5f6e314f2b08b43d0aa20ab099f88d9c8db96292567406c11f35dc101f0e37134391b05f1bded7b2e44daa1d18dfbc2c885c21eb2dd583b65794d4a45f005e01227014f568b98a74f965c02a83e44fc7606c1be9b6606124b400240220e317922e806b64cc114655c9188d18e70654b834dbe67045db40251204346ba6fe47078d499c32b0557b605bfe4b138797fa1f1d447a0456609039c7e89a2c52056b42dec45cad27a42da16b51c1523a2925f2a546d0b0b04ecfc88bb6ef42afcd3e7321b5e5c2906a19a3f9091d02616089e7b117b0a11c22d014e7e9239049ac97e3d26e2b4530021c66f1a51ac5134d8f015c6f185a37e6c019b9ae83102204b814a0fb423c5807c048024ba42ca5982b31c797924b077bbc53869b558a75fac1c1de2f93d02749f9b268b58658dabe6271127f0c5fb3acf845b2a0a58456647c49a82590737e57b2c9d6175aa2475d955258ef4aa66035140b23fed4f6365ff5e5eec3dd5e953b6578765f8feab0effc166afa5fb693a22e03eba1de8a116b7d455b36f5eed0f8ed340fe3a0e5819ffc6cac1fedcb2cafe60889e486865f601e9c0fcf80c3db3975d7bac7e9aa856a5254b9c55b3dfe0068d255530f7d2a15cf70e20dba03b2f465b129d2f581dabaef726ce0096ddef79918daf9e5e6f9fa51e54ef6a92a31782aa48247b3ad7f8e7509d2315589305e09c85dca2819d25999a67824e54eaa768256a770a2dc2fdb7bc76036a484b47e35897a8996b153dc2dae728fbfff4a4c4ef8363a1726f3c2fad7d99a52f829606f8f1ef56a5cbb63ba45856c83562f3d200aa872c7ce07810fe8a08f53274ffe2224842a892ceb2a76f43e5c3feba6261f3b4c57cc7f1f5d4494e602378948780678e649c36d806ceb258beec3329aceaa216156d646277baccc514137cb3a1306502793f19d89db77daacc7ca31cf8c7720387c3a6c5f16e94cae66cd652cb8b8451212d75136acfc759bcdfdf7275eab2b483e4655ec3c084e21630fcab2696456004b9d6d6d82d82899d5f7ecba262515f6cac0826c8c84e03050c6a8f7ee65d1cde098f196b24fe41ca76b6a6a4623467f5ce86612fd859dde04e11854b637dc661f88d6bd8b0474fae7ad29486c37a33c506206d181e80b69eff17f32c67284296ebe9d84fe86ac07dcdece54c8db359c3b3762e5b26c086c14e81c1bba75dfed79f02bb8931708603eb2ad0a723dba1aa662dcbd424844025a883d8795a621e87aa460d11708d2811c233d5756230159741e0995c0c97e6c4ed8b6ebbd57f00e71193bbed67bdd588c316bda9d086ccd604a66863fca35daefca8adb42317f2f4e1a28a5bcaaf5fe7550e67955868fad0f034aa4d763b16f80d4024b97c324414d53818cf5573fc030f08807048b2aa5835ad2a59a28313e34b29d18094a8756f02e372dd5b691db0221418b5e1d3b19253c5984bea4677b568a8aed3e4dc985e3fd82c145834d8a232b199e5733669d160dfb82c17e80038853a7f95b41515dbb2d14495f0b0d45a5a14a4c5b824355eef01f21a0227992c722e2789a313c7a13b149337213ced718142393477a7783498fbbad9ed247af67d812c0a9f09d2f328ea3ab39953734795c173b12fefa328e8fe8664de17befcc29aa1d2a04e129dcb24d9d7d05a2ff14676d1fc6d62623325416d25151f9e543274faedf3fd43738033876b58eb1880f5c61254b1c0e9f38aa9f88b0ea256e6c63510cf66c985bbc1485df41ec44fab84c9a9bc396f07bd64188fa32a103f422aef304598866f2af487acf777ac5e0a5a7aff965353f13afbca442cd30589902418700e7736b584246f535dd7fa6d1eab42cf772206e9214194d5b6d7ab84f428ff336e07ad129e67959bad70ee552af13316cafeac5a4e7797c84d9853fbeb4e211c5db82efd49edb1d6e9f40a4758e5e77b6ef5ef5c5812fe0c3c94e7796aca38ec9db6237853cb1835e363d632b209da6efec1530e8d389bfaabd31e59ff6f56b676de021eddba7794e5560b6ca2ae3e75ad96e3c090baee433a99f6a76df4f3cc991e96ddb5711e2174d1f836ee2fa45d7ce94bf9ab5a4e52e330ba27597d54e640e33def5931285bae60c35a54601828e5b15d4121f46360ca518cd49389b191f27e18f3eb6219236a48c9874af499227b28f30dae1a5a006d31ca201dfa13a0360dbe7ba2dcd11d05dab689c30438aabed8fe002af48bf053c3776ce0d9545974503f5d96d2e810d9ebdc2d9cce1b9cdacca9de0aebe145ccbd2f453b6b17a87449a5fc2d759a0c6dbc5c36212e0b0f67e8d8d6900246495399c39b98aa1ddea149a35b0878c3745344313e75e8397a96ab7302796692b4fdee74e9c6761e56c1528ead5f10e3648356b2c336d411fa0af370950d42e534fad9707d2f6345e63e69eddada6ba726dd030a85b2dca6ff1b4c50b7fa742ef8504ad251f046f62e8d65c734a0243c94242e9d32f995efaa285a050bfd2fd3a992551e5fb5c943eb8b527910c5b650cf6759db903828ea2a7b5de6a7240c1a8a9c0d2db325bf8d96b8bce22bf4ce97b2c66121523a4fd216842ebeb0b3a46f11a8944ccd158b8c53c9db5631ebaf8cbc28e3d8d7fb5847461ae0659bc3de8561d80e883220641917a39dba935d212ec17742cdc416375799d5db23a29c5f7d2764a4ef0c557c8381019d5e8abd783c8e4a2ab4ff10bdbc92e75cd75d7ec583505ecbd93226ec645962f5532b14d751918918d027726110a02d21add89e906fcff9b16202626b48902fcb3f819117b52976ba385671e4fc3c722d049d3b458efe4986baae15947be3abc9690f84f87876200473fee8ac5066e2d5c1bad1ae518a40f85a614385dca6e6f23cd2ab5a5001128ae2d6b0ba9dc51405f8c44152f749a17f583a771e07d3ab1cb5fd53b0765f715143b539a66459f33bcbb7ee7f72fbbea0fa9f7e3b73c6335d55358982b1b9348105002965e076e3da374d4471675c958ba4a30bb77d73c5c2c0cad561cd31981c830a971d465912ebc6464dff3dff8f970286bf15bd944cf403643ed37349d9ae4c5918e183c4a2315dd59125e6ce50eec533991ac740bea074e4dea58c4ec43337a743ce73a371cec1b36e05b808f5b4ab3e6c9b293a60c541a2d559895d93c8465f688c919fed19abccb1b0261a63faa50deedb656c4b9637c4a7edc7c47273bd7d2f0e875a0eb29af247790e64368076b016a3e1c592f4df5660a560734a8e49a2c7a8c13d95082480e2599625ab420ec773c5b68ab7ad85047bafc3adc3e75d5746521e3c07930d31260bde9f440f5e2812239e843b93a2911f0a128f4f9dd43cda715f77244c2e50a84faa8eb36cbeb9993b55f851432c8a0d338019bf82bb065a07827f062e38118c9dd8f0c28436b4f89de077d4606f5848d1ee45024b65082ac8fc8811b643bc02511746bb95d7381179a3300ca7b23a2e1b5985422a2de05c8fe4e8a39fa76031f1352c7be4a42542f38d99398ee8d233cfc4631ca45411f3e64d433595de354049654dd79458e5f5bc283bc811139bf76444a0fc277a54ccc841f1a27f3e580ad2d1c037ffee45d3b656f4de7533c66144e80f81e28b31de2be02060ca6578e24458a303205c31a0a07a80c2e4db3e619196d9b898709002000c720c11d1a86e649eefd0c69a99eaae72172f022a2f309f59937237a98e136acd3f0e962d7f0aac201c2e848717a6eb14c992a31b3075ab52373bbdd7bf904f9b90b7516625a1fc5af2508657aeb9bdcc178a82159a0afd10be82c0d851f61e543c7c65a4ebb0a7ebe17e85698b1315c9c066d18d91695c6fda692cd5e1f34d85df698ae4609836ae59d4808f11df0b79c6196a0600767292d5ba473beb3c91671c9c8d606cc3d84a8867963affc8efe21a31c18bae76db6d011baf46561a5d7ededd0afb0b5414d07d7641aeca7f8b90b01336166ed4a0074cdf9abcf5b1b6f262d92a2c3816e6c40fdd12a3f7c0f495ab79ff9890fb20623625058d1160f80b39fb507671a19d42a786357a9d0a9b4ec30a37511fa1c10bfd76363ef2882005817c54d15990c35761d69197e5ac185067d4f4561a9ebfb210d72013a31e56f57d2004fc8ab8998554a3ac0815702b53968914c035e3ff9e68484eca11ebc1508219664537625911004b473ce4d70a2ce8f84f388bc8ccf8af7a5e28fb3ba18973db16d6400e36899077c4cf3b6a25b0b3c7e17762a10780f1153758c2957b2126d11aaa5cf8ff319df4dc093f32d26b446e320f8df52ce63b654c3e2eea062f0aed055fc9adeec6c1ed2c9aebcc456d80edb905e6c409ad7141fc4d00806eea41774acbe0aad09d53a9c43c342ff43ce934a5e582f18460df847d331e4e3a701a237447fba28293165355ba0520a50fd78435b9d11f258d2dadb068c5e419b96135927fd8e0dda1b32d07d2f865f42994c879149bde118ad4597f32dc5ff2fa5476e291d301258dc360df6dfa34821422f30eea111f02c8bc2b199f35e145d05fc4908536c8e4165863d29e7ff3f55d08734c29bd5bb53f04bbff391966ee0e0f07a732225b1f6316f259b570098403464021ddd1a4d538648d247030a749a38619384c9dc34e1d3555a4b5480f730ae946539debec0555d25195b05e75d2ea212a2b32e889c8a3d5a5dce1fbfc52c47dab30b1c0ae342fc3c4c1e1e2e0b436e6d2df90837f66054004e1334c61a452fdebe012900011bf31b21ca33283f6dfc3994d9baa2186542a25ed9394d8f92e48913d8af3484707d2eb9fba62dab7ac1411a7e3a697ba561229fd4b8f09c2f13c52e7b651af585e3fe12b4393c76aed160bc0b9ac33d87a2b264eabe563980520c1084b6c431d6b148183690d1a34cc9448376645c0b7585fb78aab6e3bf80c7b39b116b00f0ea671553cc35bace5a4b1a085ab3aa9a0a413427e4021d8746e6ca0d6da2277ba027cb1335ef2b598d8d0165db7e3c3773815652e4ff3c86ff473bf08156296907344a4037dedc299391956136e3dc15028b879c80623530c23cc56b063acf47b818bbd09118115d1680c60eb4b8a2bc1dac542206e2b4ebe47dd14425345b355e857ccd21867998533028e93cd8c6f62e7fd8b7f10bd3e5afe2af9afb3bfcafea29edd111a1b253ff43a023c226619f8bc4739c115e561908b30f67b1d5a3485d4631926742c0059f5dee7556f2d4597aa1bdd7ea39943dd1bc849fa61e7eec093d92aad28b1c6290dc89f604f32aa21c48c51c04bfe834d48df78efce0f269afb5fcf00aa93e2b700858e040cab70c01844144ae66006d32a8a51279519dbc50f78295b86fef4c2934969daa806eea23919a8c54df369d67787166b5ada837f9ca89c4f23993bcf066a91b466dde5fa8eb3e4d76311b6aeb2615e29ecb6a89308b8d9d25b98c7992e4ccfb934725a25553240c4e101e883755bb8296a7dc6c19ad4d84ea060b11a0356c577eb8feb14b03e50fd27ac54b783dec028050d0f80b5110d5fefe0522f9f323c214d3c470668d3760f160dd82ca99fb74cad281da43a02aae6addbd65bc817697f804cc2b490c49f032d252b80e64fa0c9c422065ad9dd5272d7363a5d503b225175052406bbf91a084d01e1e93f3b05339d6c26a3bc52e9f9c9dfc84ec43d6da2e0002b406a29c6555e15af36b61cf0ed0c6f85ed7cc5fa1c72ef484af13d13b04655e9482555e55c71eb55c0dd1d6220f12d981911073f43bfcce9a7e3970a981ec54a79e2ae0f0674a63d3c8a34b781fe9c661f745523ab8f5017fcc3fd98aebde89051e45e3e7048911907842348de2f14b6bfe822180b62ef48f8caf15bb2175684c1b02ad848bd3fb6261c620a2d1af41c58938f5480a9269616a3a00a074570d8a4944b819de466d23ad1a041aeb0fc1537823bec0c510981066ac3eb27c85806e8b9c53171833b30a8b34172e011ea7bb7f2bdd8521e8067743bfd89e898ab8eca15307813da0146b713bd0bbec3455b819c1ab951fb03af80920c324545fe5a370bf06c945d22be44414786c6906960f22cd72b67980bda95d08ecb95281c35a7dd5a8111aa64acc5bb13ef98fa69db881a99c04caaea3ea85f6211823d60dc4c885ad51e791f9875b2b0c2eb1c48c9ce8ba288eb648361d7ff634d15dfdebf0988770e41847b0f19468f3a2ffc66b351431e9055ef5992c4aca18ae2825d2e7cc21398bb2c208b906768878fbdcfdae5e8407e4379e560e557c093c17daa5e08f157222a05fb57cffef8e7c897089291f7e0d0e274c0cae8f9d2496b4b445fed90572cae0e9eaaf8385387b977f56e4144cff5c275f9924819a2d0b6730dcad88352d730381425a986b4e84af7aa2f12dbf15527bb953fc55d6ba494a631885ec9b94d74055bdbbe480beaa868e213d063bae3ce88b024d7cb0f773da43ef945357a75e812f886a92abf435cd401f188644c459549188ea2d5ae4c80b244744e5f9055ff4c06314b628e5dd9e4d0082436481eab52a1a1d6ac4451a175988e4ca8a69bd2a43013419810d50142eb50da9970feb4d6838d40fdf5cd04544a95aa75fbf89c8cbadab0669a7c35eff9e574961e3416b48c635ee849275f21a2186a860f918c23559e0f3d55672acd574b2ef95c5a1180920787d1fcbb596ef0e1dc3d19b0b03807fbd812630fe9983929a0242f834119e69fbdec0c221d1879d8346835631c76bd60c2d0cbd45a329adbaf869e7d08fb5c9c7b07f3a8d45b1271b194c5382256020fb0f9c3aa5484f020b06cf23fe6d14faa2841bfb79b8aea20d9145d56fe11b317736825181cd1996c3fdb9c69c3bf25469fe9af4f4c3ab84660f789bb6ac96c60b51d9a4c272bb02940e608ec10f7896877114518297ee25393ae0ae2cc8f18b643314d5d0546a5141dba1ecaa9ee3c0286288a9b155369a0b36b797a6b05d3347aff59bc6f69ae0bb571c0b4ab0f6a47b3304e9796362ef5f90dd606df41354d27a85d7c90a909fd3855d2c24087de640f9c145ead76759510c61dc4f1eac3055d8762132a61535e3a5010d625c4161a01ccc55cc854d16cd0e5ce9efa7461642cc3a9188eb3a6a99a09e20da8b8998f8ab3c0216380b6ee856e369a4fee5756ad780a8fc64f03b07659a8659e6de0cc607932a8d033e5c1fd04dfee7328021bacfc273fe1b4d96688948789cd366c6029d7f03e681f640b9814c15187fc8846f2cc3fc241dad4ae826dd3115fc810aba6f8a88146ae91bab0f079d3b56efaf1c3344fe7cde4dd80219cce8b6e1074e30bd6fbc4cb6d67bfcfa6b5c7957ade5c03673834ffe4934ce08000e355ff5d3e04ecbc90b5387f9eb5805cc3bc5e12b8bcb4226e0b86822324b145a48d10f76c231c02d7576864dbdd19ea59b35612dd10b8068604ee4a9257e828099c7fb0dbe8f7ea0df9790cf884f172903c91a3781559950d961609be6f9c6b91c175b692bf35c227a551b57836ad7d1f5efe087f265d1e6e35360b109f24a6cfee2a317cf72bddcbc940d65e0b26121c6569da3db0e121333bb0355dbb872e404150e73d40801d9df081022e88ae667b6915744839c11fbc7daa100227d05a59a2643597602fded7fb2d4d020427c9a9a36b9b18adbd04b2514ccb872e8921aa4b1c52c07fcad5672e2935dd886c6b71edc6e0fd00c5c410019b61b7a3b34f098d6b3e0afb3da02f01b93bc08783db14ec98f9e58d77a006be9c81d5dfaf1da516ef2811bee5da9d597005a7a5c7a9f72d2dedfefcee867006c6f35ad06adc0e0312a59d61ee23569d3b225dafd0867342efb202ccc348bd0ba4772cc6fd21e34baa5db31aedc61fa817b53e4000c022c6af2f38d205ba092a81c0bcade6c76ed19898adf83fcebbe56a2987ab0c962abd1bfeaf8bfc09439ae6365a35d3c97340eba350b6ff9d8436c0626dcf96c1456eedfb11d3222f46f8e44dabd314a297840a608ec577ead447a78e0f0f56e4297947ed475ae29d78d12a01a7511c7e36449ac42edea2ac10453fd163fca2e6f69f9779d9f02c9183947d446fd52d9133955e304b6d112df17516f9ee8d00fb82e419bfc9a7df3de5d79ba3f4d3cf914ea2345b1e32a4192fc086e61fb7c8b2d15d8a774fc3be9648e823fc60b27bf74006627e303742a400769013eda8dedbbbf0462f40814abb5ac1992ceaa303fbb29838829c99e6796335677963d3d53bc8973d4bd65972df74992ecd400b992015af3608f5d1e583de7de86ce9d82d2d6ed865b89e6063cd51b8dff9e65a50654ee6346f6382ba8d449f090c093d02f97e9d0a15315d7edc68c2dc329567e7fb81ed27bdf8fbdf2371ce01af3b66a031588db0038de6c8c0b3724f82c3646ecffa796190fe6f804b703157061cd044cdb3fe63cfe10efe27376a099bd63c2cff6e974c2d0cfe978f78e9008c2daae22636f6d4289bfc870f6596bd670cdd7e531fcc338513c310e36fb4ccdb10e5bfbe1b78facf079773775b5474ab0a1ced517dab407adfa47cce51ede92e01774110110fa139056b79065d70117fc81c28702f8a5148ef83d8e8b4679d93cf1a224d37df056ba8d30e4f93572b5aa3396194667518a49e37d3ebce093b92d430f884b0162cb088c94a3742480e61c03c12ed66adbcbc39212363645e9e7af0da4f4295e7dc9a665de23f58d970c2ab104729529e05be6c649f4b38379ff7f9ebe384e1464411ba0e1e417ece077352b0a98eca3516d550550b1a38ce9c844db2e00a12d61b733b4defa84c1b1a1c9ef4627a69d1789507d1fdcb21f6efd04446f6f564d441c59db19a690b44355cf63b37ffe0f36b77dcee95be7e7f655b15e6700f7377145b2cf2995a19a09bb3f8c63b90891e8937f7d0c42731e956187d9c30404c5483182083758b93855a27814e3c239d6bf9c4a0570cc5b0aaf7f6f83925443ade8699838cef65f47487ce8f8096674f5624acb14bddc92d257d64962a5f4184edd1757d9a5d388f76ea2424f493f62b35cabda54101e258ec4468eaf9e02a602e7e5363e0cd8f828603c332af8df2cbd3bb203dd08ee23aca29c5e606d5515e70bb11929143274869ebb136ba0e2d26dc8668d32072e78ba1ffaf441bd00f24fe70a3ecc6f00d073222b3aa893e4d762d283ef179cd442c0e5d218eb788b869c6f32001184c51aa38aa4248677c54404201c607efd542d88627dfd79387b9b57d2dfcb3f766beaf20fea7a9882698af8885a0f5979feb7ddc7b172d36d0df77a7a23d5011c589465d8e624a5918b7601c961c9c8426e2f73163dbf4b9e1f967eb96e9c428dee93ec961c547222cd1022c241c8be2cde2e65a597784a0847f2a1b9804cc2168c687ae0d26b5e55800bf5d95ecc0a00e03e5cd4b415be98885705eec1663f22e4ae3154e2c38d3f94a2f021efe0d9c30dbd9434870f566df1d5afe4159a8c7efadad4eb3068c7182c5197609c8edf7a25105ae0f1524d4dd846ce6674ff051e2ce336c5f15d8473db1de64b99298dc93ede24352acf80cf59438644523879b311c2bd0d34b4245b38b1d069b9d8689d522e4f86244c60ca570214d7f72dd0aa7017fb7a3ae6e857d4a2899fba1f4017d584bcb6eabc74ac49ec2287e5d757bdb3e19a5a8f9d368f82a1e57619741f21aaaf48d425285a074c449d456f5ccdb720d2c9baec9a9ba1a36d5ded75c0661835b3b9521e7b9bb942cf54a7d23806120f40cb1d621eb2183e6a33af99deeb35bfddd51f3da579f5d8ab208a21e743314bab8d9262a4f70b83dc2ddc57d64321f00ca845c1e59b46046cb640da37762e2da4cb0241ad43103ba6f6e845a208e59361db4ba730d9973b86f8662a0ea877acfc750df46cedba07d11a51dca803c7ad843bd034a847a7985d967d40c0c040604030600809eb957a7b60d7e9cdd25fc6a6d15d29975ab95f20804c828c9debbadedbda59452cae1078d082d083e982c79736e8cb46209ca0c4840e4a4e121e6dc58898794374a2e6c45f1293937668252264c8fa5394e61e7c64d29a0ca7ce860d222c39b73e3280f5a80f5b4a48615ab37e7c63e13d0126de6bcbd7050b8652f7edf25a77bf5d6effded1b2626e6ca54942318580072ee8bd4ab612a870ba2c070eeab04015a22ce94396fe1bc754a766eeb653960b7d53ac0570e0e404b54df35cedb4a66d4658f9cb8b8f959e9724111323ece6d91be98882ce941266cccd5b9add257385f7e6501e5a0a425aadbb0281a308c1ca9418773ce8d272e64e0718483c9b92b520868f8d2e2c2ab86185ae7ae4db407375736864c4125113977657a525375e30a07961862ce5d7d2b5e8cd9088b3187878b38e7ae516f7f74d72b176f8e2c11b5da02f6d653a02768d9f5400dc2a7750e5822ca84a846bda5f1f6ea0530a6313016363a8004363546ac6a851dcead9f9249616903c313981f34acd7180cb01b4d64a872eedd6fa07743962a2caad0509d443968c170ca02258b9c538ca33716df68308acd57cc6485aa571f79488a01007f3d63a6a6b1dff99cdd83c45c95a6eaafdf2c363cc6389fb962d5cb22dad4a1377e33873667681d2cadc345d7a27411bdeb96af0e6ad1555f1dcca2674a7a579fd140e11661245bf639a771fa9c6f11f565bf80082360244a44c11e2361a51914ecabeb243d13a2c52bbdf18b561f7a8f75b5b21032d2a06dad5432245a66cd6429891ab71b327a51a7a56eb9da0d89782c6c4b7e537500d3c23628fc91fd867022fd792d21fd66621931aa2a51b2d75e6b99465a0f1687d6ee23096287068146d3283fbc9e7a0df2d7afb82d9365b24474e816b9e3705adb5a297edc2363e401d31e1045ad7138cbd344574badcedaec41549a060d66132ad5c0ba9d59097b9847f416b1eb0b60cf9e7529607d733e17d0a58063903aaf6ec5596bac8043e9bc391c83d4494b0fae91d286def87daa53321d5ef84e2a674c0ad2495dfc8173022d49117de8ea348a8f2757639693baae1c581d384ba06c083b5f18402b8c2f0cab7f359e6569bf6a2a78efbd2d7830ce18678cefbdb76a518abe96f6f4e60ce60ce68c31c6b5d6fa82d5daa5a6427ca03d757befbdd65a6b9f44d2da5a6bad6e7e17042ff8f3e318fcb8836006fd52e991520d6caff51674ea22d01355050813004371461bc91285dd95d99f12b951072830a812803b0643463ad6c01abd3a1217863ee26a2db4d7c8eef0bd1883b584ad6d2330e7306731e759ceb49cc79cc99ccbcc43a537ad0ab1740a1520d013a0e8d83bb0bb323b0a9b004af463c2a8037ae282bafba063408b6c54a8baa8dbb5fa25dd55b73e8212519a735824a90633a69146298d62f229cd292d7a9a338016e1e815e909fc3437a21c844ef3139508749a2ba01265a7f9494f60a7515ad2663aea24ad1c845b7c9aef72976f6f49ab22ad956273e6bb2ce92e7fe3a8ad25eacde96a0922945a4a69ad23c63a22f6a5abeb96d36f92e27a8d8cd6d6686cf5f0580bb24414ebae5f2b2d6f57e05ae38cd586561a7af31592813a66248aa7801dcc3a15aa0f353f7a270b54d0f5ae97191cbd133bd6e52d5728675da16a6d261b69d0cebfaf572be078fa644e19fd3dbdea15f9ab444f5c1fd5a07a456145c4a9eebb5b34002c6ebc38f5ce4a86c20918a234f97a673dab6975258a52efac59bdde596d1c254a3dcb747b481fb27480f5ceea76c966659585d9df15aa7e5ab2eab5c9a94679e01645dd220ea63cf9ceea218c60a36e113dafd215aa286e113d2bd562ad62cd3fcc355a9cc14b4bd051d8300c75e834ca871f5225a1f261013efcf16118566b44da7e82843deea99516d70d63b846f5b1e28a31c65b9ad67b63b859b474f550062bbabace8b2eba7a2d55d1d5cb47165dfdc353abae36b4a4b59a97ae5a4d9e4260a4b40a04bbbb2976e8ed3e84e206ed48d84c7190199da2eaebdd36eb4435cb074f13271a77afaef238d13c54ba7badb5a013bdc9a796c7094f95c6d9eed5384f69ca43a5696829106bf56cac51d51eb9f65e1cece5a9d2389e297d75949c8921485e8c71ce190cc350146733da9007f67794479e805ddb3a2011445e1a8a241d411ca9b183f6e2dcbdba4d8e23a9adaef6b419475aedc519a4c2436575b4baf855875a8dd6ee56d87ac248ad091edc176b89ea1ed86ad3687da4b5fa687324a87f82eaa592a7a504c65aabcdee56d86a7b637d8ac71d913641a0b4e9f1144a1b1c1f3e85d266c6974fa1b4e95960ac36b49ef83cb5ea72f4d5a9c9029398c45f02f96046ba9dc788b61508a57fabf5bf4ab9aaf4d7ef454135b84eb18e036cc0f2bfd68bce741c604315f55147218abefa00dbfbac534173285230d1b31f7a531f4f91d0afa750618928584150e73bf4ecb499a780268aa0a89b006d4745d1435187cbd507799e34d6eda1a740c6d90a1b804a84ca32bb318da82badc411660c58848ed7ad9603cf2c87ae4ebbf7de1914aee2957bef0dc38c33167a8be012bdc5d28cde22b5beafb5b32f7fc40fa8f5bf964ff416f37d5c3fd838e8a96e45017e14733fd2c89ad3c93f92e409b9ccf8deb2b495ce6acdcd74e8d96c56629ad6d7abea7c3ed095403e1ec9ba71d5e1325873e28f2229ce667b452547da8cd26b2bfe1a3ea975d6c381cc58ae750a0473c5f6d61b829e05638c6bfd5a97dc2041904b915aab954ca7c6213a0b31287a7d4c29f817cf280d310e970599524aedcce630152949857288cf362a949d82ba4a299d51edbd72ec95ba380c6734190cef1545ad7138f7ddae7412eac79608fc20e7c71fe65cebfd30e7fa41fe9a6b0dae4ff040729ab2e4830d95767a8b488c496324860e1a5efcd05ef4db26042c0037c478d30b50f24c9cfe1dc73b8edb7171474897dff1a192b7e3543512d4c46317733c76ed3b21381e03b1f2d84b943c6c84cb42e2638918951730f01904dc90e389cb9117bd169c362053dee604287936d7a0e46910437c0fc249943c10e2cd71b79b07dd7ce8e6e24dff8dc8df6e98f3e6066ffa004a9e9941c9c32e54f26e4638338ff35dc9c389b6e7117b1e1e0fe2c1cea3d4ebf5609c3c57aae06c35ad9141caebe4e152e6c21815af321727dd7a1efc8365c46f121d08fda6554a7e28997abc0486c74bcc3c66c2e43166d2e5710e373c7601943c6c4dd374bae99605f010d2e34cd98b2132d0a1379d9a34eb4df04d336fbac7f0a6a368c19b2ede220e7c84317d690961b2c3692a71e14d0f40c9337f0028793c5edff314e77b3ca8e4f538a1f95bfb5be6af7b1089a14b64e9af792b947b7d849d7b89c4f9bb73ab946bf3cbe3bbee681afb7bc9fcae575eb16e4e8394e5d861aa0990a3f30ed981cc963132c67a38b7feebf41600e98c0b409ec67c386eed69a085262ff812c3911a48ce14d45cbd008d989316acb94f2ffc2dcbdf1c839277c361f8c985c718bbaecaf310b9e1793c57f2788e30bd70438585a31db29c5bbfcd16f636176fd107ccec1842e497c505acd346c4c7dbdc4b9e2dc4ef38c9f91d1f51f27644d3fc79d3349d5a78d3c9ebcd216bde741125cfd4af1da7879479ed40fe53f2eecff71fb0bcf90fee53f23e5819f235f16bb4ccd76a35edb5da15395fdba9e131350fa1e622d46ecd690d4b99afe9d4b0929a78d6bc2e5922fab59a53f11689f84a1a9b8a210684e9ac353dd101030d598ad8a8495d7991e1abe1668573531f094dbeaea0b4b09981aae6b4561bfa5d0363917aec21705357e8af8b567e7fafccf05690fc7510a6699a6e3aaee49918bcb692f4da7b4a9ebe95bc9a8e539f0ed7975fbae0cbb3fcd2495822d34b1f32e2e1cb0e4a0fc1125d2f5d845a59fa089cbe2ccbd22b8eb2eef8b2327d09834fc9972037b6bece52fb4aa79b967d597b5f5a65b978addd56f23416f3d8c51b78c020bef6fb9a7f2879b515467a68a9a14bc9961224270ef3613b54e1d10298b11acefba4f4d7754ade75b38a913779656d7a2824d985ec224b9224b7c80cc8af271d932e3a09f2a46b276d9eb4baf2e413214f924fa49ebcb2f1e4159927dd2c79a4f9e3387ad038fa902daa4ce3383ab5f2e39420f337896da283124fc3fca5325584aaf7d7714ea5f4d777607f7d884acd5fab2651deaa8a86bf5e96bc8b6ffc367a8cbd3c76fff2d8459fd663274b1e2e79a311019ee6b4c6d39c26963f739c25c2603f73dfcd7cc8cedcc8888b9f752035f3106ed12cec673058e02ad371c58613937376844b09c80c5c74cc4873cee8d5959f417d3dc65082feba868251240caee4cdc8c09297993ea7a2863a25ddac068d5be8e0163a1bfcd6c1483a3a3a3a3a606f5d074b47ebadebf4aedeead039bf758e7eebecf8ad73550234565f3d222e543939b78e16ab2e6facdce0f0c5e4dc3a586ec8414a892bcb776e1db135695e403635c705d5b9759a44e0a5cd0c37aa98d9f23ab74e946f8bd4961e5bc43439b74e181d66cedbad6f9826d365afbdde82bd75ba7598d85bd758b6e8b2b96cb4dea2a26b8edffac86f9de4b76ea1654a8aca0e2f39589d5b3b65bd70c31c222c60c9e1dcbac71cae2528499cc86c9d5b33bd9d7a8344eb07123152e7d64d1fc81155b68255d29329e7d66f6eb461d1d5c3ef4bcbb9b5155ac2ca9cb7bba655d3faeabbb6a5a5a6e677cdc9ef9a0cbf6b576fbd9655d3aa79d5c0a4be3cb921568686d79473d76a50e99023c46a07a832e7ae294dd130838e346e9e1c39778da906333e283441ca689cbbb622062670e024ddf0262becdcb514516062ac318325e6ebdcb51a68891ae6bcdde66d32cddb649a5e26d85b37b16cd1f559a1ea3e53ebad9b5dc8dfe69159ab7e9b2efc36af6a1c9951c3a969ebc9b94da41b5173c814d18185eadca6d22c87df171a3a78f5a8ce6d32a550c6e205178d252e849cdb6ca261079b2a45b2b4093bb719f5d5260d12314f4dd09cdbbc35ca5ba3f4df259c8bc30a55dfa5188e92cd5b2fb7c894457e974d7e974e6559fecab0930b961e5860006381e4dc25125603a4abc90c32358e9cbb540a2bb2552606468ccbccb94b267a068b0725a5155c00e7c7b9cba636b4449b396fc932b28c2c23cbde3ab9e62d29e737b944d2f09b2449f21781ae1e584e5a76c8e2e3dc24d2882d3856472f4401513a37a924001d5f36f4d042ea880be7269940a0c482960cb030605e9c9b7463a6cb8f16689a90f0383719f5360a0b489cbc8ce5803a37e99b424b4c99f376cc1ac3de8e366b1cbd46b0b73e62d9220b66c72d392399df63eff748f57bbc2ab281032acc922f3b769c7bcc81e486992a6f5ac0e8e1dca3d20a1a3dbcc2cc80d4e20992738f3ebe6ce9fd58aaf1c5eadc230f568e8ca13164ca8ad8b9472f698c2c65619ae1abc9b9479f119a111aee372d8a16458ba2d15ed068341a8d46fbd916cc6c0b663dbf679669669966b31efe3d3b5a9acd66b39f15adb8c5ea48a2452a7beb624f3cdae0b7f8f45b9cfa2d8ae2ef024e52c8a2b49c2993e3dc22d28a223dfc70c1050b48326c9c5b549a3ab3c6aa052b2a58e716995440464c0c5ea670497939b7d8f4564a8f2138baaab47ae716a35080c16424490e921d5de7167d6768893373de86642159b8c317747e872d7e87337e87307e876118fe4eac59d28206264e64443977889480177c3576a8e2c2c3c9b943a59e245da4fcd040018972ee900a10b02730d6f000c605e70e9b3e3c9933c3c816234d66387718f54e9a6248a3e45ba3a5e4dca12f0b9805dce016700b0896d17e8347200882e04f481692c7dfd9293b65a79c73aeda192a1fa1f99d9df2150c3078cc79c18289d396f30d0f1632d0280325ecdcb9e96d0b1ce76d6df1d53a86539170d85b8cb117067beb18cb16d51df8373e42f21b2f0df98d9d88fcc65711b07286ec45342c8164ce55304dbff08909c74fe4aa61cb8c0ad212ad86ac712b29ea242998185bce9c2b800c45ca4c32e7ea4f47afecc4391f2ce758a3d2e64a9339477d4872ae4e9cf3d1e11c75a684957dc06a616927eb852c5b9b21513c55ba946e447a18e3eb01d13bc710b6d210317e0029e33b891cf1c80ae1b3e6f459d33b471f5ba94f183119563bbe7ce708e2a9ca15329f35206c3ebd73fcb195fed429323e29a6730c51cb925c40fad12184f87c40c1beea70cea7fa0f8cf30746efcc399feabd7304b29502f1b8393a73ee002ce88083ef1c7d9a900971d25f73ae3a5dd1423a71ce67cd39fe58f1c10444e61c95e21341e6dccdf104e91c61a5948c71f22a038c1cb221289ca367cea95079c09095733e2bce0c7a9a9e2b583ae9798e189039a70275c242990a3f30ceaca3f6009bc4409773d7e9743a5dc637a8f6224cd889733e2f38359943d3d52ec1e8af5b9a739873982b26b3d5fad5d51b667763b544f5eb955a9b57bccdd4ee154fa9e79c73de275813263618dac08409a8a63037739cdb99046cc51cf62c8ae1d344517415664933cfbbc6a825a88739475dcced9aab316a89ec21a59e735893727bc55312849f0b73fdab5a8219a417ab19672c6c0032112ac776a31add68e5e5d5086bb1678c45608cbdfacd3a7cefade6e301b9c625dacc88ae5ea3e8ea33ab71d6a28bd79f60dfa4659eccd32f3f66acdb24187144d7dcb846531f7100e268ea2b1e63e06b2ef75134f59cb33292a5198219e36b6ba534934efd38236b6ef682a6ee53a906b4d67befc5f482a2144da3a56975db83c7515403eab9f71ab5ba1cd134324f7a5c330369039b71c42ea577c65887c328955a31959e00d97841bdf54a56abd5e4e989eab8a4565e4b5fe9899c010b5dabdf0ad0354f5bce889141840acc49a950a5276c062c343d513360a1ab8fb38b67745667e26c667338036be64ee1ad67b1d91eebf1c31320584fed0e8aa6581a3fd19b6645d19b5649d15be4b9d25cbacefc161d4b63d1e5ef7acd0a3d6d5a1a77492133562cd8aa4b6a0c638c291572ace3001bb4ec8e6e6c8932896be9141b300a8023b03b9ba3140441d05e2ada5dad2482aeefa0a722d5614c79c474f5a07ba36602094e101f3bd689507a63fbb888e9b44eab532f79f649b188aed6fe98dbb50c3b1848da2a07b6f737084fc16db9da5915770853eb22d8229c15ba602a07d5823d1eb2bb2b5e1fe2401058091cd8116489e8d3cfba9a985bf2b03dc16f1590deea4660779583fa55c6d12d1176b13aceeeaad7c6587b6216b896e162685abfb0781b041684443cad8fc8d759123d8e95c45e7d575de3ca2fdaba4e15ddb2a3ae73a54d2aba567711d098691a5343101d74c8b9ddbd7e8b2897246532b4d0f0b1e4b462062a365ba0cefc48c3e2acae714af4367a8a6f4e04bba34edf3eb5ea8a7ad188b6baa1ece222093275675c2a4930121dda28a3755e8851b9d83229183f8d5da0f2e540660b4ed2a10d4ba6755eb0417f803ad2a215180da455111f49d668d150487b6ca11169fbe972c5a6197d5a1445abb575a5438b54ec101d6ae969f2a9d55617dcc21699acad35326cc9a9557468e38bd67901062d5a8dd12515183a8ac64f1a7c6ab5650d8ec40e67d33f412abac800c5c8ddc87d22ce88cce8eae7f5f7a2673dc63da6642f3ed3e3ffd07bd1e9abd71694038c444b54a7315e3c5d81831aa82b393e186a1c393f80a21a5316c54248d6b9ab526d9a4106c6922353ae66a038bc204b142c1e33d2f468972f3e2c73be085972ee9a65e2054d569c10e9214bd8b9eb1636d452d126bae645ea94fa53c751a3a73e445550ea2350fc3404464f02e8a1534f01851158a2ebe3e98fa78e82fa8ebaa6bd5ecf066593d5ebf566d01c3e671749da8ddf419f7def486ca3cf8e02e933cef40aeb33d5b2d24a92c53ef8a66c8a707dae4735a9c777c5b1f4d92b1393cfb7dc1404e7bb4255df10aecff90aeb33889c7358150b51d68bf3d91ef9f8b648493fbe2d8e2526ac2f9edfb64710a8cfd9ad6fc767b755d9627dd6b2bf169f2d18906f1b26f6d9dede8bcff7e86dbe2fd24dfa9cefd2e7245a06f81d8740c9db4192e56d369bcd7739b7d9925cbd8db4a9b17908964884db5c049bcda9cde636174e6ebcfca45cb8387fd810464e922d16645f36dfa1667edb7ee7e777488cf96de277c67ec7f18e8b51507e0707a8df916ac1efecf890d497df71104ade8e08118e1321c22992322fc21f50f244e49c6edbeff7cfe71ce77247607cee489bcf19b1fa9c3ba0e4e53e2879b61151aafc085751f24688b7074af3403b0e04647320a0154cbeecb04549ce0e5f309c401f00bb42038e0c38c2da0045c1e18112f0dbf6b69fb74101f2369b0dca95b745a1f136f7a0e4d97c67676767c71b50f27678250f684a9437dd344d0f22618944b8e943545cbc7933d198a68b608e304dd30472d374d3344dd3eb55c53275a6699aa6699a2615afd7b9ce53943c9d98cbe572396740c9cb39951def7e963c1781808080fc35f81153b87e84a3287923767676767676767676767c01256f4744d98b7005943c11a28dcddb3c0125cfd641c933b16c3c7e4cf6187b50113eb1763c46f3218840c1a8d863ac228f91942cd10e8e1db509eb710d72802b4b04e4d82b9656f57afc26873566b4c6a492cead1f339123c683982419a69cbd206ce2b0b043111f6bb0921b1949985cb93202e7dcd4d7ab518f81ac1e080808c8392879400e72f03b2eee6009f91d3f51f2766c369bcd66b3d96c364740c9b3f9ae91690edd1a058bc69b2e9a58496fba51c9338b4a1ef6ff91d2e57f9ca8e4fdf8f8f8f8f8f8f878d6fb300dbde9072879a618124979e1b19b2879d80d50f27c8c42dca0f5217c83921742c8d56b9ed7dadd12d95c7b90f6217dc3d46b3da6775c6b536b1d385b11cc19772973058915140c6c95dadadadada0a4311ecea7215294008c15c3e207b08823ab62e8fac21f2fad5d9b42dc4199bd2d3d6d3565757176e6bcb09d75a6bad15c536ca14a43aab08051450e84ccb7c65434c5d74f51830fe82bbbaba30be557430e842c418cc983e6db9e8a27fc11863105f01e102d7c88ddce84b66e1669a31a614535cf1bdf68b1c8cbbbaba5280d081d1cd185f298bc12b8e2f488a5b6ceec520f81464d36e9492b4c6b991095a04ba1da183a7238438d385bbf495a1ab577ba33c6d3d6d3de5e8d1d193a3c7851e1c3d377a6cf4d4e851eaa1d1d342cf8c9ea41e193d317a60f420f5bc00d1d5e3a2a785aede73d4c3420f8b9e157a7a73e4dce2e8ea373802c018c9ed0da6b71e6e3cdcca6e6e6e3bdcdadcd8dcd60cdd6b800d4234b504a5e5ea49d6b1d2d35ad5171908ed3297eb63aabd4a8b7402902780a359d9eb0eff186a0cf4c411ae5714b5b634cba906209c381352140c94b4b4b4b4b4b8b8b8c0281004adb22af7deab775e469cd1c45918e2d9571cb4b8b8b870546b4a581818d6b3729d5c5efcb8b8b87ae8fcb87e5ef7de5bb57e6af08f8bd65a2bfd5de1e2e28a32c24a6aaad695d6947026d24632ea5e926be46a81c675c7686517d872dcd2dcc86e686e63b73337b19b995b991b995bd86dcc4dcc2dcc0deca6c30dccedcbed77fbba79b975b979ddba6e5c6e5cb72db7ad9b961b46ddb2607ad3ba61b95db959b965ddaadca8dca638905a4204c37b2f78c799e6a277cec5eff511e071659181d0ae87efd55adf8ab5d65a5f8d20c9581d04154af1438b50f8892a2e0974675d871279c0ee2c0ab7a8ea7635a92659a25d65fc09faf8aab8453b0f9080c369bdbbdae17062097623c04355690708293d0c7217dc91184bde0f8ad33b7731e721ac2285915de35fce74be713a6a85dca9d4206226ce421104719e3d582b14d04fa69a8b0b38dc0f082dbd3ba877a8003ba19d7b9bcbe9e4723b5a34c28f6ef9514a290a151310294e73d118e31144516b1ccebd0ef9bc96b2328b9106d5a74236052d0a419ce87af7a1ae1e1d2d1d2dd5a3113c70916c3dca3509cba0a3b77ca268ad16c98b711eb4b33bbf41eea28b7e64f45a771e848ba1b16882585e24529dd18f1115a3664898000817b09eb191911bb99191d6888ba1a98f346702febdbbf45a4be9dd699dd9ee87ee7e9c9e20ebdddd0e3ab07dd1203b85ba58a4c20a59af3174c90b29171529b01b5d19d4c6d038130505c5d1db66b30ee21aea682545f136b1e18c0b77f8de203d04e292f4bda0484f84e35596118a8a8207f1ec73b82b64e9ee0a8962034abc076668a3a12b64bdf6c0d8fa369b2dc74dca2dca0dcaedeaf6e466757372abba35b951dda66ebe5b0e3726b7253725b724372910371c6e51bafa0dc9ed88ae7e337283ba15b93ddd88dc9cc617892e298638dc8688b71b6e426e416e406e36dc5e706bbafdd0817645abd2550c2905ef059331d500db6c3bb67b2f48d2a0589c8f8072efbd57a4b3149eda9d978b73ce60e8240cc3300cc3522b34cd843af41083a178af19d16b566963ce5924b5ad04db386612c4b6191749e632bbcea0e3acc360ee82e168062c455c9ab3297b71c6172b450aab31e7662ffe68c1cf8fdf3ece99c83223c5aa44531c6da5348b3338d3a5a8324a215605ce665dc4510c694122a96d25d86ea609bceb216d766734b12a3257ec238d56f2421f4912631cba4edff2ea5288555d7bc72c2425618c1883189335b2a6c9fb538482f6e482d000da631d8a269668fc50348e3a1428c6d18baebe71968846cb898f3fe8943fda6c3c64904d24f56da77c000936db079dd2041e7691529b88693bf54bd22c1b70bb9526f0681ef6d45ab338ab8123bd3a454e85dd893a146774755c2936b3ce2c71250d50a044614da15547da5d9ea2edce5e6bad1dca4b4830120cf923c190602e94a2a28e40d1235134ea080cac82a9bf1042a860473e9fcf377a19bd8e6636cc9a442691c92ab15236aa3a55272556090e5068bea10a55a3f0180ec361980c93b948aa312a12ad4947231986b35918cec4d0462d7d605ba825b25fb7b99bf45687c25af77bb3cd65246befbd4e8a157441c565e907f094aa8ad5ef12c812e86fd62432cd82d0df2cc8ac49649ad9300b320bc234527aa224291d69945a6b31b6f75a6bad0dc14c29b6d6adb594524a29a59496e468ceb4dc7b6fbdf7de5b7135412510e42181e78661ad59287eaaf7da4ab0d97b71cef7b6503305c1e0a724f0d868570c45b7ba200f22cb9998e9893c2695f45b7bfd5800a2ef53ab5fef9f747e6af5f5e6f6f8e221850a10c8a12fb0d9d719dc17d6978f8a459237449ce2bc215323ba518365c7952b676a9853b37e1b0d7d2db12cbe9818691271062f18863a31cec4e03576c30c0f4a7e3a808d39b17222468e08667c597c419136527c6af51504ccca8befa9d5d78e97f2d4ca4bd6db70f484e836fc6ddb607ebc83559bb0bfba13ec9b00f71b855eaff727e06a6f8e94670209ea9c1773340d2ef95bfcdf62c801d689ef17cb2ad9246a5bb04a33ec12c80a558f444555611b559dac94cffa9a90e36ff4a2a397f137feacb08bd9a9dd89a198db275c303030bf10c05430b09ce46a53af3fe13e06411154e16de8d7ef781d749bab48d8ba758cc7d15e0a5a9d53ada0718ebcada0b7edd2abf380ee480c99a07fb791d197106c0876576bd2584df2d9481d06b723316482b4913a841a238914d30ba0147f7083c3f97218c7f1378ef497e8684914be3aadf9e2a8b5ba0af5e2b05e7195c0b5514b50bf4a5fedcfeeeab5514b54b7f6e2b0bb9aad759cab98ec0787c1e8fde313b8c0637c71e41ce94563d2bed0dbabb08c309d3847579c39b7e21c6d8da5134f81210c7b51ca4e58029cdfa8048d777541ca0cd5cc100004010316400020140a078442915014456922ed1d148010629040744e34948763b124c55110044110a38c310000449031c4186688684701ef02e9e9f10d5928c8ff26b9734e1f04f79c4fa21bef44782b64cff33b2f6b34431263acd1a9cf0aeb41cd1374b78a6dacd518332b5de98173d1dcccff18a7a54196f43e579d8bb618906c0021fea9ba38a1c086fd556f2bf2d9050d1d075559a5579e76f5447f0bd6e87211202510d85d8595881c7c80a9cf069a92c668ccf222a71e9bbcbf403a344f859ac653afd79c2a37306d68952ae84a9cea103090d4819e2475e42caee6426a3240bdd616122147a06f8f162b742e4540dae9cf0a951ae0206f63548e2cd3940fb1a7cc335351f3b3a9b0dcf0d93763ee6a4eea2a574f9138897f8d438c8f7ff22edc651a75cb9bb6d293cf3c220ea9e56eb05738449466c793c48c33b89eda1105ed81bb1e33a5c36c4a2719471d5114ce19626ef769a5bd894d54d819fe8b05d3f510f43dd0149f5da6038dda77a442643ab0b63e51599e9161ce58441867c52513c2b3f7bb16344810dbb61d34195290ff0a7c05dc48d608632fafa76d7055cdc17dd1753aff69aa9979535a61dea977a427894a5710a2622eaeebf1269e240a5a47f2ea109131451ccf1ffe5367a0bbc0a74e8462888149fd9606fa54e0cd81a7e2bead170dafa0bbf65fdd151b543692095e9b3bada3fea9dd4180af400f92fec9e014b979b1ce02c019a78a4d81a6ebf117450246d3e46d4d91462222db459b2821d3ff2d38a851bd4ed6252d21902575414b51a54a7c7079afd43ac95e726375c11e5a26074cd93b76baa5463bd34c99f0a5be06f13d7f9641b299b4b0540fd3d5f306a64824185b587e75f765780bb9f10b5af5a41d2de15ad4bb45bd39cd2b07015f22f936702abbcd3e99799c8980b432e7715c981b376d5954d9de16b2f7089c7b4ce816db5b0867681f271437ce76348080387345dcb81406080b278d16e17b82935b40f0c32a64866e70b824dd6ebe28722686245f67e4804f6826c8e047236e628985b7827fd4c0076121ae477f46a93d6e2fcd286b270091dd88e0f6b06b9e503f01b7514cea2b52a3356069561365b8df78ded3ccdebb3c3832556c3265dd675174c865c54126cac226118c4462cc1c89bb1494bf36ea0fc7c11969937330578fe4075fb4234985809b38c547cc283e2af604e57f9b92c045976e04647eafcc66400617cacc00ced91596e35e78b57da2bab2811a6ca34993c11cd7195a7e471da8dc4f355c0235dba8fcbee36ac235c09ecad96d75bc3ab31466a426550e0d7cd2e114d44591a58bf87e66b6a5d12c2adce5ef6b50807cb8790678d5edeee501b427dac4e5d01fd93045cd6c2ebcd0bd4d7a5ce1159d08bb5025a6619ebb839a2c1598255a546a12d5ddf8a55412d12fb7dfb5ef5ebe6f2fcc62d143aba186ee84747d02ca6f002e10839796a9972214da513cc96d8a8ef20743ef19104db649d8aa46cfd5bb732a75763c156900c24655d942392247878222feddbe5cd4492a468e7e58600646d238600902c6ae3f6194ca4ee348b025826e317611eabb0374f7163aa038095d1c62e0900c7c1eacb408962e14eb14d3d4d986af0e9f5ae7eda2046dd85782ecb2004d1c01212af8486d0bc4615f192d0d190f4ce0dc0d5a45b2af7ab322aa4bd126c4d58f2e205054395d51681a766e069a12a9004903215614f227f740c11152ac9f9a54950ae162a990b467095abe984f0c45a1d3a904ced3ea25c85e1d076d587630a090096e0785e4ada6a63a6d30307b3986ea8237b4409cc7a869005bc3f18876e8b6099065d2a32bff2c0993a4938c188901c3655b4ab97a3e6cbbd596533a859cb90a283f4c85959b856f6fa1683721e3cd4c0b2727b30fc4611d952815ddb7272b351990a9e1da47219bc3a71043be0b787142581e7837420bac917928fc082c0a968c0588a048ef610d1b8437a9c139e5fd04ecf810a2c990baed356e8ac0b532300cf46c83eafd85a31a1d9018e8b286eb4de7a286f41664997faadae4e246620b6293bc0b29820723861972b88a4d71081d209bd183749a6ca0a0fb035ce99beec0b0c56a56c974a49dc25e58ef28908996b72f783a72da51b76b13a454666d829b5a7ddf1447dfa26f9fd9eec236e9518f8a8e646daa25a8d6a34de7458418a45b2373a36ada75d4cc028eaa2786ddea03776d7d0234d5f48ba5e978ac7f68076967733ccec9ac03bae1917267a9992d530734e3fb0172b242493e3d0a97ede939be4ccd985a74e7e96a2e78121dd4f4132271b9f27c88bb758312218532a6a45a5af865d8d0cbabac64c0f200eb3204e2cabd3e53b0b52b7d331c5860ed66fa8640d7ee748c41dd75107e29dd162ed220f8934be8d15245c42e882fb05d85305938de2077cb0e54670f647cd10bf606c98d0b35d0de93ec28fd5202823706cd3bc51fc9d00b6d13d7d94f6991ab77cd6d085d724059bca53c9c96288a65a6662edb3053e85963b3f8644a0564801814b8920a2470be15bf651c04c967c9cbedc0c03385c1550526bbd37691bb57aeef35096c1a4efbb7b29635d56bd9f86a746eb70f0640ebf17902f9508d8c40be744b7939a80bdf38c0507189344cedd299f4299d6e47946c5943bcd46c6c8e96a27d673a92feb743fc26cccc89ec415cc0857cb3aed15cf3d2868716f13a6268176ac540fa5b61c659bda78b7e4b192b57e8ce1a6e8ea4cc66c1790cc2e26ec21577411ef4b6452d4b3d33e31a3100c3be2f04ec19f034d005f9237c0cc80f3029925ab0b8684d5555f5be48876258bd6825235c18d2fce326c6c1784c0cc05a6b674af317e86f3dba8030860608f33607a08316e67a2d689622230719577369d94cd12d111b5f3c0c69569c1722dc3a0ecbaedbac7d1b4ae0dc958c62f28aad554920536ae125189bfb908538dfc1979abc495c2bb5485b7457c34b740023c22dda52b160f8534a7ad78e6a013df659838866803492a3ddb419876fbd6ca6c22b018bb11099b2309a8ceb187f0ade8497cef6ca94f467012d885ffdeafdc4e545ce2447dc8558743fdceb7693032ac7f4b3d6d8ad96e6de6ac91e7dbd61ca6a9e27bcfa55d26e6f7b7f0d113406605f37a29269b3433cd344c611f75d5e3ff5e14c44416cd106d7cdcfbdb3eaf1dc0c1c38c08e80196b817e41b9907f6bc1ff55a8f66380e86b2f9314da79839182fe0befa772d52b9710e04a32f846538fe9a76e836ceae18d224b41ab02262ee97e1e87c49f12bdd6e7228811b6046cd2e2796a8f748d8f91b9f13143512ad78cf3d5b969ce1e98c440ffb5fc26c2a627d08f00b32b0b34866d164d97e8614d805e7579dbe060a76496ac49d30a1b68179e05868a8a7022c4e63740d22b9564d5f0ac3f845a78fe947a20374e71b683433e960ef70d14a14dea7088a6f86f5430cefc7b307881e1576d40c765272b293f914a872492f56d239b9f18f39a4faf2973fbb98420777db576d778751baf4f58445be926862d826c27523aaf904a647d9112cacb90cf34f43165edae6afff410a825ffd6a7ecce85d5e1960ced819f6e7d0fd7e3aac42c89038a2090bfc95a6b5872ddb2e7f9bf68b71b81c1a7651e225361f0fccc5308f2755b0a38b0c5ef2ed8c96b98abf2eba8e5b36510481f96c1824660b83f5c6eedff13464422fd8e72ecf5c344f42ff07e3661d91eeddec7f641ade2bb2f41d74a522d64ad0a085c6a6d8283d55e414f9cbafbde423728491098938c1c39f48924c3508a5e37bc5bc400b65960b521580f00e920d18a0a1c3cf2bda02f58edf01ec80eba2be54bf1ad9ff3bfc2e1234733c45ecdcc6381b250a879d768296c2ff31d40cded6c9a163e35184174df29cd41615bf3c8f0321fc73f8d7c05c5d93e062443c2ac470aaddcefed66906a31e6fa571c465a86a1982c1238efc183a547ad5db8c4027473cb12dcbe89abec70029a8518ce90f672dc7062e3e6f56b6c2ce681bb5e58e5df0c397e4b1c995ec18cf9f768b6e53261fa94f97715602bc0639822c4795d076bb957327b17de77ec7a2b5c0c2b87c6852d36f519009d72ea3ebbdb0aacbaf98a37103c3882dd44f1c2718a4274bfe7f9c9d1a2a34162adb6b43e2d5fa62d03b8e712f2b3f889112ff7371e686867c561c548b4de07715c6f9814f552cd6a0943c364a37eb0d75a4cb8b5e0c17f2345cbcc7325692eca54c085059665b05c0603cbf80063b1f3d9c8d03c990480f062e5bc8a7aac5371867f445580b10b1b558973d1edb05e8948515956854c9de6266a6bda5fca4a3f9959dd804efbd6215acb918a9cac9d21a4194fbc2dac38c821501597304ef0c0394841a67dc257abd43a6d4ad108c01eab5c7efdfecb03711ed5328b7534b32c621db671cc42d15fcb2cf1492bbcb03190c6b8716dd1033dd2bc8765dcd86fafd15b1077e20a4319462310e0799059b6faeec8bfdf6088b39f6105602f3a9f3eabb6d14b8a2cc31ab7bb4c1a6e799dbee7bf98b49217a6068675b0725cc0c1474542d27411b02ae17b1f8e28ff979473eba20cc82c727c979b2b5d78c1d51fdeff6e0e46d218251599c15899b10f3994c6cbca8e4302a324e1f8e69d48ef16c581a0de0f0463a27bc84e871d5374d6eec8b816629c258026a6f22fc52322e1e41208d9dccfbde60fb9a379e1adbdd36f57b88cee6042e07f9dd53006a1af5310fc5c099f886a50238c61e287df30bfc432ecad37fbb113b2eb9936fc6703f8d8e084dda90023b87685aa3dae550cdad3375040ecc19ec69c46fdf929e63e05367443f3bceeed21120389a1a2a79e853d52b06fa196b0153165a20d363ae4fb6a0a38cb6f655ed4b34420fc7cbff100ba8c9ed865f32c930f37b2c14c12ad42f166443658e79824c6e3dc8c4d6220c00d9bd0c8e22f7b7916654c2b1f528122f83cc1bbc3030b17e9c7a0e432f9e06672a6c48befc603d7122f2d9d19c2c786e95f1acaca592ed0f67e9fa77b08467ed8217481e1597e6852eed75310beb865244b1af0707955f2c5c06e46247c0cf6ffd6d7f80e41642b9999cf7fa218c698c6e968270c55e745e5ff4a20ec0331041fb5bbd68723443b1b9926469d79ad9948fbb0165ee1c22e0e430aa92d7af794b2f4cb32b24213b418c6b5e7c7b8fe84c22469b2fa0b9ea09bdb8bf7eebf4aad2ca1ec21549e84b44082c8ba12a502a21ae94769e296e78f9368cfdac80f0e4e9b13b7c94dba5015b6cfc24d4a91e1080ddea35b32a6cc4a4d395d0e2f35b602227dff9707a9df7a80c3ba3a1d8d58e27600491ea66180a6b08fe621c3816291c147a9a274a4b83da92f6fb83c0ab6d0ef1606744a9f2e6ae5d470f829c01ef189e61598489b0b30c93f16628537e1b36413530446a85451f8df9d0409936d219e8423bc2ff02ab4a1e78b027e90b50a339219cad82bd54158fa0b6870802182ec13a82d9f3d9761a546232b0a677d8aa29ee55dbd312e91a31c4980ac098a930fba0cdb397980b9725597e5205feb08d913c7e8e96ac3f4ae382de170bb6f6b1d9d8e37b5e31b8352d0117246f160fdb8847d91850de543ac84c4f3d80ddc9fad385f72579a7e9462eed90c63c12bb10a072f9750c7b187693c9f063bd81669edc183f3c9b0aa4ff016bf867938ca78fc556a5221329176783052443bb947581fdbbf41d3f6a1ec0c3447a277ae14efdbf69ad4551458d86c5cd9e633be72e94deaf7c504ec64132012dce4a6d1a6a0d917df4eee155a796196fa50c9dc080f6436300b383759ca67de734bc54772e59c592a0444754a999d2561b19cbf6280dfb1682b5061de17ffd4e150031a66fddf0ec9d23105e54222433dc2795a6496e2b2ace303cbdcd4eacdce7cc2a4b143d403f261664be4ee29b31a212cdd33d08cdb765abb0f2e58f5399533cb074b1ba4e7228b7e26f00c63f18023186dc727e32dff97518ded73690d3f17d6127428dc2797ad38de1c1b82c6634bf998a21d47642ef74977eb633398a380fc540282badab46360c2b40905b664ac10b5fd62d5f8905fa61b8b290ca74078d45dc70131d0b9c83461c76e063e28573131273feb7678788c2ebf3b2aa08159e3d36c2489a5f5a148ee8791ddaba2ca434b7dc79d77e36799d059d16513864b304d69cba3bf241e0b4103a1716261399bba4f372080256239626c3c689ae1d73e23bd9788a1ebb31edccc2919464915beb9e215abdebbadd28756454a96a1b5e144b601fc9659bb8841179bd7be25fe227bb2f06206f8f77b7cb8996d1a2c535d718ca504068884d644093975c5e9d02f12f260641aed9ffa27e3d510c09a28c4d463df9cbf9fd6204355ec35bbcedff2847b56f90042b5d2259538246635c55b5f442bf61af979fcdcfc44d46fa2c6fe72c6af2f344a2ad2384caf8802f0432524e9356132dac085630208035175841dbc01068a6c4d000f703507aea4c35a589a62352c53a00f46ccbf8ae59f30325899d7048489c5929682eb48e388a7674ac777aacc007204f0f3c7a8956a5c236ecda2ec2495b5b263aa78c0c687faa3e8da6a4a5d539fee7632923dab1959531672d2a70bcda08ba01efbba10d190508e4d9f883188da0bb6ed01320e2c02cae0cae375dd705349f302ca90a695a4866cd7eed58797f94a06fcdbc26d8832d88d89677a051253b6c1df6c882d2543ed550fd08f7c7434308aaa7da649ec05665294904fdd4578a258ba0a119d10a89b5da274e74f708a781f3e9e9c1e9b41b9f84717dd8992947074ab1dc2bfe8459ec340fa9e1165a77b51e6b3f0a19c34722fedf6237750948040fe126e9ff0d50f14439165463da56fe144345623434c56048baa1ae81e1a463682362ccf14faafd3e28762601f8a98a9fd3bec163c569ed79ebe4e5f4433a21dc6ed4bdd2c3ca6f90e773871a42c58dd94f66aa0fb69905e8eb6e08857e166814471add392270bc69aa57101136ca2e0121ee1ded488f01a8cd2180c11ed4159c06361315df7927e9fb20a5c815633a05f936aa627ef4e780a47a3fd2877bf81d323433f1a7233b6bb8262524c46273e897a3c8be3fb71214a9c208120177dffa0865fa29f2e347269fb02b1fd1da71680c58d06ba08db27ed90a7ae40d060824b8f55aef7118eea0c1497f168243c6c6ea4105d298a5e8ee016bf2af062da3dd102a65a9053a14dbc84a03570561b0418436f76d15d95470a43db5a8e50d15b2bc5420483671f727bd5f5fa9e68b9099dd1249425b3c5c358f7af19663cd9a020caf9662e6cc73b40709efdaa4bf911c470569b362a248e18020872a5c37d090a1a327a3f21961c2c605374c2a0de9be3f28da73d6736147f99213941f72a7b8e2a18ae6b43f13f29527bc38ebae74aab3d010a0d9171e7e6cba2786e7ed58eea2033610cb11652ed9ecad016745fc84c6e119006801abadcb6921746b28d5f3aedc41e94496bf61a971dfc1c95b6e7674f47f80e09a87985354a003fe3b650590aa8434b80772deacca8ee7a649ff22de2f288be7b51992373433f69a22afb7b8172212dba7e15f364a2ce03a3cbf90f03f689d21f727223fae286bdf7a8538ce8f18289cec07b6874b41e388229c967c777684515de8bfb37aedc884476fa87ab8283c1c8d9491d9a3cf1285a56280b5c01853fdd0ba6f9ef9c902f0e26fa9e92d6eb44b1c59bc7ab93caeef89a0330e0157dbbdcfa9254492d8c853a6a113df350ec459c35370b2a574591c81ed7ada50592515d459b29590cda9db15a2375289d9317e2b4ccf324bd522de794423f83ff50365a6409d2329d99bf1bbff745ffbaf6d21e60908acc987be61eeed9d887b8267a708de7d89d588bc5318025baffa7c255b2cc271ea8342a17c75a6a6f73feabe40f7ec7083289f86fac99922da8cbd066041083abfd57608ccdb2462e5b89cf9f3ee5a8162fb3e33cd8eaeb1f45f8494179035e03c77dad1f2389bfc708b64858e7688e802ae1425151e5a8bd1b7630c904323a599de93075d8632c2e7d9f41f476b68c09cf8845b574b5740ef46156f10891ad4cfce778a05ae16ff67f0dd7cb8d84a1d1deb7c0de2fca06b6789798c536e58afb836a4de6acf4b2bb7c8e5117169e7a1e2f142677b2d22e1fa47ee128a921ad95130a110c3af7c49f07082c85997d0a4fcb594426498399e8491f43117167320f3a8f766b844c3727d9c13ce33ac780354dc38a8646222ba0da930761a6882a814cf45bd6d3bf4ec937717cccb125a800b76c1937e60ada63ba4c7ca012c6e5e8fc538db572900b59e7bc97d98ed277f0a9bb34868d4f6d66b24f1e99bc6917a27b9cd7e5b341396592177f751b03ae239dc699af8f2d4a39ac42145877e91c1f0ee7a9c8d1f91c4ddf4f2e7e5e22e4c0c8eac460db60d03d1da136608014af44139ce112d06236131eb846e954db4f450d4aa7b6240a3b692eaed5bcb2e2684d57b2279343a45400be3220dfdb420e6bb9f0d6b88c774795695e70d7dc114964bfb079a37f65f386a915566cdf18515d5f56129ed2232862438d04c4b8593055edda2558c8676359c74b195ee36a2a7d968d2ff634d007cade3b81436ea3d74a99b77686e41b53be0cc466d6e14f04b4397dcc9bbc755564d3c3db754ace740571c0a6ffee3d7927ca72293901b8185d6561a59a014f56df9ed6138d67f442f6501128c37a9cd8883402ddcb8c07fa8b0b3c601ebf253b66705690580f5d50f2b13b4f0784bd3724093e367a4695d8e115e135dc880ed503219c1dc8b16283fd9003b4926fcc32f670414f235cd18906a9f454b69b2a6c58a180dce204121481bfe63a7b0b210b5604bb903fb965d1a04b8503c23d0a39260539f256ca409eb61f14a584f0310209ca3affa0b20967b3a66c4806e4414212e5eb0256c06818001273a441c20585c874baa65c0ac81d5b3041ca8beebf6f89e74f456e9a1113f415e87e0aa79a25fd861142152a8dca84eaf6408aa41491668c00c223f0d88cce2dc02248493e73fc419b8620e326a05f6e90cb76ae5f99b19cb9b9ac974d8b7a92ea570e7741eaad4450f17aa7f4622d9f519fe86a95dd0e8fffbbe7f079ec08997ba56ca2feb671ed8b5d45f687c65645977770ee4f901edb0edd0c6ad2cea1e2ad3b1ca9165698a0f4c88587520bdfea2055589378e95901ebc1d1fc1712572efbe107b3c14dfcc692da23007a1d85cea4b50bcdda5aa51700d6771cf505dd8e64c4f53b25a3cddd8db02dd4f01e044ee99b2e59a44c7d5aff464205144cf60b3a71b41b45edfc8eed786d32ee67cfb2e89f08c39045148cac6c990da90deeb9da4ddf1e4942e601e5d8db1b961777fa0bf78e8f750938ee2c16d60a3c3ed806cb7b0f54208f36cd210423def3094175955c8203f16a7bda8e64326ee227f4572f48729b1ccb9581916a43884b4b45cc7c68ad26550e668036d7546b91a08d22bb48df29e2c7a672f24812de604ac9a43da3aa66055c2b2f73871c3f019cb50e71a44c1d05b6daeb156f70af500e1d4620d384ca0fa792ff13bc234c4bb6a302ec48afdf088b6a3067ee7b4241a9b28db1af824a63e2f60a48c390acbb5e9fd49cf69a36a8b89d54029f9dafff1fb30aa177c4ee700b91adfb2942e9eeffcdcd2a63a5c2a876a5e7e147a43f3c91bcb10d3df9255af5f578cc35656122bffcc62146899406e62ddbfaa717166b45c8be6bed4b6cc08724f1d015bb28aa998f87b4720e6881082e6804d345109329d10166cbce231d83a8c05c28a45a5672f8cbe5a1b44430ebd69dafa9c4e4c270dee8b6b7eff3475ff808201c497c080c4edd0b37ef4d6b2b0017fb59909e3c42c79066b7a35e0597ba58039071f412537132bdf77a8cd0a0ef809bcf3074694ec62ff748cbe0d00109ff7bc022d6fbb47200c4a9c043a239e49e3d595745b5be26657dc5339b0071ef719984bee5fe80979c04c373981c2ea80086d0d5ec77f8c6a00a06cfc177582aa435ad1e019637cd06ff5ecdd19805abec100a577091185d9fe0ca51e354cdca922af45f050cb8df985e20e89146f55a161056c4c16d088dc35f06f992f626fe32fd9b3626879b9f8540cf1fb705fadd0339b12411d24f7ca897f7f481cf0c19f38e32868f61743fea76b61f7ba17c77f6fabef026688677496e81e908faee0788fcc5b44a04fc329e2041b53af9e5b121b1b3a3e164312e44fec6008ad12c2a6da802ee853f02051bc4a6e46b15e0927c41fc53a2203d306962f168837bf0a44bc0c5f0746ca2e5e2b98f866609019d6c91af5716349fd026d2e3298915c36bf59e5a5a23c0d3da19230951177775d7feecf074f07088d9cf7be0d4bed51d6cc4904117771242d2c55f2891f28fa054ab5292ab1d9a24ed2b60b2f96c9d07a4248235b7fee8dbdcaa507ee87b05051fa44b216ab7bccbb8a098d554a67bb1450298caefb3404f65489726253064e0424d6faa5338ed78f6ec97145ed035257fe0cc2f389148b326937a17952da36f41b33d3aa89607d8aae51e9ac31ac1b32b7bd8c78e5c925f886e2974d4895057cd0616a4c28426faa2ac7d01ae8e9f226b94bf253b035ff5d30a65a4986d91af8f60b696f945c5517daadd565c0b3a5b45b084848c5601c27086546c4a65949282c6e8c649fd0ebdedd12ddc3dac2fe15ad952dff272d08bb058c9181a11a1e2c45c2298a42f081926faf9a4acad2c0d38113568ef9a78858d9ed266c9eca6fbbf7dd04e5417ddb1aad1e2d875e509a4e9facc096366f65fcc37a366356458127d83863a24faa80e29343db0857c2014e59eb2fc1120b8cb4e09db332dc004bade517b2a575fe657ba564d6270e7c8dcda27d178c1c18395efac9255c37b122c3fdce9caee38c96c7bb6e57c2d70db3b1b353e144487deefdbc214f2e89032e30a96f410fe1dd22943d5e3c388158dd0deb57d0e29d350e53ab256b701ebbd838e37a97c51483a5d20a2204f037c0988208e1f8676780089da7ed0aa082f88d8871688f6292be3d2288dc178bc95058f94fc0fab84275e406c6be0ac0b62b7d2ae45ce461244f1f15aa16c20a0245d4b7ea442b1743930ccead6876d95eafb5440d5b56156a6888a91a0c59c7c2dcba734c2628c4d598e6479c013565e348ab79e33f816a0d551b1bd015aec35307382cf041e4a8350741f01a0345f88f554e5aa2daed7eaecbfed2fd319d8355e4a7e7155c15cd0aba187d79a8184a4f32ce9c81cad7c91d926859518903904e5fd5a4cbc7de8ea2d5f3c8cf0b7cf41cf92f18b4ed1e24e7d3261f14af7c2381b394e375a14f51ebef1c7b891121a6ffcc56d844add98ee6159691bf1816d1c45374e431a5be533c5df340fa0d95353bffc7094497ef1acb843b82aa2a6af5ca5839e3e8d877ece3289deab088fa3b6d26ed8d22d0674b45471762ebe3eb48e1071f1852ce09a84944e48987e0dabc8fac4febcfffa4a252da1e9c325cd47a53e2d21bf48ae8528a07b0a0921443e5acb83add1841675c2e6194d2885423a4a619b1270d5f00bf9159831592944fb256212982f8d4e8aac3a760e81955b0557be904f8af03ab1f3948e66ae88044244451c889b9271ea944d9c489063d57462c5b901174dff0aa29f4fb5dcf4cd5ed908c320ffea6bd88d31d5a2f1aeea17fce98936f10b7c21108d0be7a769afb7142b32525014ec2c504aa01bc44c185f29a73f29a04d86d99919099c7e757d210bb8b8c895c351b09c74b420a4a629b9f4917bdbc1b429a74094e65b4e61fd614a1e4f9a0bca3068c196d9173c96569c2e73035b9c2176f681d4a92c1c16cbc33104acc05436c3008fa641208c008fd61b1ba5c29d3b7954ee599f631978d30d6c74721e43460390844b0d50710c1de26a12a09072096be9f0e208fcd021db857aeb0b0f2b9c7b2ddd05b139076bda48248ed58822404e40e272c1ce2e5d18bb8e9b92870f911260c1928ef1796333f06e7c40cac95dfffd17ac00192cdc951befc597db677a1fdc36082c566c01133835863baa23f2990a71a4b997e2d144ee93b0a91875a59392d3c54b0e87b17b5de427b2d93464f3c283a65aa4a25952b9fc553b12ccd8e9172eb70e690f3fa222de3d28739dba43c3e79253b66887ac4f9f4a09aae9b62c7f309079c2b60ba11fb4c116461a0596b945cc7282d00caf7322efce75f9e757da271b9a5dd40a083bd185df84e635589690a595e5fd4772cd8fa313958aea8a28fdd0c2cd69a30d1876a01302735f2263ae5b905805fcc138afebe58c1542060aab4f8d3fad345d6c5b24ac37dbbf111101ec0814c3e56da82ac1561fd41ddc52f84443004bdf61c5ec21596ed059be17cfdf30b030cf31076558b91dcc6183e01e4eb299419df8745a03dc3468cd90dbfe2089f3d0759048710ecc987b94f2fa01b068f6004531902d3c4970abdcda0949a90c8deda60bc8de05f173924fb3f092f81e990825bd0c8e572972e1dc1874eb6889a1451afd3a4962b11a682b6a9f2f3abdff3e28e04e93eb90082c18ac882a8f08782b80d41284027bec42c9815f5793b32792ae6aeb2950b6f678820880322122cfcfb80d2004f0b10c364a8139e27dbe6a1c7ccc1e133468e92d70f372e0c2406c2448a8a79b7f03a58ea8911ec2445d4e48f049157f1f73760f1540e5ae1bb528df6e1b9c5722abce3037ab875b7016a6955f05fb08af0a02f493579b5662c9973115c8b8fef596d92a1ebda44957c35c4e5df1743f2f30e9fb81e67e6045cdc8776c3aec3c2f82399d96e853e1939004c684dd8840b6cba8120f40d7d87c8b4bdf597b730940652cd4ae2d9317a971c0fe8f007923c0d33f9e9b1613dea80236c6d3f8a0e2fa20478847c934d7b5d1cf8bf74001b368e6a5c33f22737e5f7f72c7664ed9783698b9d6b7efeab0bf226c74f0a71ac2c4b36452eef74426f1f013bae8e18ea99eb2a7d659aa1500cc8262050ee117d899952ddaf07a2a5481edc903b1e08193337c35fbfb1de16c9432cab419eb4439cd2d3a50b063dc0bccb370843b385d87e6f2da5c2428c996cc69344a89efd5eb61cb82083312d84076aa26078c3ed1fedf4b81689b023d4eac17a0f557192df61b6a53384cefc4c3397cdf2317dd6d9454dd6614c1e37c7567618e3835f55e7e3633b6feb348b8fe33c7dabd4968be894edee345e4f9522d4d18bfdedc77cbb5665d33f4905adf6be7d141662ce9286cb7da0daab97c76eb1e7fb9c84f06945188579d13a1e3194201d718bd890bf9599715309fef4e27e7179701de72ff442fb9a459b561c14be893d2c845f060870646d1587d3d2b08f0707b2908d8604cd925923a12d02993c9ce7e5f85839674ef2c986d6e654d3a762647f94c50f36da6765f4067e09874e8a877d823c308a44a04b0afe64dbe64bac3431e2f93192e2055a378e0bb80a4c001b21f7463cf5c95aad90e2228c8f908db455b40bd2d374cddf2f7a6599163dfbd5963fef1ded16002494e1ba3c9fed023897cde1519b0590413bbdb7660ca452ce9c13bf06a3a3008d9329714be932c5b84ac3c2601ec13ddc29aa0ef7c6f924cb40f84fc02f744ecdff09fdd86c119bbc678161dbe617c3fe4bd80e50ed6c36a463a20264f5a98537fc427a7c4c77c5402786d89473099ade2cee4388377f991b981b9041738c405e7ff58259d2c9a7123b403185aaa83eec41ab703a0d52b24d9cab539528a7267dd597c01d6e1146fd67473c5291f6e3de64306b15a258abe4137d8d44c013cd6888bb74ec5da31383c72dfbcdef3cbe36b655cbda74676f940bb9769f8b85656030813ceaa3489de2a8b8b5c7086549c566b55aec8d7d97055659c65abf2c8e0fc455695872702c8065c1236ed243eadf29a31d994b97bddae79a6f239f4f3145234d33e68768bd4606b09a31e7ea835e7451caeec77492201ceb6589bf13e0243eb8f3f8f4a90962ce5ce189c50f473e4545b91f9570e2ee1508991ad920b9a3b6db2322e5dd787a7325b67ab849ccf4aca3fa26a124f9dcea59c4649608e12e378c2e1981d449143bbc2c06ce1d4ce53deade73b4082df58cbe0a198a0aa39efe57956b2d1b9f66aa6ee4f04d2c590c7b4e4a3f1ac8f0505b1c994add644de618eb18ec5a5376e91a4c4bdf3a8e19187b66483fe63859d4637d304635db9597609a2437f28519ca49c1145c4986a99f55d8f1261d9495d48485c2c30c97e2a4652e6e0954c46660f6804e8f0471baeca2eec71e63e93000a1764c4a3c040b9f39c82294b801d56287a8f843b5cf4bfbc2b70fca2e7a00567ce9608e6767cfa782db60905d581f3ce447f77cd596ce2017d18114319e8358a425134e77afe9186286073d779322082f633f420bd866873d4fe9eb19d4215d1bf119b50e65b67aeabe49ed29dc05a2fed0890c042a42f561dcf4b893da44b3576221b0ef2aa911038068c3565ce303ce94c7111739c42ea431a2a529cd4df23d7ecfa69bf6fda218be80f05b26fd00d13bd12f2d4897e3df06431ceaa56335c68d02bf7de39c24b052f67c7240c126983d6c254f9ced702b7f02418e651e5012189557226a627ed16a899341ab2381529de574a16bf6aa1f5b167899b39310eaae45264dc0d77461f20f093bd455c182a1d70532f64990da3dc0b9e7683597981336e9006c930f5b615a08fc3543ec03205691c06ae086c8100c60e08a526e102105a48f7f69b7b2fd30731d128ed2225a3ae58e5bb638e8949580d3406a8f2a5aea5910c32514cad377c593c69be8314eafdd311cf6a0f525f12cf41ecc94ec3e70db21c5bf23a4f817caf08edbebcc6c6c16b5015040fb39cddfa5847683e3f723d680922e7b1f024c4580edcc4f89a75bfd4d0c11e08d9a0953b519bebf16688dcb29ac1561e6cc1507247e7acaa1c9d91be395b269f03b906839cec1945977a834482b26c3705fafe3498d8a50f1055027f60c89b5b3649c5dd074faa4d6dd197a6564b6055b72f3c842d28b881e1fc76ac3b6c11e9e51ba04592ffca86b3eef2ec0bd23bfa1307bd5e844c45ede73a65fb87db96a0ae05ef363eb5d661ce9d027bc5e89457a66bd457250e9492e4e86fb89d0f137de0556179c203a24ec0e19f1156a578829744350c87a582cea4cd2c0e778ff44bce112cd17c49edb7381804427371f0d2492d69aa39a1ed431fd41addad86fd70ecf6b7c2f20744bbc2f9896620883bec68494b8b6eede4e8cd338b31fa907949e8d5d02205b7860800ac3c5904bbccfba9d19ce7eed9ff64abbfe17285350eb7fbba4dc67555c41ccdb5dc9941eec72e78108996212225186283350e15798f4b06651461520c7123c86853fa229b448d16808820d972d0362240b8e9b23a36bb1422f1d024670b40f2e526b472d958b943452053ce94346cb79a5dc368666f669d5becad046e516ff20ee1599939840fe6beab9db66d5a3bf3318f3d363cbb6a70ab7ed5ac232330f0cf992cd75ddd82991540e4d01634f70853192f90ece149425a863adecc4c683253ee7693310c5f12111f0b7f164f0be013f172ff1f87811f15cce4d4317098f99abf5c5a228c56ecd6fa580a50b857ebf7fc28d2cf6d77457597f1480014457d484e270cee270572d7e69f939f94dc7fcc87e19c777d08800ce611f7d840ccdcc0594877179e368e90425783cb91c950eb31a5deaa245f663c59e0dd77dc0b3cd763920f66d6c5cf332a25cdbd41d87b150f1d12686c5100129f0d0ccf3649d9a81064c2ad714bd56865b8b3490b46aa6e116d08de3d2059d07c5071e7bc0f2eac3dbf9ca595a8030304ccb64ac907733a5e7899e8f090443af9af1db5bb241d2b39010727b06799cbfc17999ca786acc443eb331e983fb1528ad7b1389834374973be1015cc08199e3f68c8fd9bb00f767fede5cabd9883babce5c4e7f571b597cbf0fdd33fc6a2ba542c6dcb3b66a62c2c6fd08af88601cab16217314f348976228a1e014255ea46c9e85dacf9e3376322315524d8bf65c706b34b975dd723dedc7f331f5610e0190d34f3777961f3d89ff2e46f8a4ae545bc059e8659daf1fc5c18108c60153e832a19c3ff96fc212d95fb68ac759154fcb43610a5eafb51da4776ab83fc0710db5b0212b90d61f5881864e9f24a68298c4eae2aa9f69b18300380070210aebbccaf89b73f61e0cb3d397a895c1773d7941680790bd1239d6e4151bc0c5b97100031b817b3f3930ef444cde816208eef6276e5c5eb3dbe779f534e0e04f5e1f422af9a9258876e952a9fac954c20185c3f4bbe396d195b18915080254509e680fd59d94320a99b941a6251c1fe8c22ad9cd293c3e72e8333e24b8217af7da1100cab8c0acf22328c3fa57292c43bfcef2b29f2a62ec4ad3e913d51c4e62f3eb9dc518c8b2af7b8787a2a8106d18a736a1192cb268e984d4c511f79ae2d187f886205f1e72a3f6bdedb7c7f41e5eccdb40495838777aa465034d1435164713b38f36644ef23ab828d6bbe9da6c8e46f70b07a1c17fb2d61de2efdde9e43a72ec7eca7f224f529c7755433f04c9a06f5a8aa699bc45addc4dd71926958d590eacdd950306e0f6f6503901ea31b3de1b0bd7e2c853b52c1afce2250590f32b3da70bcd162d2bdad0f0d8e46ce150feb300ac9f8d2b7d2d60d0fa3e5686a8cab9ba8e8502328df1ecaed17f1d2f50af5b29425d50e17919fd552f53cdb9d2abf068c43575c6c1e12a158160596cb7fa1b2627fc95fe9a323e320dab5306ae4d035e01cae3b4ddb9a217c59d479066e8f5791f084e17798753f498bca161f48bb937cbe2443366424360b6e928ecbe99b8657ad86af7533adbd5713f682088e072de72327ae650c2cd6efac5871d61057e89174b381de9168faff3e59b4bd4a61a7874b33a091f68d12bb24fd17ec840a867f6a8b7e96244446b44fed1030621b4c38ec4fd05ba35720f797f37227b6de1e7b60528409c16e98bf945f64745a301a363e94416c34a2e710e6efff7c7cd67541c7bcc36adf699de0198bd9121e3a366cf410d8890d4859013712f4096d2b4fbf44bef516771befa0bcd1811dd2f3f751ece82be2dc8edb3d70852cc61c77c269daa1970c949bd85872b2d8bbcdf61e70a74ff450c6accb50e17c2cab8bcdba8e03cf207a69f11df6b4bf34d2156d8b521e6229f0cd73737aaa97eecfc1d98a9cdf91b7cdfed8bb3264d2e47853d3834b278b20b8809b10002d3620b835a4453024d4fdd6bd1b3d1b34f694f6bf120e699460e96409d75332057646e51daddba53b8a4a3facc4f705470774815bd2fb95d86e290c59904d36d0cef24c3ebe4acfc57a4a6fce3347ff9b49fa7a69db3beddcbdd6ce3ae3afaf3bb01f271dd3d5ac859717f0e5988468aecdfbb11f3a106452661400d659d4cf33e9fc89110e353c4b7ed30dea4465b02b7c2ac819f182ab3f19cc49802c384358f68580c8f76d2159684957f4f180d82e1c89ff43b046f6cb860937c8fc7be58cbd62feae57522ce6d94351617bfa5da6aa0327678bf81e7bd9896f14f1b9bdcab41776a94b4ba32087b5293fd26f06daabf2e9ea3d6e7a33ffff255b974ca955b1ab10d9be90b6816f18f8c92e747e7b3fa22641b23dd437ae9a3c7c995391eafd3cb1e5794f6386d94e94011653bb6c298638c7eeccc8b95c538d7a8f6319d592c06272cd6d121a44e5b21a7678b10e6955d2f5746d74f8a60b0d494f76ebee87bff88febd74c801cc06ba3b88be316cc0a7f2e88c322ca6ca3bb49520cb4f94fef7a41f346ec7f83ee375300a01ba81ef6f8da14f06d9ff4f8c4a143a16d727d4c0219d3c7692901963caea4f9ddf39a208b5bff660507f366a3963eb97f5e3138cbe017350e59e58f936548204a8afaacb8843459263f34162a260d722ea833283651309a6720c233c88ba333122cf449dc50a45a20181504701070511393c7195be9be487ac0fb3f384b09f2e490f9677277c55264742d509551b39130c7f661bc1dfe211660dc6cb3347c125c4c73d244af5747ffa761ca50241b8816b2c3f589a93bf2139f0b4ecf8f5e5fff1ff00d8c639db58a507beab1ca3351af3a16a20ea3352b1682535decba9a19e3a26f4b76084b51505c365d45722dff850de8083217aafc1cb578cec3624eba28f881841a506969bc7d07113719efd91bccda70716ec9e98ef01401d2a37c5978eb4c38898922b9f9dfe597084f2f53951afd0c5ca1a9233150e5abb17dafc4f83b68f82f3838464661f6603c16e1f1386452f92e0ffddc19a31aae1ffc6502a00af83a722fd40da46f9461e048604b20ea8b5443e8618ca2304d010bd1f02a12806917ffa9c07c3150542525b63a9564afa37636019c021ec6de2966645dd6250e6ff803958ece0ff7d39bd6841b5eca6e69bb1ec22c753d7f43f00a3726441a21d9597cd9220a972992ab2851e732bd99fa375259d1261d76254b471a7d17b9a449044e39943848d8c153ecfa476f1d59d362eaf30cc3bd5e988f26a2a345274e55123e2f596f4648a129f78ce14bf68d411fc981cc983a89d418cc98fe777a91fb50f2d9be48de5eb7095981070f6b891180a363d61abefdef8812cf89009631a8b452bf07806353993a478ee078ab879a40b8abc652bdbcb2ff267121f946d24298e94a09d17925fe10879a2bc7e16ae62748c069722a0aac10854370f24fbaeb551e7c10829c96dffefacafa2a62846a663eb8faa5ff021aba4ed44e1fa4608cb77ad705625f2edcf335dd8c56b8cfaa10349404480ed1079e6c7030f958162a51877bac2bd8bbe7d09d9dcd27870ea8e6972fccc15d24aef238d04dc059fabafba265c5964fc83040188cf369809d1566ee96844911ceba812f6632d3a281253f988ec0505d58d537694efa8ab382d724d84d3799e3904fe81856e84f4288eb7a073f13f4d53afaa68a3005dfa4af55139adaec4729e563d8b6dbdbc105f099ae744c357961af17c0db3110b92419db1446e680ff6e43617e8e00f96aa845a8f9b72befdd67bb2646962f259b167cbe8c07f16022a662c5aba965fbd614b2810aed808e300cb8bc01a8a5797b9871f2fa7a0606db9016e12d538724881bb0ccd0ff3e10aaf741e9bfd18920612ba8ac4e0061a2cfe0787b6f4068059cef5d8cb55833b1a84571509ad2db7856348e8f8313324ae21e5aeff9dd49a3a968f468dc9538767be9aa4b1863548a95ada2579a73846a1e7303c231076e260447b8ddb1033b4c1545ea89dc3b7c858446168db07f5e2c0b88eb7186e3882aac607d562358328b50b3d64b2e12bbe9fbe7a381a307ecea3db8dc6b1d8e458e27b553dea31b1d3c60c1d649db94d38e1c87f1480ae5a9b0b7680d461f97a5a79baaa040de33dbbe5c23405f33715a18e1ce72b08b7d293542cefd5a38e45cb13343a98cdc5e76c1c3070445b828677744d4a08fbb160e0bcf76cfcea02dbb7345d3f92df42bfc61f55807bc006a307ca878a8c7c26c8f4df28379e2b1da71930dd24ab8eae5a762546397250f8bfb222a971fe17fb117cd425e78a3426d89b827bc16ae9b0caf4b6ecc03bb9e17a6df10ce275e59fe315d2c352a7886cb638d2ee6be479f2e6f20afc0199ceb8291e277d29aa9a13860cc84be8bd5aadc62417e7050d5bf9ed84fca73f7c2392481779c497d1227348648940a6754ff0969a679cf884c821a30182510f389a1359625f4fbc1b4ea876f90ffeff23fded7c2e20f88b3e52d906013da72aca0e61bd532224c3a65550c2434ed501bf26de889784b52e232ee716ef565782fb7e9f2008207fc0d4d90501345805215830855782ad185d27698fb02694ecde8c18dadf6c3439c101195de81ff633668cf91d764eb9fc7af00dd284fb94e3b1be92fc96d7ec41110362ddfc88f5560d2f91940919285cbf4372146e1567e5adc493d64a076cc92f2366ec4633a4350fa76ff7bbee20bb2d333cb8813807a5ccb76f1a6acc20aea104e651d403162f448017edf9b8348ec412522ecaf9400ac16d840790a5411cfdb977f871161d27e4243000cee87614e076040bb0422301ecdcf24eb9eaa5ab043af63469c5e1a76603ea9623ffee0df86ad5daf9776435798bb94aad2a89f0a1d431a2262691790fcc717fc8c3930adc820ed65f7d30f77c30f098d3b68fb2bdedfc0bb4d79bf611bfba7a4c9698b303088d5fe58dc54afd5a914964e974ba9514f9cfccf2e54de0c05fb4bf890e55bb34c1932995d923e2845e04381f3fe65ef5ae6b8764ede8a923f3ae4328c37256c2168876330669c626e10135864d237c3cb317e4273901cd4c8b8a765fc7b4c46b7e522d4a7cdec9194a21e3a7473e8f84dfe228b4490b9cb725ded47e985c4b80fd6d299f3d0832efca7308a14e682e46c0ac9acf6073d516968814522e1dbcb3685c50e5aa69153ad1d88763d6128ad44de019714c90fbd246ac8e8ed2336eb13d3ba61cc5de202dac63684bce669b073a7395085bca61cd7c2d881ea933136efbee219ee2ca20d5ced503b3e0961cde624313e23f5644c16fd582ddf7e3b169db5b97274f3b59ae2ecbca190f8c7d90540058079c859237d5c4a2f139c24e4886598fa9cf4cb9f6df3194ed6467718ca346bccd2783679ac79e110351ee04b429a5c07d06251f1f9be41311b51d39d8b532fafae0790c5a5ac6011aed06ed3c68cc598f0ef439b34e9c84d45c923d269f22816289554d350c0a0c9f6e38a0a0eb8492981b0b3f08c311eb2f395ad1f419f8837ba97eb1d664e2f0f8f6c1487a2d998ecfe6cdb25a1e2b7496177ccd8c706f65e5140bd3c9ee32557ba7ca3819f2b1b28dadad6e2a634858667338db045ec66144c6487199fad901c2ac8b1f10cfcd292f6314ec7ce98192b44233e16cc14818ba0cbfb70f6fb4b2293a0c57d69db494609e4b3cc26d3599055250d7db2c366a058a3912786df6f4ebd5f66a9a0be1c6888ee03b219dd41510041269a23289136ba819b19445295f5af7f85a4b9879d5587517b16caf66dc622d52295527801670d91e29cf77384b170e96f44ca70dcc0a49441372495f4099b0036b77d553ac0a4df8bb3125cae57e95c131d4d07c746f0ec0c7a744d881ec94f3d0453ea1a0557235234efb605785656c2e584dc4d4ac2188974b363a33271330140de601a97c9ee923928335777d5d6fe45cce10cdc6eccb3babfbbd17d2ae4d1dae227420a31d1d0743af5f7e8cfea6cdb4596e80df564ecc94eb8d7d7d01d1cd178b97adb97d35ecb2ff6a314a2dcce94740fab1bfcd1cba38573420e30231068251b29738dde480dd8745c08130b3863957788f74a46e9dac12d5bcc1513c8d48ea38888e7c73bdc7abab03d786a0a2d16608fa3d617c665989645a2c54cb8157d8def0c14709fbb06cfe41867746572dfd299b3f2500a825bdc519cac44f8992630deaabf8cf31367c8c8428c1cd935fc2b64f8c021fdd41f730a3b3f2b39976e99e4edffa1124c267bbabf5540b4c116adbf290e10f29d6304368a8fd1cb4c1953982a374b12a23f072cd843a01e6bd4b8609207cdb5c381b9230298d017ddfec228a310bd23b9d0fc37f0aa07b57b9f245d9008741eed2caaf711dc444e8b1999de4b136cc862dedeeb63082ae27a32fc27e55b447000300565f188fd9475789dbb906c1a7abe63b12b593388330016900d8caa5ea84d3724095f0de600ffeee1482a6b0558be5798ae260ec2af075eb07a7ebd7abcb31bc8ec4246bcebba0c6343e5e7fedf02e7f9f5ca2bd2eea855e9fbd3d7a532faaca01970224731d9b57caae0e3b3a8d12e16e8b179061791a3cc69bae0c42740afb4049d814044281667c018b31e67936027ae44778c6c7d7b37099f26564b24d431a0cdb2bee3f0c710ddef073cca22568448180df0ea75a9ad252a55514186b99493fa2e17f50788462afa18a8906dc301b8f04c2cc71e230b005fa7e89c5d43a3247086c4598824b3035845943bdbecade8737e63302286355d8513a515941496a32858f7df232260720486d622354c3d9433a407c9e1ae52d116721d0f6c7980b186496b0dcef0c559563f4c981cf157ccccd965648c850468c8d12d6704ce11dfac36d8592002ed3ad68a9aa1eefa0130f5784edb28ad93553e32417e171c42d50714c89d20aee0759c2c7ce483fc3d002de3cba8250e1107c364f0bd94f8458d22ec04e4f144b3601a10bef98518abd98b5399f5237140dc93792f4e5fdd2942cca545e8d516856a6fdb618e418d35b00e8048207438b5ea8905bbc0ce483e622f9edc1db9d9dae936ffb0364ac6c399ad6862bbe9a519d54967f0b4886b889dbc5a82929ef3862f5b824df31e0328a219bf806d7fb9337d4a6bc0c886539667d4ae38ffaebcfe540a773d702fde8e228f5a50a6a4e925a44e958f4bde14f25b5063be0bb36f6125401da006c67062a8134b70063047bfad1e366d5ce8e32f9ba462df156c58699c80101731d86bd8763ef5642de9faa7fcf7dec41c13fd0824ebc8c770125eb65fca93ebeb04dd7688951430d324627a2dc3edeff189a96c38c1b92805c00969d9888ade9034f183379044197258d4de257393ce9541a0986892ae45185f98b68954c8542e202ca9eb3279762c5ac00e6e7883d7a29191ac33be0de26840fb23e97686cba62fc312b4cbd16ec0547038c09debd33148a1d3c6fb8741535734a160ca715e4cd555ec39101ee7aaff4bd23a29da06fa8918f8ebee42a486c0422391480697d7092d3fb2c66ac9daa2b6e035164bbf29e407f815619e59e39a872e873f170434943c8046ac0e4bf30fbd3b14270ef2a0638599918a92e93d31fb1802e4b334a78c44067f00028a453863959c000ba091704ab7bd07fa7b1e0a0e84020902e8244fe560e2999c7a7920146972a9822c8d4cecc723e7445961b95be49e2b3cf7d0fa6b0875c3b6c8d57b9c156d65657cc9018d9c9ec286aba18ce26b4fd9f5a2cccc25e6bbf53a2b955f59fba3f7905ecd773a5bfbeced8dfc2a4ad93aa970574a412298568dc20fdfbda2ad9f5f2753d4f8988c2c96e1eeaccba564a8778e8ea4383e92b6682559adf0fe794e56900180e71add691c9202b7e6a7682b136e2af47096de09b4bc1f13ba46b502856f0709967e4c9c62ad88fe23aba10e6487a9f1f96749afa0c1f0a062a90cab54b095fd3b1d16583ee147419dc07d5534e5afdd33940a82a766ab14a2c025b73b60a44628c2d50822f82fe7556e7b2da8c248339db895c94378c0d96edafaa947e671ff9dcc2e8de25a572194ed52867c87975feae97e2fc661961487a0ec690dc0dcbe99a913ed6528a42e5717daa4f13b9611a1f1fdfcb822a5bb48e762ac7514934d95a3502c2a0874f9fd591266989b4d69e25ad8b852c8676d558200f49ed1b5cfba1cf9c31cb6db723e2e710d676a1a2c59be3a20a52ffb223199bb6764d60f1636f61fe02e7f2a43f0dff6fc5943172d37a8dc23bb5b7e93f50dbcb7509775086bf0284ac82f3911461d95de7e714e42b11dff3f6e4a28861360bc4d87d66163945de8c24a8e216568e3de8ca52c238a38b73a70442d9d8aad6887088f1598c10193e9c82cd59c3b5d019c661a5f02f17af6bf9400f256b63a75938309c130d19529a0710bb8669ca97ca7bb37d7bcfb58da7d5132f357650dc080e1b3eeed302aa31ad3ad52e5de796314ccba0cc3bf64b0d2fd9d7c618a4649b5da32dc6475f104f7a3e29fca4a2b826000ddecea892dce7c0a622853685da24ceb02bf168d49b428bf04564f48140b663cc4811889f6cd1fadd168402893f0fe6ef19d284246f207a5531f853c52b15b586033cf7d1cf8b887e6515589a474ae1f586531c171c9dabc621b3982a0193f5447bf1aa4c37b6f9f8fc95a0ea398404a5a46eec60f41017a66169200592d8ccc09ee7e0d20f5a75ce512c82fa6b8f8744085b7e1460c106786558479b7feca42c15e9c3a3abfcfd09d3d9b4ae2ac0f7f4cc79fe92264fdb1f0aab30e36543240e3667f26458e040868b1c6d39e6b94165ef54be9e94d8363e1f568ccda2470a71782ef5e0a8339b09ddbb11f3638d6abee0a141f9f3b9037aa9c091d92786e03aaffbd06c942e2b821fbd66c5633a4fe12dca109dd0cb41493623a306524201669499987b4f60fc9048be134303c72c50d9232a34d74ac405465d80c284da6edc0a28e2f1d9f411409d3f6c59c737b95129f4919d0d162da9cebf4815b43d0cb00809b43b7f8840c386f49da831741541a96bc88aac92064651e0657b6f522ea69c05e4d79018789fb41556515eec0652ed08936a51ced6b3d41e009e85f48b4c52d91467e9134845c95e8cad5c21e58dd35c106a573fb8a66e5bb8cf7a87642848bdbc9c6eb5ac03016ce456946dc4d478fe41730ba63608d00237b9a19cb0b938c9d368d80fd76b1dbe26e2dadb9e03e3c9ccfc7b447f16ed7d128ff3eecdc61c6805046176f193e86a5d673ab32f8f0df63ec4869d20400d42f10776eb7d23200578cb9fed14749c0a369c8cad33bbbcca68e88b17085efd69e2e551c5770aa3ca79c64a407028d11c929dcfe92a381c9b3da5125049b345e28c639858e594eba9a9068c73c1d592b3ecb1b5be8ca798966000363afc1832a9f1fc8ae7493ef7ce2093b6c488195f5840d6db72b75836764f721e4f05658b2c37d287b03458e4f819fe453468a690eb089c084039dce0a283d8e7f87cbc9b9764095f567023371f2bb4aaf931bc1e8fb40f3cd7da33756baba8a0b32840c212e7c8622eb2e1632db7f1c10c8f4f5831b91cf21ff5e24555cd764132c41ddb917e663a965a150bd9f6db24ee50bd3dfe19b77551462a49b1dbfcc745c79a96aa164a15e566d09bc640644ca5f5b666c069898c752f963b3d0d2ab3cd7ea15529bdae91a99497bcaf51f0367f9a1ad0328617540626ad1b25abd05c6bf8e7fd9ef907f6d7081d5c03cf4ce01fa54714a5c300acae21cb5fab6d470842210446877f33379a5ea36959aeeb543b0ec22af8907b4b84dada6bbcde19c780e8fc7f978b9fef1fafe3d8ccb455196124bda32c4384876a91b801c27663faebdd18559ccd077146788b426bbb79449cac00485049504ba3fc7c03f61bf96674e1c2c2d5b2c0cc1ed9fd553a03c5e2ffaeac7e50857bc599cee2277fd700ef7829a4f4dfda282fc7594527fcc7f1db918c19b376e3abffdd91ca10d0cbc79f306d835ff09d0ba7642a7891d9d3673b10f5d04279db82197df9edbeac4c1606305c22ed6c65ac638cd892b1af9af23c7268db102b98b9d3fa73d0ee4353a917e44c0f41186e02295397111f4e7996356e789dc4315df8fc11aa205ac2f5851583f2c1c9c60f5b21358297c12ac20f90d168f5f73d5e673b84a7325068bb9ba7295c31bb95a72d57455420e73a5a388d51265acd8580961d58395965762a5835513ddc4aa1784d5112b206dac72790355486022aaaab012555c5e4c1515cca66a498ea18aa77954a110a44a47f504951a2a292a2a49a872f82e5430642daa22180c15092fe50c1251ce98693af3c3992c2150213342504a851e553a42d8c1e6278449131b844842871825d29ca0a4052d1f1227c4d0f04493134cc6683122cc9db172a649cffd6639e31353729cf912396ee312e34c1c1c6ee2701377d25596dc5592247f912fdc4951bcdfe22871c6c27805b30313b43de4e99013f36f7f3831feacc3accff145527113e74c75ca71a7f8acc3ed7a99214e8e8a90f368f453ec0314b4be905ef12c4abde2f44a3e80cbe48b47c25d4ecc31d227e15ab9be128c9b36232b63b4339994a81e2e1b07a07c6068686868e88156c64246f862188662188645341a8d462b92b15881d33ce71c2e4990f38cd2ec8004e6046d9f518e52685c3dc10435946a28856186916164181946869195f2032d6610e47c63dc1837c68d71635c08eeac95edd3466981051760ae2f80758199d912cc983163c60c0988861e48693f4179a306054214940510c0004e1b268d6ba30218d5892d2833b880004357e8c4074861541a63a06fe81bfa86bea16f680cf4d0032d46fe1a94380161187270efd53ceb129779288ae22af630ebef79bd7a4d40a95dec08790eca0e4c1a0a28ef0270119094139b39e71ee61c66b283721cb98befa591d5293d2db79a8fab2bebd2a591930c28f7ea1a7907e3c85d9819e85c8ec81cf9d0c89e79a63df0e0010f2021a0b58640be108041460341ac138275fa07ec4b9816f93034720497b3688c52eab085381bdb52e79cf38bf768e9e972efbd65ce39678d53f29496c3b5847dd1fc08ada3c2605cce1d24b0aa962be1529a8e8a20145c05ac8a5d4b3d2474e2b01c56354669c728fa4a8d518480c6282912a523f8ee24fa220e8387171f60f47582df871442314c081c0214c77297fb6b2e68341870bb42175caf1749963794265054e18823a6be8c19336607060c183060c0e4f43c5bce7da424a4bab447ca231d21654a77a422a43ad21cfa06ed00fa04ea0675026d026d83065126d0255025d0245024d023500ea05ba8116811281b740daa064d836aa159281a140bbd7ae289d235860913e697b30ed3f36c391f01ad42a9d033e8144a046a061d022d830a819241c7a052a8183408340c0a060502fd82fe8002512fa80f6817940bda03ba01740b1a856a41b3a03ca058d02ba815b40afa43a97cf952bab01ec5a43d848ca4e7d972ee44872952a24081cae1090e4e9adc6083af061a982c99410625bda724680ca8130a03fa02ea02ca4391a02da02ca02ba02aa029a047f08bbca8bdec599ee7c99e2dd4092407dfd062d6e2027b851f9f6c53397fb1020a54fde313b497f8662ff28a62868c3486d3d63b817e80f04fcfb6bf8663ac50da3b6c424a633893cabce6ec3e89fd253fcbf564384311ff0fb3ff3b77562c8a5cebd70feae987cbf82b0525fca9ed67fa24ddcfd495e9779f343a69cde2c2232fd7cfcac2a4c16324147510cbc4043622d168619358ab9934425e336b689ff57bba6fff81fc4ce6bb22865a75b5bb4b8489a82bce6bd961ebd30f4ee239de12e24ae50ac4e24599fa3861f8ac4c3abed4c362f6734f419cc748906b5cf23695edc1da930725c5286398349e548c657c9957ddf7faa4aa780a5b9dcf04001c4199fa88a07ca6ad431979cdbf3ce302942a0324b21ff52d0c672f53a71373b3c6ab8798b3b072faf0ae06ca00c0920c094a32af629a673e9fc4d23043f6734948416bb8c324054368788d7a8276567c89f2dac249cde79365c9dab4b95627e380ec081912b224644ac8969031210bcad8c88a901921db9269c9d2c8d4c8d6c8b2645bb227646ffa73591bd9962c28cb9a9204d5eea0887649433f5905655e67dd2989c742b15b58202bc55661adb057582c2c0f6c16560b1bc5eac0eec052617f2c14360a2b859dc242b13fb60beba53f67b7b03f368a855a82d463a77ab22924d98eb5a02482b4fb76a7ead4232a4feda942d413d4212a111505b5886a446d524b504d5083a83b9504d587fa4305a2ead49dca828aa43f578fa83bb549d5adf0a249f535b1be17eb94aaeb2f0b5a5f2acffead7ed6cffaadf593f85fc64c2f706e8b6bbee6ba85d926956db65e9e7dcd06f5eddf9a4d8a6af37575fd203deeecb94dcaadfd8e6b83fa20f796f2e76f4209407ef82041d7c3d67b1ef7668ec0b443041df7b6c361bc67eb7522453e003e3cdc254aa238680e8a023d511d34455114d5eabfd51f0df6e73d8d9e41a9d02ad40abd42b15034fd799ad59f677408d40c3aa2b0151d8392418540cb5ca2e7b8a7e8a98322a71c3939729c1145d9a046f4e7a8d67df9aca88abe5814632047589753734740befe214a000cf6fa04c4b54e549ebd0ed447e9fc8c549f1c4620e8ec1b655ed90e5b9f82d49ea002c0d6a71fdeb39abd6c3699bc3c7b7e644ee0ea4f41ecfff2ccc6c4c4c579f0252622c671f481e9d3f1e1cca6fedc00655ef90a332ac3d5d569668da0ae69b4a222171a6c50e6d5a7c3d627d5a7474d008d56a40092462b2a2a32693c1394d7bd0b9d2d0c68006c7d02e23d188881d6d772df0b8ca77d87ebf54997a6e04139931c69cffcbddc9b8e0ff77676b93714dfc36fe0b7dc5b19756fa6967bcbf23cdc1b0fffe77fe5addcdb0e7ffe55ee0d766f1b8c0fc77d1001f0e1cf49752bd8472d7ca63f2fa9fa73b2aa3fc7b1eacf73aefa731468fa739dac1f8718cd8c445ca271aaff3a8e81ad23999d7514622c73897450a8fc54790e8ecacd9254d971ca6764331ad19f8f5a978f3e63d6287589c4ee5a335871e1af635e84c18f990b5f6b38e55beceb1f8e0e28f3eaf2a0ccebeee1aa1f10ee59bbcfcd93c958e8508b5c6b31f409772b56080909c572cfa4c289fb1c8def093971ff03fe0f4b148ed0f7bd0c6c0c20457952c06ad86a1ff4d87ee84fa0053444980032e1bb593db9345593aa497da46a52355a67aa75a63e4ed79354eb4cd3a4a9d629e3595c0e9daf0eff5e2e8a5c461e4d1a9787857b7319a99e264abacf0583e4ab7472722a9d9c9c9c78bc2099957574a43f3f6acacabb0c15249d78b5325892bcdccbb3f7417d3be517c5253765217908506a476e6dd95ce8cf6dbc2d1e8f942a23e5c4e3f178e4cf4dce65a660704fe1f57c506e82bc20d973e3e305836e829b97773cb2e773c30b067bc8cb44f28e9777afa053cf47b2cf2b5d4ebcd00d1924cb201974ea2de1e51d2f0f114337c1cf227fcd67059d48f679aed14dd08947feee89fcce89c773e2edf26c055e6f496ee2f1782fb28593249faf856ab7b4c056aaadd25a69afb4585a1eda2cad9636aad5a1dda1a5d2fe5a286d94564a3ba5856a7f6d97d64b7fde6e697f6d540b350509aa9d82229a429a3921f178315dec488c17ebc584c44e880d891189a1102b1233126b8a951033211624b68b9110f311fb110312d3c57631166248faf3d891d82ed614d32d79d18bf97aadef856c2aa67b110c3a79e29352b5d42d35a89e51a9d42ad54abd52b154346a963a846a4625429d52c7a8645421d432aa943aa5b2518de8cf552d754acd52a58e8272b1dc91940564ee655f7692a1f2af5c3396bc3bca505f13f194afb97ef716669b8f2d98675f53d27dfb35a51f99a794abe1ce947edcdac37095745fabe1de521aee0dc6e4de747e8697e195dc9b89f314ccb60f26b9b79c189c6078c1857b7bf1ee8d0c069d3cf1a5bd144a30fda551419cd486fedc4c6fe8cfcfb4497f8e2275d29fefa438f4e73ae993fe1c96e69042a54c521a2e510da9924b24433a43ba4407b68302c73c535faa434aa53f4fa194a92f852ad9b46704041aa5bd0b0840ee34ede872d3ce8e46dbe1a5bc1d1d06e40d3298b56594779988114e6e2797550092565454e422186a172e888208d080dc4017b908725054e422f84e3d9e4e9760070c20b3918c847c6524b9857bd3b9ed6415720af9488e917b2b726f2950b8379e3c249f9085dc1b999d7292fddb517d43c9d936f4e738fb86fedcdc4dfaf3733be9cf516c1cfaf39dfda43fd7d939f4e7b00db5996c1a760ddbb7956c19f60c7b096c4707c59983636edfd66153e9cf3794eddb50bbe702082c5d98b9dd6b80033cf059ef92cf2bd1686dcb799a02d3a71397779708986d792be3e7a5bbfe411dea6090e7c40be61def6bb8c7b9e96b3818b331809e14e54951638f62a8b4036109924c7de4d206e33cf8520fbf9c821d946b1faef2a09ff1258aaed0ace1ea38d4fac545b386eee438ee143c2f927d2671eff52928af453d2bf9b33231c15c7e701451138e3a6a32dad29f1b45e9a61563f9f6f14fc783a63d6dfff9acfe5c0d62d1f7fac4396c7d6202e22ab8e6ec33fd0fe67789731eb42515bc87c500886f5e7b65c002c170778df00b5c8842c75c85918e794f28a407f530545e57e8f5b17cfb40a9a9355b413751197f8eb4ff954b94b38ee712912a686c9e57155d27cd3a8c2df7fae4c3f5fa44faac4c4c22f0ed87ebcf04af8e39e6ae8e1d70c4bb5336de357a0da5638eabfdd09fd780f7a6b93ee2f5c88066b3d4d499404cdd0236906a818758172b68464647b8cf1d9579d5f9599fe773d273328392f98e51e773cc6bda75fcbaae5f850827e658cf3f6bed622fdf34c2ae9f7f5b84de1d27f7efe29b3fd72fac47bef7c8f7aaf138ae6188b5e6a3d6235e431de2fcff1f6a1dea8c3f06320c726a303dc7778efba9f1de69c769cee572b9a6a5cff9e6340d798f428e7be72eb5f9e6ad3a2ec7a72feee2999317a7812e6eee12797fb19bbbd690933bef7418f2ddc57073321311f7de221fc771df0d04b4cb13bf50d73aa4b0e1c4e95e3e5e75681bcbadc75d8a672f9fef6fdf25aea5be36bcf47be79c4ee6f5a76d35d714d01d875227c5fc21bea2c8bf8b9aec28bc98457ef70e459c4bcc66360c1286617886e3edb8d2c64ed73c6badd4715ca9fe4c8ca3388a9a8ba2c945760ce2848de338b2228e18b7e43851144dd3344d3eae5f2b4d93c595e5ed6317c53bbb5c14f91ef7288aec8f00705a6471c4e831ba66452aadc73164b366738e7255fa16c7477eef38eeb5e4323ef37bf7b5bdb88bc5897cb3e5298eec796b622ec31556f6dbaf4801dd435c0ccd86d0c31858fc9f0a39ff73ce55a4ebe9c41ab7a2df8fea39be3f2b74892ee731e1c4fcc220ee9cdf07db2c811d0f65104c6c46e85bfc4b248b7b484e2cf21076e8db4a1f71493e067b0337700337700337d0c56d882150e99b8f59029b8b2f76e4aeadb9c8431ad2d0257afe63e8e7fafd03f941f99ae70f7429f441b695fc7210b2cd24b16e5705b7022897b4fe423d67c55931072627590d9824e7b197f0357af172c54b6f92fc974492bdd7e8c57d5a309db74adfbc4adf2150e9a6006e95be45fc9b82aca444a3b52de7692acad8f866516c87be15e201b2db3d72b2288a2c8eabb8cf661697f6300cf58c6f4319fa97a2eac4ed145f4e0ca4917262d784d4ec6471f7de6bc1ce11f634cd99ef6b137966b5c67a49955c9bf0d725888cd4c411e24fcb17120989a614038974f59b25cd0b33e05c0ac48564503063c7c20858cc40fd4892438c169a233f2d4ba23491c5e525d65f497ee2fab9d972d5c6324986048f70b1f294048e178cc86205b442b34bc1872678778cee3877a5ae15ee465d609a1f24928c3445b4dc24c124273cb5366d648e01dcd65deb1c620c84965513bde04b0b85561214e10e52052c8aa28d9c6f318dd55a2b1c410157579638b204103e2ee10821f418a205041719aa7a3c41624cba42f33788fbed3896484a31dafcdefd66d11aa2444e9af2155240c2852754b8ecb8a04b971d5c50b0e261cc98716a64fa6d6112af76d862640b1912b45cd100abc969081b8060c2cb96ef016787966e24c3e5a9c70390236b8670b3d57483d48f148e88c1a1d7ff8ac94b847c451c93a4ec318965af72d0557663c6a40a92b4748c3cfd66c952933595025d3ab2b0e054e3108b3867eff6e5ba59b2c07c386a2ef24b94595c0ef19fb95c4ec7d2632559ba36566d803c5c82535b474a602be0d48903eacff18cafe170c07ae61b60aa2d2fe5b9db70e0eff7fd565f9db89d392f81b25e537e0d57d47fe4d885357fbdee8fa36b10ba768958dc238eb28b6c05f405c2c81086d7c33741a7032754d5100d29877e02951591a6a8440b191462e9684880008317000018080807849124064220c975e50314800e608446645e36944a83811c87611802310cc34088210018630c31c630c65859018621d1758f9e40655cf568492e53268830b4c85596ea483e2a7c0529ed05b523f8072b1b45bc3775096368c12a525c21c92916148396214ee46d21bbd7b26d45ce439ca429e4ee8ca10b31c9e4f34c840de024274c649540856fe74ad5544f8c9a039b36e6dba314c1f519bbac4ca66d3e49fb7f9e12353e6811f76a705c4aceca6371278ca7124a7cb7acd7e0468bc6657b679d0f1bc2ddcb474043f42d199f5acd8f80aa6f17008bb7c01e5acce891709088e6e0371dd577939fff3d050ffa94b78458d90404d2ae17f6f23966b21a80c59f520cf49de1816fa786162d4b271d3c9f8f72c16544bd85dfd8555b0ba27f0605951ce69d87db4a1cfb2d668a71eb3a1e82c0ab6f42cb3116c42b09cb206e381a93db44427ead706c94a65fccead8303a15d687e29921b14d5615a4e065da7853da9fee1432499d1041888b30cb7d96428b9323aff9287b5ec874903094b77af846132d44b7c1d7e413a4b1307d811824960a0dcd51b46a4ad5cf0ade66e66f863af956ff782c99568a4ba3126cfcb9d7fa70f8137277153710dd938fa4aadd19ab019495484afb6556dfdbb0cef275bd43d1f63052921dacf1f364682feff2aef6f5dad1f4d171ee5f63e30eecc856469207a5bbb6e28ea41d8831d3e98824ff5fa23afff93fdb77e030831740c3d9c3b1fdd1ae83b2c0a2f97716fe4c2004b02d0dda2868543a221725ca6bf7047c52693bc2d95413e12f406857933899e28bbf12e74791c9fc4d0599b8fb08dc6d483c1fc400db2cf2949e8afe65f7b52b48023c802c03d3694eff2642edb5dc130f8a40f73b8288f6a9061c5439cf19e573c2858d02d1b7477a2457cdacbbee7979446362ea43cb735ad4dce848afcb80ed8140da842cf3823b68cccb057ecb4757e1814098b705622f71103af66fc89005913a2927cc6e7f5086e6a9807421f9515d340b2616daf4acaa8b736985a1e34b71b041b75682615dc72e8e5e92755ecb1b1488bdf095993313e2bbbad6edf5dc26b8bebe3812eb298e89749b8530fcef01a80b4dc4468e41562fa8e28d0d07e2ba796c04c8afc3e92471e36f40eefe70ad64d1f98385a172f37f657f0e7d2b564db8806a752e3ac521c5dd846866e95cae69f02f40984a621c66c60f4963e2e1a3beccc5d5860364eed26004ad9133acce70b5267aeb627f03a659ca448f0f78d4fda94662fdff7f12fc14059f280a192182fe20ffce1d9e13bcd25f99bfb50da725a124b59f19457438c6dc8b1cc5237b16f2001f358416d007f6bcf10e09558cab7ffcf6e45a520301c0d5745adc136d0e350d7a11581f89c5e3f00a35469582427234355220e6c866c8f98afe1da885ff891e84656f0027a07d625a0ac3eb099486c5de7b1ad5578106b919f55dec7b4127c72ac6d706b7b40ad05df6a3f837eab71020227b741712ac09345bba6e8da24f4b449cc516f0830edea7945bf9f02764ed5263cc76e228c2be10fd7ee72fdcdde09db01d51adcccfdc1fcedd33dd0795ba97189afac6a51ebf0eb92437c7aa54858a26e228fde80321a8f33019f20b1904e72de5ed3456568d41bff7b990fe9e96a088be1e6e40dda589b2953247ca5ff96fa2c0540e23b0d5d9dab55e0bc09af6d04dfb87dbbe6ac1b0d4a2e6928bee1caf68ae78982d4c58ad14bca39bc6182098a1f6f28d2cf4a94e7bb2e77c5bf34e5811c69ea504549b7854cfc4c1d55294c51d24269f2597e1b9cfaaedc2c3d092dfa663fac713f68866b88c58f60e8207cd49aea0a94073b34dba34a0716868592475a8d466c6f10c2c588bbb43c748af556b02f95058adf2f4c4bbe68e84a36ee004ba916119c2d13e2c780b46343d437fc17d92cc7db2b60997bbedbfffee9241ba117379421fa0bda600965091ac5c17d623a455ab8d899c45df92e5ed676001666af20313c2db8298f076a41e4e170b423968ebfccc8b19f11bd9b241dd1ca6f4f4af2d371b700bbfe4fe110ff8ce1cf8e78d3d449f354564f33e1f36a327eac4155a1bc631019be06e0409927d20a24ac7110413fbf76a38c3dbabc3daccde6f36e9fb34cb9c1571e2ab70fcf87c12208ca6a43ad7744027f756005dbc248fabc0bfa3d491c9ca52120644db68b8ae33fc92b08804c1d9a856464548bed2d4471c1f24d8ce98c2fca0e71943ea61902ca80bf3b042717ccb29cb706559d05ba36a2b6230cc568e325e431c30b4d9d86b3c809a149f7320a8a9a5d19281b6b1266f8e0c81398a5fa95066cd3bdc68445b2cf8440ace5e4f6327d12bdfebd00bc403a4d840c239d4fd7cd852ca313871251a097e6cbd8aa1cbc3354cecd01b53a8d72842e754cc97a4260c408615d18e1835a95038c69674231fa20f25479cad5156a9244d9c8f10d1d6e72c9cf3cac3314637fb243035248a1f7525a171a2ae146c4488dd1aaa194bbc02e8e63e42d2fc29a280aa0f628fbcc81de63a40bfebc8ae2cd94e8f77075ab8f3e3023c929d1de5a1896a205cdb06dd8646c8e4b95f3d3f2a47c19fac1d8cb54b4b3b54c3eea3f8e03ef2b4cf7cc9e92afdbf0de9e90620499efeecf632bd3d68da5396cdd87c7c842a4f53eef63c071db55df5b3cab9587e8b3c1ecd9828d71566b86188c458fe1288365799360f49da1e2480cb09e0388af03a006a2ccb4e1a69891041b5b53199858e8d412baa6ab4310b6004ecb88b7bda8c41c3984f647227e5afcae463805af362e41ee38cee0e5d527cf5514502656f0ae112ada505c1834894e516e35ac046bd49060d86e6597f24a87efb1d4e3e0d31e9462cbccb62613cda374c274529f284b6960d81173064b9c63159aaeaa4d26f861742d3191f6da6e8b0a9cd48c59194b34c41379590b4a60b9822310b76e607becc43b8e63b72a510805952acd495cbb32c0dfb0c64f6a39d7432a55c6d1f87979080c3819a19b4eafeac58ac0c05959ee6fdb927c959bdd34dc7ae24973d0f792208fe3691037f4aa96be244de4e227c7646a57eb24e592e838eddc5a351ee779cc5dc39230cf48d84d216cfd5c54a8c27583a45b328c875645b325f3054c018f50f21dac4412053e4271be85943ab62cd10fb5157b718743ca122986efcb6b29a4407af8acf5eb042b5e01aacfbca5bff0b50a02c9fc1906f29fa4b5f880ec0b2ad4e5126ee4a691fa4a81ff393a3759df6e35aa2e9218d2c99733332acdc37d36d08a499b793258b60345c365180681df9cbf4006930734cb9e2e304ebfdb1f1b1d63680584cfbdc0b1fbd2b46d2ad8813be33a813d2c5e699d78ca498aef524f632c43b93b4da854845cbb2de09fab895a8b91a340eb5cfa1c572a18e8efa54a87a877c4acabf2d993c4b621ac83c44388a7c42977ea17b2cc4aa4dc2182213ec8fea9ec801311e6d6391264f553923a2f9e4cf3d766c12da169f5f56377cfc7f80fc8bc2164304dad7d78c479504174f2b5d66ab919a89c99afa1486c33baafe5d7385eb959bc40d9c8fdc4f94c61a26ccbbaded593ec2839becd4bb76717a407f711ce946e75247a6be5e569b79fa05039b050a8b0cee5f7a8b71ac5260a63fc35f38382bb6767af66021020a935568573ad197afe9c5c9994fc42a17bd11efa1e34073c96a4f2e087b79c93c8884a508276d92777af5b39f2d01b6d2c496949a83e92c80b09554d3c4767f1a2901f0b7052608737a950c3fc0058e4262e9c57e8b5c12656cfb5ae7b784b89a25378dd8c300c240c8055f3041a7a1e3de6364a8982f569b1b50cdb582f3f4be47af2ec44a582b5983b8763d2ceb62f035eeb0adc4722d73ea07061911f023b12541dc8f2c4de5ed7732afbbfce0390e51f8b1de85cea6df0e21f8d1e0a5d3d37b52ef8658e6b6446b613508dd54d656b7a3230e83a58439650671cb8faacc0516bb862aa503e3c9aa347d2dd70ecc2a06651a43c56adbd724f0a1a9f8392cefebeb260625a15ed81247a97f100f966be7121565c1ee938c9ac4e19fdf4cabbd217014658daf77686bf98111eb046ad2159783eb323e5956d96fd3071ca522127e98edb6e52ece278bd6c9d3432300ee24f811c4324074ad91a6b244355355d14846b59cb24cc8552f2be1b4453c87488f2d6e72ca527bd09f8ef2ce72b6d504943b2c07473b2a55a69cb2aecdac7760344e5b074f15a35488e72ba72caa8e1da01b989d59613b4255f33868c834352fa2d170e61a5e085db96035a46770e83249a343963ac2c238b2c9f5a45374f3301075d8d5fc448a96ccc83d0df7ec9ea1e560cf3f2c0cf57b9d31a81228a631035ca71e99c8190b01d574ff47c00af9da5e0d9b370405dc0a96a91f0488ca106c882b388bc3353968aedcf999ab5d849cb1b395c5a4842d1c648a951b7dc1047c1e08169d98e0d857a1bbcc0cf7424b60b09ed4690908574d8301cd4c2db902aca1191421fd5d1f51a16fc5ecff5089cc5c2d6c81bc7c004d24a544e916ac4fa5abc9794c22920c619b0afb96d67ea10b588b71c97ad954499b9a2666d959700549843b0d6cb14bd4b7385584e10d0841234a8b82d2524401169a026e02f7c41cb027726c84fa3c28c83d23253aabc674c9eb0981199bba54c600493c065b9218d4bb7e59fe4a9e67c24ac6b080ebecdd74a92fa72774c5e982f4cf94080b38ec312d1d6846d872ddd2735e3edf29a9a2ec1420386c4cd906a10efb4624ffbd55d6fa7da09c56d6b8f1758a9c273bac3042cb8e4e2457592171fef827888241f60940add95d7570ffd7b24dedeccf08155c69fd72d97a4faf11471e9a33ef96dac06a9732895597cd49e10bbecfe446a0deb159ec1cb86c4c28cec0dfffcd68ae0242d514baa625883fd84231a966a3224d87d9affef31997f4cb5298ce0c42885755d5e27614c71c49495f0186c57ee83bc8cd7d9ebfade5c6ede905297dd9395236a3a1cfe18aec6669cc9543800e0c5215ec6ac83b7b55a8e4198314d596954a7c58c7dcbc06c0967a70d99e00bf1677a30ec831f6249850f7d297567055a0f3f1c75edd4f36a371ab1733421637220fd4b5a900446a99d0d4f8bd11e7acd505ba1049b61fc0cc561295dc31f22df935184939aea7e457b7b5b5669120e4d116f00dd3fd28e895cb9d7b32155fb1802a366e8c9197e2ba32a89cad5373757ff257313eb7bbcd623b17c3388129753b23d9fc1a29115a1bd9f05dd2001048059df43107829b38ec28913c55fce84788a61c31205ed31eaed281cccd0898ab6eddb8e86e9aeb71d8f861ef88f3b23e88fadf60ac1029fe90834ae5d8ae7f0c58fca4c614381b60f62df7a9827e98e892449efbb66a78ad72ed1d8653d267553c6d16d4e1796300e6542c50b3392217f36137ab73b86334707b7d0503987df54fea2b54dc433f638baf0c5db263997580fedcec5592b24579865df8ae4f348f9c4880999dea0330807ea110087d20afff9150ba5005987937e2a471f49b5544a7f06e369bd49da9d4e4fba0285e534f93b24b9d79dedc8655ae18bb27a51ed22574861cfe14ce7a601ccc862b0c937e2e28d905c675f5c072c12a0bf51b09c8f9b457d2809a5f1c75ea7ac252d3a676a7fb0344f7127a9a94ddd1a167e636ace60ad97953f6105d426666218ef08417c5c1343ce218f9ff8ace5e60bcab0df00b42010e51e75f04a4c0737f6d9b86b4e9639b3b0be261e20d75d06c0586c40c0635c97ac1d9b79bfb36cceda1a3063a3577891427578d772b34e26ca1219ba998173c594341d6ef6d7ac60c0bbaa2ce526d6a8a32ca0c3597a8d5298c13cec101329ed64770aeb35d82e855072ab5dcbe66813868ae906ca590cce0fc0c5d3b9152685d657066552d9645a290582af79c3bc7d1e6c8425d496ca5bf8f67ed5040f94b41a17f95b68cae12c0b2f4e7002334b9d333acaa32b7a174ae35ccc214c3732c4a618e5b06ac4ee22bc95a6158cff4864806ed004b006cae19167ff31efa39658357031d5263da8770347e1312f7346f97aac2e1774bb82021aae26d77e28c216af6364e840ce61fefa6631af550238d2c75b40b8f1ff752fc8f080ef35f1fa4ca30a039586dffc7b34b4c7016b736ec6509431a0c10c3b339f09bdb3f55e077b5624b3fe8d11a1cb64094845c70c6c7b9c392e1e713a43c3c587d29382f570564156f7de1428be965baecad2698ee1d9cebd98d4010376060f4024129c9dc826fe03982f38b14a3ad55357f21ac4f66bf67263f7f17c082b0bc661d0fc3c51dc5742f35eb788237c1d99e9e3f7a337bb8c02138fbd96c62e4d1dbe604c179fb06c69159a10568d711ca09b8656cdd641f700c08119194ee3536da0567dcf21309cef55108a647494c087d99d9e7a98125c186ffb21be268029356d714de3e5b70aeea1de6d9440abac8076a2bfe94edf8646a6f8632e67933fc8c4425a811ceed16c022de298f9cd1631794326eb15f069966a9a8b27e378848525ec513c32613f0b6407d08ceb65ad570efb9df2433f2e0897dcb6b7cd18f1ccba4e2659f37843c660140e0ec389aad7f46ef43dde1997878eefef75bb260378f57f85f8112d7519ff52b36f0ac3407eca7e3b6b1ee0589617f64a5c7e39e905162c8cb011e48dbc6b79631a7c49d21065de1114ff69c15e47077ecb9270d9660bb8f063205d4ddc70d9c661c8d0f90cdbaac2dc88295559dbcc711dc43ff4ba32705992becd6120ed988db96b62a1d1c972449f360b9cbdd84bced2d95e44d2d041e5f8c5332ea3536591db78285181ca0ab07b1999e2559c1c2661149dca9d0e36fbcb7df8836ff570699a935d92afe9fa00ea527b2bce6c28fc1c4ba967934d16c0f1fd92a1b72aa45c6073124b7d8b357d6b01b9fc22d3ac74486aa59f143a2836123843ac93bf3e7ba7ae56f6477dd2c1b2fb2766749acb6b069f6dbed43c0d254a2d8438d9f72c0f379fb0a94b392d8fe5da415d797ebbb04b39db3edcdfe5b50a1c747b06705d7f95b0089c11dc7428c581bfc252665b6c02e5ea5bec76003527329b008ae7a08b415f04be29d85032191131454d4a8e755ec9a14797bf6962419942033a5a305eaa8beac51dd41a596d1891324a39196305b17e172e7cb81ae98c3f28dfbb45953efe044bb9cb57759907b6703e9adb209abbe3c3cce1fa3e02ca6a9e6d7be88e3f7e077363a34bfd4a4bdedfd6e6ed21d4692dedad371606f7322635fa5d9fd0bd1cbaa07fca13d91d88a2e3c4f72f28ae10642db9ceda2c5aefe8618127eac5883f994bd5752886056485c4d19df41747a171874319e0c2dff04ff046f73ab45b5f4c08988985cd3b6ba3eaaa3343cdb7b7b640b2f47b564d4f9701d20d94d3c0ded50163d3bc4c940d5cd4bf8c63f35c43302433bf7b059b5c8d137611a90ff517771df7eedb12f57dbc4df028d6b73d300e9aecb05645c9b7395f05006a966cab9766c07effe74df4407185cf8f360d8392e31cfceb279f6b563d3459c7c2df617cfba99f1a944eb4e20aabccd5c91b7cab899381ea4d21cc549d3eb93183187b64c22a72d1a81825faf4cebafc2f00fad28782faa20208b3978dd145c098209741d3d29f6937ee638f7c08cbd7ff2db62cd6b7442de25fa88d41028a84fc356cef3724df099887520d58a6ad272715c0aeb914e98bf30219c94b3a5f41d417a2a54b60c0b50aba31a5717651fef67e483939cfa1058f96dcc05a6b505145940b70c48c934fc81806dcffc02fdfd1da77767f52304491003a77fe422e424ebcad3ace8421328ffac7eab454ff81ae6d2dc53f7db4fef06fe96b09815261292fa2dc15eaaa397d084e3bffe30e01202e3854508ec5f36d6e98802979a462e87848a1c8ae97670a10b00cc3eee2a7d4e7bad56cdeeecff5d9f14bcaebff84d70fa084de43731806fdb20675a581d09b0c2692d371f0ee75fa89f3fa8b1a6451b0dbab019e6bed88a8ca4a28173976d61c1e37e11073380449a94eb4a719328dc74b42e1c93c9fc1c0d7319f48d7cd41753fa04f56a68ca6467fea5108e0cb1dea11ade5d93cfe7de95dc5488f05ccfd213ce446a6832938d42c40a0ec94110c081c83532cc6e45524182df9f08f414fd38317c332e17033b9d6340c95ddf0dabf460256d69cc78c9f37102aa6326cb9091fb3d31654056b3268b72a937d5ec28c1c82ffaad440183aab19ac66929e58b9bd1076b82e00e0acff4a99229c1a6122220b8cf1d49cfab2ef257558f141afa8ef808047029834fff894355d97d1e701229b5d4ee35b325a70a38e1961cc9e922a5df17d45c21cb181b34b4aff7d147570c111407b8623ab4622fb05fdd15462471af126fa55d913c5e1b3f5736c07a6697d8f785d87085630c731059bacfcbdd8d678daf6473a881988795445a1c24994b662c755196ab35ea75c721b55f60ba01114c0497d78192ce2155bd614a8c6d4df4624b5f2e41d5c76430fef8b8cad2a2560c2d4aaac100b19964775639b195d98416a02385f3042a7e909f69700273baf37445ac2623cd99dc4df70cbc39b3a3cfc0219dab346fc39b119f3576e460f5b23109f791e407de240c80dde6d37b83515e4faf265faf3af099b987b55c116baf4a284497b2b60ccc1190f2637330cd631293f45e89131711ef6a045d412018f23f0252c3535f3db7a353808af4506c6899b3960a00448a97d6d7e4ee57879f99fb5acd1d64e74d79827409c7c041df86f35e7806a3f1a520e49fea326901f15c1dc0225865a1ff4600723ee957de1e1d571b783a2bf65bea8e3559719057bd4c8f26aba13af6b3b9b5d55c4156df4a28449792ed34fc199cf14173309b671a20f15f90d31711cfd504a082451efa370290e7935e656e511d0269761ec552429ea5749d1192174e83a7beb8d5a6fa92fb92e1e6c770824925ed396ed134821f72bd59970c476bd7dd23144328d92e904a85643ab683767385649a87d9ff6416ef3fa6b0c08690c40b956fdf45368a5fad4dc7e3071e3c139efe282274e0c7838a16da3240ce3c9d04d4f95cec758a9de301d2e1d89a1b2752cb751c5a82d1c2c8ebc9ecffc95921f336f17c0cfb50e9a4f048b903d22fd64193d599d3bbcd643e838d72cd6af0055d7db8946c22235e4298d8dc38ff8d4f811840ea06d10cd9789308546ab5554319ce21c3a6a3857c82dee1e5dd30b48c64d8fee9baf1e9914834e4bf38f871e88e0e699e1f9202fc67828267546a1e55badfcb33da2cda971b0c1fe053487f87daa15f0ea268241aae9f03540d109a5ee772aedf4893c15f8b2caca08c460d2e7994d724d11a631442a4d1da92ed995da6273515fcfec27d388e2a62a92a52f26ab5cd88af9bef1a87811619f671270e82a572a45ece4d8ad21052ec4a112521c4d052bf740ad64d7b335c47c5cde3753400cf42f44f2f1b7ac52452b6a57293b82cc21a0b90349684eb40d70936f9813503bca3e40c35526b74f493537340d4024b472c2029fc22ec7c537c7fa0557e66693b39408dac1eb972e2c9418e73d6821fb5d6ea8fae3a41dc23144bf21c2c0f4979043ff09b64d59288e06dda237c037f446af4f6df07169405ba06e530cf8af4a975a3701814f8da05fdfb9044a749e08cebdd7847fe02a043d8698c8e3bdd6b45e6f4be1c056215c9d6754100b82ebdc49ab3ced282e5290c2599b3b88e0fb1d82513f8a7cfd1302b3040983914d004db4eb9400dd19226843e040e5160d41f0b650c6d66ec6bfb21657d52db97a4a072ca2a39d4fe2f19d7e54591622e80a434337739ec8822e589ff63c432b16b66690628db9523b51ecaf79506a912e3bf10600e1e063a98131fefc4995d450f07732216b55521419ab66d634de5e642e835b0726019886b09bf45edc3bd09f3f511d3fb50e0ee3316c9d052ce99efbb94252b5ddaf4d1f2d2eb6322906f4be891f5e06bcb709df30c267e559ad72c58b98d38c7a9894de601d5dbf2dd57575b887eb92a3b129aa439def8e11fd66eb0e279c700c056c410d8753983bc0983ae9c35e76e5aee3fae04010ef0e744460f241d642a17e0786552bb266d689d94bd01d7c59cafed4d4d0bcfcb57f9f367c77173c258f540f473b4cccf298c7e4ef4678e4c886f2939442af3336254acc2902884cd5c748ae54d1a2fb450d472d06a00ff57af444373242a7162b694bf56a57d6a1e9cf20a3308d903f215fc09a4a10d7635428cae27521ab880e22475704e961bff9700170fcc1bfda3e63024014e2559df23f729cac9b481a7d16a1ecd04d8370df979337a8eaba8ec296522a7aff6837d9bf61ec0ed43a50203832286ca91c5e2eab1a2dcf5b354386502f07d2d580799305a02ac9ec58c91527b3c8f7eedbc98cf770f51add31ea34c4a823ab3cc6457d420ede21547d13f7d2860aa16122299741c9f36de441d138556d0dae83eef445319bc8928bb885356e27adfa2adb9eb38b0fdbc16f360db97fa33b1c51bff40971465deceea723c414ea07896d3ac42a2c68da5859d413d7f0ffd17a53f37593f3464dde618eaa1a489c6513a2a9727ce10d9fe87466d6c345f3f349022ca1aef0764efc6c65da668a47e99682f396aa6c144639c3a3c7ca967fbe792363723fd43f6f1ce8127c3b26cee2b040eb2d6364ab71e7bb1af4143c8bc454b66f2eeb0b3a142def02baac68869c3287e0f271128cced18ebc1f2b7c54aedefa086cd5ae0139e27827310fa3c99a28207f75b5ad3d323da3037d0651fa3ff5aa4b6a16ab50b8835fc64594308bf1a1688351a4e3c34ccd57f93d508ede0891ca307b1067385652e18b1e139b68ea13aaf0d10e458ac3178dfc4ace174c1632833e01daa6e833e3ec917651974ff5d1be81910a9e96a73570fc51c075b1c2eb8e7bf7cd2a2fb42d80c53ffb68d367b3e2af9254b6afb8e1e6a5930488cc8592979ffd63df8f7133612e420a8bab704d8e903583b80826e9317299fe9d3cfafda9a9c44e6251f6a7662c7eac2ba2bb0dfecd0722f7c0aecdb4b8df27f082ef5d28332e55e168943cf016847da6a26c647bace4f5727f71a21a65de3f395d2266c1ba2d109219b93d2ca5ee22df92047bc9b82ed3585dc1aceb8a45d12d9e31d9666dce0d3d3d4639507c92272ef5e7e6e2b242ae59c84c8e1e066c20e08a4ad9ffbdae2377075ea5c9fb8b9a642759e983abb1cb9246821ce6e785c12b82426f9c0c52cbdd815e394b98b5dbd74d1b2d898b4d6b5fae383b1abcea5ed2853d5d7c0d3e8a0d061a507851a96d42ce4129fd97e0835a1ea22655fc07b0d69f0d71323ecf316bb673915914422500f9ca730e9d7fc50d15e7ff5abad842911b6a481682dd8761e05f1fa5a48fe51a8788f0171149d1554d1e5afa4345282e3fe0a1d86aed24bf0628c82ab0abffe1998b08befceb69773d57b54f54b41e7fe7e664d9a6b680a0f164062dadb3bfd92ca3a5af62bd3e8d340439a878f473a342148ec1f1d3198edb0b76a7ea907eb3919f642205e18175ff20aa04990093accd5316903a6313c9490526600cbcd68066924a9b3770d9a1831f251181824966a0d4406af57aa2dcf4481770c197d1bd88654e81f6718b01c155a46846c74577f1e8c3ad197932052ce92732f6204231d78da6a4cfe7aba40092ec5b2ada6175e641b3f5cd76c38ff6f1fed8259f2668e372595453c98ea17b4fc53cb15818675dda5f1f87c0fc9c2433dc931704dda6ac106a5c531ae9d52a6d6b8b02be97bc188d96f871349fd9357758d5b1d7cf8ff95d2de20c7538b2b010d2b5d534a9b32d4fa5bc7495d5be2244e3931b71b0602357c81b747e238fb3ab5350407bde17c2c364760f8fc58516cd56566f90bfcde3b6b1bb93e7ee30593fed726412bcda51d47690df8af7ddca3919492dee5c6a34a25f8517efac9587c3bf7cec61ddf8cc18eaa168c954146f0e3a401020bc75c2a8f4a88b023e1e524149ea531278d297c3427b20f7ebec467d1711e282d117dab500338cc68431934160afc67440330d85a691d969107802020eea80c18b931eec858b20beeb09fdf78b11db45439d058d64d9a67fbf0efda553c631e7a80e0d42588efc01fa9d3367c14265f7419c49293f743272bd70734ff5e2039b49d7a38f5c73fe7a08c431915ed5418324debd5ff2ab2262747ca7ad1d5004b7b6e3223c68ee5d85cba7065e6815acd627599b9d17cf2351ea25dc49cbae87fe18b780a029ddb2fb686d26f1c01d70c0830dc4d493a45fc42cba4beb5a22e1f428870112477a7e163189c32fde5067068084470f612f24e573fe85dd451258f522572fd3fedd7e0fbc776572193cc5ad8cb948b0eb55711ddb3c4475a1f4d3c55e54a02df8a63eb9c76758fa23b29f63d1763cd565b781b5a700c3f029b8ca768f74a84fa8d8fd2e70c0d01e63fa7d5388a0d11ce6cd1aac6229a39aca29e74b354ee51ea5d0bca91fdb7ca12bd07c0605617808ab616148da97071ecbdcabaa8fe0498bfcb4c41244067e8feecd1a0dc2b427fbc97fd9af8da45a187a13a712b75772a730189f49313be5a68524154fcab2cb9b30bdea7f5cacf2e66f007d3f79524ce279153403aa49832fb27e195f543c26d44b2298f571880144aebf40f32921f0ce25921b978d8e8a77be6f477dd3d1738d0b2238298bf6d8bd7bb278d26a5fdb5f35056b803a1c842003ce48e690422cb5a60b42f59d6f42d60a0762cb34c809ee65e54be92494bd41880dc4788a13446cbda260008d1294724ca80b7044244e4a1951122a5e33243314446b35863b4acae469910aff0cce1fd80929695de18c0721c3396db537d83a92561c9f2d10205cce9b4ac4f68afee3b2fd6f5041fc64afa389914ba4cab31e56578df528c279e80f05ba586a9c2ac65820bac3e28d5046eb58398f5def42de3feb2cc54496e2766b3c5fd3a9cc513c5ac6cfc5f25a647d4acd59d05f5127e913f3cebd32032d7b294d2a8288338fca365cd4c53a0177e07c75cadaf664d62ea0c67b8d79ad559f640fc2fa0a217fca6cf1ace8124159e10f00b045813a5af03df624f642abd66a538e71585f585520790c05d62b6a958b02390dc6141a93ea25e0dc974f489996c56bfaef18cd105675a0a704ea15f026b2a63b0aba1cdba8cf86e15e92e534796b63e99a2a520c8daac89cdb1cdba52d312c125c756dd115e7f3f73d768ee08c4ee6b9bb5eee190d59f92106b6973b3e6b3c3ce3eeeab11dfca6ed6724ff77aa779f42b64450e629f6279492e3de70a5ad19ac53e01eb80079ee3dfa643e7788d2f9abbf6dd7317c0389c4febe87b6c62409e31547f0c46cdfde7974e4f60e3d5d3a6d9998d6ecf91b284bcf94ef0cd1f2d3c516c5a59b51cf9877d611064266c135d4e31065f6fc02d0bd5719672640e44ce927a0e17b614414acc952072b9a88203316f0742f02d0da433590b281fd24b23e6f3463811ffa2c579207aff5b8f28f569c70bd24e2ab33e9d8f60e790597d4af7e68d5e8a5e0a5b49e8a9a970dfaecbf12160d50826a8026c021d041d322f2a4487540657c66ec6561fc45e604c8da6dbd410d4662a2af184d2dd56cdb31033a669301d9d5b5bfc4c03143bf3889ccae6df9ede544f110192efbc415fbbfc86cf9766a63e1f3a3b3bd4e36edc64dfad7eeaac44fce8d4f6278c8fa983aef9111865eaf7c7187b9b06f52db3e606ad7f9549276f9e1844aad68a8029932bd7f8b8ca057de29f28df8a99e6b27933d775580f23b6cdfba57366b2103069c56ed6c1daf301ce1eb7d962ff0f696e75acc61cf94b0ae6a77233c9d69b1a2b698284a5d384afc0a99b2bdfc0b84fe349e6824dd0c9c4da058839a589499bc97282ab409df0eef02d2e9531c1e74b6bb6a3a1140aace0eaf188b5ef690e8a6fc1c6aa84f25ee811121b82429ba02c61ceb68e3ffcf861d465ce248c69203d4d82eaff80d03f0346f4cd3f9446faa20c4f33831ff16ac72a93c641a419c64decb30810b0dc3f3080d2f90154b9b5bff663b4bb4c6bfa888f1abb6afe932f3496c5bb8e36f51e6ceace773b0329318cfbab3827fe86392616593d556b7f2bc4574d3c33e2a7adc1993a1aa33b379b16cc273292a21ae55acfa3835484edc159adb1ae247d3dba5b74b7246f88680854e202aaf755655c30165aa5035ad50d5ac0a4af1c465dfea8daffc38591dc620d6cf8e76aecd8cfc058717789abdfdc5a9554800cd7b6d79acf7bdcaf007026fda845ecf313b068c73698a1f2bdcc1628ef05609aa17ea39584ecbdf796524a295392013606250676063b6af5c94016b82d5bcb63ad0bd6eab0b6c7da1dd6fa58fbd3c24e3679b8c9b950f3db6899a3ebc99a84ae0750eeefce4be9e038182ae5aa0b1cf6d70f6353f62f434ed7636f8e1dfeef60d8a270e243de7c7e5ee001438f0320a0eba17ddfc3e1ede7051e9283a107e50e8080ae4702b2cfe40e0e9437468eb0df713539da649c7ce312c5d1c8740270bf2a02c7e5c6aa2254df794584a87e5379a064757fca6ba5b8a442de521e902053e010a7250d1538b49937b2f540d9f9805d0ab97a40627096dbd84adf33fdc206488f9537cfc77fb8e937407aab3140099ff7248c00009b01d4d4a43297400db6b8a96cd7a37fc7393a2f9ea103ae6c2977b52d5f4ce5cbfb55fa653711c614ec9156b17537f1bcba99c3e6d25cbacdc9c1695d463c7735972df0cb6f5746a9fba6edc8cc9b7f3dfbd117d772084559f63522e3f537ca51a15dae7b2918c1edcaa10f659ebf5cc8886b81c3ee12769798236669c459f2a550bbac607f5924841b24652fc7256e00cb9baadfc6410934818043592d0cf3b7f799bf7dd141a0dc9b17f6f710cff75ba171d8df91967eed5658261b6589036d64b7d36b6bb1df4cae7b9f5eb79046e96fd3d299c426937da10c45a83e63e223fbb00d7088e77c0993659efc8c49cefe2af19be9b72833a2733a6759c644f5f331ccca6ff04f4f87b326f73b9235e7fc7bed776f3ff5f581729665d95592a953a6cd690e4b796edc73df8502873753ff15f794fb68f7b791e7b282c25632c77d0cdc73dc03994b70dc5caa4e1fc3709de6db955fb85a751ff785e0fd5ae5772f3fc579e1ad216b7fbdf046bedc77de7490d3761c286bde1099b36f2ed138ea5f6f475afa59a0866ef1fa38e3c5bcad6810c1ce340fcaa1733a77fbabde64efb973773a1c6e2e70ff0c71b2bc1c8cd354dae65ca1733ad3190b5799732a734f7ff63efdd90794332f9c977a40790ef16cbf151a87fc1d596d9c0b4a238d300ec6b97d8cb46e91c619638c51feb66d5bf470b49777d32ad5b22fae629441e78b40b9729101124600808d1a32312b1a3364c0c480f18255a98edbb4ecda4aa7f45e2202b72db2b2b2b29272b22aa2bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7b85a4bbbba3d8a2cf39639c33cebb74efbd59467d3ad76fc641cf3732fdfec221326a73c96a772edd4be712b4563a95e61274c9c1a65fb3c9d530a59558638d754a2bb34a2d6a9555a416555a91562a9d5f7d4eadb51facac601928910e910e914e121d984e121d221d22239452a79261b57eb413e660b495ce1e289d43f3357ba074c226cc2910b02d52905479014a08ca9523942d4f5baae408654bd39627b624dd0e70b199456c0bd2e450d01b0b6825a233aa148854125b6177cb6b0b087086b4c5f564ab6869c2820a26b4c4b4c040cb0bb434c15a946881e5e90313ac25e8254b148c293184402507597c806fd0a54123cb144c650559a25011ca9294e5284b5116a26a65c6b2e8b0eab68c804998598266f03f453d3df59395f954057b73067faba7a6a7d813d2bc22c8075e3c1df1a4e409f61484250acb1316272c566059ba589a6031eaeb8214604e6019c2585e36b0b8ae68b962a5872956ca5cd290564645e095d7952015666cc1d11f95fb866dc5032e9a3cfbf37896d91ff4580a82b23fcc07b213414d8172ca2107d5942314a8584eca110a1413285027c85a8e50a08872dfc814d84023e40d998e17de30e5943df017657380fba3b4f4d26b69a6d55ab36ddbb65a336da3d756207091f33807a56c5a4691c03d54af2c5d295644150d11f59010d71d52830d317b7b33aea3cf554a29b76d1ba5cf755b66af8f21cef257a5accccdab81a32fcc5d4f08161cf6d0100c6608e3fb3e2efd1722574fd97663c8f47eccbe1a1cf421426c3cad54ad0979ec8ee2a07f2ff56ba9876044d1d2ad7bfbbb7da1e7ede36398ed7ed4386f86ce5a0fbff9186b72ea43b08b35d226d37ebc456b7a08047358f3859fc31a99bf8f0bee36ac5f5e60981638eca55ef256db58752b81a0939393d3cb56f14a75a6848ba02f86bc80eabf760a79adbc564a79efbdf727cebdf77ea17dfb5d25955352a27689a383e3dff77e3a9ce5bf34add31860ce6722484120597e04298d61e619e913d9ac7d70e646761c07fda3df449de8fe336e63044309430466b29c9e00ba812c9f7a4dcdce0e094e78225959f2e2c88a0c29529c46d802c6e5888bd0e7057fef74ff98a5acb2d69fee3b4ea9941fd7f1c3a9418931c8c148698c34d2ee26b99f1ee5fec221d25ff54573a0542828074afdf54a41094aa0c4d631c621293189bbfcf324940bafe2593815cfc2ab78150f224eccc5e8d1a3475963a3e3d97f9331d22c94fd0b65885ce477c3c1f620aa112967a553ca1f78c07d23f21063bcfe4d07dd05b19bfa0a357105b781e21584a61811e0e9e08e2dba923fd597afd68709b96c6ff6aea274d3b8d760bc461f675ff8956e4f3b1ffaa9dfdc57366e84e171f677e48b17f30dbb49e84bb9934257ca5b4d6d489d73e44e3a27e6cdfd29a7aa0870e74ad79dfcf61be5b8bf5f2803e74e6678323ceb4e1a0775ef9fdeeea48fdc89d26b5030cda77c6951bed686f66354d1522a18f345fb2aed7c66957965eba99bf7d3e3a38399bcf75eae4ba9f00b8cae078c97a982cafd37e585f32953dbd1f9d4b42877f585b92f04baf34a4dde5879f3f22663939165166f644496fcede3bc31478693af6c09d8f2f6cd2b8d83ae6eddb82e2539d5e4f00b8cae478c2f5ee936b29c57669579a5ce278e698b334188094971244551aec97189289e721204705c220aa7fc392ec14425bb2655cf7961e790fb97fa1dd439f6eb10bff7e7f729fb859dddcea7d6bf3d75f5e2d9c0f537dbf55459b39cf2c29909658a83e8cba4bcf5788c0e58fb42a01be30b1997b3b761d32e015bcebe46927938b9dc481a47ccf4b3ae87fa5b22f1630c9f98e3dd7c464a07e5e570ad02cb7881e7ac745e6165bec03dd064b8e0f9f2278daf7dda7bf7c28d59d3b2ec7e1537163573c659f3a30ba60838bc795e0efb0d70b42fd841ae736ee42eee2bf6ae6cd713636e19654cc1087ebfd7d64f52f1d4060cbef31d802394a426775e6e7edbcf3efa82fd7b3ff6b59ffcd956ecb6ba5c2e827b99ac01403c9cfdb69583dbc338b8d5a71fc2e4ed756c2d9f78c35bd96fdbd7784bfbed6dbce5f33d369dbc6ddbdfedb96d66fb2c10997c8b1d76e0c1872243433dc0b4df5659f892c3981c252bcee9bff5bba7faac9b1cd4bc49cce1af7d23792bfb9a4a11fc2f73e28f1963fcd3a3f3f1fc5ae9e37edc30eda5f6421cd4b4df714de3fe65071cd6646d9b53fbad230f98fbcd2badb4d24a3d4bfaf167f6af9d228df62f3ee0ecfdc31aa7bbbdf4686895174eeddba3a17353d6de7ae190ce6b260e6acf7961a492b5e7a8e0b09d74985e1fb59183dac7f800d6be9d348aa36ca7ac7d8db7344d7b1b4dc92b6b9aa665ed5b48fb09f8cde4d1e20cb216a1642d4691b52ab2f65183ca1a1728214dd3b4ee0befd566b4cf02feea74303404ebe1fe16e331ec222f0f43caefe5230ccf06209e9797efe5a5d7df8b37e7bf783586200ededfd18103c3096bffb203be5913eee517e22bd8fe86df7a29fc7556bdf5ba8faa6b8da8be6ed23ee05fad42a7d97efdc203e65ef5f6b1cd9e7a3474ca3372bf7a3474eebcb08df27dce0bb3cdb3c1c1fb1a478507f9fe7de9b5cbc1fb9917e308bedf47f7defb5388b7eadf08e594efbdf76dfc66f2dcf701c45bfe37265f2f5f56be1f439d7c97f2dd42e5be387141d8e21637d5b5dd376fdbea716c18066f1ee65248a9f00b8c183032522cfc0223068c8c1934300823068c8c1934563135f972383a516905c210617e1c44e1c2689a0c4d9ba16934346da569319a26a3693526101f0b583de8e365013035336ec349d8521e10793382112e95b2a919dc4effa7406fd588a03f107913e52acbdd8ad16915636c0d1b00188184f7bea689b1e38d00a84878ef2b61c6841354a9f7be12664c38a1eb8142aaf3be12664c380105ae763c58dd8abb1f2e61c6841350005929d44fe7572b1c7ac227ef8c1164a510801b342ae0d871b01f5bef66b04113729c29e1068d0a386a04b0c2833352fe4cf61bd8f564d6da40a1ebb152aeecc5297012df96f5689a5301478d0028b742e50660399bae0750be915b6e28c82aa7c0e105008d0a383899950d015a373805c891d3f5805981c60c95ca86ab99187304e8529d4fcdf5bb05c891a36300165ad8f907738d0dd7a572e4e81880851676b2dc705e06000393a36300165ad8c93c0558e101c890a16300165ad8c93c2ee4e855930ae770e05f0ebc91e7ccca6d260d1a1c0b2dec641e1774f4f45310671b9f57dec24ee6714147cf8eaec7cac15f11c1e6e06acdb5f2d4ea42ad3a6aeda93531d70f520179436b24ab3ef57024abbead61ed84f94dccabfe2c6282e42d9aebcf256fc5274251e18ce24a4439e4e851088e72b8aa4f42f0aaf5672cd7c994ebdb76a55a25925c83c821978372d85272adf5697857b27c3edd5cd82970822dce6c3149b85fdbbe225227e4d865996a2686096cbfbefc50f5f76be44deaefedfede7b19305ff5b16380ab3c234770db77deccb4abcd948f1d0733957cef6fd98720e837d993cbe522c273bf46c75b31df7cffc7c72936f932416df9462db33193791e9f84a017895e27d435c208941e459afb02cac4647dd0ea83561b0476ddbcb35a4e2510a7c6efca25cb5afc12438a686316b8061becbbfcfe7790d5f2c88b28fd317aa1063838384a70d846b8febd18af5646f407e91287e21835134e1ba586805db66c295527982a11c41c92625155441cf6e492ac36e24c41aa10390d09654be91b7925188131c55be0b08d421c8af32f3bc80d9cecba4532314a69adb5f6c82821a304be55b26c0993308f792c2aaa8dda48ca2841bda04260336c49e214248817386c1893924dbc11c7d594ae53d629535f28496962c147e6c442e7d03a651019659451468ff4c96d9db64e23d8a313ed25cf766030793d67628a526030180c06c284c061c372146f5179d365300db6c138d885759feca2e44e741152127620d3973904c23f6855119992e2ee430137c8fea1a6b4b3730587f71e799efbee3537d583b9236fb0adb70a0ee353ee1c7963ab92f4bc71ecd4ec4425f04e400ae1303e09e172cc25a3c81667c2de0109d92edb65bbadd4565a042c7fbaf5ead4a7ac74563a8980a5bbfbe4e24e7dba743a259d320abb539f2ebd167947c96ca5b3d2a93a02e7de28c447fd91ac14979863755b49ca6692dd94d94a6da55dc427d927e6b861a3a5aac011808dceb624e9bd88c3dd0ba45f9d233f07c41c8ce0e7febc70d8af259b2852963ad5109d232b9d2929553cd02955510ce91c99e1d4a4806da5b6522d3f6da5b3e6a5d259e9b402fbfbc79f582c16fbf97921fdc89b864d29fb255953e030c6ba2d6ae14b67f573315eafd77dbd24f8ba5f74c21e6315f020b7b93a3118a716807039f3d7561cf4dfee132c3fc6228d1638ecd7cbbfa3aceda248e30f448826c28a7ed97e7181c3d8d4312052058218933f13c7411d1c1aca1fa70687823764a073860ee496ad1a0158a55cad1cf4d496a758ec865cd954973b654fd93de029bf106bdf6f3dec986fdfebcb5239c061c7c27e65fb524a296bba630c8cd1693f20170a0e6fac632edb6d3677514f01ca742121e58911548c8b299804d19d40cb0f497881e58814120541b2891e38ecc0c411d712633164718287a418f06004125fd3951ce450650543d812d45de4e0209974122190a83cc1854814228824b19404145d24418310b80089105a1cc112693044144060b1031055b6a822b422821f3c7043135eecc061b0ea7205890dba48a2031530ac60892cb080558195e0c824c10e8e4ce9224b6e88d2c4143b5c9164c8135b3081b2820840182208490898ca91a82c4ea220b1c4674a174d42c4bc783909922fa8a248d441cc620827945080450aa11994a024892e7430428b2b46ddd442907321948194589185090e401082272bc0f1031f7cf18414441011c20d540039090289278cc0c189245370b0a1e3a7c791a8d1da766633055fc8c0265322f260ace1ce4999072b08820a23a81d68d0e50b27393a71840a9ab04192144de015fea249a64852583a25849843b23c75855cc5d4b8f7ba70189d98700f3ece17e2d8cfe7cc81aa82644d1264512014b45dae5fde544082f2a683e4e3184475030ebf47f7de654834950f584a2965cdc67991a7bd705593e38702c8311c404da4f10fd239f21340c4e1ef9f0ffce69da7bdeb93caaf031c46a7201cc62e3dcd4bf0c0d62f70c2044d8d1f36d00f07154bb878ea03f1d807fa41fffefd6ca00fc4133f4bc29ff200fe67a900a90926576c4941149e7e20fd3b3f3f842458b878a8177994763a67e6992319a8e4a62e26a010421731c1044433018595d6ba99300153b7bb8fe71d0793c0e16faa9744a2644a2080e8926790d2df6f5e5c3f3fa27277751d119f1c5122c7217a4a5fe1f477ee27723f092acafde44811f7430e6d7247c9a18e677f1fcf5e65972e59cee81cf9713ee0cffffd7ddb7bfad6054f3ae79c73ce39e79c73ce39e79c73ce39e79c73ae82204a42a59c934a2aa59c53ce29e794734a29e54c72c3d63f30fdeaf23dcbdc7dfaf4e97efdfa74bf7e7dba5fbf3eddaf5f9f73fafcee9def35e44c4a6f7372507e96dd2cbb52be0c4cd665445a654b9f34da68a38d36da58239ddd8f76ddce5aeb8e95da660b220abadb8acdc69ae5b86dae5c7f8b91c9844d462907a1794427132de2049ad588c49c266a1c95a80851e7b4527db9dd23aa44e40acbe4011d8830c5a84f15aa72a91ca8c3c15a942bcc4123264647b91239586b51ae443526094fa35c796062a4a4c9c11a66514c411aacc8c1aa19f1967f31fbbf28aca7a98d69ae69198b49cb9cc95bd4041ec5fa8ca22175e5fa3d7da957e307fdd5af3e1b70b703f6afb123cbb8bea234cab2a82cbb9f45f90d0a2ecda50969304d890e411a932c4a7be96094438d2857ad4833d28e72fdecdadbe4ad701a39792bacaf5cdd8d5092432e5f2a2185d130548301333840677ce4a15e0d06d0e080128d8f3c9910a64792551fc9a514946bfd507be5fa3220c0e1846d3a7e36e9a29f7449a01a3f56abcfa324ab4a56a59e84d558b75c72b0324929b2c95b313739f8e2ee6572c9a378cb934b32e66094226ff9d7bc6d30130623a3dfc05491e1de7c3958dfa35c1e255d33e893403cd5ca2a0ed68fb2519443523b11d3256f62befeac296f59aee8c6722fa308db24ab94f2b497f1224f8c1779ac974515c9fab87e9125a2a722525edcf6935beb4b4c3e30e9e6a96fdb9fbc1525d79fd9ad59d40e30674d6006da782c6977d9f15882e42da4d6523f8f25491e8f254b5b70528e9d0f8f254a1fe7d19166278304d3a29a452d45240fdb08971cbb17ac3f8f25473c961c29cddc97c792240763e6b164c9c198ddcb5ee6080e2f9357e347ccd39807e291f16afc90f929f3403cb1fbb1fad5f79255e96703fdd5b792acfa32bac0e165c2008e4f6e20cab3681a49968f0993acfa991156fdbd4e92557f93dd2fa95003396651de02ca3c9628f94d7424bf993067d58f99c7922699c792236f01e598b778011c9fdc209463d7c363c9518c2f3c963099301e4b9a743058ff782c397230e6ec29e6e85ceddbd8658a39da2e756c474dee2f26b5f5c06c95bc751d69c95bd15f6ebd51e9e5c3500f50b9cec9535fcb6e16e5ad1a3bb2dc4c0ed68ff131d7cfb8788b0ee1f2160c23419a90b7b497b786bce541f53b8f8696e1d130338c17ba925c5fe5d130ebcb2c8a86593f861762185ee851b9fe56ffc50ba551ae2f8de44de4914c523a49d8e5a991a7767f918c922bfe421994ab1258abac2ed9a42499a06245ab5056a8e4ea536410ac71d40fe50c642a3553299a4ad554caa65237954aa56c2a55bfd6243efc870724d2546dca2b2ff6afc60c9d85449a9825d7df48d001d78f393291e3130f44c93487add40aed2bcc9e2ed3d1d0844da227448ef29c4c66935cbb1d32790616728c34b66807b7b5cbd9ded6bb6edddaa6b9c1c9b6f70334d7ff58f9c09285232b71b0ce2a1608192637f970f9461afb753e30799b1ea54c75dd2e270d6f9e0eda1b6d96ea2294289e72e6dd486333d74df36416664251908bc887e6ecad97fdc89bd567ef43dec47ccca7b93e1f3b92152377da6f9917cea29c7dcfa248934d0993b04893f9cb5f9126cbb2eeeb2099af83dac7dfda372a69b64fb355628b1cd4aca665d7e903505a6661b688e889d092ec76d0b730cd165925de72a297b76afd0cca5bfe59c0bedfa6216fddcf0a3968996cccbbef629232a4a49824bc69d9c7a6d8592afb881cac7f0212bedf5acf092ec0a9565af2567fd5b2efee071273c85a9f4b823f7759e070c26e4c126e9883f5b5286c935cb72e06ccb6c384dc9ff5fad92007ebdb24dbc4226d73fbcdbb9146d33eeb72d05a2b43488975592342d615e42d6b9984baee075c634796336ee2608d97a9bd2bc5419613922af7dbb3f28603355e8603ab8ff91a9fe692acfa32df95acd5c77c9e5d79599464755d478b5cb0ce3689b231f7b25f79f46d93cb74a564519acbc6ea93b7b4af5fa1a2bc5545de3c552edeca549d4ae5b9124049c95112f701a45c7fc6e2930f28e5fa93c96f224f7d55aaebbaaedb687775b752c6d9d3e79c12a742a02d6eced1186b773e9dfd79bcf319972d23970a379063f77037d268cdcad97b39fb3026671fe34dcc872f39cb3ec6eb1859e14b55ca9a32a76ec78dbe358a83d5abb1bae4a08d231c9a48265713f4c9e5831cce231752376755aa4bb97ecd9a72fd5aa3e42044510e7b4aae358a53ad5f635993bc99f1f533277943e3eb5bef67c7c1fa42628e9be8a8942d78453164686800000000e3150000201008064462b15810a5719ae93e14000e6e864c6e4c3415c8824992a2280cc2181862861000080086808111182a2b0069b489b2b05f35bcd653cf9b13d7d75e07d2645250931e000e577cedcbc50ba76f9335faffaa80e10319fbb9d42d17f8682027cb9d02aec49c0bccade7ccdb0fde0c02e299f6f55fcaea0f66efd1b536a46ef12590a1f00ccf4786ee44bca43d096dfa081c03a8af4afc3074cb0691077779a0e115e0b481f7ddc99d03e2f72279073a8c9528a6c0f0d202f28de6a640b27640b7fa5880addd2da834e8927308863eab4356c136c37c09257ad374871b46e4ae5e17fe211bc02c92328747f4980ae09caf354655a98e9318b3366d43d6615ddf2d9d1f6fc31b9a928e00e80709a1bc6f90096272efe4f11d58e7eb078bb7737fe54aa26b43425cde6c52cffa18b25f49bcbe8202d2f06967447f4f801207cd3d1b10cadc4fa5d59ec69f70d0648893b65af235598e320fcd29a23e121fef84aa1bb59475c9e48cfaeb48d4cab55e63019509f62feb72d4377a7084c4706ab15d60e0a0bd1e698bb7e550cc3b085a67f68fbba9779eec83191c3fc786f284c3180aa96388df431260c3b62793934bc37819be80b870647b3b4bf724aacf04fca71e09e1e2389a13ccf0592999432b61cfdb102dbcd7790eb93b804b7332dcca20192f9ba3bf18a83ad04e2bc9ad6489827fb2fc2091e82428a5d659bae0d5962d00efa6b67f43ab7f992177ade95ac0e6ffa2c490c8098230fabe425d912c20b65292dc06f04b5e718227f6d91f8713357926a532918854551c716df9aca939dd654dc8ed699cc69cfa1cf54ca5b0b0602c0ef6bca43e64845817f9227b6d3104e7b55191aab27df0bb37c9b3fa4dfe4d24e0cf8660e4657f709dec7ee250621694f1b0e4bd08ee091cd7ed9c1ce29c582bb43f53dc2d6c3fead2bb47ece0b5aeeb21810ad1ff0acdf1c3365fbb0ef97fa5a713351c684a1b5044fddd90e5bd13a5a8bbf7fe0edc2dceaf14f1787a60cd8e51c93f0ef3cbe81e01888e8d5cc1b7118ddd5d5af28eb322b88d5286e6da4a69f8eb525f4149463ada06dc1c647a76794c2728b7a597061492c310e7112e63560b5df76d7693d54e3ed79f1df55b8a8554e440bc6d87d3b6443593d10e872dbeb9bd990c99e398abc1b3d7cc194605317ac907cef383900a47fb55f45f7071028bf9cd9945f6373bc289f2d2fad1ffde4c5ebd05b40434d34d54984dbb040b50d183c3f62460b7caa200dc701e2022f5b19c14403cded0de19b2d8cbf70fe8ab26bace05669168b6a69328eb9df4d2ad0cc181e4e3ea2fe857052971f61a1789bfa3aea007353d5a11b6eae8e50a0617fae3fe736c9593b757984ec92a7a281cdb91d7737fa6e9c4cffbec5385d33555e8868018f509f63db48a91eb4b7f88b4b18f38c1b993aa75f4b3be8364d5c456f7beee96d64d642aeadd0f421af4279db501cf611bd9df389dfd7bfe2df3e4aef5a7be1748b7773c803474440a6ee2a3a5286cff500ecd8d508a45419b103af1eaaa9ab8e85de7e2282b73b767c837a9a159d14eff81d289115d702c1265f407e8ecaf72a18d5a28d3602aa4ecff8a60dc8802d4e70db552d30639303144ce8f70fe9c66af96d3a6866ea3870b7451b9c8ef004008c91669381dfda188d5486e2e029ee74bc679bf278ea00c8ed5762d8937345f54f05b3a0463c3a2e8dcd4ce024c5452c5b57e757d68a9a28453ab10217aacb009be226ead43355e30c6226e078220e63c2fdd0a7550bd113bdbc68b82f58cfa5de5b2705e8ad22d53ba2d090c0232c77fac02fc749a966b3da3560797ec101454e9a0cf8d60f7a1ee5b6bc12780365e9fc34b0a616a6291b681e471b1744feb5b9f2769d98723bd48c36c20185b7070c2b54bed7f803d97ed53896bc449d209acf8e56a61c1065a742d6fa53c302a7abea67f98c3fcc76185ad2d6229bc07ad60238e950d0ad75cbbe31057c70c5dc372c1b2b178814bf46f43f3092759594c1c665cdbc535b343276df343f112476840012c43b4d9f18e68a87d957e2c470e67db67186400b900e48ad993b36c09ce7b2856d6af9d7455fc9872f95e00ee3d632fa58fc415c351eb3d71347d82fd6597f18b71b5a65fba32e16227344d59197f9137d1c2d5730dbfbfeb43dfb8301fa29f5271a407c3cf5efac1a03d1d452ad1ff5b42e6d8beac2cfca98fe1aa6c638b4d1e1a63be3434aa36637cc48beb2bc7913c40a629770b36d258d287b8e2765ae7589f1a6109a58c4697e163561eb8269fa54c303fb092f0e118feb2790cbcd0b2c4d6f2aa9ac2456e63af13f3e344eca65cbe7123f266fc9dc81e09aa763d5f510494478f7551a3ba30faec546f6a4c4aabedd253f724a07b6fd50feb9697fc52d5d5a948851b2813f8392e479c99e81bedd66bc3637fc83679b6cd8113dac7a49b4e7faaa154caaffaf1ee5e95c0722895d110a3674655b6d282c6190c4997346f3ff388f17b6e480f8761acbc6fbc5f7328072554e47aa30a265dd5dcdd1c0c3eaaaee53ce24faa21840ba5237bd894d75eae50a48fc5bafbd0fe879ead58dd4073b496bdfa7cf7fe429d39b98ce5e6736b41d5212557e5ebd9ebfd54acd16b750d80c4c420bd4645fecf56470af0cc070727197146528f39ec324536d0bd36a66ad49c0b63e367171e91cb1a042a9ba30c7f49fc35eb11eb29a6d3829d957bf563e992d4d6bcbf7bc1b30994707a9e3c3baf39d4b54ad86a019602a980ed2bd3d63efa536c5f4d172e0a9c8657ad2b8a22d9bb84652b2f5fa9f3c890b6d7fdda7f153f5ec94013493aedcdd4c5805fed7fa4a47edef1852d16f79f542fccd0dabd845801803fe550923a2e7d2d669cbb83b3759c73db66e343b7bac2020d3453949bcc45eb80e36c6462f125a6f6fd2a033bc25f20ac95c4122119e832379cf11ec143bdeb6c93b14ecbc9bd4b85465175440e056ef2e93c0bae10c0fa07ecebcce386a9df9478c2a722b1aae0842d7e695012d56d5dafa257ec7ffd5a3474caf52cce753da36f9dccc26278e2c88b78d9998e7e03dc71d03f175fd1887b531feca30fcf9669169a32282bc2453e286a0dd6deacc155b7c8bd300bbb637978e274b70c25cb63af7aa7306900dfdfa45e7ddebd436baf3ee9d2fa904b2417bd676f7f6855c3c7e5fd80c6fed33baf472db14f936da8406023e111771424a2d3637ed0a84b0c9c4792828c245f905eae2d7da9a231db7a2469eb55a1c76a6875982604b843f5dcc904fde352a4bbfff504638cf3b3d0848e1f2cb89f396dfc4c97ceac4e033f2944300014295b2ed09277859e688c5687a24534f322370e907888873cd095e544f160fe17a0850854047c076256e1b3f92f973c6de0c5197e543f226e2ace78ef451084f3fb55ab803462415f9a7ef806d2b9c1d5a20e46430784aba3885947338ed509828ceeaae14402b6247b1cf418ae233d6c5884e90b34077032f9c857d45954edf99cb525fbf6c8c7a61cc43c565b92d556c245ae1bee4a357416a1a75a15111a09c0700af18310fa06c1081b9a7c5a2d25aa6c987973a06248957b2cf35ead8d83d16baee66eefb6821006ae5d453e89f6e5bbcedc9656c7d9c4513b561c2fc79be34e275c5564b28c26cb90586b30a496fd9edba1b9aa3f2b4bcac851ddd54c5a6db0dff396522668c874ed941c345b10fdfd9b782394f8008a6c2673f770f3fcc59ea9f8cffd52bc1219c30079137cf7b624c3c4db7ad4ffee57fd761b763b007030584b54daa8da7eae3a7664e06b149fe16db01fac910032efbfa5a6c7421798fb8e4533329418d5e66aef639ffbefc113dc49e9ac9bc1c3e941470fcc5818cb45438607ce75f19188af23eabf46076d6549449068eb890e7b241c250190d417a2fa2385bed3fb136c9e84ca7db7b502a9ee198339ad347de0eb2298211fd8b50272fe622f70fcf0537d9a8ebbc818993c6a1830ea649461647acc659bda021ad50853a4199631f883fe683df9210c0d89e2afeac95483e68edefcdb8cae6b37661d012f30529cc69d44cba152dc093e7f1ddfcc4188b10630045697469dabcb9ec3a1ab6c1b9bcb363a63ce0c7435a011b7d14dde64491dd713d7fc55ff02b0f1e70da77ed1748e5af8516a8255fcdc531c0736056fa656d25fec05972a5f204460d2f432b90bf899e0de5285a6f7b73f75e0bb06106995b63323764673783207919c0debc2370bf76a8541580d4377373f75f9a77b44352b8fb301c72dba7ac5d617c69d852d4d4b6dbe8c903f2dfcb145a17d0282d002462fbb4a1d89132af60dd9c6c7af17a7a8ba3e39a48a890abf6953026dcc0eaebc545dcfb4f4f3f8d9444db769d22f4cb10f6847325c0e3a355e5dc008e7555160fa5674da1c6ed760eb738083a4f649c7883f50b7902e9b8e3fa5556a76b5193c441edd2e22b174ef44dca7aaa435227840e5218ed99160bc074456e79ff26469d0b340e60780c3858aa863426511b6ffb3cedadac7b2721aca0c9e3622ed9ece8f54cc752921ed539663e220b16a81cf6a758d19c4f807e2a4817d3dc06d7346c80515d659f0098ffb80481a0977a1d907c5c1ce03892f388bfb48668735a3429e07c7ad015d11cd3cf8b4917d0202ab262743775f7edc58eb6fcc896cd30c987322ab14ca9a01fd20ca7938d4542122f8c2225ac90581c038c2205f465622404dbaf03e3597e944663b0566d8f04510be903450e0410898e1a6d0c60c39a8ddfce730ce689fd023a9135ce801fdc96fdd3394ded29a87b834c724afa55a41e2b965695b3a52f453c7d0db88687864b0fc7abaf688e37fefdeab4dc1d3983462abf6d5e3155865108d590c9eda533077aba252905619d4e9c7324a4d6ff2e7fc17dde39c71ed1f04531d7349fbefdc1ca7d994ba78f92432a250c2963732f94705f2140dc53c81bcf52e2aaa0a571c0845c647bbdf8943080a794c06dfc27d6068c82fd090c6836486e6a3cb2661371ffbc1694a8e310dd753866b9e68c646665f0c9d402ac4376dd4810cfc29dba08142ba769660b477926c1c536d8fddbf2f25dd0c80cabb0f27189b09e5fe230b7d4d08f8787aa9ebc0989e1144b15086b07c71bc49111e72a046cee89f974dc3420063385a684aa0c008446f678cbece3170b4bb6b1d70953aa90297daf3a0a172cf5c5da915fa2608dfe64cbb3cca9db2575b27d37052a45f7de6ed739e928a744a98d450d6b207fb900e4ac0fc3f725bc6d50d7298bed17ba7601c247f9e6492f13210a795ecf21dac822feef80f4bf07c7e0a6099e7248691090a0c3dd034939338f26baecd27ffe3a9205d211d40df41b99c8ccd60d0efd80addc8055e22253b6151f8f942d4d803dc16c905ab2fe45d6184a0d6616dc5d67ef66d4b0a725046c57baf55b81526c9d18ad7744057a9e01fa93d8cc4ecca650cfa853ec383e801ce07cdd0b07cdebec81f7ac838c30838d9223f03c6170e4dc2e6e754ee09ec37ad1d1cb9ead205b1d41f496aed425d2d136e74e4f0463ef90387b68f9e291f6cc31672e4d38c1b5949e47184ae252d3fd36c97ca35422cb16b8d092a25bc11952d6db73066706be9b78835d668f1ff2d8be29d892db5a95e7c3cc356f1109d6814369214c30874609ed148e3236a9fdc1a6a2a2b2525962de9a5d82f32404125158adf58d852e3ea3e74a3da276e28130b3e208ed1aec70b3379877f04528c3891d6f6eb28e86bfc19574172d7552e6fb019c3c0ef91e06f75056c03bedb037adc232e9b24e83a083c13f74c483f8b6d7256d01e88cdafba930cabf7d25b5df996a045b70282ed921821f96d61df94580ecb30483e27853d4797b7e343f4e33832b782b023adac382a3d1eef61959a5fc393cd04c5f7a303f37a1644850df503ba1953f4ef4927067777eeaad8f19d617e12805685f52709b07874525d022ba9bd3137ac9b2d1823870992737fa7275f36af62f3a043618d6cccba4831cc1391c95fac53c43fdeacdf708a2b28a3c4d6c225137dd2d78829d5b1c77f4fcb619eb1361b99a0278fbd00eac322cf1b2293784ffc7a50bd536b4e024399e8561f806c1475b975d7335b9533d0f18b22b7ed2c69a1ca0bac6e59cead19535a4cf0385545e82f7fd034727a7d6da70e0380278495165dffea2e0716dd95912d1b2bba4408c13e2ad2f552b769c99fb91fa075138a7648bebf586e8c10ade795619e546ccd5a48035b9bdba345fdf162fa7e0a1611439f8d60f8b8c55ae5d87b135c7e046d3b80e789611df554cdf21f2c3912450525c7d31d5dfdff0f4451a5a9ea95440c9ba6f653e84d1a7b3a8617a12c0334eda026332fbe4d9c9dd864d55e5f28e98a566e49812bbbcb124703c87d0bbf117b7966f230972d8f947c6fead6d836a5229d375ff1fff59db95b4562f2929c10bd63092889ac53d24d03a6c4ff7e740f04b555f4d32a89fa0dd81421aec1574987fcf53dd4f180cee78bace985865868525c106e47a43208a43f58dcccfd0fa80736b3e325a42edf9bd817587e4a98ac008ccc5306328fdee421a379803fa75e5223db6ab159d77022c628ebf53213767c19fb9bf4b251f36e3c98552d1d5c1f9de6f915e3e51a475b58ebeb7b85de7bf1085ed34b20514e4e6cfd0b52ea55c34611554ce09c684b2017646ebf5987d710aabd7a401506838dc51b02d3e887611af908d31cb3bba7bba4d3f79dd6b9a84d3b88c603d81698eff3c1f45b2594159d09aab4cd50d8557e1a831a55f466c94056426a5fdfe4c88e22b49a957600be5f0909c017a11388c79968c45682bc15f6d985355fc44443067bfe380504271fc24f407e961a420ca4305796f21f5facc68072cb170282bddd0d648461259bd33ec60eff070204f447a488ca34271d46751f8625d3a4e5dd8d0ced800e86582341168b9a571ab6440e9ae1eaa9ccf9e1c75d462e7000587485e9171fc5e0d58ddb582273fc02c11f8952dcbf6fa209e23f1101f6fa6b24f5a9065d34d54a78fec09d54c0f44340188017625348508c59e809a73e92ff516ebd77731254d9af9a9dfd6ee5ad2fd0e9fa01d04b06d8827e6080dbf0d0844967d480ec9d1c920a4cdeb5b28f8a9d6d9ca5d5989317ca2f66aef8bb3100b8df57fcf0d104b768f1efa484f5b92c7ef9f2910e256b1d7a14f667f416533809f7c1dc84a9aae53559b4990d486cf80ceb890376115dada0ef929ade1b64dfeaea919059c01ffb5416f2d3fb46dcfd6fa795f9699f0610e44fb31a994544bba23b9e815ec1ed454d4ee1f1e5069e77a2664d8a8d9de28452289d3af7476c43909b461ff2ec63c17791dbb1e926fda0a5221c8623be1c09ec07ced808cc5b4d23c1eee2f04c777464814d742ba2cd022b00ddeca24a6e454a1e578ffb58a56cf0dad3a783686e7db24f1baffd0307eff538abd0588ab4007517cb411dee4244c67fb9acf48152c51f36b1f8b82ad8c4d6875b4030f2234e0852aaf0369af967fe3dca05526f5a94e6b06269fecbbc2e3dff3f112700ff84403c067f62e162968474f25e72e866e0fd6511694a0242be4b8a9b95a9ef8e10423c3ae438e681ca153890f98e1018010955c69894083faff18ad4f21fd3693e99da150df13ca53d33be3e489190e91ec5a458bc5a41c1a6ffc7b2537bd02ede4b0a769f1ad9490f6e08a80d670de4fd0ed43bb1d0fe88644fd7e986d96188b38b88f4d6d07ccbd3d5ae539e67aa77874ecf6f7f04743ddc36019bb01900501dfa5329d42cb84fe209e228b78fdb3dcaeb9f947f547b0614f7137e3d901164a6e64a5bd6ac84fcb18a40b2b669b276e961b943f156619fb2ec970295fe189f5ff3659ad111a7c12291b39ff5c0b6609faa8473f57bf6ad7c1d239184c7ce258d4abdb807269465f438ff69cab2d2e16409e6d4d9065895e7c7a3b043e2ffeb981777a9afd8e1ca5251f46f7b7ba58ae8f7fe29a28b18b188e484b2bc194d1ac438a1c5f9e72be7b580d92a256631f99886a422aa8d5048db469ea64bd52fa58d68b6f7f8f4c4d9afe3999e27c0e811e0c2a929f2f8135e18e3fa9202b263493a4c25c58292ea66ff560ab2dbf224356abc25a9beba1cf15609069162966afc24ad14836590a89220868f23300857ad7f4c060ac8a5447ed75986a156ae88f1045ec0310df316f3e8396bf6629c819428c1da506dedc584bfb94b3fc2aa1648ae56eadc8dc7a8e0e3d11329c4a69e49adcc458726c023e5141fe8a236771a3df3ac3038fda64abbb90216982a1f4a1ca081b5506ac36b84b75fc5a41fe0280deb3cbb4d8bf3944de04fae3553d92ac910e69ee4e3fa19b11f04cf3344d24fff1794c1ebb3e8d14fc22dbb20f4ae239212e35198a3059d3687c9c73de8fc8a978b456bd8f4019fc12474f6f2117218a782a4b9b2417027616ced63b6e6f0e9d9f4830db8699f01f54205923a6fa9472a54882cbb1cd84e5b68a9f4b004d03d7e05dc0050376f86e0166d74de3d0d919aa20bf1102385b4c8bf7acd6106383f0b006f8b5caa1cf7ca4f74369dd807e1de114239b3fd2f06dd137ed1861e8cf2dde3d247ccf968b45b859ae41ca6845007d7642dde3da7a4ee01fee8c4e939452f744d6a4ca1e0032e37efe9f61ac0523a094287f319cc8ad9181c0c5d90ee51550f0f610a2a051e0717593fda0df112c7867d56efc7e0e104c06c4c05eed7f87a3999e27922d0af9c49931f12db13bf328d4015cdafb8b2c830ed600d4739284da0f3071ec0444d8ffd6a159dbc239539d019c5d01108d9b68a517abdc247d3f370ef2043c7b81bdf9377cf36d0c6dd70550f99fa49b48807d67cb46c0725ec5620fc9cf3c1dd5ba35d2222bdf1e0165d219d7175a5bccd8c72c1a32cf64d2c1ce8e8ac2873cca65fa673671f2a3692393b9fcc7f52bce821382aa7757812192ed2a4da95cf5fc6c2ade860ef6d91c71b0d8f65e1457f90cb73338250b41321f37e76b2cddf5258743b88cb6ae4ba63f3b7e93b29aef4111c11571e5501ce482e559effadc5a2e7200e0b8b72f786d12e1189de81715315e688106fe017ec8ad7bff561e810d244bf4b9d4ea03aba66039da8f25889a3f7e09f71a3dd95bbffa478d347c04855223a83d8e34fe6c357203cbd9e98edd2c9c24c06e85b3cb6078ed5518fc689fe8d038c368ed38f220147f8b53d4aeb2773e1581902e9ee4027a773a48751dd457b11d25089f5bfedd7c68b825e8aa3d1d3880f5c09c507c80829d791f0a66e0664afcda5f3778dcfa565e01fbd2567da5e3ca1402d9a2c2f31e16a78c5139b87e239dfa093465073d6d5e8c88a82a17160c7437b45b3c960f148a2acf11abfa5bf1601a3973b5c2928048d76b1ada1997d5f0359546e81673955e48115f72bd8e2761cc66aa7cc1ec09df8954df16e88a745e195d654a552e821b473ee09c453cb426c0f7e63684ff8f7b4336d92ce0929d351f4722820298eabdaeab7a957080eb9c1af6148efa5698bdc3287d39f4da80100cc54f7171b0a2db9cb6509aa22f65fe705a98eca45d32084479269ad653d696fb54e4165d4b85bf358a7834a835f0795dbe8567acdaaae4bce2c82962ec2f736a892a9cd01c19e9a528cc169b349dff236c2c4141add351125fb8e8af9d0bb1d38d3162129c6194e60e68142dac14ee1c0adf43fac8658f35ce3f83b3208ef8018e59130491c564aa27f89eec90edaea60bd1d40ef94565e4a6257c4e95542ac464de63bdc7c9e028384fd18d23c2870a1952acab767e20edb3a568ad12ff388b8a72a1a0ff10440b99c49076a497b0579853e6fcdcc12bff8ea11275501672097030b88a7003816bcad73a4ddc530d10a1ca2a24dfc22e384bcc82b695ec420d64e5c196b27e512253cc0a1a3b2c39f9da4f0d78f1747f3ad7a490bffa605983a297e5bbf57804405976e186cc0ec458fb73ae990b68bc2d430cae704b14f35df1f08f6d5602bdcdf89486774089589ab83d5028d699582b309d4e35f91c3ab7d9f2617e2af3c62ad765faa58299a2badf97d25ee3df91be278fdd6e18486beb7ddd28fd96d317cdc9bd7a223844de9c7386c8042018d264804187d41d3286fa5393b3547a0f217d2ecc37fd8da02bc4f1fc0c2ea312de33b4489e647b1d3aa70a7e2aec313514e7a0f9582b04c6dc91bfc3d0e227de83c3491250e992303352064a167dbd2536078ecf5f82fa0b25a21bbff464202f2cfcd5b2e62f52241c0896506829c55403506ddd2fc1803490f1e9c678c0f67e2d8dad7e20b209552a55bb72d766439b1a81015167a471fc439681c18ac226cf69daa871aeaa401718bded1fb8f05903f99aa706420a1e57d1017c6251840cdfa8417f71f6a1c8363b3aead9cb7f9ff671bc16f52edb7ca9c5cede0ed61b2bbd89b38ac2c8425bc50d16b54b97c0dbd4686b4b241fb95b9c95ee352281d7228d14afb355b20ebf5b4a7e8350d6098419223ea4bcd26c926da11847516957cee6c01b30f251032c7ad1c612e0700b95a0e4215ed63d375eeca3658b2f291a9dd0a9db7d9d9aef4c95ad32dbcf8f4e3c6fadc4e2bfd275440533dc806f8ff77cdfa250d61386a573f76d961aaf5f9c2d97dd428bed692b026be52eef695e1227add2b4dd742a91421c9737ac83940811ea4610f9d39df86c5da771a494ffcb1d6a125f4aed4814cf25c3d0c4f2429ad03b443e5da43091741607419847cfafcffd3e67e54000c17c8f69de09da900fb42e402c1206b87e2a117c8bb0be8ee30d1aeaad14a3c6152e94d8a6e4554b53ed87971e7e3214138e413018ef64398607d7720b05d3838d6f1d50dbd283416969c95749ca2c62acc67ea3eb178402175351250873afcfcb3b958356027733eaa6d5ace2087250538c46b80706ff1e59374c983485030e1a168345b0201b17ccceb2095781c9a084fbd224ea2d22e6d48504b8403ad66946c489896d47697e730a979ff80c424fbfb7d125881e11acb6b593148cac656d6432299a5abcdbf8bf3a2683a3f435df9097e319e6c7f72d6be20f307a00f1a3233a4ea0842a4e3ce14f3cb06684717c8aeb9506f0f37fd927691143a6998fa9480c466e1f1508ac6ee2492d826e429a291045205424e80658214fef0cea34d33c0e50ac387f55f1724d1409ec8f402d05909b1b56a2694106bc984b7fcbbfc389fcf0eacd3709e71ed00122d082de6c2651774f04667ce5f8b9f8190dcd211c8d2c8ce8806efd01fbf296677e8cc195e8c11bd20a568b2700927815bf6754e0588e3a4ab0b4d3525f47da6c3a900e0f99f1dc4c6e25c5682588abd0f16835451615980f49beb3fd1b84d1e122e6a8b3f6cef372b03532f81ff59d9f79aa08ba38f0d0281fe4079806b7728559ddde5dcd29fe661acb96486f7853c042c55b38a926ba01310bd1706ea46d645ad3840c7c081c912af152af167efb63d425dfd7bb8668a9e1fccf5038d0155e8e7547f3fac131a11fefbb3c4bbcb3a037fe329499cb5217080a38f9059d8542562872a0b86946d7ef31f8d852c77cc2a1c3ea2d5dd8b626e9bf53d4ec627295003b9e6be0cb09c6037e6f0c61f6dac7efed1484730c9e3b0469b7521f4755a4ea4df946ceaf6ded1243b921d3d1d65b913846ede9a56094aa8f5ea40958e74fda531668fe16597bcefcf65beeafe8639af771e2dbe40da67bee08ad7939b8d11d97474b57fdcbbf053e63ef5f8d90d3d3b43c1bdcf64ba4ff1f0ab83bc5d44a4ce344a4b574a21efca9a7211d922333511ac622ff5c4ee7b925c72c215da58bc11073eb0e4a265530036450128322761f1aec49bd3d864116000473c63c7a063c96bdb2960f6d07890454ea202d4befe101c3f2703d07d8c0a580455060084580690ef7340f0905636342c10a902fa48680805a51570524f30d0d4216c1e92196fe6b4df934c445d72ded16a0b8cbbfc40d9b8e6fe5dd5a9cab408ae9c6cd8fda86a089fc2db0ecaaf223f718cd80b5bd9c93120028ab72ca4f7378c291faeb2359bcafad76dc4d895cc16c3605539cdd0e7d7436c7631edef085490b13dfa002f11df3fe713353cfb98e330fc18273db849d6243bca0864b127838fb02361e0ca48bda599b6ff8067c26689310beb2b9cf6a311c1a12aa1b562c291be3d978f46b0f89e25b8a829323c5e218ff5cdf1900773bd893160fa6edb9caee94e0b360cdf484c4f61e6aea6ffa4587c8876961391afaa9e619763849ae52cce88c3fb8daaea91e6a4f95504ec2e0e23b1b66371b1bd692d182f6258ceaa1fbbab5f1d7e8abd4efcf9c89d4fabf74784887079849ee9f0d00af14be20f3870fa8e5bf899563a83f6ac5219c4ae293cc740a45176278a4c9ecdd2dd0fc72c59e6b5c27eb430b0f2bb594fca8c5f9429b2d653ea24d2bfbbea90d9a5a23d1b9d4dc35099193b0863da910fa0d19400c62a46679d2ae9fbf100ce898db248feb41cda5fa3c4e9fe043e6efc184cfee0d81d627f90cef527432f9cf9213dd50f3c976951dcac92bd335f91366336cb2eb24f19b2ad42fe13948815e695b092464fe2bb39a858f7ab364f4f29f5833ce3650f431ecdf366fe2030ac3c5e817969b2fcdfd27393a50530ebfe13dabd4de86fb93d61d3ac1cefe37c09834155f3e985e62264cf9ee123c64afb85df8c3169600d93c608c9b3efdf5a93218a5480287606f29c90b0cb9add26ecb2be81a4eac976e3fac12836ae49ee7c67897a5db7ab25874af7d39dd17bfadf20931429acdbe15df3340477d5c3f801112054d1c676547a74db918317c4f83634a6db855228330504116acfef47b00376d3b1db78b87870049ce7848b90c2048abd6ca790115aac4f947b93dd29a18df9db0c29dcbfa4ae1b2a6b8623c32fb0b45845b40c26868c1facc2c95fb5b8cc623697041cfff66fa1f1f6250e76b2905387c4106d3041cff48b43d5fafd0dc7b8d3f55abf30820772ea75d903e51adefc129f6db6b34e876b2e5593a9cf5b32a993b2cd1fbc29567e020b65fad62d2fd0e7d660f948d79d92b69f7d23065c744c31f5f2b76d2c24cc92a973c7aac841033d3aa0cae2508ed4607276aa6c811a74229e7d83dc61898990c6310da62e8e7dc8c30ae38048bd0d40351e4793dc53a26a972b77ba33ad154cc58034122c72f7e29ea0e11660e1879e8b634a8f953ce17bc6c43e9a386f3afcbc43f0cdbc4ade9febe4e64bb08655de2d75f64d9566a8461f928dfb9e56373326377443c040f20d1cc6ed2c68308accc379460ff66ff10de568ce4ead08b67681584820742c136809c4fb0784bd1f34f2fb689fbd9d1ec643ee72131f1007f61fb1bcd74c976be84c8cba617a500f23797fdeec1f0d20facc9e739344b612ef7ca24aa35c74a9a74e6708337388b88cdaf74d3c5633aaffb59e1cb3147bbe2f046de3bfbffe46e3f0b44f493f0a2506e13c964e7b4e25623d9e30b22e5219c960579e800b1ffde715e68054afca5edd5f68cd48b629c8d6b81672f80f1e4b70b8daa07537b0e57927ed8e9b541f6d6b6b5cb8bc9a1fcd5897878b303631aa2b81ad344de31f1605013b3d7e4c074bc0a708e214d9d6e8ccdf62331ad87f08ca97edf713d8fe6cebfabc7e8a32a7621d1649e3fc30eb1d939b3aa4c5329df22add6ae5e4f48573b518658bf3afb2df3614d4aef1a5a0eb9fbc2e3023c5db7ea304c8cc6b130584d9b75ee66cdc58ffa69435871adf072f71b09a6290ca430358ac05abae54a1cf857e7a10f5583c8ae9989652e5174408aee9ff54ed5c41c8e6df7c0386dfbf9f528c5a1b7e43914003d7b319ff29716ab8c3afeb3b136fedde7a3af587301bbf4c7c0751aec048352713289f3b2434be21ac50641cdc7751b2965f204184d87196412091689f0300809f2b052cdf02497cc5f20aa27d6517e19b58ee70a7594258a7f37299848db19bc11782c7fa870452f4642e614b7d7488b8654ac92ae835d6c9ecb4464cf81e775fb6a11520500b618cffc068987adb75885b7fa5d08c1bcbb24ca6304ff1fa818748d7b5d18e1009b2c16f2710b96a89643a2bd665600c88c8859cacd4081053af5b0bcce05d0889f28250168c222cc7335c32f5f134d4dc19164208f56babb5f240deeb9d29354c0ab1b60a211037e9137ffc5939e0aab3c6fea13aef8830f09b59b0a128c4f1a49833eab6debceea2b1095636b9fb60863faf9be8d884ae048fb8060ba170d962e7e9a1b8ad3fc76f684da54dd213354229d9d17c6e8bede2c53377ab5a194e5ab70f9d0ea3fa788b0882f4f4f1ecccce27543f21e6001d164d572070346804d587143b71c0783dc17fd5145ff4ed29ce07f8d429edb88cc8554d899d017e39bb151747a5d564be7db80ee37902ab2219d55cc9b2262f160c2dfca4d9729df3e180bbd9bddac9803309975201cc04c478a719b2d830c8a406a7a4f12a76ece1b88a227f08d92dc578303c61b91f07ff1c8adbada2f210bbb1607cb7adc516b278043c9cb76096f3dd5d669afc6ba0cd4bc0af312e7fc8b7476b2fa608df4e2d0b3e809bb01b18457f7bb3ce9cdce20f8a4f4e2831a9b00bd1fc59d428dfd53aff99e34927dea257396f28df11789cb5c6fff3636b1ac3e86bf42ff7e97e3b743a6192ea735b3868cc030506cce8012c7b5a2abdd5cc5ec3c34c3f00cec380cc309465d520d6d7d562d5a73454ae2b0caeb1775e2b9d526aaa6a805b95236d8105c691d6704049f9485d23951408863b40dff01da47a2f8d3939ca5fc292bcc98446cddd5ce4bc60499d3d41decb2849c60c8e19fe621012d9eac1e186879e3f4a19a1a7e21f9c5723ad5d62bf9be43dd2be305fe0d64a0a222c4b4db99f4056cf660c767d0d86fdc35f645e95f1a0ee64c07b670762bce2c611bd82f29fb0c344e81594d10dc917b9ae19eb2f42afaaa6050116613ec95c20271b90790594c9f33fde439ca25ea05c17c55f592528c8de077970f72a26c1ad9ab30b272979ea57cb74050e7c8d18738934ae581757440096ea0f71a3b83feb0998a0e7b7e41fc56ca26e23f9be3075b2b1ddc2361236105e084b4ee9907ad0b1697691d072335462c353accb16f13cd6af9ac61c97ef4daa2838a57be8a598b927e7e6e05c76b9b16052e1062d3dada0c3e037b24566e18b3990293fe6b6fdd4219e677c270d5e96af6516c7906963da9fcdeb239da77ad1d74c4962abf9b47eea4ce7a2dbccac47565d866058b547102d0fd3030b1faec649c38418b97615b4a78f839f38eadbade053e374be784ef8c7d39a54e561b063574cec0f0100c8ff477d54025b4368fb4b047261f1e7422162d94ace15a0c7b28fc3ffc317aa6fa1b3725d9a540fb622ebc7c6ec022aca2270d38e599a352e4d661bd14340e28f18c8c2d4c815cad4ebbdc3b419b88745c4d1887bccaeb06dad9959f47b911b1ae5a8c3ea74d185bdc6d7c20ab84b97883191acaca0e1c575316f6b712bff32fc687a4e09e80a70f3909fdb2e8be2c67d6e817cc2f6e2760e173b3514f81fb83c030c74a53e2c9795d1361186b06b8671ad0233783bb54cc5c9d0b7d25b9292e22f8c3feb53e60e4696d2769f88933a4de499efb30f11bc54dd5b4f9b1f0653fd62a48b779adccf7f015e72060c1775da3c87408c58c9413963fa325c9c8dc6031e06321f6212ec364479a14f2697c1c6af22c1a247b07784cacededc2f78708a0c283557907e3c0ef064d419326809bd3cc779bb5468d9cb27569f64a51dfc92479cf5f8bc691675827ac4c949d1f160e5ce77842e2d73cfc020854da830c28315703e5f6d5f93047a2d9300415db5482a562307bca699f1775d36afad1fbd40bd56445fa9599a57fcef074f2b5869223d7cf7abc222ae0d444216e1d1d79a2bd2f3ae97108930404f820885bfc75239a53f0f44bdd611b5fc44492dceb35baa953f4afb4a38a6e01077668128afe8aace974254083bfc6852980c84db8f4b3907f76b671d40fb664218c8ec8776105250a1bd920c8703d9ccf6a516f1c4d50470fc9026dbd572ae73185930b14a22386e24f3f64fa8bd192ae5c5eb5cd4d9af47bad6dc65381cc83e5382933d91740b0529ccbebfc1f4f0082305c32e09e6edf0f1081a19118694190e24d3775f5074e2609f4433d4cb501fcc0f41af890359d35b2dba2067aa800158ad956bd4aef39f6398e3332e9b82ed6becd578faff3005e0655a3985e08adb8d8de88239c1073ba30bfb25dcdcdb4b6bb03fc4fd1766718848c7e95cfa087b711f370c30bd1938248e950eeaf1bd005228673c1a88d1f4f76b459833bc26cc9b99eef94dd12fdd45ea2a209f4d79cb30f311cf92fd26f57d56f0c7955b7cd83b1896b280b313f144e7898f2849828cb9531fad8b4878bb8e2a939bf90d160fb4cc063779703ede1002c45a52b5957803d923f2b722037ec126c5658a2cacf7288aa176a40843d33c533d54cbe951c81f0a95a23fec7ae9ce063565744b02d0e5ab34dfb06b2654dccbc2e4549c2de9adf390901ff66a70879df0cb2885dfbd724e151404b27f75ae7f86bd59d57c70b0396115f54c3e30669bd44f537a1f39083628ff8acf63246b0538851a9bb174c10e89b7b24127b2b7dca3e9302881369111f8e12e3bb56c8a80a7f4729fdeca7492beb363219ccc1c05e9bbc288f84d414ec954ff42dd30f6f7bc87614fa781f4bba2f394c0e2438c395d29ed85dcc4924aa4e24bdc8f3502e0c31d48078fe0dcef7d8828a859d95e88ad069d01f149baddfdd0778e0257c6619bd8e268453a330be071909ad98fe5e539b7d971da4f020248f0971b9e0f85d85d13473e37b29e025f4561dd78654802710efe372ca1f9b5feba23a80ff6327c1ca426b6b12cccc8da0fad5183470530b1f1c7196f2896329d25f0f64273ee220c9c416cc4349c0da98fe85035a05472ebf524fcc5f2e6dc12587c474c43590338892d3a791c200e9d5033a2fef0b20d79bde58d5d2f1e87b4c41c6025eb313a21178c0c2ad7a9aacf3aeb2c3d06600bababcc4a63cd22c50e7f6810884b6aa3b8003b0ff1bced2f0bdb516de4c5bf061ef29a0e83cae93dc21b909ad9155b97ace819e733e12ba523ae6c31e48722af041f07a919d43d06b9fab1f9399b913f9d20925e3df98baa6db00f876092b4e9e610b8fa05ac2b023de54e246bb766cb0d80e01782726081338257388d9b8ecd1c66a4b4efbe87704834c68dc908a033081ac4d190ff8cac7403bc20e12de1aab0b549c8b31314243a173721439c02aede1498bc63984aeb5b502187cd09ee0c52604d29be6f5b02251816ac13073cac4a6d5775a34e8781cf1a19429b27cb2ec5f12b90ecb87c37dfab05da0faad252e89d664cf917b89162d63307a8c8ef320abaf004bae7460090be3c3a86eef761ab08ac6b1c611c9069161ac210c7c074d401ee5d4f02b3e2e19affa7e9dbe688477f74dda6aa0d4b8697999d7dc8e4eed202c6c983246d411c060013581f79106c55ac3b50fbf0c1865a306214f8d31fdbbb76caf5e88a78c733fd9e10deb02dd983ea188bdfcd32462ba0f984761c6bc29bfe6469f579d008677d9334ed064321f16ad70d42f509eae246c4cffe8a5bf5dc2d171fa25091922eda5de00fbf5adc24bad18c26c094c5f4307a3c8560f8e6382214818523c28799e0298e081aebb629e1884071e7bed2aa22ec292e09d7b9e170c460419fcae2d27e20bce60f25860b479a359688464751460b5b4be548b7563aa3f9a6f1e3b67d2814a143cf0c52e35125598993d718319e9e56eec0a9b72354902a781f7e105fb68a47a9b2ea53976f933d297a463c2e2885370d6b004a46d6c5eaac3ee2c74b4215339a6f85fe41e424acfc4fb756b15fa85f76039b46cb45f5a660ba2a071909e86d33fd6bcd70ed61fa4b95cebd5bd29e3a4e75f31d41c2cbb60e9ad1a300b9c889ba2abca568ea60dd1941aa88ca23fe8005356e7f66dbe088d3dea09232bafd7570f17b1acbf0e358893b54cfc36f03509ac887ce5f4ac35e0c98dacb48640ed1a9023c7c2685ba8dea7892d2c133353b1ec7ad4e243a6cb9ca56d6dc06c16207b3aecc5240a18fbd0091d93511680451dde121db243c7128a2e8c1f204007c650dd20b46cb7ee2b8d04a4688664b299e3789e603d0ca70db33636353ee770f00c5c145fae0856b44084618d72fee51927bc4628c4d0e4a4cb50162be8ad7c19e6447b1a3ec30f93258112b20ccb2a76e2827c5077aea8ef0fd0f8311d80f0e5285af6d877b702f541bad9293e987ec23e472db62a80f4673f29899f6e701d36d1823944abe37ee30283dcf23c0720cb5d1795eb64df267f63dd9b3beb1be7074806850cad4315c43ad9900082de85be7c0fe8195c8596e0f2c3c589979492fcf9006f180db286f8912625782bf469d2da4bee4fdf48a02884bc4010ece7c939fbdd21255775a0b8f3c1bf4222c1fda1b46b49e1867ce2d6921f526a73e764daf8aaf388691f017d5710273666141fc7cc86aaf8f38281f629735a99755adec85652f1e3e068405a09030fa01d48f7b61b3ab45174d7f67188507b29d98cf383dd92ff0b468cd8ed9af0ed001c059616c47bbad96ab31057dc24767862fcec3b1363151b5539bd872e007f8730199172bab22aa7cb0b1a4245ea08c2b2252afde8b1878f5d04ed340ba8ad662548a90d7f99ecd6d7cf92d67b098c22389d8a580f6e092070cbf958b713ce7407e8e3ffc0999252a9ee6bb6cfd883c7d252d74519ef2344622e413284f8b6d271f8ffd63d56b38ab5a4f572c8f3afdf66cbf52ee937d7168e72e2478d606b96369779c5cd9e4835a8d94fd01f4cd87b35658eab31163ad7ceb9ce4920d8bdb24f836801c10d6104bd848098efd777975715c3280fc3c762e9e7e465b7e022140f4706a31f9fbf8b3c51f392700171ff3f498d340c23f62eca8a882a1425fc3fe8b5dd909a78ddf9c0bef279c16cbf3c269d34a7dcd716e82df9d62b284e1a4f5f0a6ed4bdb936737a74c9ad4d72f2c66da7541b8b2b41cbe13315502ce9277dc84430c7acd9e95880768489eb098ce80d0f5d6b84b33e482496d9b24cd00c89e19677fb95f4a8ab969a3da9bc1c8fb6903597bb0780d48ea1de0fc4ef06bf19fe653ae17c97a18709b88d3bb0ef92cec05cc9f5379c76b5e7e781160344e9151d96f4aa224e574f105a51c58a1b3f1cb2b06cc09cc5a60d5ce380e4e676875e2d25920efbea035e4a0c85224ca80b1c4fb1f1a0f2ee49dfafd8c0624fb586aa06fcb60e6dfc189801695498ff208b9ca884c16e1493e44e90a4d64c9175c5a6c671a7645e9275bf3fe5471e34fc3d51db1d7c036a154fb7db4416ef83a7e4df4013a6f6f4612a4484e091856bdf87b3e69d357f9c0494b57b7ed42ea847b02923fd87af429b53173c15361f1de05e037f7c709e2f2b69fc195d27203a41515f863037db6751f96eb7f9218b5ae2afa6cbb07d92405f3ca6acf04916da385322129bce3f0416862273124a8d9d1aa56d11b07e1aae0a0887090484bcbd1e5a21d914782885363004539b6f06e5cc9e3417177866e5a9a1e2f54378cbdd7de662029d025b5cbd2d0f66cc166d1e9d9c76e8a77ac9f7754a8535d83f3ccefea26f410360230f20a5c43b91afe5161cf54c841f10069297fb13014efd3cadae75b7345b1c26b65080c3de891a62c59bfc3fe52699cb711d5bda78db832034a7cd227b1df93d9a06c85c836c6f94c29648b72a4bc48b30620f17b2d896054940be2a0c1d2b0078c567f7f145c58f83b5a8e2d3feb1163efd57aa75f950f18fc3bddb6317f97c95ac1813073483cec192adb397b33dc9cbc546b1feabd02a17d824433887c8d44f5f1b2b5807e1b679fcf74ffbc75abb1bb0548253939c2cdc719f15156b41498d4e894091ab1729a61cea0f7485773e33010d8047990a0dc65b874f56b314807572258310ed02f4a7618816e2d847092f29e68c9376ff06fde7afffb90b7c3e6e8819c9e9fa28e51563148d155e331e416303447406e0c6e1b822b3d6bb4022b35422874f654f7a119813ccfe751a41e1066073710fa661681099940ff9c44058c8b88b3778f4652de8e989aff5a03f83ccbb18e906d25d020ce3c9f680d1503050ea7b1bdbc6dc2c92b9da609ec09038d38cfd708ea7209bf6163a7b7629a714f08fe199cddf999fa2986e39501d89712063681e14de1b969b70f7581fa7927671fad6bf11d766d8e4c849e44d9564f95d0cd743bf3190c82c80e437d73c85be4f073e72516ef38792e362a5680acef0d96f13d29e44751bebd43b9d4f1aea49882521cf98fbf61babafedf15c64ed5baf3ffcafcaf19ea4215cd59a0c2f353ec4a22c269b8bcba280cce2d073d9c3be4475865de28081c8d0b29e8dc79bd26e374bb4ef3311d5fd7789cae2b691a7bc7f51a8fefe28a66e374be46f37141efdd318e2ec97ab5f7f873e0b965962d784ce14a7e02d3642a62653f72c6b223161d60e10c0ba7b1728eb573ac3861c911d61db0ec106b075839c20a3ae5c2da910b7cdd70e1176563d1368eb2e1e81ba3d910ad4dd16f8afee6e81b44b559948da3d83ceae61725df54d6c7e194955409c5d807d88952d1a1782914498802eda4fe33cc84b35d6833e76cbce050df26b2a7cf7cfa620bb87dd16ef0f9e054bdbdcb83d0d757c2b1469ab52804e3da20994dd4c5867fc23135c7d77dc581f10ba1aaad1ac94668570e44ed08f56d28a16c8d297953a9b3222efbd604f4974fe409c720ae8b89421101839c551910c665228d10fb4cbe975840738ab2da185a38de47fd54ab2509be67bcba95f355559907dc158837acc8e986a33a0e9e45cfa476f924c8414de721cd8b6e192f5fec13260fdfac359dcee50bccf396fd870f0d2de49dc254c61a892a45b9db9a53e7798da8c65c556d738c41512c4434954fa1485a4a3dcd554f83034caeb78772c56afb750529c560a538ed08214bd59eaf01a4c33a29e5747b481c12954247eec6143cab93dc3e5e16024c9a12b846a9b597e6504989eeffcd943902f5335fd1976826429d95a42b9400d428316cf3f06ddc77592afdeff3fef999e96c95f0fd9f67b9ef42a37e1f56677775f37b9830f617d4879f2ca529b0dcb6ced693a8bc5a7cb721ad67469d56173c2f72b3a8e36e2ddc1cfd2f4a6b833c8b0fec8cb8d0766dfd453a699e2ec6fc697a7c6bc11a41d467cdbbf4a2742c53bebd2df487172b4af1a3c171e202817505ba4378788f8ff9adde7cf0b122f623a4dd87a4d7c4bf59aa727910d7898653ec47bfab8abe1ea8eae714474d0c5d2d8b1f35b1b0bdb193eacca88d109f72a12c7ce694f7e8657aa608e287d4486f5e044c4e1f10e990b182661407f31fa2eab3034a79e79d24c3b79442701afdede36f3d3f49508ca43ccc16b3a3845d244e40dd2f3a2daa1085b43b4468a3242ff197141dd1521335fcf63dc48f21a403f02bad34e7b0fa06824bb302abdca8e4487687e354e34332d6282653a5116efc9f536710bc190eb7d88c5a3c8122c9db53cdf20357fa653bcfccc00df292bc9326f2d106f91604a420326c40bf6035cdd6d20d26c10a85991a524f0c463a6d66330ac05cc92819a0141bd800be2cd9354be9c590357091228c9ec65714db88440380c8280d14e41d85ea788db586b2508ad9a9a1ba08534eb6928d20a34c21d4c0862a6c46699da2deae7d60409c97a1d0e18fb276366d4f670203dbc7713ac39e9d244e5b08a8f728d22465a61a19f654d2c46f8edad36b41354ba72d167fabda18866f790c92f051cfa422562f24b24d98f1c5020232178227e960be05d4774d128040d3133a8edc4573be05d9f9c3bc2db03f4f55fd52716a01add5eedf37ee18a1b750f6dd2b8c530d7a2336c12acea8ff3afc367b8a043d655f347fe9ce29894cc8c7f3895e405444287f14b42f2f4b3ca63b9f17a0a0c4192528cb8650cac1c99a3b800df83beb9d4ea8259496c384ca85b89c6fca3af09b123002c0ed0add575dabe44e11dc4d0926c1b54f41037438c9449ab6c9360d725b9b1812ead8a47fe9a659ad8265042f747712a48b15802769188852c55a27dea3fdbd6fc9134cd1bb4b4135b935fca434921f632718311412a375e5bf22d8d59b0c2e0e77221489ce758d82c47396d7516712b8f637f09684247d4854d439a9a44ae83f922c0d6b761dea731b391af05d6fd3b1d3ac5fd41f54453fdd48111492496080cb2a1b1ce414beae2447a2d9f22dd025fb1de61e66fa550ac378bdd2fea8a5c7e73651d44ff4621ed6cb75a84dd90e839447beda52f8216dc79885e3670c1a77518d69728fcf1c89df5c2d00235ff7b29874d5472e488c79a482e4327d23d72e4133c93ad1dbe30a922cd1d88e2baa593cff86a6a4a9589d846f3f742c66e50b226305ca146416d3982884a0c0137d856727728166fd462bace5840dbef1d42e6be6e3f3ceb68ff2b714603f53a343069d621235b08a20e84a202cfe7f10de9e3e0446d91ea00dc1faf4e0f5f46d9c578e28e2e1ed7091e4ca928db625fedc28cb2988886687982715d959693932e808e4600150952180974d4a394c83ecd3ecc3adc11b64336497d94299a55716437533fc687c23af2a2dd28a5c91e89ae0a244723247bface9bcf7fd712c9353555a09d4555c3923c940aac94d6aeb2b5e035e2666c9073a71bd6a923ed5caf7f2c923040989f9b0bc7aea331c76fafd863e85e5b5c6d33ed568573dbd89d0211a0475d50b291eeac48c6801ca47ecfa1d7743bb552b5c99041296352fb329fe8b03bfcc1c005d0e3a66502db81b5de17f0728264ea24429204334147a613a7cc1a72ebc9673157c6f180f7fd1f12526d4402d1f6d3059a40516a233c5592eb417b9e64ac350103ab9341d7e9a7c0d17b029b88d6ee15b21860380fce52a400308a30118eac95c6f20115893c006581e49653476f800953137cfbc86ca9408f91fbdd3a716f77ce528709b67c6212f8bcd807ed6aa7df3c61ed7bdfaeb728b6f10cd604d45a7b2f078ce3633c6b97b80982898a5b610183a4f9ee4de5a6d007f8f48213885eac89ea113eec9a857c32d8188241a86803ef06a53574bc9cd200c4fa3b06b5ac6ea77bff1a15076584d4940a953c0bbd49fc47b337f63c0ae1532c7b67a0a6f572aefb55d54ec97800885a5a8d8e466e86aa014df943f0c44888c83c04203a11c91ed63308c528428d7dddaabbcf90887fc3349ee5be2e5d4729f6d8feca14f056516de1ac8821fd2887049311515797c92728b6b25ee8d0c49f3e50192a3e30ab28330b1a4bbec2e707964e7657562de74b080bd8db74d431f835604c3a092cec162ec3b4c2816d532b6db0513a00a2bc792baaaa072963dfa4cb1b6e6676db6177b8e28b229847a4714855cf6988dad01ab2af4353d6453c94fea8cd06558a4d4e1859eb485c48e724836b26f8e7ca09357dcbfd88fa1d33fb3be22041a56047c7a0b1793e527cde1ef404e43fe405bec5b0b925cea77a033de48bc4e92a865a1e773751c9c14ac2f17b3bb0203bbc866270e9c474d47ddfb9ba4806ec269a70fddd4bcb100f28603aeb33647bb9acb19849f0b879d612369190accee0367f9f0ad82cf600367f44b3b5470aea83ac076f4ea2bec116618a0d06ff8368ff32402be2f80f8cb56291f367b2711449eda2023dfa49245d36877ed75a64a5599a057b767d38a1b380690c2fab9f02d80492336c7b0597bb06d19ed213eea192df6182b8986a31df6fc494f4611ae8001a8990fa33421b05204638d63b2b2ddeecb279fdf8127eef2c91b2a8f9b102f5b401505f7016316bb99f8b9828a40679d767fca7f7458e858273846e89a73f41c38d83d5c2e94110abe8e1264b4711a02e4f07a2612ebbd1e54ac3451569ca6bdae37039217cf3e4eb7cd813f87fb4ea880e3e65a14098d8c5f0fb4672005a4fac1149b59c9cb162a131c94164781a00318967443d10caae6f15da81630b185828a592c0b1e2e879d4eb8fb8c4de639cee4970a9eae3f6fe01988b1ae7ee4b184a274f448f4dbd6639a94f73bfa26e238517dea4c4661b6b1838478f8fe7fc088ce5168068a73308e04a8cf83406603fa2e4c97a09699cc50877888af06aecb582b884ce8f959c8d138b888be037539363a6de2861b0df3016c1903fafb11645a30d819a7036dab9a05a134ab75779d9d6bc0f2e01c666843da549bb60a1c25bc219eb06530849899cd658b01dc07ac1f1c8007b461d3b229550700df9c26c40108241c732c4635c05e3e46b40c01324c1adabbaded2d654a29c9300626064006222ffc904848eb1c79a2e7edcf8ac88a7d9ec4e2602955361459dcd53872cc56c221aa73341b16a9de9538ce4dc51e3b620d69cca8fc7153b147b852e547734415c158e54773c426e28835f438bf8717236a32610442e802257f7fb920368c5a779668b1852de4d4e844091f2d9c30e29e1a9d2cc1137d50a3931c25eaee6c92e58931c68d9a6218f5228a1b0f83dda4dde1d3caf7b7f2bd701f336170038211289a8c000a272478252981e66dd96ed1021b9fa01d5439c20c57ec40063c5802089240827dc44a66b4c0092960408508aa1fb4e85021b410c58f155bf8e009438800162fa862486708415358ae8655a92af6bdf878f558b71530b161684a08a080418523ab0d08f4bb7f77fa312b68b83bd20a345c9c2abdeeeeeebe727d79766777f887636e8a1f50fef803e9dded3dd4b269b54bef6e6f3090880206182d67777777777777bf9cdedfddedee3e3528507e39a79cee3ea79473ba7bb7ecf6f6c69470051a193c81d6ed2e99999999999965337377b7fcd6a240b33ef5c73ef547e37a95d25b4a203c39527637b333377716822f5abe90deddde434c44e9a20b1b1b274b0cd5e86489292fd4e86409a04a3bc53aace3e2adbbeb8ec1b8d170aa914129a548a1289c0f252af372d7042ae50906d99330c821eb24a9a858519175560085bec80f59a7081a199c330cd26e63d65906bb2ea8ecd84974f8c421eb546769464c21c414d2bbdb7b280a215148ef6eef21160c61c1faf6902aca1552908214335248ef6eefa19eb3863f6d788b0c17dc5d87d6b44629d0893284273c410911aee0828b1a687145139a105f8bc3466a01a5cef3c3021ce077c7fc60228efefebe96daed1b49090dbf76ff37779605e154378f1c3c6af80f82dfbbbb1b5f74099f2b96b004200061c8979bb9fba5866e66ee76ef6666de961abf5b4ad9bcbb91e376408b47285132a46468552ab659a262940a88922125434a866c6e6c8edca89454515245c9909221255e28a9a264488b2b9290842af6a60a2abdbbbdc190bf19a9bd39a3dedb5dce193d36478ed9c718a7fcb09b13fb4e6686a1eadf55cf89512726a9bf9f6055fd379e1a6e40788e54b9b9948e40fde3131e55cd7ac4ffb13d269ffbccdb9efb19e65edbccdb3e8e5e7aa2cf3c8cf3e66fd3ebaa795dbce13ff2449f890bdad8273fecfa09743f880da3ced00826a57c203c47788e2ce703fbe559a1b00f08cf11066305c263132b101e1b46491e1b9e150f109e1583b102e1c9613056203c387cc4796e24109e1b1e1b1e1b1e550784e786c15881f0d830186b90280b7777cf8c40639fa477b7f76481075c2e2b6aac7097deddde43be052db4d0c28b9a6a9120a0eea489a02a438d4e9a50d5f91f10aa5a6f467aca7fa161c3a8f30b6fcc9f46aa1130d6190259a253e70764894e58fb812cc161547f38393b497a4e204b76188c15c8121e0663ed6d4912d6c969204b7270705614c8921c06fb03b2840873082ea5c43029a59459480cc330296973320b29a5942ea5c4b028a77477e95f90e6a41d83bb31b83d737641e7d7b91361d088f7507e77ad059b925b36db67e9a1999f9dc23ffce1fef06f94b1081aeecf142a0a883a3a32fff00ffff04fec41dd9fe9a4dc9fd58124c2e839cc3ad187e0e8c3a6fcf9f9913f3f3f3f3f3f510a0de3cff2ecc79f1f2643abf209fa614afc51ddb494ea242460edb2654d9f3cd05d7786ad2c01630c5b1d81915cd0588c0c75515e5e5e0b3818b4bbbba5b7f4c602edee6ee92dbd494e707777671836a54fe9d817b472f76cd9de185683d5484123f38a57bce24c646a914cb02b5ca480865ff35aaf644169d7692ee57f9284936594f2076a45949c949c04d1b0eb4c5f632716a32736b19f69cccb320fc3b0bf91e9217aadddb3ad04d4e2a2fbcbed9227f69e6dee85b37e42f41005d1f5e6337b0dcc2ccb1ee35ee22764d2b8d2b22bdd911449911449911457e2fcf9220e0757a9324ca64ff1b508449725c6e83c621224a78c9fedf9400497a56290bd9a19168bc51a8d3ea0da9fed89a2062e8c3e214b454b8827e401a39177b700d1b2713e6ad5c8081936bd3bc69f9806bd124b77ab3a25a4a56aa95aaa96aab53388277e295c39e0205c41abfe2dab09d522a3fa1b49194b947850e2c136d65ce98a4cc452f24e31990c106200809258b29d235096158eb422acd46026131353323295574a5790368dfb354c3c647b31d83f84f3f16218aab61b69041d72ab59b4dbd70e5bc987eec0fd10550e87c60f51cbb4fd85608bc17e1cfd34bc8e1593759b762880017a38e1d01312fdb27b10c0f9a3389a1cbca1d88613c0fd002b7fab8282fac72e06fb77703f44955bcdae99da630133f8f841534303901a8230a0010e783109b1e18607e000811c7418b2030c0f312b2a4e4527acbdc1914f1c61d32c26471ca9e12659d694de2cb9a436a62af14ae941eb588c0bc23fc322fe58da6613c3be1aa0920fe5c9bc32ecc42a5182a8c4571c52d9605428430299ade9940ccbd8a83d83000101ad7657946b74c2c48d4c7b6ce1b6c1a7fdce24aa2d7508d5e60bf3104ec9b0a352a93a60b3eaf8cae955ede79d42182595cc39a7a8ce8dae20505c41e6cc0c9cf261b39e73ce193dba660e5af8b453f2a911f4288360a770005540c308640314400d287ff82d7db3e69c406950cf408b354a3e1486253434c508838620682326c747132bf6827d0cc2a8f9ad28eb41bed809096d9ff2310cc32287cd30c83981beba09ce065b43acae6fbc41cb1872ff42d9043a0514bebb3ae822fe01ec08118a29a8a03fbc2a028a3752e032a73625f54ae9f202b2022173ba03cf75b76d3f73f92f7f86f77351b62267296d8afa73fd2af6b76da3ddb2c56b99a1acfb655f8862aaeb934b1dd12d62742550e60fb7e82267ea3daa51d6d85e4f214ce0a2e07ae87e8c379a68a14243dffafd13d5e839cf6021d5282327048a96312a63c99e7fbecedb84cc25894d46f5f79731d5c5d3a264f845887c5415800ddc437e4acc24bcfce06aaa5bfb7be9df2aab7b35529b2084eec5627fdb9af64ae9eeefdbfc4259e507444bf52e341a986ab846aa6f4705bb6f9be47cc8f67e1eb5bf22b2723e649868cd4d7a0a1afa14b4bd37db3c0322b6aa7c8f359a936831ee8819af3717c78e65f9fb2d8ee8dda2786366f1062ba188cb09b6752af001561bd44bb3ebebde3958460c6d937df5f6098788cf24c228223f0045a0171c583ec6c7f886f8b6d5a77d233de68644ba5ab677d00f44b62706f56873df350a442f6a1cf275ef00046d1313a82a7f6c56931328e962a036c90e136c77776f9c1821822a43e5173541b38ff12c8ffdeef470cfc9091a6ecf3ef128197b88a8705beb4a7281f945b23a5adf1d5b77e34ec6e2458e0145b6b20e83bb3b0cae885656381c48868292b8a9e14aa151c30dda292b1c8a752a0c6ab8d59d50f4331c744a8286dbb33d51c7acec2bb453469826b78d0bb2b27d33f106edba461cfca21d54fe9a9608b2280534fbe8931eb3a14ff2e29cdbc3a998171446c5155a272b2fea4aefa9fbfc2dcc0b54f7b34ed1ef2507fa2ccff211d1aafbf4fb5e72203d7dfa11b140dff6f4e0f8c5c66504743f96b6a0f1c99227aacb13f46f18ac6154e5bb7b60756f7b60a8cc3160e446a45cd2d3c362396fd4485ef28929f9d428f9947c5c7a4c2e52947c9ce8ec11d4eb0d39bcf1b67119d75be4dc4b3ecff291c503fbd44fbdef53fb683ca06157f7a6de6053f0295040b2a2b513f485748a7e9d62f9ec232780fe3e919b2fe3de1b2ad0300e099165438cdaba7da110755bd27afc33d3dbc6d558af673b99edd7dbfe860a95d9ed3a5066c5f4cf7dbf793518eccdc4a08d182e09345691fc0c08991839ce08da3b1c6f5f68fe9a7b91dbeb2ccb9e26625ea8533df3b0e9c919e69f9e911abd22b2ca8fc7125e480450e5b542eb263cfa0a7c317880bed0207a7ed1bf911abd300b85086dd416456cfab737d35fb62bc434d8589041e7ae0a943f069bfee6ce324abb2e26823518ecac8a160b4079e868abf5b65faa1dd16cb0a0a321cda6ca9fd9d1500ee9536737524cd10fbbba6d1cc463091e3a5264104e0da5942a5ff3666030ab9285d6e0d44a34712acb21c328466d2fa58d2a57a45701ed318c870ec6711cc7ad17fe0684aaf6dbf69c68c43d75c463898969abc9c42e95eab55597f311356ff4dab7ec91b57127346c09b2c9324aa3d63dfa4299da210bd5d1c711953a8aa36ef4244f3b711e0b716a063ef58f9e831a0abb639b8aec82c86fd468e5fb49dfdc87319917e3893f5a82a05a01d1cbd7b4dda4ec6ddb9e26d6eddb34ede548ab44f0d4aca1b038e447e9882714ae9acd4c7a504c6fdb0a7a145ad1d07582b6aef510a39ad5a40fd1ee68e3e639fe5a8f46a3a78975f4466a4fd01c98fd940907c673203e7192a3f0b6821ef1b31b4ead8aa79cde9327b6c25148d56b49a12d3feafeb55eecd0c89bf16660100a83fddc375745d0d081221684c17e01dc80869249ed17c26064c2a9215107f60ec4a919dafd0c1736ae5081faac16046362783b06ec32193f4d8064cc70a12bb9bc98666cb36adde6b232b2b75c59e1510d89a8fc41c9322fab9476dd7f4c0c14d992515c5e4c30345e78efd53f322e74d3803145983731ccd75fffac931850a945f82404daaca86329e5a44bba523ff4697af19a3287e28dfe928fc92601a687015d71ca027deaa863e30c7ff499be96affbc28ec6cfaf593972d4b0592f64198d8fc27c5d277bbe1ca84f1135b988600721a2a61083fd3cc4280cc693417dead74cde14298b10412e224a4a8960bf1cf2ee93ae78a385f08660d0a6f64f1583dd3795b724a58b942f529aa484919286942f48f952ee7c75ea25a7b8c01ad36dbcc383e883ba1fe3f2a8a10c7579d47d31cd181d0684212941638bafbdb0bdc0f9e028eedcf2381fd39ddd63178353d8b0eb483793152ada69739182c6b0b9f4d018381f5a90e6d2f32e516c0fcc9bde647ad3bff0a68f3d60beedf11ee661be215e7280791a4fe323e2853f27683cccffc37cece17dfcfd0b1e23e006349cab8d8627d97ba161552f35acaaf2278318ac5d0f68d82d8d8a0c582cfa0f82425348a84e61948c014e4eed9752a45011560b48bc381a7775dc0ddc83bb2a68285d73c5a7fe2ceb56bf2f988f5c0ea607ea148c8c25d0705f41800289265520b1e3535751078b53fc3222a64ca6cfe72a9c2b919cfc71cb0634f41eee0a747ee8402d1726d49f5f28228a1a9d1c2154654b3ed1b31d6f5107b7fbda1df3c3f6f5d3a75e2ac49474451dd8378b88579de21707219efa5dae560b08885bfbe2d60bfc5abe504ea9dd7da19c82dc825d928b2953a8cdad78a306346c160090a086a20e30e20e6e2d8efe1642166a83b5fbd8a7b53bba8a88a3bf49d58506346c56017ac4d70cb045d3875788291a5ff77c6198be8e457080b94242b9b5dc6a3593948c8eb9d2c1f9983873357356253d985a42426d5ce3b19590d070ab728a0c8a326caeee8e3fc09654c056f2a1fe33dcfd2524d4e3beb21212ca7d8909caa0cb0c8ea44cdf5f6c569f3cc2a0ead188fbc23d52973fd3f7cf9cce9a5b3231335bc987d6920f057d94a8a06bf337f146bfb600d3e75bdd22a366b8b0a8bfa4012bff20f20374c2f4abfa6ee6016a7c52444e754abbee1f04b5066c251faa49579ffab31212ba7d89099afd68a471949cca429ab632fce316b704f3d9c92e5c38f9fa65959050d29798a039b5e7cabf8484baf0252668b8af9e954fedef86b25357c560f7dc13b4e5c366b54b0aa382a20e197570a760beb38860bf8c1fb55ee32c5a3aec3664071e7af02102129872bbf43d64071e7a989b0f1190c0045c5cbe38a79cbfb3eb580637f2c2fe2975cee2b33fdb64a30c68b8aad9e26acfd7abf64f57d4e1df3f5b5118f5001c2090830e4376f09e9f78a39f3d6769cd97267aad7f7a315ffd43a28e51e50fc4d414e2e6920fe52954fb6384e1b17e34b1b28c15fbee9ec7599d7bfbc426fdd3ac66c220121a39f57d42a27dba097f2524a80b5f3a8286fba25dab8b57f7da72bb9c18e62c030b744612d590971d5e5e6685f1dce4c5fe6c8036345c958b17762d7d17d8ce0bb3ea82176e95da3fc393e185a0d7e26d1246b17cefcef7423fd6966d523b46f647132bedadc2603fc90ba5505d9b9b9c6fbd70c2f433ecdebe3a65fa9ac55f483f9742d225a9d4fea46bdb98f3c159e63d9daa61c3811cc85d2bdc8a17dc31b6f55c6a09092d31419dc573a0226818353a4982a7ca1a2e50ed47f5cb20209c19a559eda71cbacd629bdaee5262add5ece914ed9940325ab89543c355cd559f7a59dd56e1d64b34e216bb7ceb548df66952fb1b4a6d186ac7d19ceaf2f4770ea3244be1d4aafad4a5d5ca57b5377bc4086a53f79de37cc4b9ea54f773d5a21202c3352bdee8778901ed5f15b7f6a764af964b4a615450d421644e1be6bc61ce07cc89c39c10983387397570f5aa539ed3d1efdc86cd6bc987368b4f0dd6511028bfbf108551fcddb0317fc401025b649400361c3218360860e096c33c6d3ac818b6213e806d87ae988d8d072e0857ac87ed0607c448c530021040b4c22f3d00dc8fd9ea54d62757cf6f5fd3618bcd6a563391691683fd24269a95a2ab54d0907f5eafddd99d7d09f8cce7d31aa9919bddecb97d577bb4813b441dfdf4c2ddd9d5de0c55794d71c5568c52e7fc9199609765d3230a1b79410c51b316794174cd58fbe19c17d0ee0cc9c7bc2084a8d8871c0802abdc2bce321a807e9c318bd26dd4a5a7e4b3eebe1ec456de27d195c36d85fa84054295df07a12c04df6384838030ab33de989fe3bc38eb615f58e3ebaa7ec4199fd6f81e0251f708a388cc9df366880b472b00218c8cba1f93e346dc3124e2e0dfe7624a668b3a80f0321bba8fed973188ed7e473c9a45bdfcf0c90531f2c3f7880cf2e2cff9d82c8b01b9621983ccccdfeee63c72d4f93db7e5caf7fec4055d2a756aeeeb91fddb2d478ef871c1babf9e7bdb1734fe4b7c890fd6f92ff1ab01acf38bf18a788dbf358e3e7236c41e339c83513b84332655a1e10bf6f1c16f6745071a58058803283c1ce12ff2f0440f3df2a544e56aecc1ebc8039ee05079822354e3139c2835bea8c6273840353ec1e9a921189fe0cca072353ec149d2e97c3c68228f3a768504a3da1935451d71052b2458255ad448181657d440ddd45748449ae40de993ff8a27a44fcebdfc9020998f6514983e8389213f60de10061dc33e210c3a0e0c7a10067d981e919a2450d16f2f7fa66bdc9d52703fef655ff4fc435435b9c1b084fa9f8068188184e030845118110afcc0a817eda3639fa9d638f234f3ba1606fdd7471fefc41b9b42c04b880f3f147955f79c55ad53622efae84f5bfc41c9022a67205935b451fdfbb5de1d0901c39e33828a3e7e48aba8d6302a460da358aa63b58651b4fa8719a8f36b8474f619a55df721887d613634d2b60de38078b2d6306aa586515c0da3b6ea5fc328ad8651a31a46895e681855ec67c5be3003bb8ac1d2b4920fd89e93e2fe68fc5a4c4ceff3f449b24146c65bb6d45086f3e12244f98756391aadfe582136200041b8345ebcb1efc51b9968fbb1394dfcc8d1ac918a713494926c10713458f51f71378c389aad2491bfb6f1b66ddbb6315bf19f619a4f1bc51d71bb9c58365a914f333ff94d24748cdeffbddb525c7cb01b83a4e7838dee2ef3f2ee322fef2ef3f2ae0b16d4054ae782056db942d35c7a688c16e37fbb351834c2bb2368ffd0c42677f79ceaeeee9fb7732f37096a1235dc6a7b96755dec22700bcbb2162f66669c5665666666de8da168b1866f5bdd976952b7c6113f35fe787f60cf2ff6696b7c13d419dc9fcfd9cb6f7b7112cd861b6c60928f183c40399af6f675778fa6953003b599c6f90b33c0136450f6e8a7676f90318b58ce16f91c828dad906aa4236da3116f981687c46e40fbe5afcdde708a7b89935941b38cd2aefb9716e814113e4907c453cb2deae6d51069161041f934a20e1d9876c7cc731ec827f9222f870c8f98ce32950d83b29be5aa3adb1d2c5c6440f7e38333a6ba4777d7de9f396ff3b23ef96bded45e14e0d3fccc23b243314cbeb6fe8519a8312bf9bc0d4e51804f44189c60a7d6065c500573ce1762084ed9e089bd058a4c51c6222f9b73ce2712312fece6ace2a58607ab4b8d92a5741c2fe924091ad2796b69186c59c841415aac116231f644c15481132e55489728cb5e31b4cb8965a2d16c49d7cb67b8aaee3921099bc553c6c49c96a0a103f9d6fd0b7cf18d4b09e8ba7405f18d8dcd11579094bb0298d22998dfffc83875dd9773ba67a7f4699f469f68748f9066f589270a7952f4a2f2d21cd5eedec4304df462caa5e0c550d01dca64703b94dff4304f63a4b99751e75440f979e34a54ec10ab3624bcda59a9d3bcaa193b5efbfc30d864bf66c2e06cd6b6d57e6ddb5a1c855bec9a51635c271450e638ce879c3edc3fd03f92b6432c5d306f82f1765f432d2dcec75c195459a90de45554ee05d8345e807129c453d757f4a04e99be210ff217501725746fd86c2e3e35c49fca1bbb309ed2a79ea6e629eb05d560bc66c2271f065f58ec0b67c5ce9d6a6dba8c83bea591481add28e7a37b8d6340101b46c500add9cf28fd08a2c308a366eff2a5e7bef42ee3472fe35b1874a146ca20ff864074957fdaacaa0aead494751ee695bc66c91b02a038c6109a294b0c00b4c898e182bc912b7973d331b6920fe5958b12ba1f722bee8b999999bb65aa0680ade443e57497da8ce8c24b72141934656954aeae546dca9d7ba8a46e3625b1746a4600002800a3140000200c0a864462a168389e47b25e7d14800c7a92407c589a4a84498cc3280c520629030800000002048080d08cd04d0250a31098e106c0adf602ac265b1a4c07b3f479c66cf619dcd49303f938dfafca7d9a4e0cf4458684414caaa78842a000bb7b71f4485742a956e6232530884323317100af3d90f347ab5ed6d25d3dd9b87adecea6c5e87594b6d1838f50ec874c23f185f32c8f872fddd7c1654e8915b834d788361149ee09724d8614a5ff669be3042b66303ef4241834401c167f48ae9ca6c74a67c7a8920d7eab4ea1e00a5bd3bbe7c772a8027b441a109f57a60ff1a979461a860726939df0e9333d73a45a5bf28cc7ce17aa266109d2a74347080f5707de57c3cac26ba78d676a7c150fdb995f97406a1e622268d2133554e4eaf08f432751138e98b392661ba26b196e08e49610d0876038ea05b3b66d36c38abdbffec4bea6cd7e52abff6be78db7980bc6246b4c159fda3f4039054fbaa13da87a16497e251ae97be1b9dc79904db5e990561781ac95db096d503bf25521db59541935242e5c3012a7ca2c391f13081d14180ef9781e4ab847a67490b0b7db9f1e3105ea494c43ec97b35a9152d0d157488de65037108267c916b9c076b5615855ba622dd3188935545abb926864cbb1bdf28a6a588b5d217f58bb75bc445c9d277c2b62a270d1d8730401e87994c239774f37ada719e849b0aa7ca45f1114293072043a13516bd70242e019b4c17bde90fa6e0df44c6de4dd2fe7d9ad819e462c41d0bcb5a38945365161d4255e59b5829001cb58a832e8ef0a536e5657f85b812d4c0b017d0014afbd067a7ea0219355cd1339de245efda69020163d7c5baa5afbaf4761c11ae8fb71eeb7eac0dddd584fca5a5771bb35d56824b000728c5e02f7d4215ec91cd998b0ae469b15ae99dc845cef93009b4941a97dcd5b0c2d23b18bdf888cdb51f9476448f970e83ee57ddc0c34e92fef13a524505eb9039cff4f5d51b41ff44cfe887fa58750faf5ae01e3596f26ee1db70e9a42791322397f5dbccda2a713836379cb14ddff665716ea77292d8b4e9e554f7e04f97c225c8894c880ce91752ce26ba63492707200360de5b2e644d09401c96c73046a160b2f12da07568cb361e94ae7094eac14e33ff1f1327f0d5043b6f6dc06ff499daf706b2e7be1a7dfbdb7ef24bf34b6c43ad8fa8c7c6a346f9607759b9890bfcca2c8fa8103a5acbf917a132b5cad115edee21abc417d2b0cf9abd706cc424ef688b10128135efd9e9708117ebd80e2be805cd0952d6b02ba75653f4f08595b6e01612b12ed86181db35e6277e8e4d04543c8b691bb218553c5b94a8517c7560c5aed408ecc8aebb2d852c25a434ff78d789eca491b87eda1fe51a7fea70cfd69e4087e6197133af390ba55e0e30bd20111119d22872f15945bc8dcd49c840921c5ae356ee97a4008853bb6703d306c877cced7a48cbae4fb1006b861cfd1745771555f00c5f208d6bea81d56342c5a559a87202e6442e6cb1f1f4d44d6c4ef5b220fb6c8b98b9df34c632acc8bdb69cd5a2e1c49013d20ca2d1989b5f8221caa83896741f74f1a57d143042bed7338fed1662e548cc8eaa9276725b51ac66ff9fb3ca6a9a74e53f0b1cc7b6b00ebc5dc001775792338d703167ca57ff04637afcc1efc511585bb09a206ced03d7badccb5121e3532ecc5bac651175ba4342f705c3e2602ca293f484bccf7606b366d53d43f72f2962c836fbb56225084fba33bb0df158fe54a7a8d5d0a05ac289116689a7117c25b25dead2065322f80a8b988f6f286ed14c537184d68bdccd41573abc1e2a888004bbbd8374a21a40c6bcc0a63bdb64f0c6ecd9fb91bbbf2f53da936902efd9fbc244a339e715fa21245e68cb98b7179c97e17e31a79631f4645b634a1e6269319c36786732fdda54f3c0d38bb3e634279982086bb29b6505fa91241e57f6f741a178f956962e2b0a737ffa1ceb55610d7869c88074c401fb7d6ddc7ce81669b081ac3ff82e80010dbb671edfa8dc2c0ac9f42568468b0a8e34a124de91f38975dd31d8b902e37d87f9251968e6b03e0c09037feb751b2477053900674a24addac25e0040b8242527e8a8d7b88939264f257cb6073f84ad5e21edf43981ce1e4739ed71609fddd67df25a2798fa2ae973f1fdd7d66a183b257231a6e3af28792ec2b4a7f67b3e71506b263d31fe2f81b8a225916a9004b37f5e529fbeaf8d37fd7f243ed661d22288136fa8aab32b084d8f6602ebd85abf4f17859a1a6d876f418d4cd94726e6cfd306b9b239af46441788d0d7c49f2555abd07e669968b85fa94cfe6f957aed0dc6f166e4669b44c629a649a888653b4fc127fe51c7856c90b4d7daffc78049d12b915145f4a489f99e84632be896bc10964dfb5160c4a2743cdddd0e66257fc0899d3cdd80582aa90546a2953a637c204d658b4995fd34b4fc8c341e447ef9ee97946ef5b2c0ab7675ad68a4982ec44f87696d48f7d702583eb491b3013eb4907f4126c4e9e6ef83109f696c2b902e75d3ae37fc00bb372fe480d5aeffeb319fc9fee1f73751a634ee57d3c0673ba9ad6de7031a0e80da7448694154d539d53a678732fd46d9d4d1b783e9e283f56af79ccf7f7c66aede5e7bb8b72a826bdd32a800c855d2323e89636ba18adf62477b37ca7afe44289e369cfe15d3393b3e0ffc030060a9717248231416e4a5dd54ea7e7a2c68e815091faf56fd679ed1e16e159c16f4a077d8736d6dd81928844e3490819aed4616d2c50d588218be4422bd771aaaf8620722326f066357b98ad011137373d4b14f56aa911ebb194475a6907e0520e2b603e6815bd528056a45bfaa66fd4a58b5c09e2ee19321baea98b1575a0b3dc37ad952c8a98f6d221bff721f86ca799d08c81dcf0216930e2f94ec0738acb6670a5f1b2c656a51ad8e0abf8c30a2b3852e1dec24ec13673856974cb01b66b3b39fb4baa210ded68738352a2b051ae7708f7a958b93c010862820e4af55758525aacc8637c052982d5323c15b8481d5e20feb4addbfb5d4433b8df9024a3eea4cd2815ded4f69be5998e7e4f3c0d4e2f701805c53f55046893345514100f39279415b6dfc737add6c5dccd85ea91104f65c50bf2080fca0f4132a1aa3a4b227f7bed66a18d425866786864881bd33ecd84c87daa3f88410bfb717b7742fb94aeada8f9d2f45440683fa45cbcd1bc3def25ce0115b1a50731bec5fbc772535ede8e32bb6f7af85c85e417d05bf8510882cb90efce510ea52f9c7aba755d31ec73832a6a69b248df425b9238f738a06a7ad6058609ace5763ff3e83bc1d25ed73ab768b1d033152dfdbf581bd36c13b6be7aa90cd42c15580ece14242495366abd68c7fe92ec18d73d918ceb7dff1dc748abb7667d470a03126c272854b3abf1a109cc7b5d6b40662a34c7859389192645f652ea28e9a29907891338cb7be39e64e633d5b67fdc1b4b0b7f1ceb18311aef251d0ecb4b5808d5c21fc6c2630e3e94fc5a02ae3344912b2cbea76d693aa21e9060ee63d8825e59dc6184f12ad4f2ed48ddcd0846ef800b537fa705cc06eb542ab6feb9cdf45888d6d7b1c94e6b3ab84110af23d971f92148d1c281736754d5be1952ad08232a9b11a3f733718023fd5b3f4da237eec54a741e4233e04d0e2109f27b0fc2854016d0e450840855b99132c8f35c9a5acf934a5d984b3dc1c2d99695e585cfca3053bc1d8a71af7b9e78e0a7580c50301ef5988d3486c21aa5242188cc924d0cd4eaffaa3fd3e0f55ff3a52a1854a3eda58e8b12ea22cc85ab694741f0f382b69f516ac3fe59af23c6f948245c5add1e65d317fff90cc86767e82b42d2c2a899052f0583880cf9ca3cde22722ca20ddaca9d3a42706c3a22df5ce90cd7c1cac4ebe237e2b31a5ee1fa20b556f76a526946bbe851368177fa57beb4e77dafa4dcfe2905ee84d0ee8ffafba28244d527dc32efce6a69758a7f5a858f28293f3a8ab849b45cecc1daa0838e2b19f695ec3abe07079b673498d9207209ae34e8aec2688d1fb5554ce9bbe98b38d5f93593e67bec184c7fb71f663bf7794a3825cc78ef758fa0b0bd47c2fb540af30e076a4704b3f69e5fc9335536654594ddbf1bc6b9c72720c0dc9c85ae869b36e8450097dd5aa699a929f5a203da0cffe97cbaf6f266101ed62bb2f1eb11750c18e9ca4300f3c59e84ecccc10dd78b150d076b82ae26b8e015621b7d7f3413d2cc792fa74e75864387593e8c333d6e7097e3f4134ce689cf268cdd92cedc57b30679d41b431a2270ba4ebf5663a23de134712980ff0742a1cde92e5c29d57ff5a46fa2b94a8e38aacf19e19795a0234b58538cc332fe2e7b315a79568498f32926accfa1da0483eff9b576f45266b799d207e3a34b53eff581b207936ced7b0d60f541dbabd520c2a297a1048c3efc35bd0d681a4e3618483fe4165d0a43654045d6204c4514b74759bbaf259605f6a0cbb099b74421f57b374591c140f74442adbc2839de69380b644eb011eb7392e3244ecb94b846eca83cd26119f4f9c2a00c309a8ebcdb1b1b8652c19293be95e43199e237a03c8fa32cf85e508e8c698fcda6a6e3a36e5fa25cd46c9a5cefb35ac5474cc4752ba77024ed842e853e913680aad284d3c0c801c9c986f4e22db1d82f641827af62de415aaec0681a5b37b546ca5859917eb6af22375dc573e1dccfbe2397dc77fc62f16a1d39c3a234c573ebb963c118b96a8b49ebdeb9286e1a132233522a6e99fa5321811fb7a9e1577214f39596a3d5decf0f7addb4272f3a0f2af01669d71f48e020c07ac3d8e2dc652ed0fcc1e4d54d964d138ec40b78fccacb955802ebf43f07353191c0ef7908fb4194dbbc5d57fd6bff8ecb170c3b459fdc7fcf3416bf2b993bffee963d61a82b3911784c458c615cd5e2db83a4ffaebdc231b70f3fe2a874657acba9c1e06bfa986919edc899e9382e4c1e7131ce44e8f178bb01841b74b71b730b7d1f14922835643c8ff6696ea265b928ba35d4fda027c8be16e2d928134cd52715ae12ed3360d3674e54bc0e6bcff719eabf179f91ebf8bc1c8b30f1821ac23e7eb2887afd8b67df4bb34c12c0891249b2048ef41c44bb07b7d158aaf9704f5deec51f11c4cc5e6395b39cd32e90350f217817f902087612f461baa94d33d954d39a50cff613c591137e930f8ad318f1b51c7dc523a3563f8c78562eb54f656f0ac2489fdc900c46da01cf0decd88be42606d4a976fe8bcfd8416a588032a0fcc1cdf3721fd872059777d05f2a4856b1f9a2d9bac03fc663ce382173848aef38995272b366c37abdbe2737a27a73bc308964b16cc22b2477ac73ac62ea598e1ef0e06e3bf67ace489f0c6a81bf951a85980f59fefefc41ae02aff09a917a0797c03ddeb838def4c1dfeab7d2962fdf358eae858a549f5d80564ff2f3a4432d8ec68a8d85eecc3e5a61e1cec34d66d92bd8adc2c5338a6ef86b28510a19174437c390d1925d9185ec14e93598786055f0dc2a627610cfdb27254754449a8c418f443572bb17430a438f4d4a428e6c1a249cb8430c2608f94e07147ac4f7831f47a516799115798d26c2d78cfe10bf677213c4f701d5dabbbee62d2e3ac155cde6658bd830e7455221ccddb249555e6e13ef82849e2a0f01ff9b10efcf97e267dfa47caa730c804e92659caed3b01c6d57b4bf4eab69ae755ec2e33a152f58cbae54d3cd99dd1758d7fbadb6ca91a769511caddbf145e8d6f38ed038675e3e7ed94cde5d786ade0ca5c55d77a7233c4f09dfed7cdb620bf5a07b0ce35155abe717e267b62e6d1885d43cf2390a0a42f9ed96c18281f5b649aab99b056e11dd439d01c21d3d1e9a885653997c006151576b705f54135ee59bcc78a62f11a19cfe37e3749ae79a4914bf41fd6e7a59aee27c79c3ad2d66787b659b79c64686614ccc6067f92377852047e496cc9b7102b0a1238114610f8f937ae256005853c8fa63c90ccb8a8f3f4027cc3b0d50b32bf296d1d74b459f30d186932567871fb56cabd128eb63bfc17b24dbb0db2ca980d96da66a19569fe867a76464be7a7bfd80b01fa25ac3e57ddb0edbc59de2859c001188e83c5793e37398a34f7ebbf64712b1d1e11490f70598d55f10fd66de4e11d6c33bf6ef8270d38e41f98959163ed6cbd1c0058e77c41066e87a21a5509521881fba44514d20b9aa630a17f6e606ac9ce54ed1697242c0386021469435933f5f3a5494955c2a66553acfc2911ff89f927031e77da7093c52e85397aa1f20dc1ecc71bb2f7ac0f8181c5107cb78c2ef90e798e2be4c6a0a66b19d370647bc239ea03f4bbd3a2b00740e2e5a58c1d367f2183a5b199dadd7e2911a7a240e66f9fecbb8095174dbcce011ff2a582b64fc6638919d251662fb00b24fd28f5de0adbe5fb0202fd62d63af4eec42a470581f09608d942a24f3b991581ac90020014aba57ed2cf6be335ca53e8eabdcd43dd03bd772a0fcc3b143d5d35878f103bf97641dca858a218b7774bb0149a06a598db924383310f75c74864c729cd19a52c2ecdc44cb197f0f0492c1e70dd748300fbfd04654fb881b922c4a0e417941c4ca047864ed0068577b527dc069227f44871238a4a402d8d4fc3545362e69d7eb308c3a2092a804667f3f120add195b31c72ebbb7cd0d49a14372ebb1c0f26063745c8b8660a3faa051dbd0454f67bde298db790490317e94450c7bb9def8ca7db188267e60a904696144c3641a1f4be6f95721837b493cccb92fd69c5647ed6fd7a4c3b7baed6932791ca645f0b5ad890d7ad63e876c9b331f7ee94cc51c2da4eccd7de49c11b1fd891b40444c00e25ce81555faadc6f842dfc4c014d22a954d4a5746ce5ff9a90c5e204a7fd278e3802a013e383d74af85d2814208a15b752aa09b8adab524b496b6a46cddd8322e55852ba0f585311dca821375a2da23b6f5473ac660957596b2cc2291384667a861dd284752a96757b2bd3c85210fc2185822e4150b2b136c248a4728f3ac66db9ae60535f58d154e761ea58eb64ccbc5f8c43fae007c94e80ffa1c8d0aaffe20c9943ceda6a539afa3a3d80ffdd3930b3dc192d3ed79f4b8de81ba779be6c12b0350a0a55a4438cbc5fee74f0b568c4806c9ee6221488591ed0a9a852ac301bfb9ec332fbed4183971fca3425084bc1f255080ba9ef37e5e1d40b4a586b7200f6883104e109043e99b61f833a77747cf9f7f675f6b0a198705877d945790a0fdef8589a2a47d060b89a0212de8822bafd2c3f63c148114ea4b070aace8494d16870f7b02d5eca144014d7fd09f0673e67f2db6e1ca2a6ae4346af5275e939990822ee4db0752cec045028c9bb95d48a582ab5d4ba07b8658160611f6efa6fc7811ec81fd2a317d81baba9632bfa36cf7b0f3f4cd6035bd0586d85a450a7a2a658b1d5edac5c513fe042a5d276b4e55808fa5518ce414611cad65fd993195564e64ad1ef27e3895eea8f7667ae03f89f4338a29c2ef30d1053ff0735862fe0b9d8a85a0704643560c3f47eaae96cdda4420982a780f875ee635399213b81126b4308578dcabf55cba1d5768443b170e69050cebecba3fda815673d27acf13a607c24a41e509d88265851b7c5d3816533181adc715955f5193bf0fe90e8c03fa82dfd531954905ba05e169e7126c2442ccd5928c13cdf366d50dcf8200daabb9ee451002f20a17eb1a082f810a9e05d4cacac5bebecf3a8bac649965ac83155330652c6a98c206547970ceed5e84a98a49adb0c1d376742bab6b5aa097179a874610e1e53fe9cde4f150a86dd1015a77e0e1d4abd826707beb26c785899c14810fdef1df30821debeb7907b4dfb48d2a7db0a8a626366d52534d6f122629e5db820b57d52ed8e76ae5fdad67708c8ce7151b4515b51fe023e482bb1f182d7fbd07d404a0edbbbcffc34030966528820d04a2ba225189c225626764e0dfae2e5494856bf6caf8b5160295f62c81f37cb1b89ecde3484bda9545277f9c6ccc3482040894f14e364283fc5b269ec9a2416f682bc76265c29680d985ca098af26efa11e5bf8cc9bdb34d14f1b264b23b9dd2d0847205c29fdc05f48aeeaadc72bb0568f118379b6014bbb3b2bebf71a4e9541a299b25421ee9645df975cc2009a4cd367ed5f729e407231061cb7e98bd6bf66339c30ae4b04eb9b084657796c2d0c94b01b0d97eb9b9c47a022dd9de138313b586d04aa4cf2477d972f849c7122c84834227ca441c85d5a44629771bf2ce8e5bebb8985f8b2b62b203d3b4212a7ca51b3f25537da264003b08970c243c851ebbc6905f8258bfdbf1d537c5ff6fb4facf68524c1a2a749bd84e49ce091ae3606206959024677706955b7b6e6a2a8eb07fc1f78ec99458a422516fdbed2481e7223fb6286fc46201d56b0c953e9b45a09b70ac83b4464c00923bd24ddb43275c49ea5caa43fdbf857bc2e2912853225b0ddebcd94d52444ef6723d773155b006acf05a082bf38b1c27b0bb78b2c2c293cec075e62549c043b6b48df0d33e789f2b2f70cf3772e1dbc5e9e51f57810f9d7d3b4cd4e49bf1f671c7a88dc12ee11f31dfe74494735b766257bbf1f69ed8f53ee2b2376adb11bbddc55c76d5f881e741386b627936c45a22462d9eb330d726774d72e469bdb7d36824fb77afd7221021832772764915a89e8c54f52e50b96e38d354e27b162e944d92d77498346e253c1d83bbfcecf69429349ebe4b7e208c6d6e6bf12f76a82f577dc318e294a180bc1c5b62f13dc5e0d9a4589e4c1d667545f9976e418a26d0ec15ac755a3feacd82a4268ab290596ff84cf773b5daaf659622cad78bba496ebb74a4da67673c745d76c908dd69a3a1e70941c1445159f9dfe6361967de0fbca1ae5333740bc7c08221c07280a76c83fa44e91793f164c2a4334ddfc42b791cd8405f9a12b6792ecef386eda56bcea2596832acf121b2391963a7959f9854538fd5ee23809568b0a938bebc236950a0ebd9ef9c2a5e8491fb0eb39a262ca29ddf37bf533c23d1477a4b4b73c63296481ac171a8cb1e550019b6280e1e1fdcd7184b5d0ca06d9846bc73032405069eb51033254437452dbd0512f4b284de6292db75a0e8267291606a3c7883ac719f9e9b1b4ad224b2f84b9c88ab57b5c40b5e0695783295fd692296f5f11fb2b1ebf9ee25e502bcffbf37621144a71c2e6dfec06097e22bf06f17768134f8856f24bc809043fa3b338cf462accf232754e8f699bbf97cca4223cca9612a2542057d8789573fd7c3895e1970310b05ba9c5efb244dba14536d95edbc4c9f647bca058437a7d85098ca5472c71e7f7b63764d82cf48e914d25b5d4f281964f2b96ef69bc0704f0295abdc2c3526518a650fbee176a1d5817a73d144b2d7be984dca57b9f912f13570431eed019c22f43f316662547b78e72f816571197c75d5bd45af31db8fbf6b04ab26155f518eb63d9b3edc4d13c12f8e300881521f20c21ee72a9e2b706fd4fee78d775eea7c0e2b5321278c913f770b32d8fdbf3f368b7cfc2f3110f55202c8373db9338d48b3bd9398b9429498830aa187b59add40e16ea3de6503a8c4fb38e7b4cf75faf897fd7e14978f4698faacdbb431001181a0476c962a0406945c6067e1454427a2ad81c7fa5ee4db5661063dce5d06ce5da00967b22e654a6fc752820baa068f0f1ed7c4c72afb277e4ff6a490ecffa688a35a70cbe183a0929ec8cd4f348e48d145f45c8e3214e4864a4edf92e0c4ffdc06f1bf99d35b5c889499aecaa5117066be00e62a6cf86abc554616bef177e5b05dac1dc12594a8fa6c7f14f4df55b75f575542b8542735fef01eed7a65d2921f8584222f3cf2a1ecd668ca87115e6a9bc055067343fa61a87f0e525c918996bc067b17c34be94cb10cb6ae4a4770f71c55ee54719a1d5ff89d8bdddfce26b12cdf56aa86ebacaae8c7900a3528251ef8a50aaa7ddae0e427bde2ad738a04291b69ef8869e2d6863e0e9aa08c807f667625e01f0d5adb4e0958fd3b22d03143e6abd51f5341430605b14ed840e84a3a1b798226e816df536f122e3b36c6bd116c70fc6338cafc00681e4e1905a56d2a39039e02c8314504f6588cbce1da9a40ce8eb2223ce8ac2a2e09c7df98509e4dbf5ec27f136b06b62a95049d69d9383bf8c0762fe051bc79ad63677c85ec5e05540191b2f5aaae3e8418dc0cf938cbd00682e87d7c4b3395293e4c87f91826752fd8ef6625ca7615c2f107c48111499068bdd166e382f99ff8f0c9b42e6364774a11f7396306903c3323c3d7c850faffa4db5d1bfa2f7f12444d70d1990641f1c037e559f24bfabda62699cb12b9f8f72eb9d6ab5396704b567ec3e85d89bc5b207605c1fb2928989f966b3c1f331a3426d0a1857dce3b02577c0c8b667b2bb3d7ba04cc8f27cc17e80f08f9bb0882929530a0dba491bab9eb7520ead756064b1a53578b82d52e355ce33cf7c51bbd492f268a5086e8dbf9c81401889a2b611239528c3e90874d61c5af30df46e057929a6832f0bd344e46c62a09f0ded84cfd9898e94baac2e14c9cbd1cd3ce6d785926d347a3a6434ae94126032748000eb82488d95bd4abce2a3667c9b89850cf156d35a4487a3f6520951e6f0a3bd9d0fad17feaad6dd903a05e533883cc586f3db778a742c4d7105cf075e917c46e8d6c1d5039655b9ccdcbc4b5da2ccd3ca55e9bc3f95f0ce833bc1d819bc3a95ffd1f986d7333ab865362c9ceeb9a4dd91d5689a2bf60b85f8a7a49a5ff6198319dbb59140a8d47370026475b3baa45d78c5f0061cc188c4c1f6d8b59dc2871829c6776647ccfbc55c3c80e2e79f7e8b0dd3fd1c05a8e7ab0fcf8aff3a1ed265a5085715ad594f508c5ebda885e4ad07662643832b7ff6a906e09f52374ba5983279e8289c8fb47f191d195c8434b974de943adcddffc9c8c32c52a9ac11fc73593a016daeb5554c6567ff4c64a031b5c69cad2dc2d5d6b298bed28d922ff4ccd4d78d861c6e10c9e7c39426c7e8b3ec980478f865975ebe808a9865a954675e67c0ab3a7bb5697844d015f7fd00740dd7d5330cf664d23480186ef6003a70f507d8bb1b8d57bbb59b08c5780d7a92f7c7cac59f8ac6bcbdaf10fcbb3bcb38c71379a1b268da17e72881573f0c3b0e22cf2405cdd2a28147f3771ef6777d3c9b0337737ae155e441ad508269719521fb639cedd353981fa9105736fc670caa65285cc1314745579f7568fd36d24cc1beaddd81abe3d2e2434753b9fd95b1feec7041efe7342f7fad1130fbad4c4fe4d2b00fe1ba71f23038613d5a966e317c7f438bcb24894387ba703c2047b15374f589f42cb027034ea95f30b763355d11a4739bff1aecbf9391b95f3c38e8b9c5fcb982b1433e089472310282a13ed2880048d3b0a9abcc3ae651e603e4a8fa04218d7ee492527732a75765d1523e8be2ba666ef609c54472ccf2e6d9cc3fd2ae90765b3ed20d2b45034aaae698740c91972d7812370272607af0d87b9d96a112bc67472d5f7a084d03d2c7d36b2718401d4932813db389fa16b0ec7db10032e1aea7a4d8941e8624536b7ddfbe2523c9a8a318e4d283f26adb70c13e387753e43357f11655d42032bb43f46a213c5ccfc804e627806836c0975d700d928c8d62c55833bdcda9a5c01a9431e315e7cff696838b82ec547b85fd3dac08b198b08aad26c66b8a78fc3c149140d0d8ccf72d65867f1ac7d2c8a150ef96f8f1f163e331460c4881179418d164e514e3259de8920c2a4eb58a084abc60f1ab8b61726bfac1a0dab3abf6ba56a4e075ad5d9bcce516ba80b080081eb04a135e9fa1550b11bcb0650cb9d818f3d251ea0df0139bba7ba2991c530c17d27a203d4453d0524620ed2f6c51f7617cdfa1f91fa79cc56942189abd86e0b19653a4a97ae281cbd810a527e061e225b5372e60b7086cb78abfb48d9523d10196b7be226f4f7896451f69987ebe1474f055d4698b2c09aeb2b7ec692cd339fdfe885706e9cc4091224ffb218fdf9adb9a4907ad24a9cf67c98663045384f92726278c9a26c9897934bf74e80401475c58d6a095eaa1fb773cfc3f002b877fea65728476261a005bc3327bf9c90e5ce79ea5d343bc216a8832c2bf7eb4845a099ec1eaa50f67d85ca092cc791f63539426839340f3908d05b7d6ed312c03da087316a381feb09ca781a73bb5b131194246bd19eae28a708f05921fd53f88f847bfa40ffb7d828970025e88e2d8e86825e60b8ab8a8653c85f4450830cd81566302fb035bc2c46f745607ba1ecea939a957538991b832a6309e4f46a62733338a749a48265970669ddaf3af512b0d235f31a4deb71d383c9de50df7ce2fa1e09abf46f80c7c275a63fb56fe34f207f24a4b8e8f78db4511f911f12370b655b0f6615ee350cc17881b63f706238a79da088545a66e93a3795beb607efabc846485980aaafdd472abbecacddb3edeacfddb757c8835d313d50855b3ea2d9697e13853d11159ef265f150828fb1fb661683bdeae99723b4792320f454c813498ee3f02f83892b40cc735848541eaf41c6deab4683986bdf951dee94698b7853af4c76c5c411e4ec4a53a7459a7cca498838cbdf60597469266be562a6d3e698c868e2fadcc3810c3e306af47b67c4365c0dc5b24884f78db7cb4c3b5a47af392ab895157d3744af6edf632136d3d38195d7505dd28a640211313ff4f3d41e787f10dc379d06204da2470c5266d324f79c867d0861045b634630e149811b4b139596a559e49f204cb288081b3304d693b8f31b5eb4c555ae21674bbf83d4ab693efebf95a9d35c4885f3de983a9a56c8bee407040437a0e99776008e45dae1e8b3b03401ce8f7661676267dd0874c921548f4fe3c12d4307191f4ca80a24e7cf6246ffef38f1542cb98a6e1b1423a8f1e21ac22a6d8ffda37a0997d5889341f9bca877efba97eb4a038e6176ea558d325e3b4fa2dcdd5d2cf07f9e766ad0040d62b350c9c61099f01110ae18a9c4a1d8ded5471f757c720788bac022c852478cd7989f00e202c33ed65ff58aa07f3cc45dc432891f9d482ecde48c52b24a18c70c9936fab54700bc6208a1435416885cd1161fa9adca5d778be695e6164ccc7924e124f0959d987787684dab6540228e72660e8de1113983048fa6b2d33b8747bd4ccf9c4bddfdf1f262f83a275d53f7332bc4f6d8e37c67a0cd653b960502da974071224c401286cf89d8cac66cc23beee66c8855ccd1d5aea479c3706a53ad90d4914462df24d51850a0f0db86c594007efe4b1080fbf7dd1a72acb60ad2203974763fc08761c6af2098125f0f0835ceef65a19172a5418d20fb4d4064ca4c1286386ea595d3a656ddb59db73279b22ea84fb57fb1fa8567e57337c17fd5bd42027910b16469b715e7c974dbcbd6ba06aaa1525991e4686f40c019d5bf0fbca3f905906fac8f26c5738a799928b739c2ae44ace20852ea414c9d387e16a79518b0b921d76bab4a52cc9ad8fc9474997ef607c57cd2df50c673a43597be3994938828439c8974362d08344dc17a9ad0fc1e75c4d86f5a27dc75cac2f50681ff10811dd2c01c48d0bb70deed3e9eab681d5b556a607331d49f4f4b635836cd572eb20550b0d42f59b223c5dfd2e6c010f972cf83088de2ec96818c9fd3dc12b01e0a5aae68df9d984c877fa841d115a23509148c9e51692ea3e20eb45921a9a09d320637578b34ff7d40d3dc981f7685b12d5ba2e4a78cbe2d3a97513a434ad3aaacf6d39fd6a3f262964e840a9032c7fc44d1a38911af69b50909b22632cda1291d7c8a5b73cce2d434215d4a25b8f6ecf69502b9101a56f587234393cb7d584c27a8a5c50cfe6c6a10e6029c4bf54257c5916860336974cec13953ddceca1fb8c6641f59f4afebbcee2c2e94e697f19a7144da2fc903a5c6a87661043e758157451add1d5d2b686b747b490ea134a35b651351cfa1eb07ea57cf7bb6483a6bc07931993a29ffafb4ed8ce525fd2e7e00cf4222b740075451ddd122b330d48a8be16d37f395b44f29ed3d4a204fa6c08a9c491d7e90aba2537cdfd09370788730ac5dc808b2f2b158078c6c036424996942091b653782c2f17a3ae9e6d84ce490248f64b9478bdcd95fc1625d8b4705542465017afbe238e202760dc7d32280edb7b2e28672b010720981a1602c93da8aba489de24a58c014bb84412c8f22338c4cbdd01894562e6dd96019737b4aad195f5e27af6441e7e58835275763384c826431f78f62a66378598174461ba8496560877ba01b8e8992a0e85bb5e0cfbe0b8a1c489adcb1a8a5df113c00669d91e9f61db4ba043a1f63a3a424e40d728685f607eab893080581825e82f051c05b47cb8302ebdb6132eb8b8f40679dd67cd37694ef96b47acd33e10aecd126651560049e5e40c755d868674eb4b822676c942c4200ab41d4237a2bf05372c2ebc29a342fe58a08a10066549f768951f8f7b080e25acdbc76ef519b147f901227410c1e498e26e7ba769f3850770a601880b086e2365ed4e5e92ec5b8ef4690d8285eb734afe485b366a8baf20cc6d240d41301d4b64af3a657131a6005c0700e13929d1327338e74c50cc3644b5f047c400a94b46607fb3421de629a06c41ea6a7354a69fda3c5e3f8b89178267b1c24c7b032e72352c5ffd7a904697f718fee513c927b175d1bd12203fc3de98f2bc088e9459d026110297b0030e339dc912136be4a59846d9cebbb66e2be2b119f7165175e3d5c052fbff0c111581ec7c6184e8a4ca4d4e1caf11f7441b7303735e6fa5199a235afa9ae7cdc335d867a97380388e0e3a6970c959f17a2c47fd84b709cb83c12749c265531759319d00db3cffd276c565b6193b7a2c261f3ac211ca5d45c037f94476d43f52a7359a35597f3fb60f807f4c243f083b79261ce1c5c158185c107d3088c04c57019d89eda9a0ee3c137974a10996999198e24b6875902f68882a50e3e1c32af553a32034e4281de0cfb292b8f709974206c70d303181847b8d78e4fbc942c2d356e770af8b3357b388912e6bca6a466556a930ad32adf825ab29eb2da03d248be84478df2fb505562a61b34b6a9fe404f771ed9a398207063fb96dea60175fb97c74a98470c8982f6529203b58474595ddce4f048bec6c495c927e501e9eb8e82c78a160957b8da7a9dd55efd0868db50efba466b39143dad72083c08ad6c21c3a3a29f693f7b8a85d86ce7d6144d308a18c3cf7c723ec26c28949cfeaf562df8b3bd515010a1fbe4c8dcb52bf78b2f0ae2dd026d37c4fc6c81992b706cd772012372002f72b42cb4f0917f7661efbc05104f3a10d39283a6fa02d93c8c51616e2138ac45b35db396aad448a0d9ac6e0be3f5d4a822c84247ff43da2ab4d39891a55d5446818549e264d3fe79cd39b01e1a8045cbb704a51d322d462dc04e9268b4e9c5706d9b14dfe3361c89b6555a57e8ffae1f39bb91529b79152d7694814f691957d0896e068043514e784c09823c812c005cb984169c9098b30ea24ca1e2b0927e5712c50b6b6bf40cf431c8dc752b666e124d95bdcad2a15ea74da391b00bcf319e41da77e5200bbfe362356e61292cf8ee6bd071a792e0397a6e864be0518acbb91fac586c1d7191920d37f1dd08b542e985e5b65204cd7091e8b14c4465d3310076b3a82a064c65baf3090c0021151206ebaf2dfbe9840583bd456a22479eb1d90db5c09669d94ef6d4d6fe624d3b13f31384e1d567237407636eece1c91883609a173d3cfbbb76566699073b4a583a400acfdcbde24e422fefecc33abbf2382905d05270db12a3837c0b34b5d65912d5280605ac11693fc8425c3731c6f63b7641eb465d9a19b1a21a0aa233931d9212c32d37018db4226fbf283dddb0615ef3d28c53e02a42893b58a23c8acec793e2b8a577e4dffb68cb9a9146599261515263b38917d6233d9b4995324c8f18c8c04462a91ef35c4599ee6c4c748a38f6aec9fb165ba60f505ea52d1d10d28f512242aae747858e01e3a22af55542437c84c641db0d90e4cde3489ad66292979cc312c931bbdda7e4cfbcb2d0f27481382d221585019eefbe6facac8bb31381614814e263cb89fc2ddc89241bf54b02575613e339ee16981358eef77777c6327103518274ddb64935c5310e431af2383bfce610bb7874a1c33da5f4e438dd78978623c64355283e46adc2404a9009ba95c68b69be5e40ad173bf6ff2ee6ad4c8b4cde772abb67a794dc4cc8f4ca54a401b44cfd150e4295790aa37db011b2787afc59c9dd6046530e514076b08293838bb44be524793050f641d427a8c4d79805863ad1aa9ad1e460dd172c47289a4ea52d1e94d39204085a7b7b90fbac9fb75e6508fa60de60025647b28b5132afdce63cfeb27e504352adc59d5554a8ab27b7aa3caf3e349e8eb335e07de14e020f99e1f870ff9081cad80860148fe80a103d4ba76c1ca28e9585a3746118046fab6a84aad53d9d9596ea9032cb3120a8bb921e06e1532dd62940c0e1d0b2d03dd7eb06d124379bf24c199b4a63e7aafab8535addc4b233f1ca88fedf068d6cbb614a9de5d261412090931e73038e26710430c6418fd33f402ceb1f0924699aa075439caba8d164fc728d36cea309844871b388cae7c533878ab02c95b8e955411df645c074cbc1771e865ec4fda77de18c3f1972e7d4ec51c98dc29ab4e98a170db29dacfd0f5314baee9c48e1447973a2a24f0fddff45e40bfdcefbe545c11818c06993736a18d1832c80306a88950376114fd277d3d521be2e7d876f1511c6ee1e74ef372a5a90a23c26a73b0ea4114e59d5b6a68543295def9ef632f4cbf4a7bedaa5dfcea4777bee6b4a0b7b9bc70c15f4e5cf5d7163391bcfcbbc70205c1b37300c46014d91b7ccb5545476c29619aa29eda7490ed266ef17d547a1f51e4a8d692714ab22cfe94e1be4000caa0fa5ac24a943bf39c71cdd4955be433dff66ff90a55f934994b696c7948043df6d05b601aead1f268262b26fba135175cb57eef9e02526523e667d26c859e1fca66af7d68faddfb995b4e574d833f8c9496f5192679df8aa221e851ab4f84a7137f188de97168954c549ba3842dce976be3b1cba946e1d4d122cb8fada50ea87b47a8f2fa74489bb3bb351dece1f1d3d436ef5b53cec942fc0117f2da3c209e450b3229d5c560de03b6fa125a8ac76ce5508e308a234603b10aca3dc08dc58b9070775363834336aafab6512b28d636b290733085455290afab3508d83fe606b12e6eb94dc642c0d6bd30ceac6ced2fb3c01783e2671adf8e0a8e8a6e607259f9ad99a95c45c6a51f52faac7cf5e4af40e9d00bfd9513fc54d0ca992bbdab3ffefa5311c69f0d323d9651744a9a65de7908db92264ad0804a4962f9dbc8b99a734141260a60da93933566101feb6c6410d3ecb620b13d1cc474c091f1855d3efe853625a62ea717ffb0ce4e878895f13a68f193a24caa54f7611021356818a47bc2d7430fc59bc1cafa5a198b71f2468d38ed78c19d0e5ab0229b7826a0becfab9809b39b59c1b27be1497a6b85add4bf00377aad1a118d7dc88a4374ce488f0308d48a07e423745ceadfadcdd4c8b3f7040dbb5fabb846e1f4461fc738743ca50f5ed2d4f80ce0cdd8c4cf83dd48429437b2bffca89af53e7e9c84f9c9b39f534c4612a8ce4bc0921ba036534ca9b76b8e85a19cb655b503edd664353a2415fc482dabd89e149609fe30e6dd26dec5e91a56f5904f08d6c265c62011fa03a1cf10ba3918962deb650745c52892eee15597210d909c5668973234c97f4930c379255088138a38bba57236015ea8e74297e9fd0000f4abaab905772cf5594d0cddfcd902d709a1c7459690a9a890e722bc75aa7bd7add491b0711e589c569c223f35dfb23f4792c9ce1caccde5f0265cbf40dab8e16354e579480d2be71590f4e9867bd2650518614c898985bc24167cb986ba0071334dc62eb2e007bed66262564f5a007f276be620012cc80b13b91cba85eeb2d67f3e1e30f857ec78fe3ccb6c113923b154a8b31ca84bcada010e99a9863bd831a57ab5efa0073423af80f3aa40ddf8bc393aca0a8f37eabb03e1b7e343cd05199c5ca6dfa7a667c3d7b6fd41389cbb2d0a03b1d5a192116b14e43f8b26b4c92a3ba51de3b07288668286191049cbebb710a66bc14d311d748a92c2bbceea929ada6ea57392b2e876d40aab33cb8284f0c9def1a812769a0ed33b23a336b237c3a623e2975c54903a415b6ba1d6672ee6594ac509fdbfe7428b147df5457496de05ef60bd65331e00f11b6b80c21d31c7d873d33ba0861d16f08a4f560d1a0665dfd540a783b8b0c3816cfbb1dc6c33539619b7adbe669eae4621027d3f39d3a57cb3639e2a8c03a3a728673832a851b08901874066eb047ba81ede82b38f94f483ad699ee1e9a80c70aca291f8f6d328d3d517fc9702d611221aee9880d8943b0d12327d204f9ce0ecd826cc9d46012f05bc76f6b0032c1ff4bd484e1fd3e6d1d2192d527115dff6f88a7862bf90c81af61864e21abc9198ef3dee241e93a50538f2d4c939e230eff8be4a2c465942511855e4398bdb40b096ad6bd6914175bb2f5d5a0e1fd1a73a994a569d31945b83f3c87a388f3bc0de6286805847f314a69a11be5092b747220b2bbcbe2aa22ab90f2ed72e8b88e2abb3f664582b3ae6bc38407136d25196d4ffddcc12f537f0da7247e7f303ff272c403412d5a04a3a9453093eb349bc7532b09058c608e2461d6ba6112fd4c2f3a09739f810a28ea367f9a173481ca52ac5e087906e26587b9edb1e2c6cefe05160bf62559a120f93700d5aead0296678da3df47b34a4e87dd18810c733acc6f06c96638d54ee1fb5e54e897b01ce406692abf23316c0bc0d8bb56ac750e0e0694e681223248bf461a94f8385853213768db1d2a4c1a1c7c17bdd500ee32ea563185d549da86657fd1794635144020952ae88f8d35412c1c4054a42df44829d26e6ba256a5613ee822c2334e1b2398a7319373f1449c98909d13890169a24788aaf884aa128816638331493af2250aedfc635bf14c69362e85875f0298888983cf19a593ccf39682bbbed82388f035b66b9e11c7ada176fd5c851bb8cccd36fe6a1f11b604b540919816d9d358b5278092fed1b15922b5e192085d46f5e6ae8a153ddb994dc69ebd21ba28b32c9175d26e0bdb5628868b26efc43a3c3de369ed4ced70a918a2208d6c982416624a1fbd3980c851e223b092e07901e84dbdf43841b7861c01ff9ec2620c6bed6f8eb16132feadff9c674c2d839546e9ae4aa7a18a540bf43d4058db08b5787c08bdf2de4871048013c60933db4095c30b1d390d02f0400024e872794a26a47adcb9808d43ae6a949cffb786fdfb8ee9d67346adc9d773e65c301c3377b2d21190199b87b1e1e9f173b68ae98f65344bf75071d39f086075868e486c946ef94555ca795399278e425d321f929ad15b07e50d8dd13f68f52528d4bc18a8003898b21f14b63ca157381c65939d22ed597c5b2937ace086e547e9c72d017dfc33f2bd30ffcf542026950d04a2b58908b9da775891ff3d540e6f66d69c2a779cf79ac2658a0f71d85982d9557a6769ab1d0f51aac784c4c9cf486562b6a064a5c79e0f5e2b0a8963da996a350f24e54358301d3b9b1cf6b29bbf70883c11939afdaac6b0ae8a8afb305b1f5169b956625eb24ed92ae2f28bddc76c6b16192b93fdfff58614527549d8dcb9a8cdf4df08451f26300f8cf3d49c6e25b4da90c90bd8c73532fe6ce44cb0546bb4356e7eac60aae701d61f1dabb138c31a4135519fe177c992557844382a3c93a8133449b4cf6289e4ef883195f74bf1a819a1379e2790cb13b5880cc66a9c8a8dd8ce08a9144710b9304f1ce2f07620c3bac8538708052ce8d162b81511552a891a77e46f1901d39749dca23c24686d0f6a87a207cbc52d6e26c0b91db31e9c082aa48c18a360b101b55c7f12ed5bafd9bd55b6c9ac793660de5604d3cc52620a2ead5a4a30b4545e385aa3a4afc36466eda7310ab748b8a26fe89a8c3b91e3ed1130f53c7d6075998f2a7308e7642e370b37d8fa6f62329b916424e532ef88ceff5f828615b6d5618417b714b8950ddefd9a7174e4813a829bc91038b60e896d69ec5e17f2c95392690711088acc194ac0693be5acefe7ea5c1516be9ae361a35b0617d19119a82e5e370213ccde3cf6430dce430dba8f59a5033cb23f1581673bf9c2eec4731a0dd6586ad74dff6610b5bcdb4e3ea89d3de59dd4bba84d0235b0a563aa5180f7628bd54c299937c78308ea388cf5fec5d95d39064e352ba6f1edaa460ac6a342d95fc0c621c33fa8fe3d21b00e59c73d8d7b729cc2cf6b25ade85205d4130b50f924326a5d5af505fcd1cb0c8f49d7af0163473ba4e20e96bdeeaf4b361ea5cd6395789f7306f82916ee0435e83ef658e4dcdaac306eaad4824a653405d42c9ba0407adfc69bb277f225dbded4c88431411dd88f1bcf60e89fd83737eef2349e1cdba5714e8d2e3da9336d563868c88287f6f2ecd54020957abf1ebd08f6495403847089a24b64cd906623290d058519465e04af52575c962ee95792ed796d437d7c9dd2fb70d3c8e15459395fe23d0c8a8a611c8c7dc25b202e51d73e8c795f99c0fec6ee20da92545f0406c00d480813d01f6c2de04c8a81213b793c6e1fc654ddb761847fc7064e06f942fc2d0083bd3a4c1fa0813041190843b0f80f46a9ae27559df89a70b0516ec35066f5e5adfdb9f8d25ebd5a9bd89f56a1c259a1f8397503dc0351f167c5da3965344476e176e96a4d62fe6c871689c9671ff6184d94827ced1d49c95ed53cc5330d2da26540a19edf06c7aa2fbb2ad2bf05c75c8fdb0da0298f645da46e103e85c98ed8ab5ed27214d3364e07e3c61cb9f31e6c6d509c2aef8d2b326a93ab2f6762a016e1d7ea1c5ca64bd6b2764db4374b87a5bf6f4074ce33609f04c395e30be4b3c18d217a7d77648dec5888a1edec2deb487ddf28d07a3b218d4888913f090d17576e91abb5f237b067d9abb4bf99c658e7b91be362b5606d859de81e7cabaf6f7c04ce8cdb05e6693abf9fbb0fa8eca6c73900f3b27f7c4b6d6f6943e1fd1646352621aa499d66a1389f1c869ae03a33438f495daec9257a4898ab495d1f8420cee8f1ccef6281a2ce15c6831c1c358993bab8077fd89dbc4c117b4b9e44700f80b372a7a4ee38f527561516724dbc62f8d7df7ee505fd1ab537b17ead42958d06780f3b864695d672a1edcd30a99888cd680d37b27121c6d58560c92ffa83770a58e2f776cc7e003f1b4f9010d283b173eb1582709d00a2c995455535a0c667cb60832d9159d706aafc440ac9a4cd1d91ae23a98e8e780ec77827d86de9c02247889c85f0ab5208ad575083765bc8593ffcaa47e8c72ca9f2d4c399cd47e06b3cdbe31f5e3db72d673983642bd5844a292a4f83a07a10152da6032540d86194292889568e174b07a64b3730f74048d1e06d34a98de172b1e88da3c23303e59caf3c3cecd16ac8388d6acbbd2a26875b63ee827128c840034aed69675b62984f5dce1e737170d0b0f027fb9d0d635a013ae0252624e5a64cce11b64c0993d321b93ba1de6c84ce5b1e76b81e69bc65112206f8ee7e8fd0a7a626ecbd31ee6dbd073b4dda0d1c1e851ba417bcd930c2054230f8568ac0cf54f6c9bc88207e0022f27697c9706aa940c6de90f16ec9aa9a269dbd9dcfa48e179a9034922c12b444cc72a8cfc4e670a6b3782615e333a101e5d1f7513a33496f4ff2eeff426313951ced75bf946001ec53780f29107580303d213a335bdbf098ce74ebd4de44fbb50815ba32b12be186f1641daf5e742b6ecc81e1026a776a4619a251c25c3457aae2b5845d1141af43c3b3b5403dd609dd9ab517d17f2d0a5155c877752191aa4a633a26df8e2a1702b724802c3913f4f77a6918f85d5de4c0f996d26b775fe1ee89964257dd2713813215fc7130f769ffd5156dc9db4d9d5c0255ab20c9a691aebcb6d59a68a34ab495267366f25914a5effa372fb2fed89526948d98134f4447248d835f128aaeb954e2bc919d9075361551b844a3624352f5f5a40ec0cecbf437174158896662f94ad6455f33d6c188c8d4d2cf6321ca64026fdb0341f1b274f17a056aa0f339917b46034875a09704357421a5f03c82d2b8b60c36f98723de825bc35eb3167db37d73b3d9e3d3adf426ff3d279b0de8507ba5182e4d2b2138f0448043e1574aeaaa190291c2460e895130a04fe89791b1a9ab1c9638817a8b177224845b67011fa6ae380eb0e09338a17d4085d158aea2d4f3fcac7dcdb323a98ab2daf13b3917d5f06614135720340aadbdcc01c24b04e15176619aa1478584ad35eaf3b1d3316d5d84e7d19923838b9777d56131e1279e185ed722815876bfab57ee85a3d3586a95eb55243c6298e5b1fb6451bc3403f046913f0df0a23de83f6d727283ad79c4f70337e8e95b811afb13eaaf507935feb0b951fa484a331848a098e7bfd33765945e34c03a9c7c34b3bd585020341a44a3f8d45685181645c62beed75663101a257de1f4eb86d65817f9ffbb8ef19e28e92f341abb9d57c02ffa815332411934b457bcfb1a711f1bb8a116f0e7e542d5870d5f9db3bd8346401be71068aca83297450d588a568752d8784dad081f0604e8b9cf9c57b9278d92fd89749ab9694b233f8a2d0a45d3508a2ad327d134648cad24e6ea358ddc998e1ada96d85fb5a480078a0f12109cdbef2b9e38ab2b1f8ba72cb2a9463ceaabc5091bada842b3a1971cc97bb1dfbc4bfde17b0133186c742f56d51a9662a0148ca19eb78fa65601098397526083dd3f3882a6edb1ce7e162c383e55d15857cbba1b501084ac66bbab68ef6b1a9ceedc4354a19cf23c59381cd1d42532abcec4d596e71b3efe575845d6dafe3a90dd95d8e8463f3d5b0fbac1b1d41409afedce46cc4454e4f645dc9983738ec40fd1caa545d3c5d25c281ba00101f14e1fdfe710bef22fea76ad144a3cc3ccde53756da1d3b3eafa80fe47bf15a134274b47ff912adeb514d2604201c818b7d7a84fb795c052ade8068e8e83dba08df6ba746e932f125014878c4d979e4ca41321038d7badf1ee01419c6aa21a81d7171d2aef10dbe1e35d787bfa49908db001c5b5efa9c7b20d58ba9fb31981775406167c5df3e34740ba52b265c85ebc0a13887b4f43909bf145448a2952a6d11b89b09063beedddf0aedd1c0056bcb3a750c8a1399cac42f19586c471c929a7828860f28ec1a63eb5d6e7c70b77c3ba0f6b12b3e2dcf1bab3c572a6deb2bc77c8de46f405782e4a771fab74de495b5e2b84a06b5f5a2e602228943829425676ea9ea384de84a0964a1f49d9d621ecf2a99d7bc57290911fa28cd4dc1ae90a479315bf3eb2775199f6811cfc9a6862d52a7ec1f0e29711d66d08c5caf6605ed7ee9c65d6c9c90ee9afa1c7fae6b33fa1bfdc7488e6361f23181c8edc9729a8e62fb7a6668ae52901f72d3c0f2c8cee55b211eef76b8aadca9e84317a5ed97cf1f51f72bbfcf19b8c073cf09e85f6c142110620371a607dec981a5f5a524a383265533ab12a996d440faf49e815ed041d95b96c5a11cac3d8c2584383bf94e5efe17f0c4c7be0db428b98c28123296ec31dedcbe5faf5c5d89fb59ab6893336e9c8b9b7f883513c1e5d0c7a4233ea3ce9b9c3105469fd641af70ab8d6d22065bec37da13b6446608f2b629bd5ed03ca2cfd052aa9c055e43dd5cc1eaff8942a91d77936b8d86bce82a1608b56b117c1a9829b3ad4bd70574528ad0e10520487ddf5611751ea92e24e1132aba8a85ea5faa258ca5bf69ab5ebd5ded45383d442477f4c852e1766aedd16e545303e5604cf27daa50ca68e9b5b15b44c9bd42c7dac709a88ad7ac3d9315e5f828caccc680c9cccce0efb4bb2f4ed3a9a2ecf596af549bc30b93d4956de52960c8adf452e7b5578f390c06088d83e118d7c55f2c7c13bf4f60b1eb28031622fa67dab9c330e5ef1925e4508ba53e13da440a3fa59fc98da45327f495d0bcd27d118984878a6f87dbd438ac67dbdf11bf0dac1b0685cdf65e54cd3b66d907a338adbf69f8325837b4315bc634b699e2825990db573a1ca561324d1045918d5434caae081601e3d59b806c2aebda1cc92c9102b40ad6be25b627787784fc09172af43b8f6647a8819605f4373baf54cd37c854e4d9251d55f6bec947a61ac3dfe248a0e8ef72903b5cf4ec91526ada2b04a25795b921f9a30bbbe0e2346ffa9476fc7b8cf75c947a2726625d83deff03a96948d2c8fe9d8bc1c2558bdd6cc07e7444a8bb9e3c4389a67574628d5dea3e459043629b71664726a52555fbaffbe53e9735a0900f8a25c6a3d68e638819b15f9a2a7077378370e9182a1ef1dfd1be1206402527bc8508c4389a6f12d3b21199e287cfcd13ed02736773db13445dedf10524dcea0780eec1de97c502cd1a8c96c98731a242447624f53c638b13d0535552c15487ecf888945f4b983181aa21c3552953ab3b0c5c6fdaa7fc889ee510eb9f0ad22e55e36931b11a59ed0849e0449bbb2de9904ffc75129010d1bd867639d7d2c755130ab6c541218eec05e143a09f124198a03dffbad2f8682679f01d32ba66ba6534306c54f651f3970a34d1a0ec20b0f3fc82a5ca0476e4fcc861ae9e8ac9464397ae9e0b8b6a3b3f05ee17f3c7810c1836a4147a93ac61473bfbfa38e1006aa72cd9d8e79f0c0d36aa858e59a06a990e252c3e6bc62f6e1527573c67bd5518c910154bf87dfbaf0329873fe6452c101bfc9d9f7ddb1a5d2a9483cc9c0f5d69db63a96189d1d4553dc21837c001acfb5a1054ebaca6b897c984ac15b548a495d4aadd67224838b1f9502214ef663afdd64a949d865bb80e4724b58f2eabc4f29e36dddf50ac74417433bd01efef8715bba7190ead92a358a363422f5962ca58b1bfb996e3657ac449fd9b01b825a86acf79488758afaf2bf59d9d9136cad61d20100bd81f4d9d724644072ced881fb1fb30fe6b100a86ee9211ad669b4453c3a3a3c4a93fd28eb64019b164ec9dc9c31a2ef3a19b45e5f915ca3880bf79758a3a0dcd6093a2be1c7cbc56348cb2122554cb07acbc072db1567bcabcc8dbe09dd5e9ab66bb2240291def3f38ef906cfc726ef8187b15d5203eee8c919370ad1131da67ac3271eb340db67a26217a5c78cc413b99f3aee381d662ab17e1f24c024f8269c7986cce8546edbcb05d9d42597d992b05360a3be8a705a4d4281eea13ee8f1fa4d249fcc6534e31ce4a5c4f1bdf1972bbff6c9ee8a362b2911a1a5182637ccbc8f878cdd4661ad53765d15703c6116f000f5626ed919ff04e727a2a1deddac0005322804cf57cb087aa3503b11519add5eb8da6cf4d003df3461512f4e88c78522f984107c8f17e8349a5d14b2e0f1ed7121688929799d0d71c360db180635a476d2b7b9a14f1b97a80f6eebc0c805e262c0efbf18f4b51e3ddec0932a732fe93f27e708dedafacdb3b3e6e35e55437ea51a8628c81558be9a7c9059a3622d7d83ba25a293fd08cd502d75a1bbb115f4893caf8763d442152acd11836fe311ab03cbae40a4478e0ad4f6e00766430bc986da5859675ef5504321ab982831e2882c99f1ee5ac3b5b22f53e3e7bca408dc5c190d76982cfcc8360d0d8c6a932bf900b7f124e9a32c0284599c61243637a26de01e05ec173f3795e268fa6d9a73628a2704aecc3ea365f6928a1291f9fbafe01a276760401889c544f39d689b5068f9534e242e98a3d86119ab74114e6447a1e0eed8108811b748a6d373a201f283c6231faa5b5f9eabff9f761de5705307311557f2aac8ac9d56e92f2787d234a758a696ec3c069bd012f44ecde96585aad35aef1b1da2605b3e45e1047af4cfdd4a2718ac8429edef44e3c4b3353c3db39d09e42047f8f13acb8caf5c0b83b63477ecb4e9746862cebe7e9ef3c42fb2c1006917ca6a9e1af9dd01f8587afc5d57f74840126a47134591a91a6cc6c4168c85288acec1a91b8f4e82780d66c8d54c714c19ca6ffa7038758981b5435164861898a5aba8ab2e3414054b93eea4468918d23e2ee7a0b0860d5e17fd6d35b61a1faf3311a6ff3513a16dbf05440c45d1f049543783653c14c5a489a447260d5114649e5fb6cc752ca2b20b2d5edb6bd150701f3a9dbd5e07a285a77e2a17fedff77b37de870f9fe38710e79f8e02f4b06f86c2bd73b5d325f27412a9b6a235d3c822877e1eb8c6740282062464bb450dc509e3021732b7d7c5bbe5ad0c7749f45766ee8d628ebca65dd4afc3bb25abb81e5cc30a36a12cf6b36cde9ca752d53925b7f3b45b07a8c33487de9995ec5e2672209b12c9190f2861172d34df14d535e6651b618a1a705f4ffbed508c748de034ed42bf3d91966182224c7447262a567242b60a51812a36bfa138ebd5cf8a61da7ab5831fd080f4cbacb020922b17901206d96e01bf9f0574ee29200258617e031386d4c4e37bef426967da18ad7ea3a3ae579f5213a920ea2a2dc62d2bd5926b05cbf95b4f7c72749ad7ed94a83e3c04675ea15d1399a1e69cfb15d99ba883a350f4f0d2e389b3cd1adc7b3751dae635700f17fca191cc2e09f092cb84363745c855c7c57386a849d045718e18011f4b59df2f0d429be28981f65a74029e502bdf7c2fc680f58133daabf31d1dfe8ce66322f9f7af8e54e5d94e40937ca403ca754e7b5930d81da5037d9bc9c866b3d92c7a6b3c50e1cb1a77bc4f1c1c48add941c8490381c2a8ceead5edce5cc02fdf38d4220f1ef07a42cec68d385871df0e7a06735c257c6657132f17b9420c8be6ac9584ecbd37915bca2453920196072207cc07140b94f5fd3b5037d062fb552b7f2cd644a1546f08edb56e3064fb552b1653e8287ab51fb20ec7d3938a9e501a455db2075e484cd02744a42659e4200e82817ce0cc3ce2237aa4653ef9b1fdda69fac4e168b20fcfd1d1d17322f721fb89ff56a8f7858d48d7e301834023f37b26d7936324c535c580f9f16d98313ea91a89d5c8ac3d3993ca2c28ac5da5ad5cb5893a0a9ce97f393244e8287008d47ee12c3487a679958ddebff7ecf619b1910c0ee8ed28515a8a562487d861a37282c4f67f371f4322b66f084f0b1d24b2b4cf7c359cd482a2e0bdb1ed7707ce0e9b20209f1a04f9fc0021b1e4081217b22aa04c502eddf59697a3280bea4141bc1cfd2fe7e538504e572102bd0de4400c7017b222fb892f241901bdd34a2c68fb04cda0eb2ab01d740417244a1a0073b808ce0c81f6b78f63d1bd2cb0ba23a4d87e1c3b1e11330e2ba0ddaced844bbea7271d662704bd13d6f880cf0a54dec3997e1f5de339efc5e7ef410066c14717e48f00b2fd2b1cccdb0f55773dc3fe8f5aa1545e500ad8812ab2fdaa15efe06f511b56774e604526f179fb715269ddf5bc2cdb94b5c389e0c50824ee03db4d73bd8993a1264750a4482fdaf1fefcdf77d75a5014e8f5264d604d9be0cdf407310403db2d44932ff6d297838de0cc0ff4cea939134bac375962fbb9c9500ff11227bc845ffb55c7da6133df0bfd324c509926d0db422dd44465fbfaa1f77442f5903bc1da71c3a48bedc7a91233cacc7ce3a35fe8373541617d37cc1dff0d059a06be0d5b9ca679416ca890b5047a59ac97e101bd28942a26795e984499efc3d7755dd705e1c52c351ece48bfd0be8141af431564f2dfea7a904d01dd9e406f0319d5cb947650031d6924b63f2b25815efa7290f2211b1979bd7c74f4eae52d9772974babd8db40b619007364854570c6a404bdfee33f0ee4415c544524f9e173e2fb0b2ff4471ed06e1f1f9f143c0c9a466503274c6b08d1abd98c7db658cda2382e94bf4b810f90cf0ff561a07ea1ffb1404fb5852428c7042a63047ad9a79d64454eef4ecbcf4b918b95c74817caf3f85d0b3d2d09b2fd456274875aacd7cb3e8f2b62842752815ed6e2e5ce9af7995a171b649cf356b7836cffe604aa3150ff3410031dd14840bb835a6812b1c4f66b27f83f7c8eb3709c7cc8f043efb40dc316433df3a2502254952fea8c7ae65918b638ea9967af4d375c821fd19d5109db8f4364fb7d54415948bf8d01fe71485b5214ca6ac0cbe9b4259b11e8fb37c335c5ffdeea50c4c22cab218e3ce1ffe17364f417fa4b3fd014fc6771d4553bcc16ac235e06e86b09a1c4b684aab0f4877de017a04b8ee52f6a9a0c260623a4f497a679569a1cb1cfc6c0248ca6795698788901892a9a261503125d7c54c7911551d2dfd596f9465234290eb9e98ed3f4717afb7e1caca97dc6a56963b2875f8a711b13838699e8e9f65898cfa026833bfddb6020840fe459585332bf035fcab8c77097da983f7132dcf31317e3df167b6c8c41a1e460e9e340182ac542d7782a43a1cf6524a13b22276d6e9ea5af695886b1233066c6321309c31e23c166228be19af4faf724fcc8e14067fb362e8aa88da63184ecdc90190a3333f638dd750de74052c1eb61c47cfb1dffb93de97b2cb3d46c6bd83327391c9861d3fd495d8cd0fd278c30bed7989f5d1cab830efde7c78ed2b2a2c3f983948a2aa25a6891fae3d8418ea1748dd633fef15b4af638ddeda0affad5e5736e3f703a3233cbe7975f8af1bb4b3176c72c931dabc3c162c5eb23ab696275d2cbcf481cabc3d1c97fd61f0ed60524d64922aaf1f8e2ab71057a57b7c3d13492fbd11d3f7bb14492c47a565957d0cbb2114298c3d3e2520913f31715c3b9807bb09532c9e334e46ec0000e449a866d7c0ae8d8e0a36be8c76771ac615a390866d788bd7e4e9e189e859af61bc735044376fe659f0bbf647ad2c31e4b32695fd2fee26e67d9aa16e78cf6396b6a72833fe1f603f3487a12370011507f9e1cb3c64e20b18c65c39e9947c933237d06996b2ac8b3fc409ee59aba7ee7afc7786c2471dbbf2d468e8866b79edccdc1668f03b5884241adc6384540e54792855afcc9b9bf5fc0c6273df7ecf4a9713656f7cb0410420899e85108af961d9bbb6195dc59b22bee3e85eed1dcac837540f820ac7fe3bdf75a0455dcddddbbb322dbac507eef6191cda669d83cda3df2cbd10c6b77f7912cc2c7b97577f8de7baf9344c7b81b06967de84010bdeb5116d9468e9f0e089f1bdab6469a7bb48e1b5f7208a0f59df8367bdc8dd3448837d893f0a12834fa0d7843c6e8f344f6604df49c8c357e33f02307b301db0f63fb5f0eece9e61410c54775343d5afaf38cc4ace4c139d29b91df037549f758b9f949cdbe55fba4608d74e76858949d21632f4ebe19f80fee603b9e6c0c1be3ce519b619a73269b69259b699a739bcd36cd39cd6625cc6630da45b2d366319a739795d1a1cd6668282d55a346c96b7c39e0c30fd8e6f7020481ed8f355210426f41d69f9918c040d8c2cbc2cffcb9bb7bf32c053d2c58b060c182050b962b57ae5cb972e5ca952b57ae5cb972c58a152b56ac58790f0b162c58b04ce13d2c56ac58b162c58a152bef09e1439e0416772c58b060c182050b7dffa290c17fabfb8ae0d1e3f1be7830889ed2e5092c84ff155728c7ba03b35b1a57a80ff9101278048f58043c3a198272a8113f6294d2fd69fede7bef69cfdf7befbd1791903db797edd7c25e7d4d22a02af649a975f5ea1e638c1e6574f7e841f0a24108d3dd10763b1872c2b894eed121840e55e0ec1c07d8fa334cb37b7bb787e1b1fb61628c578c1cd923757f24187e3142edc1d73fefbaae4b9baa192dacd65d37b7a6d149213333bf516bdd9b7c87793d2c25373bc312bc27b8d8cc94694f64b13f1c0687ee4e2794eaa58c7172befd8811a541a1e549f981c2cb27e189efe3e3c31321333f861042c8eda9212c849f1f1a11b98101a24204919b2d78dadb0a691f1f1f1f9ee6227bab223e3e3e3e58ad083a9b86888d851305a11512b3c40a0b6cec571eb6b0f216fdcc833bf41feecc27c8f865bcfd809ad74d869efe21f3cf649123575fdd1c5f728fc4acb342a9eea796d0f957ab3192838f8f8f4fce0f9fc3403002f8fd3523d5c6be3d4be8ebaedd23113e96b3afb54496a12674d3329d7a7d96b5c61bd7e7429c91b8ced410146ea91ad09deba3bd6fb35fc1c7c1da61223d89547586b8bdea497542a99a463e8f421e534250f96cefc34fd58032b4699a9210cd02c13ab0ba4415f6be85374b50b1f057382c7cdedef6b61fd14677cd310ef458f9977fd6ba823d1b93a0602b69902feb85f07f70bd3d52be8e14d7691a7f1d0804272b13982fc17ca65d9f9924174bc3be961351c895c0248d846dacaf3b1d20885ded638df3e15f3146d36f5cfa382b0fb4db5579da6e7fb17ac177bbd59d59b787d75fad5ed1ca9df9dbac3bf0a3dd6add6888165606828f4418b2292907f3120766509b1465678cfcc9c9a75c4cdd62e405c3d1dfb8ecb3c951ce7b667e36b5c7698d7b4eb9494f284e65a43ee8d03a1532f77e776ee7ca87df834bf7cf1a5ea5d893a4fd75912ed245ba48a4d7b81dec5d17e9358d94658fd31b86fd45b7d7fe9a7e23354cb63dcc46aa3c6fbb5bd30cfb2f715a46babe1fbbea6d534b2038416407605fcb09244efc580ec2be56135dacbf97b5d46304c39e8164929d4bfaf83d58c95d12bb952efd79da46d2750b335f63205887343d562a61a512f69c84dbd9fe6114c3e49bb037491d20e56e0f76877f7bd3df98a7f3ef29be7f8d1276e25ecfd02a612a4f5bd284a9314af572a0e7c6549e7ea63a25f6fe1bc74068bcd1a059ac5ed2aca7ee3893a7ee6a0fdc43fb42a289a3eef83cdddd4451134d9a48620f605f8b092dddfd5bff167f7b06da7a8bbdc5cfb2fbea7529b7f79bdc36b9bddfe4f67e939793ec38b4524a281f06411d60f677fbf72f6edb766575e3913b0da52cd58df426aef2409bd5db8391a63c695b5f4d98d0820927363365d9dbfc71fd3c6d3926945801d8d7ca81172d1601f6b5723064b397f9a5733d035d0f5ac8ede8605ffb33b4d77b7fb9f2b4bc34f9aefcbe590d7d3d736daf959ef2407b7d7c53dd2a37801f2a2b0fb4f26f1cc00fcd2a4f5b1981c8ba239b5479dac2dee19742f865d568d0acd7cb0f2b03c13aba9eba2b755cc2c45e2552d20c42a269f11fecdabc6d406a3c069f85dff006d8651b57e3513264626c3d46e03bf68e04831bb763fa1e2c3f1573b76aebcb2d3cd7dbd6f42dd4db5cdb74b9325677ae373d77576a7b8c3084fc38f0cae7e91dfe1e6cc34bfe067fbbaec45e1e0cc3eaf524b663c088c188c188c1187f7b4b8cbf7d04238c30b68cbf54c654dd05dc3565e3e563cf823537dc781aff33b82f9d626610c2df1fe448b8473fdc1e076e2db1afc1993620a6aff12513f637b4f077dad4bfd473f5bfdea877f60d0c6eb05ed6b08fcf828dd5fe1b2dd4d23f5833e31face18934aa58ae6d7018c0a1bbf834b4f9da80d4f8ed25d7afe2b4674e665f837b36c5c5a751ef44d53b67d44b65d44b4bac8bb2b1be8da9b7b330f576945e73a3cccc3bf3b1a7ee826bfb57e5e571ed1bd318c3b619aed7be32d3df385a53a497f5e3df70512efca5ab0740e5a0c75ebae52f5d3546bbbd7c6daba6f8f1dd05d89b5ebbb02fd5db4741db5fd4a576abf23dc85d700306ba8b7f495513bcd8b7af95441325b458967d2d25a0d856122d1c081959cdc29f2fa5950321fb827d2d285b6cf62c405f0b4a14dbd9d78212645b50aad8ccf2cb18ff623ed334989f756e9fd5cba56d03527a7f3ed234d9f3fc57fa2c9bf57a36dfe7ebccf76c07fb1eec7c3d27cf78c66920b8873f67d3f4d33467f57ee6e975a71ffbf9f72fd77bf518e9c1f26733bb2198cf49ecbd9e87db99df8365ee4221d06acce96441f6f234b49771da371a6edbf9d9054b7fb1f7af978ffc35025aaa7c4f32efd59ff972e5696b9a01ab332a4fd7d48ccf84cce7e7671d06e21efc59e58bfaabc4993620f0b9eef0635f72feeb7d7a85a5126f1b90f93b1b0d9a9df57220db7e68527846d350a0d2677f71fc3238ed6538983f6d25aea4d35d4c0c2e857df6cf9a3e26864d1508ee717dcda0d5fef2c0cb03b5baf357fb8cb37fdb0cf3d9ab36430c29a6a6e65f3cd0f25f1ea899b4a7309c7747eb9baadc80f0ef94eaf671a341b35c2f077aecfcedb5d7d1b4f7ed873669e8ec2ebb640c8e7922f3476941047c848184d8d2dac19716951ef81498738a0bbdefcb8a7b823d3386b1900e05b4f8922b4454f1f124458cc49f58048330b4bb6ce609d48f7417dd2709fa110ff2c0aba126c73857e21ec581403b4b77f1db28c90dfc664cff483f30474cf53df06a8a3c1e4a9aa649d3f44f1fd80436fe7b9783b011fbcb4beab5ed2084b358edba333df7197313ab303049c644329948da56c48817347bf9b78ddc54df0533ae1fc3d2111bebd7ca64f51cc7d68d8c8c6e1bb5112b9b9327a98522526e3ffe33267d12e84d6047bfa50ca8ff8c5afc1a1d124ecf9f5a13fa7cfbf1afc33db08f2f81c783f4f127f068eac7d5df590380bf9447cc9b991ff39583af7b3ae63bf75e0e0070f357dc7cd224658f9132794d1700e002ac159bd5492492d73b9f7f879f3e4e63dccf76d243278ef39fee805c0000d755f44cfcec0a22213972e4fa111bdf93344dfd9ad5c7f7218fe244bec4a1b8146fe24e6cac9ec493b8121702d236c583dbf93a98ecac33361a4c3f2b0f6cf9698c2345608dfb40eeefaca169b8ca909176ea633e5538ae72fe133fa505bd5ef5368a340dc9c6c7eb230d24ac24c53c6c4dbfe340ddc59feee2e368e31b61ec6bfc15d7443d1365feb611071d61201f1cd80277d9b680d522ddc5f937b21a9ffa22469ae6dd981bcacaf8f7647cfcc9b95077f17d63962d026b74e04cfc49aa37e2abfebe2f36d807d4cf97db10d417691a1a1fdf08fba07efedb66bdd9c37c46bb8bafe24eddc54f7135381a286e06c764f532b82ff732121bffc4a16c0cb7c305c3518e87ada9cad05d7c9d58aa7792b46a64e307c9e244cd1a6327b9ce8b6e7400beb4a8404901a14505d14f9cd2a2224a6b8a93d614252da2a11691921497860f1241a2088b580b248244cc85c8aa9864713e52c9806addf50f3ea2f66df1b73427c1d2401a427a3f72d8c5892cc50525c521b4888efcfcc2356849b1c576d132a8c019f6b5a478e22e448c08296770c5d8d792e204b3740592530183d91285512b8a1e584db3af15c514cea40667925c40ad50aa57fd0a27888fee7c10041314558a1044e18b143889c1cfd050163168c2959f2a6e2004143e40824251a5403d4a8582353850361394c8c2022438c1c9175d8ea4502288265daa60832fec25007bb57c00642f17ec15054e10a6a2f5a0c85e971050a81dac57354e10d47732ec6b45e1c45e949d42193fb3669cac806261ec6b554194da8164d974c73bba63a2c4ea8eafeb92f4fa560f98d8eb6a596185bdaeebba64ca08191d768a0736fc46d027650ad605fb5a52b4b0121dc87b45580218562001e5b13181d086767e42c5132c4fb278e2c59110d94f67eb39aa6780e66cbb60fb6dbc175053f80e91dd08bf8effa669701bdd6bdf1e7868c87fd334b25ef5f54c6cd5cd45d570e343061b6c6c90f0e2cdbc22bc9967635dc243028c37f3ec8b5b64f0676f3f6030a8c1edc789b583c2681066f6a1b8878dbfd2be8f525e0ef837a268bc1ed9bf4fa96cdebf1b01eca039ec03c05756db7835f486634e33de878f1b1f37383ee01719f48b8c61a13bed8c18311ea76fbae6f988f190c298ea756b7a99b7b9f1d7a6351a345e0dfba0de3f3e1e2dbcbfe41e36defdbfc67bbd446e3a8804dd6123e53d0d6d7ecfbf51ef0d7bd947c8cb01df061703eb80afe264e09eb36183a16d8d4a8197033e8a0bf272c04f5da1a8f77f3c9a896e66c8e8e2fefe685072ae1ed2a8da3f58c37d3ff74c4f575c102754bc99675de08238c1f2669ead5c102759bc9967358ee38238f1e2cd3cdbdc4571f7054188a7ed9c362926f4d9798a115359ca11bc99778237f3ec13163c91014be98ea83b58394a0a0b9d9e03f9c8a83b16cb491196f0669e05c30a382cdbacb5d6de2b2d71a921be637aaf279bc5c4f9d341fe1068a53471cf6a7cc4466c746f6c0d3a37dcdcdc2061052723707202272c706e4e0dc66b726c6d89f3d7f5bf8e7bb6eb6b0b7d84a038acfff53278338f8889040de2a47b34d37158a7f06995281c05d6bc1c7b33ee596814657e141d98857f368233ece587d3d9d4311fe3e0cb319ff466e6c37f818c9d3fa104dce76be51f1f37ddc1bf9105ca599a862fcb280623b25c160cf2848837f3907833cfcabac49b79419e40f1669ebd9ca47d6c745d92fd708f5785cb40d8c726783cfa0bdbd732da62ef73148842f9f4f10efa249d907b4a0bbd9af526c1e3d14960f60de5635c8f85d3a5c7da2923a87ca0d7c6067617d95ba5e093fe67049c859c27fcf3dfe3d1969482ef3d0337c884c4cdc9fd3073606c8c61e36fef85f8292ae8f517955d1c0f3bf04ccb1ef9751104969faf19380b57dde17a9e6999af8d06b7bd491eda5e281ac9f169f3dd4bf6568f47f3db81ca410160c3da938ca4217d3fd748fd7438d7d3cb21f3ba7be3146fd808b7c7e9e67898d6bf833535c099f853ab77c61ae09c57c642ce36d7137d1dfcc9696fbeee75af8344ac53cd76571d8c58ffb7d5221bbaaba1bb2804855ff4ba481b2069e940a8abc123a0af850589bd5a07524f6c6c524ee6b479c0162b8441851c1cf1450ca29430743044145e00c10a51b090f3fe65c0a15f7e0485d2885bbfae182b8fdbb7c9ca43432e9ef4bffeb8d3dfffac777bf7c3ea49e29c97bbaa5445f418af2b5e33cae8fe504b947c5d9c039a80c678c1b8bb9452ba747fd121840efd0b2dcac265f69a86fdb645ea3d1a4b2064cfa5cea579969d9a869df49ae6fe9926a5eca2e80db786301420352623fbc5457708358fd16177c330d81906652fc6a8d3ddfcebd44de3163bec7b2c151534ba9cae095d9d5551412f9d539b4d5454d03b55535453bc6a8a0b321b42d810a2a351c511a0745cc0c6011416c0212339c4424546c821a31546f4bea0a20418510fb688432cc5141dc4a176550e9e5176c513492cbf11d6e5c62971a889888338e5b211858f432cc51429e210d64568bafbf329b4bf4027ee108975f7ef30ba0612f5977a894029902876ac2ff6d22f32acac10e80af0081c6a1c4059c18443b28b6c6243894c10464405bbc2094c07d8152c95178ce87d41c50f18914c90c7e8f19aee369d143631b60a0a270f03baff73e527b42e72680a39050a394565630839c442454de490d6c54745e417b5a326c883365182c01afa59954982f06ddb8882f2bdb1b1f1099a441642d50ea87b6bedd55dc504f5245818abea4acf30bb63af1ea5ac44d83f254403cfc87a77100bc772485d3373baa8020846d60b1f2cd4e88988bfd6f222082b2dfc8714caaa3a1d415513d69c5a5d8461210972504d6465a1ca08faec3d39777a23e8ab615fab0b2258695fab8b2cf69e2ca99d087e5a1366ee6786b0a686380f4fa16ab25245798296550b08559cc8deef9f5102bd7ee45ba86a09bd7fb404aa2ac221f36342318e646fa5c4baf5990566b1fd503b350d95eea6f5aa620289b2d808e1c3f02fb2549265a61417ee66950d5436500d51c5c8c852c166a6b7520d41999999354f4d81c2ef77d58eea570cd96be3831ba15e55831f60c1022b508ab802143d4cf83829a205250062d2b2620a5b0f7e5cf8c11693155e6c9b7d2d2eb88091457b352b8a322ba890b870828b2655b4b848b2dda48e503ec8544df314c24cd360d5e1b25946e25259a60581eef09348cf05d01646566a9af640aed7bec742987197b10cab902349ad36370a72ab8a83d534f077bcbb177f90bd55962a028d97641581c6a979f187711aa5f253424e317ffa1ebb4515bbc3bed60f8a669089f132df63b38c3512c635cf392de460fe6d7c918a5892f61897fd3c7d0c2e262b71f14d5ca95b350d7dbf9e524ba90d467866409f7d5b70d8de297083897b16fe9c33aba921d7cb0772b911cbb454e2604a6d618a4cdea8a9042b6972279a0a02bd2c164e0dfefaf9cbef1972d5a7ba9ebf2745043a7fa5ba56ec836191bd08f46fad1f0cd9edb3f76867a040fb79eee09f690f7174cdcf93cdedc631313dc9f4441008b5b35ebe9a14206fb7f7ad3a94f2e6c77fe76615465abac030809008398942a528cb16f7d2346de1930d4af17aeb0c73ee00e45952dbde7e94ea7b3a6ef6fddbfb36240436db86b4cd74e8c1b721fea47adf661bdb21304a77a7aad11848699a6c88571825bb88f8fd40c8f6f726845afed93a309402a7bc1cd0ff2f48053a815e08e5a3cf92ecf5134c989afb8988de0bf2e371c9eb4a0d5dffd75fdaaa3ba154524a499b6675b50f9c4aa28bee8ff1eb9b42aff6eeac512dec50d0a6b97e7a8fd10a4b297fa4a2a01765a5ea579d464f8f1bc0cf75315f2cb998d76482fd25ff5e3525a4fffabede3fbed39c734e8d3952f7cf291d637c0a85deffa68953f6169990458ba126b410cac28bcdfa35c3d212f45d6922d423cb016dc11f130fb801ad804397825e6a639cf4348d4cc701bdd0f6e3c14e541d50fec7caa81645277b5b4a0af5b9802c6201c5aeec6b5d41c566ac71e4d8d618c04fdc892fa5046d22441989eca5b0d059543e592879a92cd03bedcf23ebff5a586cc9f109b7575f9b1d04ca1eea3b677966b3df3e631837c8f505d1805e0e2aea1f48b9e8c4443dd3cf2c63c65f8ae24771336470efcdcced073351d36854b2672bf34d03236b504fe365fc8c9f4f83e32d908f6a66d4d733d8779d321c0cccc7701db76ddbb6bf7c64e3c7f853a97482f918300f6360602aedae8f60cd0d6fa6bf69bd134365da63db0f0d7ee90720029a7dacf0f98837cea8bd8ce4d4502e4d0981e2f48d0c11c2222ed6eb4541786acd8825b685b0d87245d0153eaf087dad2cb4d87eada22ef64ead4796d24267b2d70e98afbb02644056a92f2b084396fa42fba78c41aec935d84e669c0999253f972a6c519654167a1f15ef87a79ba6995a8643b344db73ddc3483da7eef8150551857d5b9200e3c7094514f1c41204584289087650842f8e04fda46ff6a3fa9bc55a322cf67d0d51b6e822c50ba814f1454ea4c110472862a20589949c140fe89b3f64cc849b8832c50e04648fa67b5da42794eaed7b386c58753a25ee5714d838d5dfa07128150632ee84c2c1c23f11b150a33958f831ba8c1e7d634741aa33ee57bd61c0f2935202932c33bd6fe64e2581762a095d8a0bbd3b3cc585c61e2c5727b2b7ba1ce49fa594f0e37a1c767df37b3d70601dfca924505aaf2b5e2c6dee2b08ac9938708f15eb6053bda84dab5db770a615f7f0c12b865dba3d585325f272e4d01d7fe783b469b5eb9da46fab2a8236dbd73458bddae3c2e51259d9f8da101b6175a62ca7685d016a5931e29242429696952aad2a61b4aa0cb5aa0805b5aaf808b55a495248685989d2b272a4d5ea4222699ad6ddf6b65477b2e7d7ea3f12e5b13f9c886679602132961fd2680d8c17639431c618ecc088075a96944a313a9abf57a7a4e89581e8aea7184ef52719ecf5260e9636eebe2c9ad4d14911c163fce581a418dceb99cc76e57f5974246dc902eee61411fed16364e6d411f88232b6066eec0e7f1070a66c40af0ea73dc339ec8fc447660f56feb5c39c7f31c11e073af48149ced0626a07d7558022b44870050b22aef892002a80b8b0020a3f504151ac125b3d4c8ed4e08b2eb090c40c5c9093012a745142480a41f822899ccba25205152b6cf73fa216152a4f04a1cfa8944e35653dea1491040040008314000028100a06c442b148241e942545fa14000d8ca448724c96c7a3208651108410818c10020001003020033233228e02189a53f8c2ac593db9b1df8584890e7dadf10bc0c48a43dcf91e9f091ece8590e19bf3617be8cccba6527550910b5064248061ed999fe183c18d0e956a838d74bbded34de032ef0374209cb1b7749de674f703d6297c40ecc6cb0a37f1c88d4e815893d48db9a4817ea6582d975bab7001f968009cb115bde45679ea2ea637326d34eb6ca5127f81fb0bd859608e2b10e193208646dc3274a60f1b1279e5ae5b3fb80f0cbdb28abb42e20fbc17c3c7e082468fec89ae1c2293106e2821d6c6fe84a16a0b5da518d25585934bc69e3bb0da2fe6d0b436c4ee870b6263e620ddd042ecca4a452d377655dff990bc2aedc3c9c6124c8ccc19e7732bf0ba7af63682415f43e147701eb587b1d27da7e5aae565efeaed7b647fe700d242b771bdef87525aca94afc32c3d522a2e091aa7bf192df65b55d9e350a3cb75231e86655724abf8b587ccc9988c5931cc344e4c63746955bf30f98e15480521d958cd4a441171f77554a244301282f8aec3f21682e88ff13b73c501268391b4387d66d9b899ea2fe225aa83bec6b0ffadcdf081ca585ec49c40e2f3076928f198e63e0bb023dee306cec7c2a80074a714ed77d61cfc88a19e12c42077ac5af8fba258f713b4033c53eb99c4b4900dacd21ceed1e3abe29b43263a780cb23c9459c61fbf58a818927b7f1bf13bfe623f7b1d0e8f6863f80944d939fa452b6b8df5dd5cc33215bc10194909ab92974b08a8cb33cf535db635ebe0066b7d500bab3067eb7227e80d4fe558477f51a98211605785439e3d8f4f6453884567b15e44d65d00930831754e28ac272ab493c0eb80e045ea7d4e028c44a84323c9415a2e70193ad25b4b0a26f1ca0aa39a4f5375e4b7cdd0c63dfae11e04a84c2a1b99e8580e3dfdf6a65fbbbcafac183abeffb891bc931ce7c966d58cf1ae4904887d64629b87184ff1278bf8853f199bc9fc7c45f9acaec85dc18feea7d729eb69e01dd5ad34eebe09db3f5d029da4a5d8a5e4d44f850de89ec9ef51b2a4e021d8bab6c33e5d2e214224246d4b6f63a27d15292a6d2a4aadaa5c35c946668ff380b924aaf0336bca4a5ca241448f1925ed40623635031e8c82b98b2c817a58c48279042a1c09a7764481e9905520a6d4ab3a947614c06c7c6b577b5d936f5e09ca291a61cc9d66314ea389a46b754ba63814460da5c40294e500392274ed94df2c7e366cb81bc901ccce82ede76e50772de14655910f35224dba41372d047ea373b70fc17a83ec54d9d2c691304b3ae05206b7ecde8d8f2d4679c97ee27bb1ae247c7d78eddc34da3e680a66a03df338d51ea6d2c4d90f31f78193ec1c5eae308024171b47825208cc1255f9971db200a68be4c784d62dace502141d4d636a6a9d2c545cdcc67d82e335809a48c41a32f75e639cb285ad91d83d67af04e951dec940e39438b35c539e896232533fa03a24f04bcb5367f5f5e52fd074172a1eca784c8693726daa8b0d62f239ea51430a7ab6c732bd78229d57b781314b8bd38b1a9be3711533db3dbc8282a577189836824c5c6127bd9ac16b903c9320c0b7072a51b901dc1d679316c4f5d5b113f8938ece1dbd0e43485cb748fee5c5672ea6dc62a1ac193769efd5bdc58eef760651f1db2a6312154a20e325bda069dca8be5674e1945ca7244da46a40ec33b7783b9a1003a325e55c68c485a1cf6e7a0afba112e8eec74d46def717d81973d144edb30633c841703943a001319858fbb01158a9af89702fa0b0a8d5d06868738a438dddd0cbc0edcbd9fea885cc6bb75c790e5a907f4524643772d5a11ea99764e08636727e55260cead63be8c96e6291c90d93661255ee17a5f2dea0c5194b1672571cc08eb7aaf4e5033304ca6e0afd70522b2b6407d070ca8d09ec1fe3f6d6f69c19c52e4b0779ce85795bebaa84e45300172ddcf226d6ca1878ae19f3c660624486c9ea8b3918408c69663b17ddca18860422b54c65ae8ad4e4520c9cf8913d6dccfa10365458b93a4827873f2389026fc4c82fb42c51352d6317182fc373d1d48bcf052cc69608cba8c37d42760380654f3e86758c93924febb72feb47553f9f4b97f544e69cc0f95be3c2bd25b946f0328bdb8229f1f1a6fbfbeeef777c5f87775ddeeef076f7f7bbbfdbe99dae373a7fa3f3fbce6fa3aefc3eca470059ce8018c15c86f79ddfeefe6ea7773aded0fd9deeefbbbfdff17d1dde7579bbc3dbdddfeffe6e7764ef4f2e77505f8cbb865b01fc6719a9945a304569a2acc03844ba5e24ca85e323dce5a2a8281a03e16e16475df4f808e1ed6241949bef1a7bfc68bb283db0c069d89fcd8362de64240270ec23ecc731ff556016f7f310f46f67300cf132390bbd9db3e97c93af22d623500dceee937b8b490005d47e3937c2c3551fdb69fdc9f3028c5240a461ee8f2d2ca03b2db9e63afe1a696564ebf03ce387f60e105ee4a76567cc866c049996779df7f76cc3ccd1fe4191c62c2d7de801a51ef5e79cf9c894c5ea6d9393b07aca944b0f55c1e6a5b46fe706443341664ab3716dd279122367115f3a11746c4547891281286932a547b8378218373b59271a5954431e2976e73352f3cdeabaf6f6b9227d78a3d078261cc5f27872d29f52a27a9332b205e6c84aabcd55adf4b7acdcb38befae6b951e9d4e647fd6ad84c85e021ca99d7614bb20841963a3b21f2b7c6703149f0632fd78497f05ba91d7861e2fc699caa1044acbe090cad3ae0b0650adc469965470959bf2a5f4361b4897575a360de10cf7cce83ebb06e8579a7af2a135f67a929065e8c4d79896fd09d620d1f0c1c15f0245f11a7db1ac6c4d5046d54a3578310064616a9c678e7b6c92e553bd3fc6989e7a022343640e7b86c71170aac10047dce65558e26b6e158bb303a3b5240fcbc26d9a4c7306218956434f81dbd7d89e4151d3a60cfe40f3eb71e698671ada6b383033be1a5b61df7840ade6b0dc8da2ced8cff4bea0718ea93a9cb118e8c5a84635e18c843b53d14db17a4367f661f6600a7f44e03d41ab32cdff34239c7c6d9a811eacebc250ae16e8e25ed86c87095ed5c2081af34cbf1e72b047ef8105583e994d6214131b2abe3c07cac07d106f422f06443ab0e1a49622c537fcea79dcccfca64d4d9a446a3cb3348bb600facd544615b84dcba960215114c13e8108bde142dfcb1c8654b97e192a440bdf06b938ff39c84861c32d8c911ef0466050e5684d6a587330c998aac394e7b2d6ed866f5a3d7a8853bf88e8144df957f9f067a6ac65d6d22e94665b56b0e06cf3ec90c60d1989297667b2d2ff9aade8db3f4f5d3d479a74aec8f767486040f07d1cb0a74f70ebfbcd2ac68be79d7962a36fc6c4c0a54134b1d8d6a00692323dad575cc7b0d7e92ebe78921f9f8f49027544f3490d6bf30590c975700ee55bdd06a1810b0cea7d23d8381b731ef909dc34cfd1598f544f523b15b72438a4e67a9590cba86d97996a27ae2c6c4f90d35d66efbd08a26b001022177b5524967c32643ebb914c9dbc9bc074d9262f103259128210e73a73694827aa6182721fdd4f530c601438afbd9f27e9bb40112e887c24c4b8664f984c75bb7cadc8107c783f60699d8492d77940bc581e10274947e49b970b817cc6e68e8d9fc314fbe29bf54711ed677bf9565adfb221ba986f387c072ca0d6929e2a758c81deb547e9e8c1bb92df3fbafc87c32d873b632ea7a2583776dcf1a1e30e074500d9bb717dc6c064502c24f9f2475c1e74bdc0f32e6ce6bf0ff1612ec063798624c7fac36c93f4ebfcf76ba36e370652b9653e8c7b9ab780a5a761a031f0d550166d7c7b1eba0b14a2c3ac6907d82b2e548973e36ac955e50bd57875037e99262e9b7a1b7fa4c6597e06f020c42faba9b4ed552cdbc6dac19f9c5d43a774714c9f10f8b6af89e9b00c90f43861aa4d44f6e4a871f3ac0ead09f3f2c7e68329c85107250e6f30836423b5fdff67a2e022ba80e76acc35b1619c0bda9df7efd555bd212d6f13795b2d2f35e15a640578c68a9ca4729060609ee7cc232ebe8739255358ec4962029044a3ad92fa15e1d827f422d76168e4eff77af9a33440f891ce824c1f54a7f5ab7d52d7fd77492319ef5c6345310f5b32b712df21915687cda6c01dfddb21d81026ab2fa8ae0af073d771b64486565e98cc952aee4f3d466480f8ad504bf9d31a8d546586390a5f6dd9c1dac065f472c391bb292c165445b96afff34673f17ec5173e1006a59fd388b653d8ec67660bf2344f19a271e547f042c318284f03035ab72a99e6de1e8268e4b2c8a60f95ea5bc7960abc0d29f9c2d71b8d0445d7c96cb7051e9e388c690a438ab00eeebb2946881e7bb903caee7bc1ac68ede97489260fd82d92c99431d3a754c7a2602b45765a7e10cd1838b39d8d46a3d09fd7f26a81398851be9b75cb8b5c596bebc508e9c700b6d0117d098f18ffc3c7addc238f8212e0bc23511f972495def6e6b133c01511bb16b63798d326abfd3b21dae4ef25a087f294f9f2865034dfa8f10862d77eab2b75d6aa10e3db86fcc8f6a37c99d7b1bbee4dae3dd79f36b1bc7100050be4a4538c8618b1bdcc0891015c48631079afe58fd9bd60e7c2325ca48fa92f0fdc81d2419576ba6f5f4f96a3db5141cb18312be1555ab8dbcc0525fc04acbfa465073c897c5cc39c436f0deead219c9b26178aa814277f2ff4be011a5ea156a1418dfed5431587c4f1122e94b9fe7a129fdde2a185c54fb2abd3764e451256e23ff31d1755dddf0f01c1ee1b66bd7cc3b7209a3a61bba07e78ed6271c6d944d4cbdd887ae9ecf784cdf49122b832023ba785ec726b80170deed650e6c085c265b0826a274b006c3f2d06713559e114a571999d1efc05b5a140eb0db8ed2ffec34147154571a5084a815886aa709598bb5200aebaae55e213d61594e66fe1327274d3fdc6e09026c3d82b58b4f99685d10be7b89d6ceb00d9d28239548433c144e46653ad99a3dee5f181090d4066417fe1ce780458d85b62f2966220ec49ce013a7dadc372585d915ded03a6e8e42e24383f10677bdd3f736fb28d00a13e46c1d3f59a5a7092568e14bcbb66fe05ad0168470db0eba24d70d8774ea59e2d86651e8009c8fc32b5cedecf46a62254ba542c9d95498d4eeec5eb77268636e9df941eeba8c6c44d0e24c5bd69fa41510e7fb3461b50488a9fb1dc29b1852945331c7bbc20308328900a4ef926d25b95b34f8d659713dbcee53f82baa2364bd8def700b3e374b90a9268c1cab8485a2b048bbe7539007fb649b9f29f0a0e3b5d5a9e92aa72e77a27c34fceaa130bbc0d933441b44a21f776179737605ce13e27cca57138d4787c683530d1035679b5cd9a98e742d1379fe937b7f00a5f876297af00424950e1faf6751c33518a5c0c97e3efe938d108eeea4fe88f2a6a710c44a3eb6892231b1b410ed3eee38f7df284560137a0558556ff4111405f2100992106cfea644a12e0d243d37627e1d85d1cb30270c8c7ff3fd11726732973f2488af5b4cc61a7f6a4b31fe3107dd93ac0f644d5492fb4d27d381be12ee6b4f71b45ab3701a0bcc8b6d13fc8c295da734bc71ddedeab3210dc2a08c96480e7d54bcfd75c981e25cc01e2560db6a9e4d396bdba094925a6f72f3957d4b30c6e2a11f3641beb58936e95f670e3d223de52aaa3dc38a7743847a01116acc661eaac2607a3be94aa8beba7ed1269747ed5375b820c74285f88f3aa4404f29486e0e592859b85518a6def0c59da3725dc65403df604f4e1c07859de95503e032cb39ef9254715fd2fd6b4c63a287c24491402d8a55dda05f8f3bef64aea8f35e9016a3aadd0f03a967b0508533dbea7acc5dc12179009566de0a2581390734c66031b62f724925197a070578f0eac4cf998c710dc9721acc1e2bee96478d757f2e5afa03cf9d54c507b994a6237d3dcaee3c92298ffe594ee2f00819c335a8a49708e5dea6fe6dd43c164219f03e3e47f70eaf5211651427a8003c80ae14899c8dbdf7487ac2787604813a3c78167f60348d2305463f7b594594ea8eb5c142530058837ea17613a725256031fffafc9e87bad6668e1fcf4623d167a67929c15d1f8df27bfbe5527b622362f08b08f392b36d1684a027112ecd76154f382b569dfe7b99ac5fbc2e2c366d0069bf7a84bb3c39e650919a1ba3080f3d9346dff27948808c97505294fbc4e117792907ce38cae92efba4ae8910234c893b7484be83ad34f111736e82a2517834bc8ddf87694b6eb28d49e208430c9f3669b0868d5469a05e5d3d287d35ef0656ebe03c26be46ce04528a201247786cb0927a8817b514f3335fb089ed01c0106dd19a1c0c227d6c62c660fa777a0a4ac574de82f66fb04185d326529801908870fda1f78e33bcb4827bd54c8145799633eee7b8c4027996465a47d5d383e797551add939b7627b9e84edb4601d5b29d580e97bb18a7b655bfa205914084c22139b1317c7e43f2c6b9443423d92b65b23eef6653dd01974a4f9545bce89cccbe7c9727638af48499c7db34000a90a0bb591ebc69ef03796b1284d83f3362e9ca7c2b579b9b1cd13b2355d8c7ceccbce5b674753ca2e65e6a0e83a6e5978a5d9efd5a12f4d37fb12312e2176dc607e853418cd7be85a98c857c62013e3e1ad2175e2ea985b3cf47befa2efc57bfdf5139478c45de0b44f525f4d0eb2611aeb1d314b5a95c923726a00e0c4e36217b0c458701abd5e49b7840f7f5593873a91e6a4e02dc5c063d0c4371c7ca821fca3970235600694c10fc0e7010f1d361bd06cc8a14f0a0b441d64813bf31ee379aeaa5bde0c16dea9f6bdf74ef361e72004e0a7846d94be2d3bc5faf6644d1275b135ed0d75bb231d7c09aa922b0f01719d5e9f1635b4a76d4c34f02855a027f6fe5f59bd10891bb1d82d0c69e70a08ed75da062ca4da096392c1de8017187de1409605bd7c50e58120078a6c90c806291f6499a0c901420ee872409607bd6c042acb44f90a20ab65554d992cbed21a246398a7c434c5a629364b91090a66506e8262738acd53d21c05261498a6c434539098407d0e0e1929518a6b5d1b79361dfa0eb7d266e102287a329711f163d5299748d9102f95b5985a772517e382678696c1a590e9cd7de57a73319ec0059de1613da252d1b720abf24ccf0b52063f2e74969ab4d6d9f940d1437507082fcfffdbee424610a8c7d5f415cc5061b683c3b1285531a0105669acdb8b29870517a05ba801458162684caeb089fe222b478cc35b2ee6567f566e1fbee09a72ef4d3eb86315fe821bcb74924caf7f372c01d6a7675306799ff9b4761647b0f34a9354c68b14e32e619a0b1b2da496af8a1f80ad22b9bf3b84f8d6843601f0ebd909370040afc4abc6b12826d0ca1d0b6b416e7e2bd4fefd72a1685cf622baa15702a3f89248d5b1758eeb0ec4c5580ff6008b6996bd2a3bd7f62313f6edd930ef2c594fe8068672d4d94d8cdc21277420ec2f9d713a74137e72adb3ac345559752e39a495f4741e228008b7e8ae620b3b8c9d91b229a46b206a0075c7b45be246054fe0491123e9e1722ef0865ec144fc19b224511b101be96953024ad257a29d2f3cef771161180b86acc33f7021553e486ccd9169721a1cc82373abe2ac160241e8d006222b9fe4a64702f7cd2a6c26fe7615b204523f74a9e14921f62942ce6411f192311fcb0a19ec02ae074474757cbee4d9037ec246f8901afb8bea60b8b1fb28b10290225cc98c6fe931b988417f303e3ec0097d5ff6a13d97356ae556ddf12410d88a8ce885b1ee8a1c305735ba00fa7a4660548182262c54809c4e2f3a46f637a6176584494aafc668ad190f5c0c276f9574ca354803d85c7061a8ac1e97f9da3bf3f27636e7eef21e327f3de122450d059b57b63865b48b841b8769cfc6cf2e9e23abb744b40de8830b5c4b6465776892d0d7be43922158429fe7a23b013d00d9471759d5aa94aa25c8c5893bc755717e3be4c5aae5b97e067afc626c5474e82c7df721efe575046b6152908beb578dc3a0d847e8f35acc2a742c7bcae9596da0d12be5c4eb5b5cd314a50c34b2f6be69845255b3c95afd0e676f83f74d853d02688cfbe087b34fdc6557f7810daf0ca9e2b5bab7be04415dda1fceb64cecf0e275ad6b8ee043878a0792e0e9d39b06facda256b994bc953bc7724f65c1ee982b857b5ffef7105a9ae2b7f9fbcd1fba59ce38593eca32ab26a2a91d290b6d9799f72de198a7c8a9261970bfbb6c68e6b82b2da781626d5d09a5a43476211b3c9d99cc127c0721de8c500e865371efebfa30b566819f41fd1d0a5406254ca8b684b399663f9f70e419a4eb5218289887435221a65c204d8d324288d883becbe1f79fc0f4d763dd433909dbb4a4d6058deea0de853cbcd15af63ca4f9e2c80c960621d2c745250a42bcd3d509bb2ea030a84321292b1795ebdfb803549992cd3994cb05c7dcbf1172c3387373c202bf12241bf53bff4669fc1f091ae1fffe3f5ddec490f48fe642fa14d739d2e6b291d508702cfd7b4a322ffbf51cf2231cbbf5fe0e5ac86f7a9b47f2edc1fe84331fd872248891f55211387ffd473e9cf9c0549b13046f79329e9669f6800ccd40201337f4b20e13fb37fcd8df1102b014271e530752499e6c0a61594e3b07f2f3a173bff5f908eba3e30b811c31d27c6c700cc9f9579880266bb08bb844743b0f4893b72f170ef576c1868929b119fc864b69ca33f8862424382c76cde7a3662fce19a48ac6224f37fca6fc0451cc0018f7180b766e51105d5d3a9f22b34c22f71d0641c7684045f6c9e24941d07cce23f0141070b2a28ead42148f37d58a83e8d7e22070a984b557a30003e432d82e037cda8acb92aa51eaa0b32030890426e308c81459648839100df4b22101b5fcc827c44781e66cad539a5c0b0dd4ba58726235823e388bf5a2bc2d5126228abbecb06677c7cce52ebf737fc48a0726449b5d3f37fd8ea24ea591dee2efa2ae8f860766cfeacbc7704c7f6f02835eaaaf3ef93726f538fae7f511f50298554a9bf0ae3a93c9d76914a94d9e500d02b2c86b362720470b20038d733e7e8d21475b7de7add09829b86448f6e30d61a3e0c1e838b18c1756df8daa8b27a8a4f0e9e19e79aa74217545e0ebf7aad221da57b04e95f3f210cb45a6464002997d0c54681a3e8df2c3905956a3d69a067725b6f35cba3476aa7892bcdee8aec6e18fa9a61d1b9ece698bd9789aca3937abfb270ba89426f0ada8dd210e81028ca3066bc5f3da9a624942552a5e956c4406882e5cc6950176cb3eb710d1436afcbcf82acb5c2961e9a75dc9c670f47fecf37c7e892a9bfa8f80e14d5f3744180f5359cb30eaa97fc0d5a35053ef0fa46b37aad67bbe6a73a5435e3bcaaaf1a94269bea4d8ca57d857f96a2221785e052f00081eec02c284413385fb4e52e2830e8e7315535b2693b59020238e6bd670daa60fba165c411f594b7d98dda9827edc000f91eb016c173ca1657808ae5ce88ce5f4feff1399cb390d16c63bb5c2aadf83a8f8374aa0b32249b4048feaab9ab1e9886d1dbb86e66880a83d6a3bddfc19f0da64a9169f93cf3cd0b04a29eafafe18720058dac691d2cda354be39b195bca845e2703aea915c86dff74e3fdbba071a140fc3f1f58aa5843f808f3a7bf04bbc38f088c8f4003cba67433ff007e8378b0d6756fa9b9411023c56fae1fa67df50ac7c948be608ea279cbb502be7ae3266b19727f20df9a80d420c82b727d413fe4d90053aaddba28b31ad661141392b80c9ca5207e9e9a85e551e6c9f11c943a1587da861ab2d15c158e32725032d486bf18262f25fad58120e9dc5b12200850bc7374c843e4be875d82b7bc7a4194146f7b3da74cbd95c6a5c5ad0224366d36189b71c0cc60ff3a4b6a4cff802c8427b51f4edd88054eb8ebed0481aaf7d34e9c19ba84c48f63472370f0e979799fdf600b526c383feee9b95d5568b1b60a922691064244d4b43020cb5077f03f91f777ba7a3ea544f9a1a932b6a46b546d2d09225144d4156de2b76647dda23460fcefda98feefe1a9a777b0e4ef11c5c0e6c42f852d89e21f6279eb4d84339e4b50f02c67c1013a79ca183b229a93ffd7bb61244fb10d1e224bc905ef447caf1eeaef572a831301b43263c63d5a4292dc28e62afdbfb40ae89a4e900d0e82bdcbf3ec55c1f56559093f68193d5556f224148cfc6736be45f860dfb0e68f4948082c63804a22bd5ecb7d4ec60c18b770c70a2e41baa32b01753837e2246c394b80b66c82dd9188b566b4f40c850947eefb6d970bd7ac9b947cb0972cbed362fbd87e4aea6d11e341c8407b9f9e011ffa72d1043f07264f65023ccdbcfb2bab6b89d58055688bef1e841a0300c9c7d4b4b2c6ece7b598a856918dafb1de2f63881b2535065aba79b347117677490729dceb24bd5a403341fb322bd3bc8bd98e3b97efbeaef16218c71557a5a1c0f048e314cb92c6ed6a2e23498dfde92e1f28500d75660210766f9bb080fc7488f7e03bd2ac9032f50c9e7b18045cdf6a8f4e5d7843950f396694e37e25a2dd625930382b1dcbfb8ebcd4fa295466bfcbaaa28c4f1cb3a5b00b6e1df0c837626514e74ef4f811c6f0917e417a609c41a47e0de75237c84f2edfe70e0debbd7872b2e1e84f4cafb7b95d2cb9b157bf983490acd3a16697973dfd494204335cd60c77b4b6d56ad377ff4d1178fd1965a0f5cd92807ef679b56a32f7316a803be746fb954bda619f1b45aa61ee4d9e9524ac6f8cff1d68d9625975921fe84ebc6a57ffb68646e1628b8b28bc77b777d27a4e25bee94e286dd003adec8dfdab7b8076fc4fa141e387359a9b02879cd32584a4e98cadf00e35a7868bf5306e4e66c930b38b2bd2e6c786c8c14777e0cd83209db55628823700d62a9dc1ff53271df42f972ee5b8e6f95ded02330bf566348e64fa7124e00e9765a582e0fa63f82b6dabf017ecf5c2bc37dd8ad74e9039c37c6ab8c4e8e8988075ffdb8868fcac2d26231edf858ae420f383a449002a55d222f09cd78ac57f547d2878361cd6b44e2af0b1fd1622123c0dc042cbd7c67c8a5af23b17a06f3c332f830203fd26ab086979b80ea59b6d2a18ed8c242260b82a6376644dcbcd4932534e5cd51b9b253847d0bbc8762a00d1804e01a82fbb73a5176bbbc8e4210ce1ab6de53da8560926492c3cdfa637da9485513dc94b829dc944fb6ea13156981a7cb3972fc13f6766ceaf1f21ef066d4677e8d5a2f7c81ad0408e3961d6a0ae567987c568dce62edf5796d649e391cd48024685e1ea9679abd9ca042f72ba1d0581a5ec1227b1642f862f60d4dfb744a8870ccd268e2b5728dfadb366993d7ee4626e5a71101e6f8dae63abd0139eb4842b9c05f45e27ba037b2006e29a0845f279b18ab94a191cfc5594fcd82bee7405611748f800b396909e9481517ceb43d7e2fa734ef120e8a5244dc9e76c92d002521156158c56ee9f23588250ee8db22205e7c724d9b5c403dc92bfb1660f48e483a13ef4a299ae747e5c82f6733bdbcb9b65d6c0faaf1aeddf385412cfc23c61fcb54803958423df1fd5e0c3ad88c22731792a988f764516c94e7570709ff55024065ec8a6b97224387bf6344dd5dcaf0bcc9ff575788765d31b6cc4664d23b68eaa91fffe5078954c45b7c5ed7a734c58f63a529b2e45463dfbd68850c3f5210ecb1339bc549c108e3905813037f94fdf63db435b4af5e50429c77a4f28183a136d477b3b06f731038b563b3b952cb074f68e3cdabf9362887954292ed3af40038547bdd791b3d62663f02159a4fd5775dcc584203a00ea6b4f2807735c12ea9061d4dabc93586e8c3d5386cea9037bbaa450b5100c860f482409e38295c6da43d7039086a22287435e5e519544d30d31af4c20256fac222f4d251c06fbc23a47d7e500cf15f9a4ac361eceb2fec68a8d0084a210e1fe161e7ef6cd3b856d39e3a119335ccfeac210f0a3933d2e8957b5ed896c3c6dbbc1bd3cc49d4fcc9748c50a238d15084f4137f1db4ffb71f33750994f5232613301250514d9dc1f7dfcd09b0fa31d949dec092b424a680a33cfbcc392ee467ec0ee7aac44357503400ea0c69253dbfa4928bbd8185ac747226a55efc21a40fd9da5e594fde0adc6fa19ae13c2b6dfc403eb2e00d0e3de7cf2611a9db43dbc3ec73663435033acf143c517e44277659f72777a987219144ec8591f2263106a58503aa8b64300005f62ea92e11129062b0b94315c09ee3b0623ed80346b3434a4e23790a8224260116fb5bb78dbd5bf63c04aa7f7f49f755da68cab4ebac5e82901922e3cc5cc9b3537054621f802621d5bb8793286fd337c56bd261875a45727171d77436941c00f705339666983750bb5e1a812274c15fecfa94d2fd409ad440d7c75997db3c06504a17a4ce0a32a780ad5487b302e7d498839bf57f41bdf153a20093271fb669f9c1a8eaaed2a7e187e75b7d238818c7d54530d9902806e6db4e272c9a481e0a1c854e73eb526c8d06fe4990bf13998b8891e4ce30ca50c3b9d090ef70e955f1fd73ed82ab053a9981e4c89d3cad96f77269d471cd19e0a641269e32b75c1fb1959844f7c8fca512eb5d927b9019b362bbdb633059c044ca77e7d3d37cd2b24e5d46c3034f52cbf863afb9749178c0019d3b53ee9a5a04b63bc1c17dbb3e6bbfe85684b05a32e18106ab06d7db8759447abb6b334fb742f95aeda71cac957479c126dd9df6694d60fb8f546ede90344b272229eac01e122775913d643960423bc49ae4818f1297a32b8bfed60395c9683519d01a08262abc6c163d33dff6515bd371659278cdc557c22376a6ae180931771d0c597f1ee10ea5138d9d9f7b4fc282ad2d5d04ba64f1c93dcd5ea77fa48497a7c23c650a107da469afc1f25af48b169ee7a4d798f6397c3d8bcbfc9a00f54fab1e5a6466102887bfe2c08443731dd4a929be9c7b108c58560804174c8d444aa9345400110fafcb033ff5a01444f94568a85e2ec0d9c39f1dc9d88d93c5768e6c00a16ec4ffb19ea2303f41f7d8a30dd1617ff35c2df55b366fb3d97dcb6a2746fa275483fb1ff1470ca0721e273e75c684c350ea11118a8da0059889350238a5d5b5cc7178f4b9d3a33233859302885d899658adbc20a758e2373994a1eae538995ed160b029e9ac3bb9d0dd62813bfabce3e3a45ac0b3372bdc707ca6f532f928c3d623c24fb820865df970e58fc017585688055e0c0acc370d71a6bb132d2e24b4631bde3830b83563a7ff72fa648d935db566e092a54641d8292c6c364dd5a531b494a021f62a8a59d02234159389b523f0e2b9d7530d84e7597c5a4cb6da2a307f2bdbefbec2aca580e53dab43e6972dc802e176705069b7f836f263e42c332628f0167a08c38cbbd4d8cb6368d6884a00391375e9f3004dfd6f0d1bb385dac45a4652cc56f8340affea585127596bce92650361d2fee254859990dc6f0a9f8138f007aaa71cb451f236a3480f153a73b05402876c11cf4dfa231a6e717307c46d28626692dad2b3e6e0d90fd2dc3f249e0324105754f0013bbd14003b7a917334f0c9f54e0f0b54ff24735fc226848143bbe6f835b2cf6b4445c54547dce73e6eae9e9beb00bbbbf244642ccfc69b47523a42dda5913f1bed1aa7c5040de4fce431770c7da2d32dec54e116eb10a0e7a3d6f8a53aca3827e3569695f17fd4e712ffc7d19095c09d580263dc098414ed995b0982e39a5f25b087f8c1bfd64ad057beb6a87207400c98e3adb98f4a5cff9309b149d098fbb01fc44b72ddaed42f886aa9b2977d413b2f20588e4bf109002b72ed6d428f1ee97cabe388059c77d13d7fad529201d4bf8e7707797f01d640e557a5ad44bfa53c983b6dbace0e93a5bf43668712816b052e864a9945ecacc40ffe0bfb686902a0a5b59b1f960e5a5be30acd52f685a0bc1b840cfa9f60ad9f9c3806080b2ded718b35a3ad3098aaf07916ae5e55651ed92d3f36b23bc6d9f464e569d81d7abe5d23cb5bd324dde9ba19105372f10dce6964d1f9d97e9413d65889ea9e8872a858454ed0a26ed7eb0d7d211285dc02109d3d79f901389c105b1ccfa33d9f3a789f2bb575fc8cb5dc184a0953d6dd6c458d1d5440dd0e89c1ca72ef4ba89083aafcbf7e8e9b3d5f27025cb85110cb0d2ab3f17bbebc1b1b9cc49cb957bed2ec0b159a8728d4c6531cd324c12fe8e82883ad96a1e3d27b49b6717c2cbb5d4708c383f2dba74d436818f48cb5f3840e0172d7f781bf45a240b8cb6e91be0e120bd5019ebb700baac0e8bec9d803e666f9e50e45ab40be2df2e4b2547279870a1b0ef4487aba7d4015a25d70c8f8dd1961d1ae3190842352cd824b0a206848ffaf15d83abdad2a473e64aefcf654ddec907909b014650d4d5e95b937cf882320c63551ef432e52a0710947f381dd5656a1c4eca39cbb7d4c08833eec3cec5664594563df6e274123b85f3c55033873089fdb3a478e5e9779b0dc9848d5259bff77be992dc562bea3257c8f755e766c196520f9a987b8fc955ffef9f2ad9810baefbd6c7b112172b040822d46d95be376487afe4714a8423be1234882d64a93466095b9d5c2ce7ec54f8952491734212b7dd8f0a8fc7377a051c1bb643d9388e8fcb887b1d2a8a0097b5ee30409687495e90301d0c2e4f092ab7ff36f48b7c53442fc95edbb16456b6b0251a85365ff10da25caea4015594c9e8b7cd59330e223dac82dc6a8658ecf1b6a88055761d89f166f44c8375dc7f0c635c21f67fde1c0b8941263ab3f2a2d79f14af83a666697d677f11f83b7a084eb1e46746c6a3235c7493070d5205daf00500ed073a41143694dc0fc0b269b60c783f7006ff478e171b10d9e8e7004090198423829a4d9465499056b6065f710008ec3630ca6400716a79bf53120df8ed9ef7414ad155070d8573990e34b0528d3afca3d3ccf5a8e767e22c4b4df4fdde11ef9c2652fc4a21dfb70df10e27633149475a1a1fd4e84303212438ff4cc8dbb62cfe8207c7fded656f07478a96447f22fbdd723b8f6b081f620ba8357f5764f58e641fa310f621879f5c58c64b3f5f1bd385c45f0195c40685f49dcd16a2138d611ec0d45a15feaf2865dc7c1bde1cb2b76c9555147b5956b035326d75ef5b349fa2c26569963970c5d2c57c8beb07cf2ee55b5e74a88ed1934d044aa17d9f98118e3f5366d3239a98ae16475dae6bed269d5262f41adfee64e0e401ca276e0d413cac1214b4efe402d5565c81f11217a716366eeccfea381069f564064c0d1e7307c7b9201d426c361edf1a6301c9c73c13419d1d4c74d23eb813dfede6d0b747b33c29996c7622580cbe07be9ac54bc58ecd762c9dbcbbfe61a3923ebcf2a8891eb228ee86124966b302d28f00ae0a20aea56ada3fa223a484c1ddc47d9af2704366e151b3a73b882c9b61d6679682bb80560072065f00323a83c34861a20dfc0078d80ff23b80bd08cf92acb45307dd93e2a272ecd0dd26e81d52d1097c21d7c35e3c8d28bfa730780f2011c6c619830b860670c37fc99bf91e5cf117e4adedad07ac59cfa1b4c577a38ef1c572ed2f2f8b19ee5ae9bb5db0e4509ccdecbe0638cac7fda4a6bc0d1b76c7653e1068cb6cabe5c14c3d3e3b3f5a0c71f1affd23c2cd22fcbd8604c2e48aea52b31c87dbf6d01afb88032293aed3d64d569d5026a53a22036cf0e74d8e050ace61695ddb14c96dbb682b58ba620aa951a961202b6f2ff1501fcef8cb403457cff719fa538e2bde80148b8fb56c46813fff9c402a61566f0cc65f146d626c8c4c2159fe3400624b36be5450eb26793602aa43728f568db518d1a44740948d7fbeaf89d2f83e1657aed76110a7f580f9ec5c38f4fdc37aefdd57fd61237e7cf16b315e8833dae142d1c3aa173ee52ae7b5f12513f8a8f4fc2b43384a624c2fd1e84ecc8569d147439244fa7d03b9feb3cfae01fa70cbcbbd30614a47b437ef4e95a73a2f84424a0c71e04b57d742a093c4c259a48c02f89e915e8063893fb5f72ffa41518b6f8dad03490ac90e468c66eeee2a9d54dbc871c3e090ca271ea3712fda73954a210e496f138552d589df4776a3724ce21ebc0f68d0b06fc01a4432c9a9c2a32ab436e93c1408268df80a9f2e0f569f9bb9186859d8294dfc381802b048a9457ab57417f048bb3d02c0428c649c6b1f92e4422d219b63fb07aa695467c4d46b689202fb9703d75a051cb23b82e5c7452cd8de86b8c8f9e1b48ca2e8951acc5e754c26a096d2cf83d3493281a3c367dfc8aa3d860f005cb0a7083d338f1a31f2451f82903e4d9336b4bc39e9e82bff7e94442dbc87cf5b03a47fb429b95d05e60bcd923eaa5ff97e2cc4c4b12ccbfab3d7e19109ac3634a57b4cc924eecddf5b8fac304fd28422fd0a41eaa779926ea89bac8062876e2864d6e011708c3794851a22dc65fc99c25da713bd0027a54ec26711bb20b5993ba79979f959affe4c0e8f433023b267d36870dbfb91b9c41ad528b3b19368a1a36ecca257a8dadc6c93e72781d318e0fca097bfe4aaef5ad8fdc5f20363b9ec2de4c480006e80f2014b791f644b890fc3ea1000942edd46974cc878d6f5ec5000cbc18408834b393c52f0ad3d4bb667f9b1f155957c2c9a8d2169a902b78d64c7185e58748e62563421e1a9ffef08cb36d1e63342e5f4768c675e07d248311f17e8972f2e3685220c1842f21be2a99c7ea2d78bcf1dc7112ee20c11875dfa53a763c017af0cc25039f6f26804a7bc4ee5624034b8ea3f4c8d3d798941c7c92127852abe6a1045fc4ab1b617236b1d3869db9ba09ffcafe5829fcff5d8f8e85ff6a8d657c5b519ef7206ef83f5c11fff2bfb06ca9b95964fcb1425fc79ad83540c2b4cbe072e9e8ff0a96ce6dc295e0a5763908045e9d0203c8365c72b1763932bb3ac0cb07109ac6bc0b479d595d69033f3493f8f82be7d6400d21d3077b3325dc2170bfd98afe02dd8f68a15cf859dea4e39e8f7e20666867408f6accae4c8c5e5cf22acfc7748e80c4360a59ee1cbe7e9740f46e50af1766e1366a4a72988fe787ab01b604a91e3363c770a809bdf11fde0e8a24bfc7f05fad1f4a9ab8bf81cd4e4c02f17bdf690184cfcabdd672bc37e0f2972e3278d16717607e0a1e93ee9ed846338c2305c1b31fa64cffba0d07e76e5b123f2f3aee150370602b62a4b489f36adfc9b5de312634042a6644c50f5996e3cc34e6cfdd56560164d73659e833b865c8706bae83365ea3563de1fba2d055847cd0f0af95b1f35e6631ae0bec7cc50e2ca126e3bbed304275cc176c53148eac625974e78b0a058685315565da4e8193d00cd80ee0d8091fa5e6553d4e39b932ab70d90cfef768f9fe2e5ad3bccd2f21d3301662382eae932ebb407b1980bac067cca00d4d342e97da82addda7754be7ddee6a41c43600545197c0aaeae924af74b98f652c36504e8174ebd7e82f02a0685e5cb3499b6eea696dcee2ccd671bf7e86c5db18f6f00c4def546c8ed2174f740aafae5c3d118419db9edf0fb6b2a32c95c17d64144c1b68291055ca109aa156aad4f3d9858e19b4b1c7baa706fa8bd87eea38db97f784dd4ada2cc0fc868ed0f60e66b3c3a78863dc08927c6eabb5ae77f240b371593d6cf3b107fd4dd6b679a3a5d78283411b91b9051822027aaaf03ed7db4018203d4d41d617d36b08cdfde4491dd2f041a2adf2d0b7de8edf1a352938045853a40e2c95d0bfa01a7a32c8d0a93b30094597b00857a23f2297acdfe5feb4769353b6654e4a88a333c0b26abdbed19c9901d0ae6c03eff12ab740b135a013507e6f3ed99034ea0bf062c6a78ce2919f82554bc77d1bdb28163127e81f0bc2a4dbe9432d0815c1678be989ac0168763ccb94265c7c12853f9719dadacd87e73470a439dfffeed502a8b8cd2657a71a5e1ddedf34bb55b98a1a9a2ae387614399a5d32b4b18966ee0804fab4a70ce6fcd10ddf57d86020b7a8643af0926ab727a0be8971a8c8240eb1aba4d25258e7b4b94ac1ec4a16938a18a772375f49c2e7f5059d56be417bb49d12af3f8d422b9c370447c266de42feacaaf62e0560fc3cd329b6385852f50a009459ae86c7baaabc5dbc6f360d8e24c2e81082f4f29f4d6db956ee9ecbcad14556e957ae703be5387fa72606e493032088a4af99fc51fe467683dbc93f4d7a0f011f30f7ade9e022ec0eec10856172f27e417ae64fbc68600e5a0fdfb353b34b54d3d2d3b13dc423155c419615b2ee1fefa7bf172e72ca26bdd4598f9986ff725da41505b77d85ec93679ea0d0a8bff0fad572116e80a2072d83633b0e033f63dfba5d2872e17f98bc1742cabc65f3e7adecef4b356ca894907abe73d0b773ec5ce2db7f0069d960b97141a111708842178316d89ee616b3e7b28071b00baf7f23d2a0c128d4d5d26494600afcd7949b9cc4b0e36f7bed117fa2debbd5b9d1fb0b1d2fc2d9dc5507beb06d6f5e02bfb43d2731648d1775bffb793e9a983e33f77b40d85745f4fbca71d13c5ea62949f9a8617a1f61a53201333d7d310c90ae1ff6cdfc598f8c22b11f0f5d7eae49eb59673241c55c9c29ddf5aa0b7bfc1b8cbd9e2569a8b505acee2fcb52b9e164cecbac4620648819d91f62ae7ae5d809fedc654800bb6ca3338f127179ed85a6c1006d434672bd986e593c2d06ceea22d36d2bfe210b2684384c2d3e347bf31991b30e0de3a3e68358ac86614733a3ddc74d4faddac75f7caa694abf5605986356ac3fc6a6ab58591c90d294e94c48be1e45d31f16ef3e908d67e1da8c4af976ef3e5d091a1eb9debc6ff9089ad7a9ba6e50753a2595e410c802302fa87f81e9bf31376a622faa27e456c5940017c09c94a1e40d4ed2e2b88911281f39d1a2adb89e2354262665fb15c5d17cc2397a5a3b7a362e29f864dc0fcdc4ba59211470a1787040c907477c29e62e7f4417c27e25e0d8744856473dfc9c8a0b4f4c2ea47118fdd3defa2eb319ec189ad0ab460c02bc30fedddea0d590eebed33e36e06e6b0fe6e3825211352e24b8a991e08f106f8698d2f29de323f86e53c57a1ff5fab7c3dd460316e249ee104e6fcf7b2ebb417fc7642994d5a859d3e17b56c8bb817c434c5a467bb16c8c5f0fd3b794dadbc8967d00f568b53e43c75beb283fc9baf96ea9c081c34e2548a6244b64479060f300a50bdbab89e1a1ee63be723642924e4d20ab460538f26f10560f9ea34a65309cab5e8fadcc49a94626b4b47d89b1b64f82d0c272d78d7dc44b36aa11cce4fc527e84f015a0c1d9d04de20d0523aa3b7aaa60deae3283f9b65cf5adaf79bd17bab1ee901fdfc20d45223ac5cc1487411fee0178bdb022c8e14b9b1185007470814b306f42de89f292b00a34709e2dc81a52ef4acc503c7f2e99baa33c9fc441071b848acd842f769fa38a77473df5877316fd31ea6a4b805e2c7aad033000a5c9b48126c692a8d2856855e6af6330c71acfc835bb389e03908a32954afe11dc65f8a79e724c8a578f9db46b4ce99389e80d9b0041a141ce590e5007d96346207fd8bd9ee435eb566bc4ad8dcbb5b0fb3a54f354696770a7e4e6ccbcf90a3090cb6022ab1155b204865763077924070783f8120526267d8fb6d0b6feda500974850f2448c9c1a0504e137703b096d4afad6d816f5b2650f8afa257ec37a1d10e8abd00b67b935b7adbf0436b1d5c186ab2897e93e1631652a21e094e33b1d5a0cae6e70e1014d43905d8d0ca68ca49ba37965ed38c9eb7211f6939c1b2989095a4c9a70fb9b4ac7f054eb00f13a6f0232edf444a45281bd5c35a0f288c3e372499bfadac112d1ce096f7afc7a3d68f918f41b6ee595a7853358a14dc70cdaf450c24f0c42e6c8fed448f6c7338bdabe983e43a4d45a2ef1dff0478c69c53b64987eb1ed47c657ac0a756f5999725d0f302187a2d9fdfb258389afda79f749f6dae38a8338aa7574e38947a58747b5b83b2844f377c22280425394406ffb99bce1923f35d6125de9630fa4eaa9222a0c42d028479c74b73d067a00e698724532b0523af1adb36254cc987929029ae1df18e496fd831a30b3174cd97529132ea09cd6d19009fffc68eb68ac7603a9a933702f58cbbba0c1d61c3ffc5fcbb4e6ec00cd7b8ed1d2cbc9e810c04688e9e688f2a7b442e518c42859be6f16c02c40a5478da86fdfb0f4af59e704fd50586b5126ad9c7f022e6e120a25ce3deb5f50c15064bb9a3e6dde07a41368d57b583c4345d6d2199e79ca9f7cb9a49091a08a3160623c6c41f050e54b16be21ce916aadb28819bb648a4538c60f68b5a516d09a6de4ebae0909f97f8c259f3b227ba43436de6643b12ab5827435b9acbd2c398c59d3f818e92e87cb1a8f354b8f48a81cb34db91810ebb0c69800c0713ff91b1562fe89c2bb0f937f5cb348b55b4d011a5c75960c49de2b79c75e315ce8a868d10cfb7f6d61c4052d9c32dca69dba9d0d949b8897d465b9e7c3a483629491d7f2f4762e812ca8e5195787822e7e887a8bfbdeb8c0d06aedf19181162fb9f59eab9ca9aca26604cee5ac24b58d7558639900c811ba65357fd3411b72b35818d556ba8729c388f87e79190a0baa0b352ac019d512a129a4a5092423e457aa0a2e63ff3231ce4fa056dcc48bbf42d9b345aa14d217f35339d02658db3a925f665b2de9812305db837b0293e01027a9b40e8856d43605edd7ed917c4c17b561645d2498fbcdaa376f0a56fd4bfceeeb9f8258cc48a7a93fa981db32716dc62408e483d42c3947c6053bd758e76f533a694a89a60087fb1454904f215fea009efd0b9e7354e86f8d1771dc4a0ca4837738ebd932517073625a5e5a13bfed1b7f54e346e5defbe586ef1c85724e0abbb92b101573708f4268f2a202a1c70bd40a8a9b779d7a68ba67812b5a04f579b59a05f27cc99dd3ac97de6260c335a2f87fef3d16bcac1c0164ee993b3fde93ea93036494bf72eda48b661778b73e0eded587c8c7436522f7ce336aebce41d95d0f9f439adb776367c8bf119ac4113627558022aff8b00d1d4724fad3983895a77c82fe09e7b1fa441e37a83d2bf443204de76a06c4318028e4c0016cf30637c8cb531d45ecb906d33d0451552b6c2c0d8d86a62563d833ca63eb3c70dccf6a1f9acbc6c4b0e85ef3fac83bb3acdd3648570222ce583cb403a2dee151df0b439a5eef33cfebc9320e2aab002a225b100712f5ceb0f59d2e4989534fdbd1b987e6c01f707b964682291eac5b513887e8944477e38169fa213cbe5da816b57f20ecead940c1fb8066522986ad3600466635e26fb2e482e4ed5b8b113993aa62c370b3d36050bdeff6c852964b0f7511cde0a09163559e432331f377962a3da830bdd855a4c3f8a84d896a2d0351a547bdb1a3ef39cef09b940f68c438bc45468d9e0cacd55df2e536f38868fd36f8e913e4e2220495fa2d284553442357b07b3fea6115b42666746091f8ad55f050f7c9233bda10e9f1972247499aaad4d9515c919964d1846d8f915d3e67209d1bca575504b150503d465e29a08aeebb2cb16dffac56257ea03d1a8c2b99567ce23ead111263a94c687ee2f64d27b3f807a0eb32277b96ab611f537702ac349b04c412c5ba899a896a40a9275b6943ab633ef975fc1296811c22a1c1c12e9d5922563d199e5c1f08988db2fe46f940f45364f2448c30992f17abeb7308022e1d6ca59c58e2965377e5f7368c2862d4360bb5bfb688cfb2cff05839427ebc094a5a041ee0effaf9746c05c123069d6aac6cafcea28ae8d341a27083ded1125180c97c185813b57fae221a82403cdee0e15112aac5b394c5e6fae3cef129bae28ab171d334ad34aa4dae4d7101bf678bd4a48c97bbd8b7b1fd6572aa540c58047ce7ee393de140584912bfb5e2c3cc6a51421571f1e4dc5bfcdd529ce5deab631c5e07b7cdb1ae1ad80b384ccda784fb308a7eaa018858d7c992368f8062d4cbdc38cce32a53a8f086208794783dd5a6710d77119821c34e83eec50dc633721c993858fe5f9b4d5f6a592f098f26f4fb1998f6ec47ec9423de1bd810ca6a401dbf533866ac45b85509bf692c44175c2d3fd87b5581980d73a70d801abf99c63d16fa57b4c0593a4dcf794c3d1d8552df85bcdee98d120237f15267798e2469a5718408634f75416ff44105c1e20c7b2558587c6b402c441a80f1027332401346172a57c0c1055c9e355158731432476cba508949f5926461bc99cbe9670dae82ed82dc92dfffc3fc2e61786789b11178f3c5dd562629afba80e84f3c55a2c7c972e21452bc30ed754c9b41bc66808d72661278705e7026bd1baedb9338e268355994333f7b6d90cfda7b8ff0451e573f897bbe5cf47aaf921233f9654dbe599986a0f6bb1a0fc7837179a6776e400949be71403bdfc554f00fbc28020dd9f7c033279993d119924caceaa6c5f71a94a82701b334d82d7cad6f44fd4d288752ad508a53eebf2e0652f8ce6b625bb78421bc92dd5fa2333b7a1137c61295632c451ec93acf8a7f278ab91fc2af1ec16a76555ab653268ecc654d46ff90a413196c1adea1fec7f66b5a92a06920e5744c2af1cb032fe61760b7f33b05159c7d267089e6470ae7bb786bc5a47dc406bf01ba33637224d1fede3acb7e44408ee53f76969ae7f5fbfb1f750b30e2bae6ec246300d2665bd97a21ecab71735df804098956f58162ac1adf42243d5b1406379255bfb78889c820c78784c69f5632fca15a2a423b22bb12a0c050d2c5fbb0ffe9e7acb9a7d55fa9cd74a4dd12b65ff73bcc6702031a590003845d2e5f20092cca4a25e368a4491a36f584102ffd1872be40a91ac803e34e390b9ac00b276b6c20d4882923eb35ae29ff871f9c5697d7236018926dd93e0f554d543066e0e813375135e160ca0c1e340a090322f54f4cb5b18a04fe52f776258446acf5cb763f02275fdc4e8d69b5862d5252faf18f3c4353c331af40c2c323a30a4880b7de9bc4ffc0e1bb6d9b358c6b13681db9a1bbf50726688e236e0d6703c4e8e5b1254e9f6b42fcc60c3c5f79737c7e493de4a7f8201510f3faa6008d6ee58193ac4120588da4ef91e0c0f47b2dad9b26c04d194dc107f46daacdce2b20b71c4a1c386410debb48650ad522e5f816e0786899aaea1fc14eab105553a5ccb51a2fc7076f544f137e38110b5d8e4a76ea07fffb1bb75e8ce38b5ee2f4f77f61da78799fe8e479f6e2374b6ff51044f3e5dafce10bc5a805111fe36deb17fa61cb3803df04b133ae995f44cd3c5046d550ad98d02bd549b3ce702f1cc54424c4ad50258cd81fcac664e1a0d19a87ae7df3157a067f4c51385fc714afc41c5e698d9941c1bc58ba0a796ee5dc62673718a41c8d9e0036395cd8b525488c1ccdd4de32f28aa8d91c96439521cabb1119f5b77547bf78e134f092719254e8910d2b3d55247c8236e16b801cd08df4459fec711e61b3e422ef73861bb9c930b90f7d91895168b5df4d80e1e510e91f6e5e3b6e778f275db913c081a444fed1803cfc04a65804bbacffe832263c76075897f11283c11458dfc99661da5575a69e957825014505e6b07035354d1360575a46024c50af7e258cee6dc18c139f3995293e5a2dc5a600d021f870c053a671b7c49e4e88ac2cc13357d0a7551d6f42e2d52cc5273a15b898884387b68f3ed0f54041609988d3ba424c2f5070db5bb6af9289f01c3c463887c5760066715185089749cbc647e85d1abf0834b79de0c846e6c7c56f15a361331d490c88c1c8290d3d0097a0314298364fb8b662f9de547afbb0ca70cb0ae0a0cb2dcfd3056ba8ea3414228aa07cbeb3adc761e37583814d5ad8c003b1983df1f7dcd169428d5061a259ac65cf5b787c8fb39a7f59829f6673302b8f6ac68986133a41e39cffa07ed2fb4ebc00809d6694788f542c4e2d62101d526af12b395e8131c732251f3f807e8b30d32204204cdd64b1b8daad473c855e94ade0996755a4a20e6a3f8b5525da4a667f7afa7969428a6c8f49d5622283a52d86f1697a7cdca90ef15654ce59e997b3793e818a23f5dd9dbfb4dcea8ebdad679c008d1efe43fb776cc31e3eebaf0d017d5554c88c6f17c604589e8015f820189d357d68354c16b44f548b06bc304dabe0f0f6878c133ebc6dd02f0a5a931a5525d2f4886a647c70b68dd7628406f89231c27ad4b66e39690039937e1ed3d33ba911712a6d9cd2c21831a8a0542af1881bb7e29e33e58659dc782ca52f1f65da4e4d382dbe11f48fd763f112ad7691e942412462bf0c16eadf6bea806473aed118a951c93b1679c7650a89294b9811ca46344fdf5a42f1cb02efc12819e08738b856c05b3f4a157cddf4444c227a3a3e879dd4fc8331b1b8a04c047d606320aae484c024c4f8a74019c985a7af2d5eb89ba0a3696b93f1d1ad23b0b54035a3e0a2fd1b913a70ec63ee68030a8037b4aa6bccce6193b3b74db26d15b5bd56514ecc065f154a36a0889b206c265f034e990a992194b2cb1ac242c6f2901f8fff7b8511e3670a5cbc8cd922128fa141d28480222880273e5cd53d4de72318e7741e32acfea6f90afa9c259b77392c19d9c91a2cd3c99542a83acd074b1ba4b3727d528d99ef7ad5ff0e28ff516311acfef3b5357033830f77df8b98e7d3bd08bc240f23ddd16954358169a9b4a825a1ece6035d07d195c61a3434e2ac49ab2dd16dd9f77396f4c86077e696de511cf813626f405c71140c1b01259fb393e2352daee3ee14ff782e6ec14445b3457839d90c0e987be9cf1c3e031f6501033b9d2cd0cb10360a427696e90aca312e0b234040a3b46c740fed270ad4cc55a901f85ff4b9571f9f632af91d681333ad082c5e3ac9dfd30557c9f9bb07d1dd436b699fc7b84f836f58a016700739ebba44292ab00dbc3ed33aae32a924b8f75e415b895ab40630c718f8ed777aa6f94bf40a28f1d354d02140ce750ae2f7916c65a5d450798a005204102d850fb07de843cd4a29bee1420d0bf763ba27bf5809534e7fd16e9a12ab6d73573abe81252f2f8c6fc77e572df2562b201d9f1efa99767863b4686b7eef07fedc03f281a5faa53b4a004723b67add7fa4f3d4e74203fafc3012a5a695e67890ee76550cb33ce8a5a77ac0d40e701c7b50aab5e4c8c2cb220d56eca1d50f25d7951e9bc2cd6fb270a208087d37912a19ad6bc91a81e334e595d031f8d01abc277132a07b05af4ad31eb0c0cae703febd51ff3f3846ce0349b0e829abd2f51c7b980c04530a381977e6fb4563227ab5adfdcbd3f75a2ec9415daf8f59bd41b845140f67cf42333632689fae8f51b057faa82401ee7e4dc5cf9dbd54353adba50a646c28730b8941460243a992cdff43c4053355e4d8e04c770fa104091c1d82468531230737de5f7a0ce124c5da24008d4f9592ca13f3e454427e3b0bb0c1d7150a96513a32418d250eb18a890cae9cb3fbb8edfd2b96a79727044131925d72a5396c3c000c7f3932286d62b9a71c2178113bebb6876c4e79b37b87ad2a8d60c86597c508fa84623dab67b0050c84d413ee044c7121949689f114d7640f57082760d5ef8618264dc975b3c534116245d471401338ba7dc53e6898e795c6c84330262c99af4f26434e85bc0576ce064afb598ba5fb0cc6c3f3b0fb4be4c15b9327bf2ed23bb87da76ceb43b25bb28d78da1a028ea3f512fe961c31d51734f7aedced3130a64cd13e71b8f8ffc24b4810b4e975d536290169e788b4da3d444b895a2fc4bceaf43bec1df11638c49f0824c7560e75a112c0af34bafeadd90b1a1aa87ba8218c2466a95597ed0bb49671b17864aec5cbf499cc0b941b2a3d64109ee1c4b1a982a373f0850ce4c1d297266db6c8b5427532aea34c0c54b386562c2a23451a886a8d55431a3cac5b0c801961261138df7591a8f948ac9ed14d27535543f3d81b1015222a67934d79bf0003aa45fdeeb65f160ca24db33b49a036afcc377708a65799854e1f3ae159434ad474005f175706888e924d8e8e8447a5e04a015cc5b599079523b1c174ae7bacf2e703dd75deca46922e5a7a14e2019c740d04ed6556593c6c0db284cb1942bd41fd772fc4e7eba402510d4c6b4d6d723b13ab1d88cb387ea5a5363a1b199c84f7941793b0302574c69fdbe2e28b86f3d76c4a1d35ec0718f869e076bf88387ce5fcc02f888b56a554973c7cd1db49ce74a958a578d0b5bd27ab8c6dc26a2656bd856043689d7469f3ae80b473af7667a01f6d167d27f214837e2dbdb8a7398fc40e7bad24a8a932e769b27eda508758e91af59a048c8feb499b509b171f504c381fc320f62d81cb49b7a6ff754423c42e519cca69f46689fa9902f813c563f3a74f8621dd4f23a549a1384d632a2e70917b74a5232481be1b1e0ec736ba91035426f555ba763a67802867620201edcc1cdf1453f260609b6955376189a952b54374372b0d57c279924b7d5ba31ff425cac06be41a9f1384a157d5fd6b5e9c9e4cd8e91350b4053340e8955c7900fa08a81ead5a06560794a054069cdaa92ca610aec63a540018728d3eed619ad144505d1567a19f9c5e9363e1d8293f179c8e25e59aa103ba31fe2f64f8c0082bc06f08ac3e5611c19a65bf3ae0d05ac68f666636201e910f9f84c34613bde30725a00809b1bd4be921518541dde5c5142b02630f5c41192c4bad743d1de29aace5e90d9e0b6c3e320fd453b5a41e12935d5869eb9d523042ad3c97733a8120aef6a38f612abb7ebbf7c8f516c83b22530e5474705d66a0025d88c40f39c9ed7f54c1446910e5076c402747fc0b12db30805cd49f82d67bf2822810b127fe54d4eb174e884cb5d71eda12c93da39036d92143788d3ccf7e54d3bed7272535c39d75f675243bdac184d7b8d013bb2ecdb25d2864a44ea8471c3c556ab694f05f08fb88d8020035218065ca71c9efc9e4de383a2740f43425f036a444f9df8fe99f51eaf6c208bee7ead802e7b786ece93d4ab779ea6d394c8c353f5b8088366d271bad259030b613a267078e740c0e296420fbced181b7a0064682dbd5f883aa9c47e873d5822abd4d4ed8a7c4ee97116591ec017acb1567abf51aaaf466b617b350d6402f0ef97b5910e0f5f3ecaaf8a848cac2cd206fb3c3e79a3e6106a7a32d5d48c3c930aa6015ea4cefa222436a4f9ee854a590525325ee4acd43415aba75b0af9f1d613f220050155fc20478b6bc6f553c1203c7b92d37ac47b7c8ed1855764943a305ab42427668e8caffee01abe0265431abc4a39fb6d6562ba02a64c8fd45c142eb951286140383b61dff8abdda1c6f1aa16f4f36e35a2f5fe4c71d542c8524e37c132f1f11c4f4d8d019318705cafcaeba2e874b71fc0acf9ebdf41084a881ccacc169b7adabd4a693fd16e074bcfd75ee5809d4625eef22741928f151c32c1b2d71c57f2a2259d4f12c4122841901f737f3fc24904f282db39601085134c1fd3f5ac574c1f3635b6e9fb609dca2524842d326d77bc6bad526aef1f8e307599117b7f01909501d6088a726fc17dcb0a4d098165ce1f07596238172a840f6ea6bc5b3b944ed5d96484bf84dfa29ede170f6af41137a63262de208841b20008072931c490331d88fb82423d28c9ad99523ff277d8eba39babc68d13079d923c1c22b62f9d70ef12b85432a3844efccd330d3b7a2c4903ef5378e092035a521adbed29ad1daf989ab378fda625aeb6abd3120de27c7d2a528c920221213fe36a4d9d630a093d87cf0021d794e75483d840a693e0b22a0457848dce5be7ddc218926ba6ee0562e539b0899b82adbfd00a48a19fa33b9a0dbc48410042bbb090ae480edf6cf98153832e5082d415a3bd595e404b74e17a3bdb0c48630dc8702f0c221f44535d598c0c760feec9866b6a2b3d878638396ab8e1bdf434228a7bc1f21c67bf01cc94719f09d1785ba0ab56a9010973121882745b6c72ccc5b107209b692ae894a02c3f82f035e5a342ace22ba0fea4a80b2c86ce9cdcf58d16d6f15dc84afebe3f161bb513c61953082e845d5d9d03f07ecef81f3ab47c2cf7cb7f857f738fea33b2677d1094e131771e0fb3f4a4ebfbc267575941fedecd0f588cc42fe90fa781e32492a6287e66fc1ab957cc35c4350fc40ce46aa22f967ccd30801b5575d877385943f0fa0c4530190ca9d62b0902a71cad6b65dd076ee718ee84d2020b7b2e0282991aae66f24ed205689230453045322a731c8cb34fbe1e319b31b4f0063e3295dc6276567f5114c0e0ad37640d3e88a7ecc02f6c9dd2eaae80e51c7c1e39afecd36b622101d04e8b66a28099dc03eb2e8e05ced173afd3774fefd9d5e5b36fb159367048d8ad6964b11f08c37f618a78637fcef6b0d5c5f7899a05f97b71b672a9bf179f321daa4a524e169dd5a820dbfc1ac5ec4c3703054b8fc45ba13c500e06cbdbb274bcbd96d82fd7a8d7fc73004d63e52a56fa11ac723f3d627de309976d0b1a200fb7e748eb3ef74f128766a8739424268c091861f09f92743f33eb9dfdc6ac1896dc58e5a8bbed6b576b138f9821e248cc2763ec04251bd05738de9f3749eea955eb9fdd902ebbd7ffe8c5cc05b564d1e3f4078cab5355d4cd7d586feaa1837bed3732b27998e0c2571c3951606e47d9c9e055de17a4220a79e3f39386b4ccdc450d03a0834c5bc33dbff4cc8a4c1ce576124da4dc172514b8d0c14406735f39a33ce148f1944fca9f6d427d7e660463b783747ed0a999e5028675ad406e1982e5f18bf6de6ab6e54a5741c914b0b58e4884b7071167a05faff881d437f1fbebc115a039337e5d2e58fef1fc8544044de3f6865d1d9a2fd23fd4197d46cdadd2f60daa770caaac847854eebac3ae47c17abfc985455c0ed79dac4e6c6093b7b5620ebc30ed054daa8294a1a2a67d12939e9c2c4dc4600beae57d6f57319aa78feb2b95d68bda8ee4b24e08ee2c9aa6d807e801efb690f10ae8efe86e8780adfa031740eae118ed41b21ee8cc1936c337ec0eea1074470ef1e63db08e87534112b39f587f83caae5bc7db5d44c2e369a881d33fe5bb62285b4652f24173f24bcc166f3fa6ef06266238103bf3900a2c19639f339258e8f0ed493994f82ffb351dfb2088e3dc66f16606e2e5af48216e425f175daf97fc7496d61c7a57644b0cea7ae77a1628a4c488e3f329dccf8fa908a0cdd1b963f96b2c8fbf9cad45515cd976dd782e3906101eee75135834483ca8eee4a035fcbd3217c7e60cd07b14f21d1ae408cbdd582ef7783b366e9c447315fc9dad84bedef3cc5ede7b82ff67e0127d33a89073cef25428bcf74a77fcdd4df868550c92393fad109f8ec9de84262efd9f2be2249228ac5618095075241319effbb98f35253ad86a2814a147406552ede378eab1440813ab4c4aa88f117c7862d33727efdd511fcce4f01cbde798c27a842ec09a96016e00d1ecf7937b045bbe0bd84968fc0a052bfe0bbf10677df790d08bcffbf9f5c5a07eb23c0bcf3fdb1031053f7ce7964fa34c82d10c38e6645259e9b47072f22382685980114dcf7a7990e2ef78eb8a3d7d385eed35e310a0aac1f3ec2e4bb1b3d4cc40866dfd0f513f080f3e99802ff8742c870f2e205be061a3341d69d3f9277f5dbcd982c66ecb4c2215a623fa860ec4fc642ce0fb9fe739c15a75c39d8d95feff6a2b6da686410d25480c50094e9632c9858c2dc52a7a4cc2d58b1a583c566416428e63c2985aa80aa4d61b7ff140209380ec1b5a3ce1cb0c023c56af48bb31bdd9ece7ef7f0b319ed95b916c1d982e6e8501c1e74212d42ec632555de8a55052c9e32928c4ebc84c1baf32f56068b505d47f0e4fdc7a817429a59adfdcf22c1b6dcc9b3a5756ca52fff56df24592e4f4574571bc85c9ef8434282268ec877ad5d5250f37905cb9b9f330500c76a14b7ca71b6a555361ab5059b33995f983dae855a7c4fb026415a3b4fc3389f96d58d8e307451c9685184ce6c2868c3ace1ba541d1ea57a5c87c6622d0641c9950539a17c1d0970edb09ef36c82b81db75c69f55d8e608baa4dfb087b636975bbe36cbc25c7b253715a802a05dd410b9f8a64cb480d52122999499e38e181794849992967cf560af127e7bfd8fc2353ed5e312c29fab7463015cbd3691cd71a10459cddadc0ac5f2649029229c18e34ffe8904c350b631088f5e9f913a801c7b90d8c642a1692a855ed18b85772585730cd1710998ffe3139622d153c44a2664e00bbf3f3ea40ac2d1370408ac2b65e8a79b8d295090c8b8e89ca2131129dec1879527d49d2ce45268982b8b6eb609442aaf18f585e3b8a5be035c1c0dfcdc07bd4205cf6e7c73ff524c191019fc3e31b51c843fe100f12f7788462eaacc335f5d8bc7707ce56d571d5d229574b5a22b3cd7e201e090d42f560f93a74f3b7ff63d6cfd507e03b308d0280f5cb78a6085dec7800866f93467f7665dad839f1956eea8a10c64d81e2466f09374d5d21d4275372065cf6290ddf2c7685ba19f9301ac9aa1079c17d15f78356fd3b4807aab8f015fe9abc619be01ced26e0f650da4a55d24afd800b6db382953442e36e640e7c689ea9366f584e409e104a50024a5a0994fa030e5d2d869550092995030ed0c621f87c5e2318a98e466e640e7c583532a972c77c85785c42bd80232642692b81125642a57fc007b49d0c8334564e6c48ebaa04bd2461759044236eacc6d188e0c01b6ae8ab19bfcbe012ad8cf1491020a346b8f198ff8dcaf87cb4db88acbd1775e7a757b06021d58807e8dba8d0b46d4d4816447ba093ff2bcb6ab3d48ad6bcea6386509a84a6be1a2556e6787d9f1975423893b14643821d19076bff63227427e91aad539584e58812080e87575ab738cbf529321efc0312c112618d2a13489006ec6201eacc042a5150dcd57405fcbf5a84a45cb9bfc47674404f11780d37873fe197014f709c38e385cb50ae8957450c5216defc35aaf4dadab52a5ff4a242d21e01f003c70f1d41d54631d7993122d6daf6df7b4b29939432930286028b0276c8e3410b903edd63eefaa1f0d4de000f3421f799a9b90f58c725cfe5b1d8028fa063f55c46fc68d08c3fa60613712fcb0a4dbb64ced98d11c38cf931b1704b2dadfc70d288bfd1e624e1fa73b1aad987645fb54ad5cd9568f5abbb9b9b5591ae4101a54b3683db344ba1a10d35381d4cd9a1db287f785b3e2da708ceb00537c5af3543bbddab6ba7ebedd92a96d7d55410077cc805b82b2c8e89be28ee0a3a6575956d1120794c250678bd9c7ad6b26cce3eb98d6259329649f5f21d3b6459dc148ba88fed426138ebaa29ad2dac822c1f0ea34d62b18f7e501401d046d1ebf039bcd0e3f037bc0dbfe46b781a7e86a7bd0c1fc3c3f04afe8577e15bf8a067e193fc0a0ff4485e854fe167b94c6e23b3d194c9e435b21a398d1c95c764a88c862b57bfe99b5ecaf7f0499ff4571ee99d3ef7b977fa9abb3b0e5f0c9ce3a5bcd3277d0f6f7b280fe5931eca3b7dd2277dee739fcb5f3ee9933ef752de09cf9add5f054f5df754c275cbc2d0867dcf28d886e99e54e0a9b30dcf3d6d58eea9dfe96d9f5b407c2b8fe57d78dc4bf1637eca4f8f1bf3d38ff92923f14d2ee4a7c76d31b3142c9359b675cfe3759f5e9ba4b4a734383fd00b5534483826f0fb2fbc99eedb4768582b87d1f7a24a69aa83d40b368811d0eddb9a331f7888d8f54c4920c7ed2d0668cac700fb6349f9aa757fac262aeda934a862cd99c394084d26100475c153cbe64c4efaaa3b768a356744339f09446116816fba12b62370186de280c3bc249189f219d98cec9473b98cec253765a64c461e238b91bbe4a5cc256fc9b8acf45e7252d692b3e4303218f98b8c94b1e42bd94aaef25f642fbe2977918ff22d53c95ce42db216398b7cc4374929a5943bbc686a1ec7982b8f79b462e6579d291f9301045cea3ce611478d1c2543d9015e181f52dd9e145261180fc380335fcebbb156e690709f5c9c0ff361fc042fe3b58256bc80a7f6aac1caedce095ec675784ef032bee39ecbf064aa436956f7322907ab2a13a9db77cf96df248fa8a84def15db9ff8e84e6c990e7618fd71f18ba22f36ba19183777b1c8c8aef6eb7aabdd331bc771f4eaabd52d8a9a4f4e4a2bc645a27dba352b86fa7c4057f4da15bd7645af5dd16b57f4da15bdf6cdaef889548c5e18d65a6b75ec21d178aceb84c2868486b6cf7d52548bb690c774c3dba6a213d88bfc898b7e67be84aaec942e7e55fcbbf947fbc66f09f50983f86e77fc6e77fc6e77fc6e770c6b58fc6861921bfaa252babb7ba538fac296e90a594b460c9025a30468cbbb44c9964cee1217b24f35e9e1d5b64f3db35a9d024a97ec8aef0496bd36f57a815c7cb9f87ab9f87ab9386bebce2c4bafaee8337cb40c3a0b78b6654ea3591c7d7df12fe7150b39c6f48def04ced9956c59b61ea46f9423701875a9b664a8cf97254b972eb99c983b76ad8f36de27378a5b44b50fd11e4ea8cf8d72c79b26fc8d975a2e3c539cd3e48feb43c55018a5b92dc5e4b64c4b2d469291b3459ffe8b0eb1e73eab9bedb51a98339d734a39e594795b0d6aa9b3ee7a38f67a620830d0f16cdbf251059e7977ac0982d05704b198cf1021ab159db256154f7d79d1b80a45670ce7d0e593f31278c210cb4db83b1378de0ea7cb9e672cf0bcd9454b28f149e0a945248e207262c44ddedff4453c1178ea213cb56c82a7fe21f0d4f285f820f0d40f84943fb28ad628b09500759f544ae964340285b2ed8f3cbbe3c23a28dacb83a20930f34d792a524a19aef4501735551b7937fe86a63466db437dd447fd91d091d4fe514eab3faa1d79ff477f6484a706bb7842bd284a034f2d75512a1d9a15cea9c1f1f1bc0e87cdcd8d0d8e1b3835397845a3a3da49f18419fc999e2f87a73bd66d591dd5e500d000a600364a42006cd0769efeae7771b5370b9893901d719fcd5c89bb144b4bd949d2a805974568688372a66a545609232a4b9096db6fc952fc162d352da316d153007c243ca5f698b6d4dd95dad6a12db53f1245c253cfaf5b92328bc7f26d79f359a5bc6dafcadbac553a6b76d6b6b7655e90fa58aab71c903ca8c6326bd5e7d30d9e4f98a96e3aee396b5e3d1998d6599a4bd3b4169ae3bcebb8015e8e7b65715c15bf0e815815636154d1007026fcb6b7ab4ecd1603f4b500b6b3ed3d18b8563bdb9e9cdfa7aa2d55eeca952b57ac58b1622587019f870c6409e053a194522a6ea9a5eeaed4b6fa53792ab20e0a7052aff676de37038629150daeb9617383032767a5b3c3937f86abcd32cf8ece2a07a727c7d7ec0d8783e3c6e6464d0e9d6b4eabc134aa9466f14cda7d4a85e07dda54cfb05a3bb46e7c9af9ba968e70ef00c255ef4cdd9a358fa6c3b5da528a9f988200677f62cede018425ce16e58f1e1c2d4c792e3e8b77fa293fe5738fc56bf1653c16dff44eefe58f3e29dbb0ce5cd19c3d6d18674f25ec79386ef6d4366cb3a70ddfd8d3866bf6b461bca70dd3ec69c3aa3db30da7f6b4e1704f1b06f7b4e1993d6df8dbd386bd3d6db8dbd386ef9e1abc09718438614eb80a75747654aeedac75677b6b0bf862e0a925a5944a6fbe80830ea074d1219ffbdc27b9b5d682f46d3e6aadb7c94ff167f8bcdce5ee49de8c37e3934039a9d7cbc54ff165c4a68724a594524a29a757153ef74d98f608424a2973957adf5df283474aa7ba23a5938e94755573a4bc16a7d312472793524ae9347df43236ef64efbd01ced48460586b18a7c2d40352cb9e1454291cee184c614513506ab0828914b964658a24be80b21205ccd218162a65b1bc22a85563db45896dadb55abf3cd6ca4f621ece96465d9874b80f5c5be6daf27a8dd1d77ccd25265c8c706aa1ceed9a3594d5a53276ad1eb83c3f51fd526f09b775b634ea8264096acb5c6e2be16645282b5af0470ff563b8bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdbeab5d6ea135cad74adb5565b2bd296527f4afc971e243d487a90f420111fcc8379300fa647851e15c8d460b4e589d11625a3bd92917801fce48cb9206ed90a57db326f95b58b2788a7e51642673f9fc641de4f121f3f9e0ef27ebe6f8605c2f7e903f67769cd2d40e99c3ddc9b781a943d2d606984a36d99a7b471419b52a528361542673f9e963e83bc1f4f4bf9a389a765ae3b7959b2116457772d79efedc008f5b4cd9629217536132247a7b287940b502d9354169946a8aed56b4ba666cb5900a58bc886a087449db69d9ef2654db0a1651501b5d5e007e4dbae7f4296fc991276b50d5bf702a9d9ce53414a877a48aa3504d43b52c04464d4a725d33ef273e4876a4dc4d3200b08d4d861a1960e9b81a98189c8a86dc4f7d5f2474a033a2dc39e9e101c09e5cf0c4bb6da1485edba6e4f83924a293da5fa5a21d0ed69707af75e07a9a78d78fbb2889c3a40ad3d02a5fb1055a2ab2bab48952f2be46b4d09b39f089b7e43828888f8d81d18f1ede9d73ef2f36950a680b8fe58409f4e4244c4c736e206dc7b646f190a9e92c0664a29a95579ad10e8ee9c82136aeda80d2b510874775df5d6140225106b82dd74ea395bac22bac8b51648dd7742994f4f40f3697ea9cd1f8268993c7a2c58d2da2a32f7947a4ae0d1232cf50924c00c8002e0d85575d8d66575dacbf1f5cc3c98439ed44e8ed3a82490f397d411060080220023170000100c0c894462490ac349168aed0314800d4c6c2e6e423e2a8d04229138300e8502a1501084000c8300088241180392248773d4d4019d1820bc7f92341bec6ed4e468eb0cbc22fac7144473179cef102c1b346a6b4963df0e49e9877cf5a4e5046ed62ec75442ae30d98ef32cf3dbb444bff1207aa94fdba0aced08fa6e76654e73bb4e531288a50840999db2c70ccd6c69efea8bf1b8a391fe892c35d34d0c8380a7b05ee6f8c138698efd77647ae375e6988c5614c68b3b88d5509a22e6e029017bb0d0913956f14ecfce28dc8b3fd5ee9cc9090c1de38a51df355431d1e1665a28d3266248d32c27884deb3745e8f809504d4b1c48f48e81ce0117a2c29b7d9bf768a63a31b6e47fcb82e11c5ec34c760e4f670e019e3700a8f39c3a514a4e99a465e4b4c8d20653f071029f94d22668a21de6be6c354ace4117fa5b84014e432df058f6dfa78fa4b733a3636f2d6d7beaa9901dbd6e54bddf2ec4c61bd39e5728f6021eaa4ceda39f605409d370e51fd5cae917f5e291da63cd72430c967658fad322119636567d63252646c38957041ef68c1f0c32b78026c8ea8cc26ed4182c9535b39a1c2ea6dc951efd3a065bc0477f063c18d6f03b86ec5fca66c90f0aaf6d49c22e96b49ecc520ebecd02b961b2ee8284877da5c5da130eeeea9d4c347ddbfb98d4f4e96c497f1cc8cbf4293d615d3292af07a4a82b07edfd6ffaf97fd75c3311914249e4d03670682c235c2b8ff39e8657ba50c324075758ec9221d1638c3500ff87997e20b9eee3945500dac0f88a6d4de3bca6b470afcef9f989081d80c4b4bf864898e17dc9e952b9081ee47dc9e952b9080e8cf601721a057a100f08ba370f9141c93f90d4a570912dc8ff90d4a570911decf6a7d2b588f72a44a49ea48152bf084ee465e48052bf0826ca9451a3d4f14424a652cf8840e467248152bec826b2392315d0cd8a37e1e46912c3a68a23e190a1a10644cf3b92d3a7f2111c68fbad8ab4d9bc244ed19dc0ed4cc48c130dea4d8a9038d76fce8e167e3d9c86b7b346b60309d88d67becd4431f423e101c9895b33fcbb4df58ee7a28c133e2806024b5a81d8d37553a84d9c2c2ae0e6de05ad1e580e8801fd020f57652f0ca48ca30523f18ddd0d94aeb5c601e460986aa2fadff45ec22a39a4124f43aef86904fe805d2742397b0919908cb49ec8c362b8544d8a8697ceede6fd02de87c5c677e3223e04f8c103d1862d9b61fb858e696db89ee8b969feebd80ad9b0431ab67d78fea541251d2f76cdc0c40ffc2c60338c8a4a8a0a792d612fc4adc7848eceb6f71d3e9f0d33c8e893b228695811f9245d8c38700f6037e2c6cbe49ad06024627aa0de19fc791a7f720fadb7311167d62e1a3721aacc385b84567b2f474c7e1cb5c98eb4a0dab6e67381566302745e9048ca81b3b28092b52e25f4011a6e8bde09288073d210930791cfc1af579ff2136776fcc3b6e7d0706d1fbfa933ed708cf27e5cf9ad7d610b8c9be9913da8d5795550220c244e1ff117e42377c8c2c505e30383b629212c494f4b129347e82c78fcef506d591e4675d0d22490c6c38d388fb861e4870903ac220296aa674f7bd92f39b6b520b76e45d2830d8282ed636bb9f9f1b51a11d3fb9b458636bf604c36f910e3fa427c0eebf2cc352e9fb700c92470439559803c79f7df59752bc1d199c678ea65a2c66ab916b9c50acc605d0264bf70c8e58dc7071c0f1d386a84384e6d72e59a6dce907f1bfb32cf4bc503c18fedb29f7a7eab1b706d1781ce0754ecda84e9b5aaebbf56621d4040171538516f8e4400bd179eddbf93c4149e93cab61ed0d557164b21dc19e5b1b2bb87c2c8277b22b5656b7e4ad1b9a4e5852cc9ba669358a556a1b05984bcbd9eb3514815f5641bd857bd027b6bad268f20b2d012371ae85a14f6b7d445bc635ee408b0416452de46a9da6774c7e195d8b8310a56fd786c55b2cf8d5de8763444b500ef608b6fe5f80563d5ffbdf28eea32ac69a45e114775a900618346013055ac024a9f5fd001e35b4f0b042482370f855e50425be08d8ba4727a70ed787a2126108ccdf056773db64cfc4227c84d0fdc5dd916e7dc6d23a17b16e8559cbc04a074e39551879f15c3e244625812790b8e1578c118424966e3c72eab688ad3f3852933616ed2b0ae7b733eb9e91e6c8b38990dd966739540dbeb3d3ba2baed3e8c0946657d708a4e65fca8222c6f73bdccf02d89948fdcc8ab8be4f25721c3a910030940c20b8037b8a73375fc1c11cffd264b7e7ad96c7530697f65a3fca57eeaf0f09725aee017268dca6116988322011d38b21da810d166085e1c7179fa78cb767ebe743f53d29b684eac50cfc52234e56de0ddd8d25ab6531ae927103946b46303208f4fb26044d1a31e5846edee4d1ccf3d39073a4907f6c7c0643bef169e33c95b33bebf28a49603a2d605c185ba70a24d9163e12a397b5164ecb0cacfb415081b26259e03843ab80556a03ce30fc4e8e53de5843dcc93ca476b06df33af0a4287aaf4ec8b2263212a39f7a250c8908a4eb45e142254e513ad0b1d0977d1498b226384557ea68d2fd003fcfe6060964c55f3bca3e462fea0ea46d7bfa4bba878ddc5834f3591e9eed1991dddeaf465bc722f3bb297aab34eae834a5361968a74df0055c280580e7b0a2ddad25f43414dd80cd141ad9217d0d8f9319dbb8baa549e55fae7dde6f9b22321d0810fea73b26ae2ee743c6efadc4ab38fd28d07c9e41f3b25ab2d5a737358b0d076c9d7a1eda36fa25bbb6126ce117e845b728c631fbd02878c16e5b63eb37d247b66163a37ad4286b59bd04cff93a0e06ceafc30bcf04773df482875c195ac8004cf5f733cd57755f8fdef4246183458daba369e74d70d898dda81893222c472bb007b54971bca53e907392aeda72c65def250033fc67b020a1c295e950ed748d0b1cb807a108d30ed42570bf1c8f040b4eb8e3b5a4637f864cbd0a8517b8f5b09b34f54a2efcac01f34670f460ff242b6ddc5624f8c8b7d80acad18597896c6454e5233e424e21807b47470b674b96d8ad1045e05361ba256e3190abf8edfdcb1e8076ee2e654d838f5e342275f33c18f8bb881f2ec0b957bf775d7a37f0b338cdd4ad07b7f53203b47bdb9386c04986c9b40a12d1324ac8c1b0b1ac5bc37eaec188f5744d9ed50f9179fef65b645abd05be8842f67a37e867f83be94619ee0f549a93124def038509e31b246248f2ae4e632a52ac306dd5633576190aaa4680b210b1116059c3ab078a7abb2ea9f91c063db22bfb0e110b790a478a9f0be585a6a8dd150b9d65a597d7da8d6529c99e4df2f1bdf578d80c06264d1f442ee0b07ce7ec2daf6732560f48d884bab129e2aa0514e33740935ac9c46655e5eccf2b4bd67a17b46254f62b4434430148debe518764fdd5765946c1be97293ea8f75683ee875cc6337178753e74fd9dfaec5d1250b51e890a1ac629f6ae771fcbc27e77e4445a33339cca89495059d0b61c3cc3793da7a36ec3f704e8f7824885127d3a2a2df7ab4094b8a14662e909226ee4f2909019e91b867a48f4052ece88dbd679d89098d25d9ac2626d4e9248448f3e9d1aa330c19f72d7cc39d53a983d08fec86037057d6471bb74026b6fdd4054385b6f228a3039df025139c8bd347c93de3d3e312e1448debf45891ba81470e6db6a7c8b1183d56456078ed988cd1b2fd0cd9afcec73a538f75faa019ba2272ae9c2fcadb7a383137e2e4d43bf00e165319d16fdf596cba210eef970d5dd4caaac2371c128c0f56d9b537866edd806c8d9f90d5cc82d99286214f4d9246c1d8b435490eea709613c8d94491a6005cb70a813c1a289cdc3ed170dfd2fcd2340293a58f5474b25d479a1b5737b46eedef0fc49bc6b3fdfcd7a0b1ef9c89d8cc6faa0fa17191408fdeecf0e455ab8869f49fa3fe0beef772f2fb29523baf4e06998d2b51557e6e3a57cf4a0ee4bec736798d162f983b404ca6fa6d6a6f105e6cbed68acdb3e9e6f867c57deb8633f19b4490ed88382d597bd70f43c766ceb4f4f7dcd1cbbfdf827961c104b68751e5a921570a1b1077a45b3ca5ae03e5ec5cc754d55c75f11f8fffb3b00d50aa8a55df096eefd2d1d0e694c22c599f3bf7ca90992d02787623cdc79e6724ba30b260ebb7fbaa3d15fbe7a64959db086719ab9647d5e56c6f51a1e36851ec46cdb29b07203e2148a95a3565af363332568600a7f8522ab84083713700cb8b72ca23360b73d841c802af089ae19186ccff07e8d626878d063e2f6f239529391eba7e5ebd76a3be5522d2a91d048d01fa4d1be9c998585da96b057b3708808d423713adfae7545fd98e683c9eba592a7c70ee83e01dc8e738b6301422ca432ae6416a0019f76da99232cc8df8732d94323295fb1f189d71bdd8f51a11f3072589f7dd4b88b5cb2bf954b618fac34985971f727b1dc9ed84b7aa427d95179b69e5294a8d13d94efb80acbfb94bca740c682bc6077dc63994ef7bc8abcf8676cd4cbd6865d31a03c90415b3a97c670e5f496f3f7d61ac72f91bb1bdde018441a16e6ce806a953e3525bd86e1001d18878850a2574dacab16ca3cdfe3a2c7b71e8171f72a4aaa4106dbd68cbb6ea959a22b033fa7ecab71e5e5a301c1ebe46d77df5b52af3c0d0f4130963d73c858d7db7a2ad1e8954a2a64e7e05506c914a70059675a8f5ac6c4c77c6a9106c567a6d4965eb7ca1b1c3819dfd17ae99a7006a150f6484573ae86ed39f1ebce0c7b581071faa46327ca88d829e6b7cd48e63a4173667fdcae0418b666c322d00b0a53d1b50b44c55c0507ef1f2020e1d79aab28d2a67d6a371848205d8f16e07e4fcfe066b9778c650eafe419f54ed66f5f1e85f34ff52c10c23a18b9a13c7d52dca76dcd1a91fcf3c93ba411110378370da21e13eca4689d984f0799eb13ac3550c1ca06e3c9fc1c1d9aa4740e6f5f3c27c7f4c52dc0628ac7738dea59f0d05f2614514cb5c1d13262244c15ca9da425c5ebe8846e479752443ad1c6d40c914baaa5cbde917a0d415eed9c2812955d55705ea698b04c37751ddc0404f77ff317c05dc7255374960a3f53dd18d59df9f5c79f60baefb95f0addc3a50adbae166b649c2b6107d4df808514d51b8248b55af7950dad54caa6a9ea13f14c8ad504ef467476a701cb33e4d21c4acbce840b2bb5259a09d8d9e1cf8369d44c772d109ad921c516e15c66ec46ea7d44e5d48bf539f5920d76c875ab86bf0f5bdad30f518509a0021fdda052fc2cbf2aa30093d39d39c5b998706bea9b870d887127c976dda05f6b53a6ebcb1c3a5dfb5fd26cbeb3bdace7764524be44d0948af537986a4159c23877f89a8c602f70b3e51519a4fe1dfc9e8281bce4400e41fbc90541e423d4262f7a9e0bc7b5a56ab6d502fb9bb764b03eaae3454827791fb842cee332bd4468ae07198da0850577dde6ab8ebc523751c9007b853990a74a7c0704aa111eff46c5e3924122a6a999f90c25e75c9857c33af1407bb87506357eef2e64a691b7d53df2b379f71318fd1d3ec3c674c27f55486328cd84f44e0c158b059f6130121fd8db2b0734db1aaa8e11fede24a947d049e9557c28696352dda02210643b4238d8ad033da3646abf52a7578dc081c7995467d28e7b81aa641976acdbf4d11172764190e18a2f68f6fe6cdc75c9a1985dbb784533efb5646a203f38906491dd7c700b7359fa4b3bc5252a61e146c6524d547be98f814ad41859a8f91873b093ed0c768ca83127497d907b06dc0d9c3f3fdb1a09d0ab68f18353459073c0c295a97434f7fcc6d979eb3c475200055dcba815fd711ecec47705ebeb225aa54129baf884cf6951220fd4575f86442a80a9fe36b33bb8052fea509adc6e61ce52468fe6390ecca478aa4ad6ececa92e32f1d9a9c59c5b0afa5bc44d73b784cc0b3552b99994a66f9ee9ebc370bb44507e20664f26cd521bf78b5d536e0c0bff2bb8ab1f10236a44e839ca00d4ae6ea3e3f9cb824ce1168dbc0d034fe634b2ac859f5f0d8692c539d1607a9cbb8131bb7e8930c4570d597081cddce2843ccaf08ad325d523887fbc750e47826eab8c928b6638649511aa37d6b952ece5bd40f1e9807816aeb5f51cb25e18c8b5bc826b6cc0bec5ac6f7ae4462e28504ccbc52041b33f8f49519b942ce4a1133d395e0e5e07b2b5297633c5576d415e56222d19497e5e0f4a5c7d4e4f285d9a4de36288ed251349345b869a8de895cfb726bd6f5c5e414256fd967502f10ba35cb19f910ff4b9baaf1fdb6f801c29433e06b50a64b54468897754442c4ae0d93b9a6ccf81a2b61052fd0a34838538de31a0180ab1095a009e1be8fef5f025e6598dfc98c6c5351d0708d2d7a1816889cce5a42ea4b6e0bc54ca6d81f40363f23c8d666143d799e37538c047c816b15751c727356460f9b1c98efed73afaf9a08ebec32e020c3b1e0445bfb3eaf23ff5ded1d1161c81e7350eb8741e2b18688667b9c21ecbd748b125ae3abddc9fc341ecba33176201a42d4f8d1a82d3e9c8adc6126e154df472e20c8a48c20c34b2cf04b321530483c14043df609d6428292a233b8c76d11487278225ea80c015acae14184a53983af4583ce084068f889193c728ab9626972234c7a85d490814621fe901f3325a0354f48d2d6df38499b4f43638b753f0261c7302e5e5a14f2866258fda12200f13bebb09a19cc1710d19f5f5e5a8ddd27dbb16c869f7988c9c387fd97178643992f72cc498480a33c6f1b7997e986046773cdb5b2fe43cd808a97967172dccffd69e2e82cbd1b66ff591bb3de9c56e4837e1aef6f94a39ff9ed0b26690458295fefc71369eb1512ba338d09391636b4ab7623c6821f35f3fd9ec576e7b12adb8003ccfa6505e1918ccd84d11a007512dcf15bd23b6808cfbad7942deb278578902ecf1acd89e808dff330fd405a8e24f45853b7b4817abe48cc7fe4f1440ecc3e5d87189b905837f901bfb9ad6606198f9ab4428e0f54c4cb33a59307a6a0f0f70ae0a0e01477eaba96ba2fde62b655cb5fd1362041910964a2e3ac87fe7921367d385fe716ab49f3dfaf242b2c265ffc9b0289c3ee9c2b6b6a9d6b7343190caf6c7a2d3c8aa5d6f5cb186195414f889362e396f032a653fa771503444c66f7fca1fd6021b1729365dc1e27591ab0a7c58ddd7a009011bac8397e1567c6683f82a60c5979f69916c4c28be511453b940e88c44643e88a6caabc6725103f54389ecdbec3c3aa63b8c4a4394057c5391c180e18de80201bb0213129dcf3d2e5051fbb46e8969282418c36846564c9c85080c80aedecc4ba8944821efd0610a92c4678b12421a938709354fb6451a58f1dd3951080ec7224814125e6dee995e7bc6dd20470a24b10188d7e03adc70974f2ba455fb57ba87dfd22efc080e4e5f155297e89f03bdf639e024416b210de5f90e04ff0664dbf2221c68c95f8e7eae3042f1625338228f9d83a3fff56945a0dc4b6c207546d236aed277143a78e3d9da9a5ffd981bb410355ca2d2bca7962c55ef9951bf784fc86cf8174e79f2005bbb60b59876cad729b7cec4540da77a9c5b5277b1e38bc34c67ccf8670e1e3c52d7c7201caa28fb54ccda360c97a4c4798d3e95bcc70b13f2788bbbe5fa33b25499636ae98c87445a7d017492309dd66c13d4ed765133671d5cc432fbba7e95a51aeb5e8b4df5a8a01b787f2b6698280a14f58a82ee785589ee180a05f17228d6f6568012c5992cdc309f503571c934b6003c1878b99c9b1825727a2cb5313e8b355fc1391171975e3a47faab073d45a4cd9e6fd44f8404df5730942954270c2c35bd5d0c50cf6f8c5531019bb5111e6b23866164dc872a3b068e3e210f7d6396d4eb1f0e09ae38a529be6f0ad5cf5cf28a16d110335dc1f88b2dd04c5f302c235436f6bbed544acd989b0b11de2317a112e89f82ca8993a52651fa601ff57f8243d9820f296e82174e64312171ecc0725726b6a1adb532a51f4d05da61a150c1294ba076fe9f93af07775621d96d4c214d5a0cc5f0094f048e7175286f155a2faa8e7eae2ac7dbface32fe4d9f65c8a97e59b364cb02980151ae2e3a4235a189e72ee25f0caa941fe169d370243e961ba66484d7dc6c98c10db039f3a4fdc4ceaaba9fb0ee4174b794f6b8039e730db1c3a1dc2ed7d740c54eeb65825ce528953abc7bc96ce7884e4d5f81f7f7ed51c8dc4fc5ae1f41eaa45b9117998533aada565516d7e33c48d14c68b7399dd2147623b1de6306bb88e4e81ad7f3756848aad3488bd68ee2efe62c7417d5c9d6d6b83c2938c3daa8c0f931716ac2af32f280caa26331cc0e59963460128143b06a88fb10fff9ae4008618f38fc696d90014949f5b0d833ea05c1d8f9f142ec6d5a4346523b5e81c47d9f709c6460cec452740ead057efef15acbddabd6697a00a3e58c688f805ab0194b21a037a7e691e8d54700a9d237303fbd4bc313da7cf72a5a340bc86a0e8e8986bc591da69c2914fddf6d31c6e5740389c8f42e92bf7b77e6528c68b585116c61044cddbe90469bb0491a1e98472aa992b40f3e47da4130ecf588f17ffcf53f5e814d02c179d1cee009bdf6c26703927919b97a30bdefd1dd03620509ca6f19dda0f9993a2a3b5aa0041923c4c0ca2ddee43fcf475db921adb9591d9383458134f35e7375fc8707111854b4478c565d4f1a2b56adf818df04db5bb8fe73a8a23c54d6fb07487b86138894fc8c3aeaade0d5256bfa498bda0d80e99b7f133c3202411855f9271b6d20bde5439c61dc2570e7ae2533d50fe8f0b57d7271c05034012d735e00a30379fe5d476a4d7f4948b2351d6c02e50cc45d4b5566d66b7b7d9157fd582d99fb0af30556d0d40a000502752a42cc82f7a9bd8baff369c13f467e1c252a184d8eeddca334304656e41b33aaf105b61abd679c5bb458c53fe912c749130c5b4aa47ab9e1ea5f6aea6ee201a71e0b845a8da0a619c51e1cc3733ae625a756bd922d9c5950b1cb12374832192774b3432bd204bd1b6d41c21c5066d2b395224ad0aff6d899ba6b7aa031ef6a6a98536f22f2a9b9e3fec98e0272431db0e40db02a5f0a4250cea9b04aff057032e44327503ec23fd652c6a13b6647f96fbc76ead66b53b1fc71f8fa04197663eb00c59b72fccb09421b819adaaf86ed259401ff3ebd3c789cf70b710d800649a00e9160a3b0f1732e3449f394e1af76dc4e67fd5ecb27e3a96c2ca94516324e118b85bb1f29ca4acd3f0cc4646dfb08b7543ee769382c879e8e05f91bb1d32272c209da0f4c665a0ff13c5ddaeb956a6a7a44ac95544e04549369468a9c7491689d3b75b983fe8a3014383de67e71e31ec4aab86ac24840c25e2f135080349454f58541f389bff6c5e1a582a8d3558408fb9e990118d66687827b813d90fdda00a22ec3cedcdc2670b4f446e2302f8f957abc132b098515e9d601f0ebd2e011e1292851c1f272fcb4e05ddb019a231fdd6ee567e16ec64f601aeb6aa5a05dcd8c5dc342a0a16b2a170697ce83a664f4d8b312d1d9059ea98f72c3df5b05589e794a7500eff356a494c5d2036ef477168da76593d2e7cc6af603d9792e583d7468cb4983005366205fd498a8147329af01493f6cdbb02c76142e64f24c088296ce312ee6883301c9318c7f764b2c47ac283f0069ad24ab854e54834597546088beef24e73fc3d5041cd5215443e4825c0739732504c270c2df9cfe15d271880ed4b51e272534fb04d8680553e56f889f62f2b525a44f125ec42b232b840b7601e2ad7fb55deb52dadb2336c3318fca8c37a1d10c13bea8a90597bd9e2c8d805680daa9aa979fdaf8956a88e640807aec09c158ee68f4335a8d15575ddf9dc0b5982c1551e85f187643c81f070d737cdfe782e4e49f260af4b57494bc69a8fed6f0d43df62f335c1971ad747a5b301b84ce96c13a91f0f4f36c04028008d4d30f64e1fbc389082f74f11bf6a2b1dfad3eab21f978e9b2552dd6884a53aea66b40c3326dd5ccbce499f834d3150ac35428a4a80e08201fa9a36e90d14d3d012d33456ae98712183dddd30174d563139ae5838cf5a5ac45f42284ccbdd96557f862d67c1e93c4decef0b23595d3944613b5e412186265dccd398af5c44ebe47d2539b635a3d08ebd0175ec11da186553bddcc6895457f241e804df37dffc06e45881d30842d6d2b485949f762ec5eff79b2a6badd88a267c90007da30635958661d1717296901d8e45354ec6551baa43c69bd148fae2caa5484c9c80968354ae50427d147c178923958442c387f889cabf9605e7f929716f622ed44df41b65263a279df7c9ec8f82a98332d30b1c0a9012877e0c7cdccdce2a8c7c85537f561b7c26f03b5916250a05d9047cfbe38c9f6fd609f7fda275c29bdbe7a673e6d4000c88b8a2a8f2fb0093aec388e756a62df94de7fb1734bd1d9aa9e75c7989013761df397c199c3e597bf2f9e3d9c3ba19cd0cf96c249c745ebc991ee8d7a7136a97cbb4947039f2a84775132fe637cf80e074afd34bc6d35b782fc7c140cf932ce0e1dce74ccf53edbd582dacf14036d0bf65a33516aee24726ffee926bf0259886afd00220bc1ae529855a376b4868d358b9067d9c4b198b5bac00cabe5fbaf3bccdb3986910be7636b358f4d1ba0feb01506f7da65f56f1ac5582ae5deaae564c10b0b8db8e001c5375884a42fa72f13b11724781632cfa09008400fb4e92f8b04181a4c65502c635a0b024a030b0ac18ebb8d50a9d06e30af50e417227e27f4badfc97d4fc647ba4c2f0a56345d1f84ee42a9c27db211ba6a5e01c26e119be4b29c293b299f6b047c0de4a89defbae2d2be11338c10d620ae5bec05cd87084dc469a6f667d223612f13c6c595bc7f99bc706d1c2c4a2049e1f6b41e6e8e0f3c5f04891cd4d6ce791a2ed8112457e640e66d49afe1da3e2ea92e385dd901688304bd58c73cc13f203c1cd4b11330d246a1258bcf8150586d185f99b32dcf51032cc479700dcc9c9043b934551baabd13c90a20656d4194924a6cd3d17f5d3d9f468afe61bbe100cc0598369580ea261194f8c573b8f225bb86028bc01c495128433b18ed3280bedbe74ad158b791df6f7da17418a4a949c782b153e057160cca019f9cead0754387f95cc9e5eb660691f0814c2f68de3e313fe99abd7e6399529b5e9c6742344a79013a22bf853587cdd3c298f23ac4ec4082875a9822401302595bdba98d002078ffd9c74b8c5ff898fadf85b27f37b1d7d341a6507c5de39a88b43644ad777945754ee5d220e8e4ddb24f3c2badb480a1054c013db800f052788ab90986fce4f564419246b070c668fdee3411c25a6cc48d640cac702eaed6c042bad74d97903a5b51d482b4ac2bd52ad7797a11b6d5f368ea50eacb07a3255633a6aefa1435acc1d900a28f23ca2aee3593cc0902687a65f384fa5ffd8be9ed04dee65a11d344b3f70c4291ca9c2cca59e2a8702bef49e23c7788fcd5570c550ec168522d919217e7dad8819b7449ad622cbd528af7e69fc2ead320b04800382dff1e24b908d9689c6fa265057a5d6e79a6306253dcbba3b08e84d56e71910d5d51876330854742420edea075d98643d7a8097a92fa751488a265c9d5094e9e27bf1fa87f5efe028a2329615424174cc8ce365c995fe122c84102f8250ccfdd6bfafb7c1c2e9d2162c697cd73de0bbcdbf25844a3d04c565827c7a9e2923a85c2b81fe1316030002abb831cf812a84ba954f694e2cc2927830e998353a2471e3b9c1759459f3bc48a3bdaa765d58a1f0d7336d1f8cd0a0d3c0c8fc03f92260e001c90129f67c1401b09a997ad410abb272014b297a48010f38dfedb5a739548057fa495a471e1d092812f541357290397531bfcdbc45f2bb8710f42a91ce61c557e91a80bf1c2fe65023f9777e03b761a746734ff1d356e162b40cb8a4b0a3a7cd64640b084398b9de83011ebb0b6e96d05e0a091f0b5c301c0ec6bc0ccddd78e0773a6dc9cc6f60603fc1f900f647a78e22810bfacdf901959288230fe828d7b146a25dc3a109b7a1c855d50cb3566c09d31ececb440708ea404c994d9aa45709aa5c7e1acd161d89ca39c91f601a80ae49aca95b8ce623512430222d2e9033ced9a0256c2c09442bb0231cf6368978d890c79a8a2579188d7e0d20f3891a6094a46d8533368d4a82d4e4cc02fad931645d408a59361db0a263280ba7b6540baff216efa5a6f3a30807de336ba040127337f02e1b853335633ac60e8a512bbbff18acac3b5c37d51f40736cdbff6db81503c087c2c69a4b38565c5bd99b05c7d3602822126a6477db724b29a594324606ba05510662a05075f3c4b54b3689c93239c19d80abc29d809b5242b517675c126e15e29cf3ae8f3381d3123784d3f2a3991a742bbc7e4eb229913d3540214cd4f5fbcaa35edfcca0871f86b81fffc4ef6b60bf5affceaa48c13a58414c825703f54b9a9b34b90dc3300c3fc4781c00152054fe896b7087c25e5686e9b2346957bfb634695991c04480b03bfba70676671f8742982c46087ece3b14c31275db9da6ba34658f4f3cce15638b71a5f9b15873117c522b5eef7af029323831f6b73bac35d5e013cddbd5b6697a1a2703b71f5a1a3600179c5e75b326e19af0fd269799e93213b88b5fa6571b7010a34958cf950cdf9224076858cf5a091f638cf10933a8e34a7280d7c31224eb10efe2aeb8f8e2e6f86934d74a5a49d9d3487317d47369029b20ba2ce4e591ee01299090e932a55f46e28db342aa4391bb910ec55b07c3b024b2bc1e7e0a9a410f4ff430b43bf069fe3e2351e46e941fef306ffb7de2ec392e0837818082848e78bdf65bb6c96d77e1d34871b43f61b89fe89a1b97a2a5595c026eea681c001520558e46dc146eef5bfdbadc78caad2c904037c5df75d2b5fe4f97e62d8a5e5b8a29f2c2ad8316575a4e888475098306478cd24ff6928014d58d1d4fd8f0d88a7212a58b0c1a232db60809f122ca09170a51aeb48471c116060b4f579494215036bc62c850438402634400e1479616624a0803650b7324a7e718a2eca8a46648520b213300098d8c39f2420d5b5d9e7c8d85a1b1f3254a009d627d5de9399d627d5d8d4b1ec7630802f4c7720aa050aaebe708b6ddf15c721dd452f1527d15b9476a5f3cc0b0f95ac115f585e3c3218c1ac1e01082a1a1df748a05e6fcfab4feae3f423921755d412104a5215ea817196a90a185075ab08cf1fd8108049828b1c8bd6096004002dd32febdf9de108633a3df177720eed5e5bd608ef47bc158f57befbd392a076d9d90b9eb1607baa54cb7bf75405758bcae3cc01fa69bdce0e32dd4ebebacb3e07fe09bd8087cb0b46306c512dbc73344800b13a6242c6656c8d8a235e9d102142952aec068a08c182e2af4bebe3411c95d96386181218407151c388ae85312583774617999a95fe6e2c53470e0a2238727685c442932c71c15153118585a78b2a528db10f5e51abac9f3204a8948982c3cc08ace103c5db171b2e5d4c3ab899713af2441d545155c5395fb658e5be2b8532caf10745da4638c31d638b0cef86bc6e245a4dbc7f20a72bf64ad1ed6778218ccd070440b9424438accb17791e0f5d4f3ee790593134a08a2e584258433451f72dc2e1db419e3f8187f59c3e39544b49544a9298411c26008d5805a71654312293abcbabc0420735142448798172914a858116e3ce98232616bab0a4e94714b8e1d292f8034d1e89185890a241d3868e4f0a42442992f58b52e156eb296a0dd65c21eebed2f493afede7e5f56e818638c77d01d22bab7fc6204c607a25c7ea1728163ef9d4eb1be78f0a5452fd380c59584e5a5e98877e949bfb13fe997ab855bce92df0cca4fb5f4fb78df7b332ec72575f5965c4ebab563a7585c413a4ea7585c4e3d29a43a5db5d61a07d77aef764f31a8194245cd12225a49890c295b8044d1b155a49f6e2c5d6b9d4b119783d38e7b8f14b7cda5b28017171a70fc176bcb4cb79689959292254fe8531d256fce546bfa7d545f7d5f139192b5538a5f246dd60ac254b58f0ddc04ea95005402da2b26753d26706c77660ff5e226ef22a5b5d4f57c0f198a6956b51eb092597d20bb322bfb815eb73e48b8d9c3f1d554dd3e89ab4c878f0a3e29f888f109e353e553e5f3e593c407cc078c0fd89eddebe3c557f029e3d3a6de7befbdf7de7befbd63dcbc4e216cadb55a1f3357bc4edbf6ac8751a4da537cc4f89491f5424a29a594524a29a594524a29a594524a29a5949234289a904ebf3605d5e973d2b4463a7d1bd50dbeb9b9b6de581f76473fcccc9a3033d68545023bafa09c57537a56d5a9a9f2a84eb5a942551fbd32d9adaf4eff76d12d33601808f16a3785e8555058adbd17e35cedbd18e7ac71d6fafbf606655826bbb6cabe0d823259188ab3d9b575260b457136a3d16a335aadc6b9cd7683837170aead383738b75b4e8e8ecece88c7f1da3ada6e70706eb79c1c9d1dbcb3736dddc9a91fc218bf3d27ce39e78b31bef862b07783c0c0af152d771162eba244a8b6953fe8f1bac9eb9a7f9bd2202b4dfd3d39d72d28e196954bb38c5b2accb64e4cbd8c1f0f801f2330b2811fda48da8324af6fcbd26d2f42b995a9ca227214b91e3e7f3d9bc0cddb6c0f92e6d84110acdd6eb79b8ececd83b4bf791b6992e8b6d7b308806feedb9bfc763b1a8fc6dbed76dbd54a93c4ee569a24fa0dd1b5e9fc0d69de3cad1c800b6e7b3e019db795463a5f2b8dc4b71d8d4763d7991d8d5d1cc5d90e00c671676767e7b673cbc9c9c9c1d18065c60c969913ab8c901a698ebdf637d224d16fb7ce7fb4d99e3fcf535b9adcee744a1c92e775746ca599f3b7c7791e1c5e9a620e691e8dfde6c5a7ddc6dbedf9df663f0a91186b3d702d70135713f769c913829ac0bd529aeda7bbbd38eb3177bb5013712c7053a4d9d9157198651abc590fb7bcf17ac3dd1439ee19b03b91f384b85fe2b2b84c0b4e08b724cd17a03d63c59f6dad96841c06d673b628be6e649f05daebb5d66a06751125adb5d65a6fb64fc3be7aa3703370fb9a2c9ff0ef4dbe69efd3a5482b19bec513d88ef9beefe3f1783a0aecce9afbc97fe2e183cf49d1ee6a95f6d56a8ee62edcdf751847f87d1fe500edea46dfefff489376f5ef432bd22edaeca592be2807a80709d5382995f3361cf29fb86ce7ed07dd219dbfbd0de7addd7d6fff86c43d76f7edbedf2177f6e77b1df286a45db60bba4337dbe7bc8d1c89eceefb1af9c1eebea7cd4891bc0003dae1fb1c72db9f0fc4f7b6cb3ede8dcd59f0fe28ed9fb8ecc1a791d8eeea177e2f86bc8f3d9491e63edaa5f83607a5f4ea2539afa0945e9db310100478bc5da308afdfb350787677f5429d52f55ee8ed1342faf404eee67eb3ac65c813a2e29edfb46fd6bfafa287254f08f1c30f4b13f7f088d7c557d1c33d9bfd9e95a018ea50872525cdefb70f84dd85187fb03b9a6bb7165b4bdaae6256b118a5988876a0b79c33bf406775a4eb398b1b638c69883b79fd6c0201d9dda8690092e2f5f18f8f6915bdc2a2571de342b0b3204025a8640adaa19a42145c607f2a2fec0bcc0c092121d5ddec10102e0a37753dd6437e59893b9d81b2f248ec1bef4808e901f8ec71af15b043d5eafe804375c9fe804f9740d86808d61d1d7c73a853276a00f0cd04c868352110cc2008fe3bd1d9cc8260ad2008667097486a153885a4825848a5fa3e9b26ff897f8f03c29dac07cbc396e067b28620885e68b30f860fce6618d89d7d1bc9e9590b1abbec8876b056f6077c107c5c0c20f820f818800f822078e2ebb3cf0f7ebdb21e660f3e686e502c8f686f867b26290882571d7c10046b4fb685884a9001ed50dfd6847a82ba8da6c9daede66d592985f37a78adee013d48c874c9ea22ecaed6767f7faa2c68f64fdcdefcfdddfd1bd978877838184084bfcd23dad565bf29e085e215657f657f81ddd5bf35fbcd08e901b8f81848eba7e18f3f848b232e782a6ed2adaeff9d9c9058fd15ca88f5604b4dbb90520aff08fd7b739397d48a7aff13077187ead2eeb89e1e710106d6c39476f2611ee92a9627b08e76b06f7155b8d6afb343bb483f90e5d921ba755d8ffaf91dc2d58a5e4d290d42efbdf7664d73ce3ca46ff5678c31c6a62e975f8568074a9172ce99524a714a78fd295128256fad63980c14325038b82093a5e3408543530faf98a1b08fcbc3765d9696c9ee3e7dc2561c5d9ab4ffcc6d7badf5be43387f67cf1f87bc21a9fde1a5ae81b87fe6aca4f571ff4a23b1ac54b983a591fdef6d69543ff75c5ecb24bbfb2863125d7f88b19b243a7e22fbe9920323c6649ac09c3aaeaf2dfe70369b801593d59088fb73fffb2a55afd548aff85baa6199926c8d24bb44993e9d499cbf52c41d0a4b5de252e0e6de370c53f4ef3159d6a806c09fbfc4ed39d32c9fc234e7d0b3a71fd607492babc03ec8006a2dedb1ce7ac06535f98cbcd99faaff96f4be6eec58939b946152f696a45b3756d1e4b7be8155115a3c06a7427d5b0377858a9b2f169685736026cc849dbe7aefbd39056ecabef7e2a678c0f8daef02dd11fcbae2a8e0a6e08d337202779cbf7edf87f5c558286c824b4a29a598528cf1d30e144785d7c77705dc145c2b16ad8c315d58604958013282f4f8ce98e80308288e3b3d6548757394f104e49411820b1d104c767a2a8d755aa7a7125837837a5e4b575a0d04b650e9b86105275a7c88b1ff63bafdeff45482a1cb84a0c83c5e90bd7956542888772e193967aca0e283ad2d1a96aca055e40b0923cae9c595274c5496dac86828d1ec8c1f1f604383eb2b045c8298e9c00213a9ac0e68b0a0c25219bc9466d7a81f5ae94ac60932b85825c96edca0554d46929a703a3d9544d8147f5709049c801c0e59a7a7d20dac1eaf17db3329cb19a38ba9c5928b5349a945ae49a7d333a94cff3a3d93be2c8fdd3c7a7b20faf44d7a8232bbed8ffdfd9d31b23aa5d269af7ee91487d44ec0836aede30ae560fce0dd7b6ffd6b6f162fe74237be15400b1c5e43b068f11146858f2e251c2841d3d4e505346d483361c02e32d186a91c12b539246ed2ac1c928a5ecbf0deeb0363ec542bb5d626b5f0810884dd552c9b0804c6328018dbc2e090d5c64c0e4ea82a60021634362869e384020ab32b5a2ef3442312b46718750ca149df34edd70c624d5a59be3c4a8a08ba3ff449f35e59bee41def0f3573e65886c94cfbadf5fbbeaf04d13b5740357179a186534ccd6692c534a566042e37b498d1718d1c1c6e9d9e2b98f4b0d37385112c6b90dc211d6a9da5a52b120c285847aa54611f05681106f7c77e63112645dc9fefbf12047a97491e0bf07e5c6445ecfbf37dc6ffe9c7f9f36ff2f1a7d840fff7bb44da40ff677ddca1a93b841370b34454d24ed547a2f7c782fc3c16e0d722fefe58eb638aca5a2d26dcb5fae1cb4610d96a45557b6159605a5df4fe34a0f25751143eade4c13f0bab53b814615230245e9de8fdb12045f8b2b7bd05296a2fbe7e132546d8fefb11fa675f81d4fe907f1e217e7e13253a507b891214a045b4a7002dbaf91223782c0069116d048f05b4c7799c120445376503acd3fda96f2339c953145e9202b4c8056d6681ecc1bf234684236a25ade4b93ffb906492913cb714b1cb71a7491e5b8aa0f74745d1063515d77e3984d4e69274ba5c0c8c753468470c5f8c85ec8e62459df0e54898165a1833c379456bcc922d688434015f00401581978197980b2c98c8205364031b36ac20e6e403a82d45f8e953c7d8c5908e713a2623ee746db476380e1d12b236e372e06feaba79cb235d1f65a861f9c86f4242bdb661a1dfa5a27bdf14e2519053e2b44eb1da20e926e740bbdd4648cf9d62b591eae6ee0718ea0c06a60285135e844541534585895882093564f450b092c5c2e24fece67b2b8b34600ba4104c9f2cd0e460541d501ba6ce3bc56a8324a64f165ae70a31b46e9e5e73c01a0bf1648cad11e2f61b0b73f182d3ce81763d138ca5e9d18d91e943c2efdea2be3cc6cb97a58f795919c6a6248df55cd800748a3556c2988f6b73001023a2f560aa08ad68c11b1b243d36561f1b2f6c04a0268bbd564b0d143555bddab0a690c4c9e54078ff8e76f7a6ae5bca43e9bda08a598b91c4b8acd65203c38a55b1dc5a6bedd34b815939e8367f757b827d9c17af4fefbd379752fa892c267becce014096eceed36c8a006ee6e70921ebb92c51ebd8cc2870c7cf13a2fae8b8a4567a5027ba745681a55862553afec2f363537f36c58cebe2fa737e4cda6ed551e81906eb286e6aa19da1d02295c044d5ea28c4aeff3e8d4a60a222f5120ae8fa3952d7df3503e8151252d7a58912140c09a99fb8e9fbef3d21d2d90432e8da440905744b3be03fa1fbf761d5a489ef4fe80760a097c8955040afb40306c25862533ab51e36b6b69fa8ddea24d7de7bef0b1845ae7740c5eef5776d415765eb7269adbd449d7981b9caefc2659d628581e97768d49aa1e30abb12836b0ceb29e9b870ae53ac3022613dba191425b41ad3ac8069eef99b2f2398a912a1832f23c4d022064292121a5290dab147e8f8c51b3ac6d80bc662491d63311a1de31e3c2f23c739ac1163d1f1045eb4d82956988d5c428fef1f7bc294942c579ab1195c639a30185c58a701d3cd20233587af30b1344c5870a5a96a81e3b2fb0c589a291d778a95a69782be2159228599e9fe0ea8e8b79646f777a654025d9af5f1ebd2ac1f3ed1ad2169e6ffd0f4c43442ba399e01eb67ba2670bb59bf032a6ed7a511ae8fbb38f8b49b62075f87c8f9abd1fdfd5ff8cd2af8b40e918deeebfb9934c26f876a900673e6aa17a053ac334d9b92b0dfd7cf9852fb192c670e50d1f77e703f899e5f8b381a65f6fa987a1c0d4e675cf46d06095699af9c9dc7f999a913a0a614c85437c71fa755aeb30a34ad207f9fb7e65ff891fa3319e2d36fa4f9471ae5cfd9e8fead8c1ab130dd993367cee86c65a3d3457d9fee13e185cef8da1f37baa9b362135ae15430c746a7fbce1f4bfdfb5efc7468f0184fbcf54c8975536775c5aa7cb045ea0c8b2145a2dc68c324480b2b76d0903165634fed1095a6926452a0d4182e55034d8a8a88f34556833d49603aa17ae4d6f042385528432687d20d3a552bc6f088a1e3498bd4909b931b9d24a5630cc9f0482d8552caa820baa8a69ddd26c74bc7ca8d0b270927e4d2e4c6763a3da7a63a003a3da7c61a183469a03eb09d9e501eb410561bbc0635e37c32728e607542b9f8748c1c97eea7d3f309cbd30c2598d82640c8ee68ede58d077de1a678ff96b79c3fe772db9d26ef2dff156ff56fb5d6ce6f2fde4c71e409f195b8e409817974b6e57f4bfb73ce39d775eb9bf5eb572f2fbcdce939820a61a7e70854a68dc03e9dc044edda84ed9934b17d7cefebdbefcdf75e1eb776434c25e0f90136842da90414df6a95ea29c254b72610d0dbd34755b7bfad86d14d119bd928ffa67657b1558cb3d387f1d5e9ef3b6340fe4b23703f63a3bfe52e29dde18b459b33ce240a1b819e6a00fb7a96ab81db9e3a01d86dae74c600160bd0623d545a6b6823b8f6eb18b0bdb97256ac58090b3b7b742959f2848995524e4a4e4a4e0a0c30c00043aec9b6b9269fcef83669926308734bb6cd2df974c6d7e696f05b5e24dae163a1873326897a58d9f773ceb9347944f94d1e05198f39df2b38f7987287c09c6f16987b70c939e32b370848777af680e196b9b4f6b63d48d871b3c61e1ddc6cd6879eb307938e358bdc95170182980e1123b27a1510d103a18b8eac7dd3e909420c3da7d31384aa514b2be7a4f62fb02f33605f6bc2aaacaaaeacaaa09c48b26865d9d2caf2d5957531ce59eb6fe3bdafad3b6bfd7d7b83dfde202893855b0465b23014c5190dd368d7565a288ab3198d560331b3b25fb3aae250ba3dbbb54c76c93631d925cbc33ad924ad2c5b5a59bebab2a8aa102354554815923a5591d6541715694d5daa491a605c1369f6629cb3feeef7615bbfacbf6f6f507665326cabecdba04c1686e2ecce66d8d699280bc5d98c46abf1cb39b695cf6835ce6db61b9c8b83836dc5e1b61b1c9cdb2d47e7eae8605b7564b719036aefc9b9a4a9b3f9922650b73bbbb337820830feda712e47bbb31d9bd5da7b31ce59ebefabc24de0ddb369b92b7e52091e014eb2f48a2b3d7254383d794c9d3c9c7253383d79249d1f2039792041c91b47b956cc41e119cfa8adf4454de69b73dec5c0eb87f5525c3e5ec234e47adcc4e27ddb8f688fe756c859e5b0722ce498e498e49ee458c0f5e69ee49ee49e540cd66dbfab71ceb8dfdc139be3927b527b8e0bafddcc61e558c829c929c93da921e59e9c2008397920c99de70eac1d4e72597ac5b9a3c9b9a3ca6e000992bd6519ef6c4b1073102f488817a63b4441093962029418bc3c40d21ec0a045b00384155a391c8162d248414f328c3f80c8ca1f29ee5d72bbab1b470e1ad72909138d39d9143e8040727f68cf447768df0dd6314e41e4207420dd1fabc531c660199442500e1f39a63e102151c23188bc7350e51c472ec67b6807f19ab25ed72442138f5e0312d60f2baddfb29e3b5cf4b08a50fa25afc51d9be8f7f4a04905ae1f386fac396f28710d62221e05392a8fe8bec9a3e0ea9bdd55a9ccbb431f6c5353bf43b2143895d12ab7249c767a1504f455cac784a5182f4019a215a6c8dc69f06484cd112c165d382832839a6c54399b7e77362dddbe189fb601a5832be78d182cb478da1853ca9df09d364e1b5b36b274f3f64c4586f086e838c8aab105ee6c3d00e94e26aadb98ff8174547c7780c4feecfd59cdce0ea2883d3fcf9b08c74c53f767ecb13ff53908d373a727075ddd1ca3a6a674533c9af3e0dbdfb737c0614c9411b2540102a508192c4e594a72984253f4b9b0f3586e074fbcf58c9d9e35a0d4b87aa1b5fe01e4c51495146af0983ae3454347d79acd8f29ad8108e57ed4102283500da95c2b225ae11722e81f55be1ca97241c618224c3d2d5e609012030a5a376ab8f86accd0c96ba2442b3ca3c777cff8686834b68c607961e025d8682ce1349e6433767c62a850108f460898f7e3879e2143b4c2313e7d6f638e04be3b3d67b0e8a6502e8a7f9d9e32d400ed78a7a70c30dddcd5e8199ff70373e11b7e2c65e5252da0d00f2b42ac36dd326478014406d60c20bbd3339b05a8b42eb6352d64332508080410004316000020100a8703e2704894a561aeab3d1400096b943e665034160723914890a328088228088218c610630842c838a3d04d59017debb7716240c46e6a0eccc80ae3a432422ef572eca94e4f1eba0b0b5a15525d72a92ec6ae6e1890796ba6180fa03689c55555785cdfd62fd74b0bc9510376521ab0d9b1e76761cf1ede0c23cb7709b0d6bac4e5590c8fd157e82058f8273ec4657fc58876fe9348f011cd8b4338cb4ac21a70dac31cf89a90ab308f59559a43775e85aca75cba18ed30eece29fd98a1a68831498b6c94fe2344649e46f797f5b29f48bf2c864b4a959674e40fd8757f689d08b2725c4fe292aaf629a17a6a222edb714f9d45cc9190015203d55c04b569c85aa19da7970eca1916ac3a541e9b6abf47688e14864b14b733a5c8419baa3955dc8788118afd9539c82fcede95555b8c2be5dba70219251a02bbe581140280a1c3f8ffbf6371eca98efa46f8057e307ee621db776a1fcf3d04e8a1846b29c8286dec3424bfa708b4dc8c0302f15161007989c8780c9ac5acd6790c31fc44a44c5d051f6be200105c73c680671657e4bc9b6441dc17c26dd6092737643f455464b14a60ab8ed0b480847674202dc66879c7e3e616f08b0b42a25558c6035e2c4f8984d8f06310832181624488a746c4ae62f4bbb7d9af3c84361011e29d9e7c8f7781cd201a1e1c833b819096ddf89478de50e37049f1bda5e6ef37815091725433ff1a39cc513c209d4c0d2a29f169e35645f232c1696478ec6bdc651afe079f190dc93c14ac591e8e90812f95765944258bcdbd19cec1f61802cdfc7fa47d619b99a88b6babaa96ab2bf700ee316cabcfab6eb95d02ddcffc8556ae3c2ce49e7547fda1c20ebba8be80aa5fa7b8a9e8a82f039208c20c62b58bc446dd2d3280e13409315bda84b2ad190ff65df683efa83bd7078802303d267155b77e31dfbdf20c6a74238cc912ee129271fb01b93177aba269846ac80e32178efae7d83a12d5d6a75d33a466c3329a363cb28de8ca21501cfee551844ff52ead0242d3d6a32c144655cbe67113feb90d70872ca33263561cf7376bc0bcc4e178498a28a33e6592372757ed3f0de79f7c9c6a49ec7110a7ad1df37759ff4315c4622581fc245df1ed293850e11d6298e7fe948003b9402b673e73c1d8a422393a747a32c6866748f4dfb5e4f620115c24c7e0628d5b5271ba9e85596cf8330b8b66850e63e427ca188e76e1056ff7ceba4ff903752268b35c647ff37b1423648972b54b74c2d9c40e97376c92176fe4e39f77f87a8a460ff1ce304f63cd52f15124a032fb9df6641dae8ac5b123ad6355b55bfb2c8d3c15434866e8d91c6498a368ae8ba14ab5c583e3e6467dbef0e6e78f683b293dcedcae478cb76bfc476a5b9552d885ed94c3e8972a4004711c11a47ded18adf58e55eb020743e0b68144c522e2c611466725a35202da3f1a2454bdf704319e1313cf76b1fa1bad9308d16ad255ce701950ca2111e38a4817b254f69e0f2d2b1011d7c879dedb827b8b740054edc143abf8fb1ae4ec621e53d92ed8f5e4d8fd2ba8090678829de5f0772eb7cd7008223fe2e915abe3df312a8e3f3b5ae43e27c22b9ad0030b2a11d863edd7fd8a3ae5b6c45546d85606dfca5b38efb65b8e07f2635ae243c50551f8a7ac0c873799585a140736040f10b595ff94fd58dca01fb6eeff111cc6393c61159cd696691ca36a28b6011f91666e5ed31a9eb69df663bb05b2c8af8edb12278ed2ba74f0fde448537876194cb2aa8420e3be4cda9dc90382145d1fa0343f32d5d70be8f0e75ff1db27d3b5592b1c7622c16c8608bb25f2532b04716ad825f97ce1ed12d4601ab190412236f14dd986fc7f6199e3ab54c34f17ee76e281d02e3bbf6b49d146d1e4eba8d0c514ed779361f0bc705057957ce0fa670f53a7db260f35fc17063df3b2c75c14e1ffc211e88a3cfd56f7dd82847d9e37ccde265f34515cf9fd3e2aefd932c8db6831e075eb78f43595c553596e0cf205b9fd33c1e1a9296535192503de7a073f78b0043a4b21072693a03712ba71a101af6deffd270bf343dda73450d63ee9eaab1d531e8c1be040575be10ef0abb821f489d142c53f018d877e4e9c5513b95770e50248ccb2ec70932defb3d7f248c99279027f10dc1041bf4f478a1813352716ef481585085ce55130e30fa0ea1ec5f53aac01ed7842490d1eddf4243c1802eb43c173718ee0969bd04c81a452a024fcb3209132db17c1fae231201dac4f2411e7ba8ba7d46faa7325a8d4b112b2cdf3cdd407563381a7a040d4d117d261d1c13325812c9a8be68173a5f23f1e91b61f5585563f239b401c3d8831ea7c5d801cdcd9ee3795387ce131ae000d47345674c442e552c09004ecd0fb5fb5c290b8dd02dfa2975bb00c74b31eb5a2d5fcca3f43b898a331ac0b86181aefd4880bad0b6f6e2eca99dfcb4d128d8b51e365c21226e84201de342151fb2ff8a8c522e1b4c548de520bddc6190060b2f7739d6dae85dc45ea79c1230ed965948337cb1db99c7f96b06abe42c8d098603823412d579e5b579d97d5dd8fbd25acf311da65b31254eb5c817b744082759d2fb5727d250c07caaf7305062115afff2bcec01ef0debe99a3e2e0e493199d2d970caa0ff573710d94a79da943b73c98224a90bb9697dc741412694282e0c11aabae9917368a57bbfdf53eb5eec663a9aec59823f33f7e0326db33c2b20d2b3293242711068548b4bd4acea6174d22c38aa7d74fde7a880dd8369e614f5f3686d726c9feeb3102ccced732b320ec31573a1a94834dc3027d342801496e081bbfca199e140d620f0c110d0daca7b24f605096385d99f82726f8adc5461a3b2e029ba327b0c1f7182b1da39b3d8bc4ebf1913cc014352c6c1f3b930e84cf2da705371c1611a87aaa985da79c967f5728f19850217b41f1ae82a6cbb115f4d86b59cd81b5a6898b6646f4e3c28622fad3131a3cc1c20a95d3e8ac188294d15304ab1818689bcaa24464dee8601d5e71e85e05da9ed46941cbb4c76d7830bd28211aab256f5f61d6a11880a905966656adc85bb0db705b3ae836ab259a31045433ba7fcf075dba257e40d4e1f480ad0aa687b5d1f95649f02ab213c5f63ef055c950c2bcb063500171bcd6d1a1c4651619e2e06ccaadc90e2b07ba90bb744f0eb8b86da9afcb871719a59320e530104c5fe65a28183bf377e2b349f41a28cda01763316f8dc18750573e3d690bc0ce7ef057ccb92cd6952ef4ad542c1269a12d02deac5a23f5f005abe810a40b86d96f397fb519aefe87465a39becca40a855b24cea86e1a709b750269529d8c7eb05a2dad4b10881af89ff52eac4bf276e77b31f375beadac2a0bbf01b94c870a6e4edadcc7acdedbf7b8bc799ea2a357864a31be58678bcd340203583b916029d05c759ff25c8608a5d5a44375e0db76b935095300c2563be15c961af1e184f5e678a74b363be739563e2c84f2820c78a9b28facaa839a88c2a9c61883b6a1147394c97d1d21a92378435135c36a45729e416f2aff9dd52efb88d92a74e24173fcd07da30561008f2cabd69074b6211f98e014b6d735e075c4a2678235309104bed1b5f6eac0c72aab00b502e5c47bf4a6de4b7e8388dcc3dfe2ba61b384307620f9ce20ce8605e6b0bd46b358f574c55a69f1b2f48c4c7947be981686663bf095adbc2a0900e1a341ec352135578022f6b888955770e059c55da92fb09b8703ea794b0f3bef772b9f44ea8ae6b0cfd0477d8bfd4137af4ed606cda0905026ab754f334d5096a5b5a7258349427cb6a3d4d2322371be6d9bfebca80cbbe4263cedbb632b5714b64569bf6283ef1c692a9b845038150421e6ac711c3a8424b7d4d9d106ceebbcf11569c3795ad70c49c276e6ee2d76c3147183ca241dbf50428c9cdc07c782cf78be356cd7edf74c39360566b9c0190a19412d6347cc4f2d738c6a2e148f082864794a8841f1fb45c782a56506b15bdd4b6b485a29e30e3c97ffa872977652043b2a6f186848f85d686684596b0e05a4a4f54d766f207222f130e321f998b536b3ea8fc6280280825a86ea3fd8147592d426588dcff1328cb3114e412fb29e223a54c40447fde4acfd8e788b65ddfc2b2b31a61d4d346b173b07a9b6bcb6075d044ca8ae3706905ab54f481d8ec1bf446bf44429d7087a12a65f2485e891875e931b15a1b57741e6ba816906593eec4c476ea73fe4a72a7ab9c16aac91fc416e83521c261c8af7dd0b4bc76b37b7cfb20708850e4028daa54376d1ab03394ec2407354ba19e387e008ce87b6a9bc00fa4642e333087105247c830d145304584ce0b4e5c6d46f78908fd618e66083f7e5556b928dfceb1307702deae4181ebfb47f63cd1206c192b1f48c21c738a1c6c3d160879319d285b715fda77ce0b1fe89dd1387b00b841506d43eb1d803ee16261f6d1b893e275037cdfba6bd81b33fb409b6ffa1c359ecbdfba7862564e0c25810d5ada8092791b165d7757372247a0058c48f848732e3fe1a39981f64e11f622eec2cb1320477a4a583064972ef9e022aabf624096d34af7f2a5ae0c46c66e36daf723de988af4f01a87470f1a408b175c420a0cf2e789fe395a3c898251fa5525705db4159697f24dfa688a309974fcf55a64a2316d677ee7ab5e7bd7c3465954008fb40f850a3d67a69e94b66e985c2ab4862d05e55f0c8ef2486c9412c4764400a418747bb69ef618721d45183997618f79b47cade8446b23305ad8aec91da691ce00143fffbddf0d31268fb6c7e7b148f08825c771cf35b4cf5912f5d4eef0c1c3297bfe51667485a06fd3121a85b4c40e9f18cd6084ba5c7e098454f714f78d5e68e68680ced6395ccf20477f74e03fc65bf0705827bc3b766ed0a0a0a0635a81e80ded646be26726be7530221dd7f4573b536529db5607178237975cca3e135c742f7386a9f193191fec745c978a9074f3142a1b8b8df70eec072867d3d99137e5167597b82baa4fe623d1377bae15b89be52f0a3369350f237cf9dfcd7ec9acf45a240718c8ef4cf7a3374d941122e7e0f42f8966f7d865d458efef075e9dd53bf05121f301d3c63f1d7f95474b91c84c0f117a20102545901a28d188883c504b808a0d25def07813f40d8ab0e94a1d1f34ca0115873d94550435c9bc0362bd3c87a66441237bfc6f0ff166e02b19d8390e2b004629df16d65bd1af38c3fc4e77507eb67c8dc21680d3a5b1ab9185cc11b061d1acb37ec1c5865e751223eea959d9b83eb22a6509fc15e0bbd90cd64e603ff18e1b30cdfce38cd189b294640bdc8d52d08a618a1ebee893deaba8a661a746e41307e9d90144f58146f831ee253ad14c09ca2d81c08a837a9cc55de43b2e501988b844fc21d9bd9b2e586f32451dfaed796f61186f19191e238dd9c5b946f28dddc3e37cb84f974333ebf549fd3723a5443dcd98940ee423fef9110c768d75d36d0093bed7a8560bd8b5ccf6953dd09ad7e8a1d2e57919e6a55498187cdc4a663d85b02ce4d8a46bd0494193e10d293d6d2a0c97f6bd01ffcb292ba0ac8d7fcac55525ff961ed0c981947c0a98e49d9375b8a79899930773b2b5c99ec9d9f12c939c499f5a2f687cb3b8e34048ef7e3261c95afa786ad946d3b844be5a73904a0074e9b9a256ba17ec35342ee2f4e56581942b81237e84b3c98cccf4dc5be03751642df8e56384b9276c09a3665e48bbf14e21406777cf4b9749eee940eab73ca2662b700a951c19d4fa41ad26ae55bd9f86a28166948562dbfafc4ba140a05db539108ba858fb3ca81e00546d41ddf3d9dfd2009f65df7eaeb166928a6ce3e5f6380d80d1aebf1998b4f1ca31a4c5aaaf1ae619b03b4d2cca9080286f59e41212a1d7db04661a06d67915a5f4a2f4eec2c70cbc1318fde725c002a9da96c462fc95ec1622de2481b8ac744ff953e5cc052c85e6ed8f69edf3a03b0c7e4f0b43b07054cc6026661cb8183fcdce9bc4e168a544e970067ad263f1a460f50b3185dd880ac41eb2e0fc95d7a6d416815756c45939503402bc928bb497fada8d43aa7b76231da22aee84a4cd2d29b99114c79b762e0353618931573365fbb0a31289a42c27b6702f02e0c6ebbb7cb99844cfa2d73b74e204887bea0168d85b333c703cab562c43b9d4d70bd33c7bfb9ad7cdf62b03fb01fa24c517ca6581ae5aa354e6774b68f1abf62f8603c3748d892d3babc64d6694ca9a7759f4db988e2ff61818d1fd409be60b26c9ceaaf5795f4f9cc2f757a6c551af0a0148e2f977f2b3d3dac8322665fe97403832f06ccac3db0f1b238ee6efdb8cbf294b4362108db8c312883612560d00f1d6dd952c33b09401e190616ea58d34fd116effa103d88e97cb03532d8d3abef82b39470d6aabca9823be9435ae801b38ab74b587e072843e71a0b071d0e2f801728aa6ce59ec6240752eff5fa707fdf70c5856fdedb7bd8f85180262e4529a7d9c904e2103c9f0165b2bd2a96db3d4ab8778b30fe5895b09bd64d9843f7951518f198ee088349b123cc352b3c93173e36806b2dc0c08a0afed6bbdba4880ecadb852a5f0ae2677969d9b40630eee20b8c7b039885f63006c27abea6966d1306600010a8e8c9d231c4414bb72055384771ee00084d6158a17938d1e54f84e20e14986b9f9a2cd28348eb0105241b98aa4ea4803b482f5bedaa2f269fae3757071143e6f0d691b659b168eae4705f7e3012abbcd94b0dd4e10699cefa82579824f2e3e0a74bc77a20729ee5af00a0913c0894d5bf2b4a88731c72147563c3f1f7e4c243658236dec0656261270693d6dfe536d4bd9213928e5a21b96f8e73b1d88497a3e42f4db823382c24a5c7a80609a3ea61687308d380069e4826ad0cc22293252e0b15c0764f17c6defd54d02e0c099cd40fc23201a4130ce06af1066d12be4b31358039ef098b04fa08cb68b1d48091156d12cd29d3303030db042f9a1b169d680769d7365eac54ba9b11da1267db81e8a448e1bec4cd0289b456edccb1b3d87bceac950f1f7ce6c4972d27b1c3173258eae36ee6e83509ecc50e7783c620258024e847e38213acaba32ada1a68cf8be586abdfa53ffa66feb851a3d9e2480e2b82e48f679ab298844138442efec3862ea5b0bcad4f3076d527d01082e97dfa1504a4195269577b1fd20a69f4300479e6180b49b742a79ad17a39cdb2e417622f0234d9429af70839c6af87e0df5aa5f6ebf732991ba88936cb08c4ef41f9a0c968516f5e667b06e62c0edd1842194fd4a57b68a5fc1e6e5a2f92ab500882eb019a199763cd4ad6df21da8a463a4d315afd4180574c9e1f01a79c9aff3fcaf065c2ced236c1eae1d0e516401145ed67a77f426b470bf5a41c5dc625c873f843237e591e26b2a6b559290bb148679c515a9c84d9b767913d383f1ccc4d21c42bd30582f7664f2ca3e8e66d5728851988feaea47c5a0293c21e3a1229849142876224dc511e767bd8d2ed98dc2951769f71f33458c84814ae208392d17a20610d67ce45a280929fb271b778f904650af409d60f8c477f3351223d5b1c46ed962c7a162e6c883e8a30e444e8af7e7ec549840be1a261c2258f2182ecabfe20f1762202ba8c8968a09c8ace18d0185f09019f70f0b280ff951bc73ef2a722ca2ff9b0e0e9d9b2648a34b1cf9164ce88cbd48d01925c7836a45262ededd139c34da6437eb49e28187e5dedc98b78d7e275bcc7cd7c09389772b7c19b1909ffd42c0fb66afd512f0b9443f7e88885161b80bd90a6bb70d4a91537917572c8ec2c24602c67c1ed91f6f2c70a06986c3fad2793635e3bac9cf68dc33a98b398ae6ab317eb268be519ec0a02892f3de92640f4ce5b445003abc58b12e1c063937057a9211434a324e57979a250e7709c0df6509871d626b24de5a6389e318d1a88af22075ffc200b38ab0f1118174cc51a3857ad062dc1b4c83139290f5d2898f1f235c124bb893c22da63ed4e63fd2327c884105f86d0352b7fa0b6e503f6472b496c3441dee7b8c107b8656fb894e98a7acdee48b72edfbc705b020c263c9ac6fa1c6fbed260c00df46cf09bf0ca4ee5e7fe8ea82b12922cc3e9e983226c3051c0e316bced25bd8c4b4cd8d0ae7e497d17b545dbe0d2c7b2a172d73891e887f3dee642e31c9aeda2e9a5b9d4967ec104ee68e4656f0f710db78c82c2f8ec35a0d593bad15e05d324dd2b71d7c0cf5181142ce514560b94c8ece153fe2a7f0db433a8b89ea0634f115aeabab6759b146d32b7cce1274d13c0a66d38e6ba30c1786717d1070178372a8b338652ff7a4075da351358af0292fd15b04c40f82b48432dc7f5a66e431c517c5ab4c4637d9dc0493e799f434a7e0af2e2e75cacaec3e1d3309e1a0cf1426d74374dc39674ffdfdda70edb90cb8c6a2470b2239a80042512e2b19a70f31614d49fdf1e5114671b0a5e0139c1dec113a0c3e6ece59265b14390071b4b011065561b2a5c9315fd478f1c626b49a2611a94838b9ef503808d90c80337b67243a50178ca70a709f030dd35a5c58481cccddb8cde03ee4a82d204c27c0d588cb57e5fb646282572b15ff071aacc25d25e040036a780ab4622e9f6a4d99a6f9814dddeb504005e6f76b04734a64df5eb7382ec5a64175c1e3327fe2a6f5575906f94fc12416511730dea1d9ded0ac0df9476d80e3a70e1ca8a1d52db7a03d12b8fb403c904698906295bced3be2378d82aad64e7a4f77059fba82b1671840dfeb969bc571e60d306b03f9003e6e229f8b2933edc4d53868722c9e7e8bfb04ad04198872052ea4e0ed619a35c2cd7d3051b91e04d0fca60bbc709dc396ccfdc080cc0c7fa3fa8bfaa949ec2a22fbff08d11820bca49378e7d29825dfd1f30d2bc09ed8fc49aa1ff1daecc448f46919d1901151dc4a786071501cf12970223b67c9dd3c1f5e507b648d026d989eb44cca092238123c5a67d2a2ace788279ab54689496a84e70a03c95459cf9482e73bd9f06ba5ec7eccd93ad1ce3920f5ee25f6ec161a120d58b950a7df3e2a96131b4429c353951e715abddc5c81bc6483499400e56cd809eaea73567748b16c76acca53da77c8a9712301a6f2def4c9544bc15d4698e37ec7b950856b8898f3748067a87f72fe34cefb0e6bd880f6d3c7bb8aad40905f085e5b68ec9e2b9b9eba689ed5ed4a4929af0f606d41ef11a9ef35a36c8c8c1f1b2b109e0c2749cef9d2d0206a549ca389d3f61a553f373002e634a371d44ce4e44edd488a6232f0a1f81c33f468470f8a323e9c895d135436bc501e11790223191bdd7c52d584e31c44dae120515a0e61990a29aa92b7d8868d41a8d239401293ad6795b0fa77dd45f4ba6744a2fdca535468413172b9500ff0a013ef38d84abffef2101b332acae7ee1009074d001f0a92c97002d9a2315233c0a400bcd71fbaa1aa5f24e0df1388be26cdaa3f10c6f2dbad9e7a6fd1e7cc0a71c6fac84dc83251cc8968c52dd52295c614f6203cd12491fc7d116c3ba97ca765e8945c587256376b54d9ddcd7a912ce22431912a32c47f64911788b79fc45ee20597abd127bae2b4e8240b620afe36b6ce41693d63e4755571486642a2beab05f0c93392d3f6e19eebeaf8c344c423588d53393f5e0f785044a7e24d0af9c040c945f1452cd2e259a345572d4eabd738f03e7098c7d93c6deb50ed78632d610f318c4312398e5ea452afdff51ff7123db33859631b80a15636bb06d8ec7081c726ed49d4b37907b00d505e40219dab3ef6b4ef1ca4c35fc58b43923c44f162dbbd3a96fc58152d657541235d26a2584e305f9fb55cb256c766367810083d5169e4b3c39fd09be674adb1025d6da3658f1f84df823ad5d051c8258b4fce634d213d05831537985795d287ffd3c530ebfc4360ffd76d78e7fd5ad0c6e8c4e3b818ccda6cc080e631b1cadb5f289e1698558f9044947a20a63cba4dc260328d44e287ca6c1a807b4c5f0c655287b241a9555d1ce7f3b0fe845c53f55e27b62d68609f8ec7b21e8a1aa449d51af617ebe1e1c84e09c757b8784a111413b7712cc23893baebb7e813fad104823464431827b416a622fb9d495973cc3bf47c762cc60b02fedb69a5bce04cfbc7f9fee9ebe15ea482db8665a8f338775fa96da7327a41a69b7f8c63c3694db0b897b8c97fedf40242410788c784e7404591897d3fa11a941049a97615200afaf69adb02cf8037ec18fb5692b27ee75b58a84b0202dec69ca725bd9658dbb09fd6318ffbb1580625fddbd8f96903b3ceeba3ed75851d83825def415de683b84e676046d2d06d96ac4a7ee4d4035183ec5cf3a956b44551089f407a49a4eed8a9eb35a63216c53142d37b6e23b89f2ffa95adf5aea72130e4416de0153745f2140b1c139d8064c3976639b4317057a241e640950543782953cc29604357a1f04eb495fc3c5c982bac67ecf2c67f2c5fea65298970f7567ee91af6d5869152a68c6cce35304ac9c191d2fc756f15582c2df19ab54641d3b92cb2c58199c6786451b912890756cac1447bc744b73f362b1d0d5787442bd1c8a2a86f4fe45871aa118d601ae41b81cf4a022a39e9a93cb5878ed813670b23cc00c71ad2b8699c6e2001f019f102acf7bc502e24bb7372e125a93b628db440a5a2290553a48d2251c60f32d559ffd1aa4a493443fdc5eb7f6c97ca7b94a6748a861476d3cdc1ca248803827e76159d9274721f6dad43a8a85a039d5f9e0c73f08f816314c70ab3c08c9d8f1d5d1dbec9a9b09349c6e5cd038be81aff730f17f5a9d956d96dd546d491c2b938cc8287655e91c149f8219e1d2aaf6fd9486fda517e09ddad02b455fdcc6c629d56b95ac92eabcc05a95def46f196f3e53f183f57c03c2325b18a05c576ff604d06a64353ad3c44ea57892e0947a2577477291bee52362e714f1482888c565b9c181113efd769b84f2d329acdcd6571528f9da1d7f64316eaf818f893b979ac48911930966411fb91483a02f7152e4e5cf3d3d2080a0855bc270ce60c0295275c320431287721e7baf886ce8e46788c3b2b7b985c163a0382f331f79fbdf4e0d0c6231c106b1d8f2caa9fa504f13e51c81a5ae2b7c3829728400f720b205d821bc72430a36c2e7eb8e12e5dc9de590d93a27a455271460361ee0917289e4e8898054c94abf0652708a6a10eed2f5c5465023285245f8ccd53b860c6b381d693873af5ed7137f804ec216183c41b60901d3f4cddc14794c04898aacc7e919eafc835f21582fb2561b7c620b0a2331a39f14b97e4d50ea3e58759529ea58b18b8c85bbf555d1a58e73f38f0fd9536df6ae4f61ae45843f6f0a75ad7c6c5a1db9cb51ab437cf70993e7188b43f7a4c87510162331c853db06c0a5780436854ae9781ac320e283af156db4ce175400bd7583c06e7b758bb27d18c60419964797c60687a02e071b9ea4da793a4ee414061fd5f5ce83e00f4d02ac4ef6f2f1aa56f8bd2f76834f48d6b50cac64a1b1e879a9c5e5afb8772aeb91b87279ab550c57b79ec9e568cc045baac0b681fe21a92f995fa4a405fe3e609b23a671f171008dab10da2fac12c6979b34c60cd5d6520be8f96e0f93c2db460881a05ecd9fd4901a47fa220e87520ffe1ef7e8020d7228844a5b440247590378057b0d83c5328845d06dd0778c49df45fbdc18ad74105ab199d2bf764c9b5261473a393748f43c49951e922fc96976d20f95b9d4e9a1593d98da1a651d22421f8006aa55ff1c1de10cb91f92e1987eb69113c53dd5faea794b92c9bafb35f68743389d3834e1257f7f917bcd525547d85cfc4c6973bb62180699d602ae8c9674c3b88337a2c0a6439e1d9ac64b19bca033defd87c22f35f5292b659c41884a66b230f676bd7b6f05f7db83e98e4d2709ea4f6543460e817d24325688c8f67425bef63918b8cc2f8ee1a6dfc302c0ccebae53af71f52313f4191f2321d5d025506f5f6ea951410f3093cd94b12d5379dd5400c1c995a8a3a81d3d0517490242666d266f097e06c712e4db0a06f216e8e734d450895db3a1e37595cd3ef525b6840cf8b588068c2030c8e4612ed20462f5bbb18e049bf62e16e923edaac2dbe32ead92cd15eb852529df66b3e747d7382ddeb74b34b8f674e2f6baec688c76b45a014280152112ce3d49bdacddcef8a5640d19270bb7a2ea3b4aa8fd5853ecbdb61751a7be630a3434eb8ee24e14c7c28de1a6a96f8795e46ea025f2d04286dc9843115972fbfe411f553a80febaa26bbc051503fb2bcc2eac763b9ca513d80360d55da05fc49ec2b5e2257b2258d0ee3014d2fdf43829aeab86bbd1e05b593b266bc46a51a72762004226ae92b33a439c14119a7a91c533a235253a181ff419502e5ee9dcf3dd7e8a9bad20693073599fae02da21d9efd9b5986be20a01d052cbd6e9bf1d3fa034b95f61ae2be05ed5e437d196f8b28aca0c9cbe1b8242049d2bdee901258780ff3a54a46fa26ddcda2269f0f0e0a278632875021145da3904e21cb3bd2e5d4b4a05d58026b6efc6b86d978afff4b1b7c911b88dbc1c43a2aa0ea96be926bddf684287f71d1dd1b163e42bf3b4e50533e08f493d47d8cdfc0663020d4463b7c6b9f2e0cc3b2ff2ea16ef7fcff21f880588c4901daf4c4e34922b8d36fca6c4ae8af4d84d7e4333ed683d86ece76c8ef482de44bb11e89f980b830a857a8825e566a54d5c693a5fa655597de93d5a8fe6b1aed7812105c5bbf659c7991d898d4f39127d8bac6879e9a7ba34411456d12af1d2597f965e31fc092068e6c13584eb94978edd992d467e777fb17cbcd338d03579011405d24ce6432fdda3d7e65691d2b6c2d2899c62da465ab49a49b32a807b3f73c14e6c7968a1ac8b9b08ba77004b5d6739f9c83fadae6fc546b09dfc860c62698b7de819933bcce4e65202ab4f131424accef94701e22a42d4d710f21f99455293f9805067dd77b6a74d309a4c18190101fd58c427bf81ac9b950604410cf7500ec710c01542ede1bee5bff4cdcc97eabd867ea3224e2225eb12d399d4069a3dca583c42ef9157eaf7938879390bf0e2bc93e570059b46688a1e1b7703081981f0f119c7aa4cd89d287f4c700161d199e11126e1bb3c47fd14784df8453b5e63453b0298294af434c5289dd251565c870832f34216f53a31c8b5549fc5b807935e4d310a97308ea8419e2941a66f483dd56cc146afcd2400a1d710a1b7d27861a43c45e90914aeb665b3761e82c7aac9af98e7aae9fee0d84cb1630359ff2b8d7bdf6030b5b40c50b53f313a1920586e9b756c4a1307d99851d00ceb104e8d16c54a4e87e01a7bba15ebc60e25371b5f8c4654758c18f862de5bfe6f12d770df198e1283240650f374b5294b709fdee51c569951836c4ad9b77a35aeb2460f60aed729aab9a4c505eb404f473315c368be3e21dc5c5a0439c16032bb52691712f07d3323cbadb41863241e66f25a21f0576eb80f93644d60a0f0125762614332ac98e5f6d37880a94d763a3699222ddb36561cb5ac9dcfabf1f6b635be302ca14dcb06af78792ef63141993c6ca965f813ee9abf7317131cee4ad731c888441e2d5267430efcf6d7a94e117a0132bbc449b3afbc960e776671fb13c28a133506a4d491482cd64811fd085b0c4d4d294f1d4aeb990ec5917b7f16eeb7298f9c2e924f903c70b249ecb370cdbb316d45d15d1b21bc968e982c84309f295fda480642fddbb3cce8f1ba90cf86ba4ead60d30b2d2f0974f0d098feef3fe491bde0892b16356ee62041e53bfa97f75708b5d3a5a3112cb0b81f8f9a420c44963dbba94d2f7c1843462bf208ff5080caeec26f4654048e9cb54983c70fa435adbc596510701ac6cc9526750e52c4160b78da81411d3e083e9118f47cb200c451987223577642874872d229907e7b09a75b2d6b39dc378c2b94735eb5c4def66dcb43c8e4dd32b5c099c2f49a243c1b3e881ba7394bd784dde2ea27886974b2c5348a4809de288bf4c7f4338ee589ec4cd7f54be60455b50d5778455fe597040578bdd25828b3e684dde47b473315186103c134859ed260084c102ae5bf2a713d0f46ab4ddd6a12749d280b9cdab05361c139e7f3e4c163c366a21557a12a0a4b261bb7d5de6fd9b49628c6b5d295a2d0cb6e32dd458c3720470ada95cc8c307be32406775b58a1817eab0557551f92c3e842a76f098e9ada6c8bf3ce90724b388f4e9c797cff3c10422cc0bd81f73db38027d0c89bdc5e22f703e5110f453913873616aa98ae61ae26f593e419e1a25a588919011064be2ee5dc45674ce0905244b330187a2cf38598b779d45199ede3fe8c3d6f6c758f1be16780be569986923f6166e6af2a96a0ac8ddcfb80924b20e458b3589470ea45f34c7f47c99322e0a419552f2f98254e8a0fd075e50661001a15e43f8e625c67b6cbee561bf8a652773ae1fcf290bb7e278ef816e8f2de4eb9d1c10f3c740c8e23c57bd7222adab28e17aed1ecf1c265bff2646bd8211bef58807b7524efcd69895ec39adb39995be8a72c90613152137f36b8ba554ef6c1ad0b098801853d541be2d497dfbe3e38e5495b7ce5ae6d09703c1e6107944b3e4000ceb6de3ca5e18872a1aa6e92c6c5e8da104111f22d5ad41fc0a9dd4f0e15036e315d29c0305db652602d9443468592110a832a850389c68d1e3c1c1d3f8d0720d6e3c94421394f1af15e087c2fd7d9143c4d5c048a8241d6e650f340713cdd49f569ffa98edd2abfc223c08354f2f48d8d6a651ffc89e4042bb89942f59951aa9653d0d294d67ef467471add6f8e61cf0643e1c4af4e2bd1bdac11da9b27a102a4e89001b9143ce80e9cbfee8a868f33c948d8a46ca1bc01c246061a16faf6ac3d28ce49f407f252933171a598bda958562cbac75c8148995146f21e9895377c763fc4f5f47448a52ffd1de1c750299cdef603e69ef75e0e86050e3fab275f1f7b88a71f36483226683a81d030d4d804aa8c3b6c4e68604a13e73524ff40d9e64e8fee1ed782d2080335862b7c963fd412110a40fa9b75e5c622cddd773695e8d7c735d0e31d6b42fc6393fdf1b6ac74b45b83362a685b18c77ca4bc1e0f974b15dc03afbb92e541f33ea292ee0314962b49629489684f1c388c0976844c19bfb4d53eef3242d23e2ce8765aa0e1c8c10d7a829c82c42d33a705a4518b772b0ea2f1b66a30729276585067e2ac54346951fd782a9ee781f8dae22d4106188d617faf0116eb3ec0d1109d8f39c5d99f41cabaf847f3e88255ebfe083e990f846082ac0a26db2f12c9cc98a4304b3dfcbdfa6c1dd56711d158781c48120255a1f9a2b68d6154db28ce6a8dd6184718367f2e88cdbcfaeb496a02b21746149dc245eb54ea675457d6286a656fa1aa67ec3362e0a7fe45e15f3e82b61baca2d159e2c19df91dcdc1b6af33e3ab62cc919e10e1556af11bf72a2bbd98c434fd0fd426dfbb5d8840ed6b813094c475990740b880fdb78cea32e9ba04d4dff882be94f73f67d22489a46fb22b8700e8936cdbd065ddc8df9acfdad484717ec20d015b53270b8e0ceca80660ba4218109b1bdb2bec10d5618bb278a7bcb00cf89aad715c5d0367f4f24add40edab548d64804cb388a3735189702cf2f99f1f3359a3c5691f2984f86b9d5533159c2218ee954b02ff159a9d00735f18140874007e36ffa79a1d5e8020c6c246318de7ff842987147697175902050bfe71b40384f693ce31d87e17f0f3cbf46c974eb63eb81c4c2484475b029a194917a0bace1d88282848595ddd56f90caa91ae6daac9a7548f39a6a1372a0a3112c70ad3e32e886834438a56eb9d33a6d716e7af290789f66e0e425708456f7ab81feca41d4fa8e4b603b95175c30b54ffa1c2c139d417b8e79031cec161cc5f3dbf3bcca9beb1c5c43abe98bc941840ce48008a48462b01070b607480464a172c538419183595f056034a6f4b1210ad3307652393a004412ef44cb1a9f0d0d8578d7a848facd693ae528f82f38cda9f32886b18e502eeac036895a263b06fa374fc22d8165c958df6b1901adf13031f2f8fb24ee637f8aed3c12c980ce4fa43bd45fbc76e58dcb9c9be91db8ac4ae0f9da2fdfc052b309ea3c08cb8c147320f44563de3a6ce47560ebe1f35e5e0dbd562e7edbf46b41f0c26faac1c58e756de2638b4cfc421ab01502b4ed746a8236f6e28fbfc9f38488ddde1b63a37544bd692872fe8d796ed391d343ee822bc844211d7205f58eb5bd17072abe8aa9924887c3982308399cba1f6c14e8d85cb0c0fcd823010ed683fa8c9b64144c537cf715678c2b4a9018ee666d571ff603d9337583e2dbec212dd87ae9cfdb99cded26d7918019956e72ae3b34eea9cb609e280acb2cc3a8fe71848742a44d78bdf5e2f56a159cf7e4e1ba4a43a5b8e5dcf201f8f643625b0d6200260776d3a3a67ecfd412f54b50e87b29f1c9c9ec4afc077f095972d9896fae93ba61a5be99edb505d9148e0fd7cdddd0c7a4073b65ad219a25a381b364a52080af893828eec96804fc8085f11f5ae9666d57dbc78acb7616b9beb6c916d6b83c047aaa4b98a78468d96dc4aa699be85c37b99527ae2a608292b8a7dd05c82a1742a6109fed843ce3a6e93cfa72268a02b0ab09e6ea9f0faf94b2ede569a69c3babd1a3512245c33ae73c6d0a32f4d1b730483b233410625f561a1fe0b39b20f17de5b500af494d38f212bb873a2fbd9fa428760f0f48609163b9028c9627e7f6f6319b08875a820f0130f6dca063b80c71199416dc019de61499381aa1af9a1074b727ee83d8b3ae9abfbcd865f77c0db9533416df02738fb6d90130e9e3075fc73ba5580aa2a99660f2275b706e0d31a9f3435e7e6fd6343e2777a468fe5e69fda61f409f7af30833d4168f143f81b30e27266133301d9023c5285065997aeeb0848e7a55f030b28d0694940acf0f9a4f138a1871e5267b1f8fce79dc2f2e24d26707dc820afe70da1776084cadf9f8e28dc9eaa9db6338dd1a65f9ea15fda30036cd60d993432ffab97c574bb26b4ef8826e078f4ac6d531c40365e418f6fa48db3ff711082b0cc3e03dd0fcebda5461f46752b88657cc3fb81dc08f7068440c4ece644d09689e9e46654118d256dd9cb0dff128ecbbb8a39c84f1ade40095e0978bb00e0f087f5abe4c841b21ced7813dc3e34079d6ef3959196024277f16c19442b61f837ac278acb2a08287c3c0b4ab145bc2c6c2da2c36dc006773159335b3fd0992ed70ef0de153787f69a6d8d66fc2293dc29b927f1065e7c0ef08b0e3d49816a61d8f29e23a4c8951820c9f715bae449de5e12047caf3fb2a05af46904ba259596671956cb70ab045a278d6aa708d39c4c2395ac00bdac1bd68b8b78ee4464c47bf0c6edfc6a091943ee0ba15b3d36f630bbbd1fbc7d38fa1dfafa32e4be606164611815abbaba0830c7ca41819a9f275d159441a6fabee72a0216328e8031796b4d2e101d910b6164c9e3a84431569d28db0d6d420365b8b3ecf26fb66e1f1cad96b55eb0e692027494e5bdd9aeb13b33f49e264a191e4b076a70476c7bd8656d96c10dc7357ed81be15508dd109c00d31230987f3bfb40008241e340c9c24e35a3f0bc3a814dba62edf6d1494d9a1035e21ade99ae641e9b6fccccb9a0f9a397bede62df0596347f842e505566583a85402b8910630e22a742ff21974bb8a85916840aafd2407af57239120ceb4674c88679c6ccfb11c9493df92a0815c89bf0f1d1a5e31087913df04dea912436187aa888445a3197a81284447ddf14e8831aed7f31385303373d03b5a65c18569080840557a5f26df9fb8816543d450c2c2c12578246a2e1873d261baa5d65c76044510bf69d09597e791b4d4373e95edc9f09d47f54df0a06f7d0c55ac2054835c8551a813db388d7ec2c685ac128c98071e234b4890624a07b7d1c7a535ee440b50c5e2a536dd9ab6f1229a7aa8fc76f0085f9807953c77dda8f4c7daee0e7edb582645efeea892d96c2689fe0f263cf4d68edefeb2a5f091498aab4246d3076d5ef3655a061fdf941582eed74c6759880b8bc5988eefc2804136eb0b3dc653b07e924d6483f24ebd90892e98a8580c2c4bb0546a913d30c4ed0dd5c29aacfa92076c64af7b1142a9fdebffa860d47498f95e8a3f3c761ac5aa34593793f942fea18218cc15a2159ca73aaf661d73b8345fed3a61e9c32bf1d9906258c3e6329e97b6ac4b9f6bc11c94b82d2457a54eb23aa00c4ddc60c37473f3d09905520b48e42155c60df470b433c7c218f8ed12ee6a90aa33314171ed23c63feadc38322aa31eaa585e7abcc11d5836313bd3c0d03dbaca51461b8d50c04740eddc02002e61ed43e926bc8384317dbbb6b02d4916c732d207e1dc1274db08524ea8dba73cbe6a11a1e19adb67b91c7c5361b2935e126cab424c350c853b665cf66416cebbadfe0bdb1ae5e427086e048d09b999228e2f9a149a92b8ad80053cecce66ab5063cf7a40401ec15ea1590dd62b829adf08f7af1c28fdb62395cc6d01ece858f9da2e987dfbfeab88e4efaf04f17243e9eb3b0455c0f10ff419661073d275401679f41bba181fc2f6853521937cea92c71ce9d5b6ca7f869ddd9eb2c609349e011432010fefce0cc66c5ea6669bdf9fac71536b7f1e07d7d012aedde00d189b5fcccfb10b0a1af6b1d8bd07588849f63ac04377976c69d0b6d599c19fda522d61c6f952db37db06ae142989c1300600f63011a8f8c398152638bb31bdc12ab1b54906d92f0fc25f25ac60bf5e2197eee9334ca73fa3ec23021c4f8b3d89e98f920393fa61406b7e2e0347907f8c88934624639823c6275f9a11252c92bdd12503a0b2cd627fe65fd7c3c7801c355b310c232196c8f8d546ae30629e0f864a1da948ce1055d8f5c40c04d942a6859220c404e59b9b43b051d083b4ee2cd8f5d7dab678bafb930fe9910684e8fc5b57aa290847bba30db7ddce48372a10b46bd283ea5690a0aa49738e81bc370322b73987290e1a1712f2f21ea0d86f5b125ad6025b88407caa570ba4d21508e33af309107cb8b7034e15738ed3ab6a503614abc2cb88ef6508063ec4abc935cfe77b8e57e4499566d6074c94463b55124d1eddca973d359d577afb0fea17facd1428a42d460d08774525828bdb9cd4d27de4a6927d3fa1e2ea15361d525de2cb43c13714d5a1422cdb24ff481c9fc94010a8ee4cd37831ca15bfc296a3d4ce336b849b70bb97d308f0319de7a30571f90d60f7d4020e113043701fc057396764cef9c828add6b7d3df612c0c4b653aa4b974e47e9f63380684cfe126546a324abff437e384cd9f74a37a50bf9a5e088df8248cd5ed85666fb74332b301cfbf9aa2bca5dbbe4ec16d2551eb226b8ed8f374b97b379839f08e84dc847e47b105cc927de222b09f132bc89b8fededa444a828f6855d66b6f2250e5fe6ee95bb0d1dd3a5b31896bc67bc98de98b48f81826605790dbcebc56c5c10eab0ca9850729bea03d4b926a760f4ef41579eb50f39d75cca39edccb16bb927b9e33bf2309fef0e2d31f109bb95814747beb9b2a152325616c43432654834c97ed2b6e446f10259e2a3dda5308c23e2c095593d6a0b4ea619d6ad5c5d1a854a36fe8f1229a6b940a7a875de6f7d2f1014d5dc2177afd8b7a8b41b4f1ec9179029c881d03403b23542df429124310ab92b89f9192b2c87f8025f6a213c6c8b33345e6c3466ff63e82fb8fcacc85b87457b17dc773e2c6db39ffdb9e78cdc1cc0ab1e1e079b1d63564a04ec5e115332eb58179dbd4d738c21b8a03687e5d42f094423160fc18e8dc3dd70a463c628f8e3d0f00890a17fa0eaf94320bceff7c656fb642fffb4e1e04dc42103e840dd12b1d22f4acb68568792bebe7d388ca9f58cfff4eca96e83da9603d94fd4ac82bc954b70ed07879a44743bd6c60e14a1b4fb80a40c2170be49079bad5bd8dcffe554a0db56d41d1de0e092c354f85dbeb226d2c1bf39a5cd73e0f333ea9c25900c0aed5cf184b347b2bdc344689c793ed5a574097b35403c190b23040c441393cd486c8629f8138be467543849abac581fd6b36e876929d779e726feaa50932d4ec433b5bc45174c24804a8914d95c0ea5b68dfb29e4c3641514a753d4b8f5dcc539447dc8d6c43f2a234411f5bb0525007154d8fdb8a473a27ea839abfc0e6931b4d662a2771078c8ce914b4cf405dabc74af4430ba4325d964c74b0994c248f045965cc7f27cb49979a5f60b20cc43712e97c9a6e77a912860678ec70b32709ada5d09c91d13c19b12377248e368f0b138d92ec6ce7604d0b1b5f01b45286ca3d974d8392fb686a28cd11602ddfa67b47f2ba5cd89f79617a8e3ea39922dc92e8c21da2f747c4e02c97c5f60e9b61a1d18c2e28c692eea7c59f6b0fbce85a1fada95e9f4145d1ac01e5c81a4c56cdf5201f2bd2ed2227b9d2b25be60e377f43e2f5dcd11947fc3dc853d511b59cf1a07fb9c047923528331b81c500378bef20e8f53d87828d8ca6c125ee1bb3287e10bb42285433194cad5bd64e21c9cdac302ae70953d8a0fb31135b049254d0b71144d7d9baa1ca0e544a2d9244f10344e0180d4de190abc54d3da0ed8b612d4f306034dd167e633524bd0d6d1d2f227689f7c220509d5cc8bcf69dfa3e06ffac33942ebd76d09427fbfa1afe082232d304a595a4173c54c4efe8eb7dd985f07bfd669c1530f2d71aac25a9dac001e264176af14ade816e58d8c2e3fb956373d0e3679189a283074cb06f91628861cac9de74db8415a803daec2786b0827240cffb1478d779bd03552b92dc3ba5708b8400a9986ff09cc236e9707817064660406d4eeaf79df1016dd7c23361b91a9ebb168ab26ac282d78f050e605699d3c5d620863541996144d2a76052a4c41d7fc570f08cc5a41c62df29365801203f721599f54a88cd17a2bac5f9a25be4bdf94212d49ab137aa34863cb2485c761b2145884b4009317263bc85d15c22fc3019240b52102e734a3956c3dcb485f2f951807e9bddca20ddc8c6c08d60c09bb980f45e1cf490c65c3a784e55328069ea35023ad2e350a63a831c4356a3e85407e27ca40b6fe4417ece23bf8a1ca04e0450d72a87f426229a7186cdb8700e632387d14bf3760ad02358d9140b905247cd09ea088486f9b8ba412a3e9d3a844710cda8a3a32287806a92e2d6cd37bdcd91151fbe0211a0ac974b6e22c71ce18507ac1255b6082a53d969a798868ce37e2230a01d021ab81516621522f0d2fc083939fe9d42346ee2c802322ac32e048ed13531234d210d87a7231a594483a38361b30801927fe90af357badb3618297980fe6436dd4a0ab1181e05e3e9d6cb46311b11d761f7254d619e1f2854be04808c164249299a6a5f389ce25388958730dcc790b6b1bc3d3ff2ffb3dd619ad7eee3297836a063f2c366bc763559cd9b3aa0d92a8ea686e6ee3c08a4b68f668e1cc49f22b70baba754ca08c036ed3eef23f1b95c2220a9e16423be4b435b64846eb173f4a46921d3909598818b62699a1f8f9e027d5536b699a589eb755d6e10fc8d5617efd733542016184e4285bef7eba36022ed8deca38a66fc828a91b96fd007181de80e060697a90c571a78ab79828f12a9047d504c61f93e7b5355bb0cf827f06c6a1415b669081d6db00df329de9984f2729eb58860c128d310a087fa50e9f572e914b0399d4922ca8f1cd12f43be7ee414419f0590d30404aaee3ec522e6aa547fab25b717b17609cfcc7a45f117b04f61d3f5190297bfbaa29956d8ae09d4ef28ff8a054b778066255e231d236ec6ee4a79b41c63e9b8a645919742b259b608daacbefe287ed1a006d1f79585319f45aa37f4ef80cb5ccc8655b28e6f6ccb386e4401d2bb6278fdb1e64ca83b09da1af5fcd679b53b1ce1852c1dd66c6db81f9d186c1f32d04bcd431245bdaf5c6a4b0801dd83112defde6be5f043637533be372e836deeff73f36b9eaf70c845116209213877f5da31716d356f2174f6bd362e1afd1de1a19246c2c55426753a92938505f3025fc869995fd537b9b70acd667efd5d0d4b91097223d6f24a6d077e91a2b1164373c9ea81b366d8e6d8602b8e68f55a1ab24b477a55c41454b9534224862423637e1d1c5e2c297550260e8c8176a908ff14ac7ca1911839057d83d2144494d085e95364956e5b751f4187ca231dad721fe47bf84c3b06447e5458dcada56604b8b454fdb83526de79c0dc6efbc5d0fbe29cda70a7394584c431a71bccc645baa667d092e1384987090d78d86d3ea0f53e31769aa2d6e62bb7820bb56af403134085007e1244be44d81566762ad602b2fa62b4921ff81c05dd21118a2835eae6890580dea4140ca0f7c5cca768b1e2428ec8e556965979cd590edaa49fb49853af223d0c5804453861ccbc29c5dbfbdaed50d2be67ca2d15d0cf32a910e9834055583b9472fb62125d55755840cf2a3f20d448c19476a96102fab9844c81876989095ce9c4b050ce498206beba47d9ef63bed3c6142bf0feffab403dfe1b6925fbe7e3e3c6c93a923cbcd8a52d7f0e1bba5823332279e66fab528498880015224ed74f758d633d125ee805154719c85cc6a0f1ae89e8f7dc14f7da88aa347fa485568b57fcf44d2b0d2d09ee57c9f0e652de1f0084dfb83613a32c0fc5b10da77c7d6eb2d08a2535b808ce0fd40534ff66804c2964bdea41ff5543d7644c01488dcbcad01d84fb98e10fece4f1fce80ff5113055c5039bb82034b721d73805d834a953e1ba2a0b1d3a7b5b2f976ac1e7f7ee6d86cf8b5ae86f14580e9832d0c7127b5128557b885449d7d89e91e7de1c09168c105ce49d22443dd9a318f4296784f8b466f54e1098b88e995391cc32d42a6660b0c03ff39aa2fe32b85503ee92239653e404a061c18141c2e735e1404963086f850608189c6757d3f54f86b5b5e056864671e8527442e0e875a09b4e5035251f11ac7e854be375d5f3834791ff7b62f533800b707f2191640aeac57c5275daa8ae4dca495b25e0aa919eacd138d7dd8ba52fcce76852c255ae85537c17cdf90214f4628efb0c054c1beeca595aa6b42109c904a662ea5952471d9b22be7c7250f7b5bc67c9f4c806e9a12ea907215951890c0fa7e8c417f25ac76eca5eb91ba6d19cac8e844820dd19e55db035f818dae87588fe51fc5580ace9d7fa99e86db977f6aa8d495daa94605bf9dbab7b4b7fc3eaec1c088e4300c947923482a53592505a5ac753c92403a3f520c15012e864342be60e66071e43c0c10fb3b9362945d596a5291ce1bc92f92e0a909f7c0f037a4f92755c30503a4a738be37dac1d1daf5ba2bed79a4a76d5829d265dc5f5967f9dbc9c39c9f88529ae4d1727a0d022a432ef42e8e8e63ebe877931dc793af298bcca2e2fb035a3a311b9ea370e8d50a3f79963c01e11b1b6b5d6464b4b4b9b04f50609075807311b11ea2db69b0133203cbb4acd7e8ec7733722d4615dc5fe9c9cbfd70ab137161abb72106c6b2b8d8d7fc41dd9e37b328c6634e4d4cf70379ede8af0fc78f8d12582e263452cbf41c2df208364144f7362e3c11d0b3c872139ab1fedefd9359c3d270ec21d98e79d79e66db5da71734e0bc4e0e238c9dee4620f9f237170205c499c599b37bbea5a9f7da0679c70b3964e8c62afa50b1d7fd94a818cb8d0f33e8cbc0cd2377fe423d0c592c4d9cb109fac798b392fb8aac752bdbf8ed836c5a87b19e6857fea32a4ece9b29db4a68b73c723f597b72239179f40743ff196537ad57a64a73928067165a4c479c7a8997cafb53735326c68661cf5d4bd3603cb57ad47ca5a6b6760d7292cfb46860daa86e6fe64faeda19d7e329d9ab2264b189ec25824f526171236b559df96d8b714d13dfd3a7dc4f253eb6192b1efa516c4952953a6cc6d538672411306cd1a65ca9439bd4803e67280e469a9745def81d7aa5fa63dfca35f04fab9e0923ad3326ce1eaca57a95d07721a68befaf43b3d0caebc3c2cb9392b0b1f7db3853265cab47abee20b573c90a503de6a7d7c4fc53d70258fd1009242c7986bc47908c440f132e6dcf30388e3f11c8fd74bba5e15e4bda2b292c449d2ad1bb0ba74693a0604bb4ef3696ffaf5de5573e76e5c286cbad380982e8cba901e2621435e783e16b319cc6f4862d390179ecf505f404a9740a6978ec29be9d76bf066da8624607a093b6555d6c7e7ccdc47bc698fd46a42ea6ddea290d265de3421f298e9d883ceddd8e4af679a907ad42ddee2292aab8260371dbbe9d87529731a90fa2d669a175f731b4d48fd967d2b3d3ea787189c2bc0664f6f83e1d36bf04693b7a10e7a5d3afd0c0632fdf5c540da4ba76c836dd4b93c9a909ae598391eefcde0bad60d905a85d7554361288999ec693eae0a88941ddbda3ffb190db3187bc47e5da507d13e723d880a4901c357e94e43c1d928e54d9e6a3dacfc8f9e76cec6264f7fb0e6dc8dcdb4035737de0fece8c21baa819a1397854ada72694b3373ec2165a76fef0997a79e25cb4d7a4859b84025f74a1a124a7a48491706d2ee425b67edb3b9b2a04cd76a6ef3065b7b4dde609bb8f4bb4dbec436fbac9519c874edf625d9a4243026a4eb2fe9ea62da1e972bbb7cbd5623f3a6e520d859ae529a32d07b4fe465b5fcb258bc0549954dd2756d325ee5eff5974df22f8b8c1c24ed254f4fae2c6f2a64814a5e161b5396a48bc2d96bf0e910df3ce2d42dae8d04573333a7d1decc7bda4c967afdd855e30e996766b2ea7a599e02ecb59b4d29eca2ce0d7651479eb6f7244b968794854b963b0369b660d9600a105f7aa75d0b8824da064f7a00ed5a484cae74d6f4f1ad27ad205a41b482680561fa924453b3d78cca7e8c31c6183345c53bf925d37ad097e50c7c4fb1e91946f1c41d2e45038704fa120eb51f2c6f37f5f2f698b755d3bce1c0b2ec3dcb3010bcc9b2c7188ffd2fbbc933b6205843c88c1a7983ef25e40d471209795b61c1c9db99a091b7140f54598914a519ce8ae4c00e4fb36a1a12a27fa6b7991e0481a2c46acdde3309a64d9a90cd94dd74ecdbf55af326bfb4e9f03b3a78c6ccabcf516da6bfb2db929484e50a13567830ab9404f014a02bbd296330a319cb59de68dcf4fac7e452dd6a279b5f463ccd1bfdd384c42e4f01f43db1b30de7a66ff24bd7a3f049f3418fba89caf8738d1c4bc8246455de2ecc115e85934df49ae6231e08e6fb2cd298371586aa0c7a9b9346ffaecadb4e9b7e615a8f8ac28f067e4ee043a2d1f487a36a3e50cf6ec2f13d7106be4fe199dfe096816df0095fd8de2db5f1f4c4d11b0fada1b951679e06c7ea4f99f2967a79bb31bbebad488e97b79da6a171c20b17a874ecd6cb0ecf4e692b92632b9263a76986d5675856b12cbdc80f441c3856ab3f957a4cb0d3e768d3b72239dafe34835fbed86a3e4caf9a90ac4d7f4ce2dc8942c70a6ecd9012f3562447633f656bc2ae65e9e5e1703dea73a2e35ae9e525e1bc1ff114fc043fc11077b31ec9ddb2ce501952921f74901269494b9a82a3a0fa00c6872f5ab66bfda0840accfd611acbc7e650143c300dbf93a4e1732ca086fb1c51a49562e753877c6a8c31468a55f0d3a76215cc3f5c0b749ece7855f072618c515e05191d10f0d1276a280cf9443ce4e383961451cb960f4b5a1e25b1ea9dbe05a1230a381f787ae713b1eae51fae0578e783450a381f22177574e4efe50496f339029a57616610d4e8f72144f17007cc411d73ba396dc52a56b18add6119085ab8caa8084bd0966c8411f6c458f17661139bd8b7d7533ede8850cf4b6967068a325e8faea0dea01a63d4f8d26a128513ad264da46e132a77ea00854081b1a486070c1b8076ad26336852c3497073f02c003e6765a3446b88b9d66e2820edd99b1009c96e3520d96de9d99f668f6558bbc54080ea2f0b046dbdd3b23fad3ec340ef18762db57a0dd767d7707c2603a56fd7255661aa926adaab9e9546845a664662cbecfac98d4dd1d8af4beccaefba6b51d1a5b15cb23d31cb886bc0a2916c1f8c21690cdce623564d394bdfa8aa947f2e95cd3f57ab6afeb9fad1fc73756cd8af5df74423420de3b3843424212902abdd0ce6e64c0657286de55ecbc996f14049c7961062e818630f9e88d2f30ed5523e2bddb54a5a08913adec64adb5c7b3c4cea9adf3c1e76e97a394567a7513afb7d10a874ad9faf4b3a3e7e7b4f3809c2989ec1dbeb995bc2db14523abee6f1704e6c5e2d486cabf9b83d6ab299b6c7b4ec693f1eb8f1405f416a7ef393f682b8f29b76ed6526cd87a669da7ba016c4e6da4fb462a099c7bfedde74a8f9b89f353d6af256fa9cc137799be9eb260c34ef1a35e38106c2db0c053e440e3e4051c5113a58e2e39ccee99806c4763dc51876d27ee24f782bf5363f6383b71285a5de4a0f41675ba9af10f494bf58cb5ba9e72550049a0f41f7b8ae1db3c1f212cbb8868164b81ba599534c3521f555fb91bff6f40b5bac0a72facd4fbf396635d9237589b36b18881ee874cdfe7ae946e91653bc3d21306e34a75995ca3f436dba0a88cd4fb7f9e9a76737983e33d1f80db681f2333e31cd40d967cd4ff3a8f7444c663738a331f4c28c97c0b9023c9f9e3803cbc0291406caeeba060365c7324de60992fdf4eca79c232403653450184ac2051486865ae6cda4456028092785ba05ec429786fad24a87da853d8876e958297b106d23a7ac85b6256ca446979268cc85b6570641aa8352436df3364d3987f67cb8a5762d29581db34dc1991438fc1edc4d4627e1caed702d27ba347cce7b4470628a762d2758bda35dab8956afa468357441c3ef44155cd76a026906cc411bba25450d0d77449febe0be0cae5cce01c3c205a75d0b0b152c44606992d3ae85c504368490a35deb4a0fa876ad2b2c68c013348ca86162c2210a2451b0bc306961a206890c8819ed5a50dc40a35deb8932ad27b4340d37d5aef504151aafe266988678281d98eb1e98eb5fb9efb9a73d8a1befa26c23b557a0d14eeff01dbec3a701b90f0e01b3f0f1528ccd4218e77d70a18d0990f112db380077a137f4e21302361b091d8e406a0ce6290db7ccd1163494cfe74ba358e8a0685192d68084137994d45a48687139304b1ab047c37d872b26f08824318c4c9a54a894fac4c6a01405c915062bc28a115a32164cf1349c297065a28149026c1cc089ce7025108c88c1dde1c7826b2f4dd22aa20b7434251360af871eae9321816498b2cb521832f01430fb491e92e4c2254bd27b5f8eee12f94576915ee41796cdb04ba8e9a7cb7943399ca6df9ee52da7a98da679dba1f43b2d557037d932252fb1099fdd077c267334b5172d92a34bb2e7cecad51aad2d3d27c2584fe773a4c4192abd4984d42a424a8b881a72c82e4e7e99a2e4ba1611442d28637aa65d0b8a1612ca140e0350a8f496ea2823928e2d28513ac28e1152f8e66db85bea3dc29d245090a4baa6706aadb5a2ee829bc249a16e80034f01afebeb59a8a9c77232c49876ad21626803b46b090145cf2925bcd1a58fd95b308488059e025ecfa7b0811984ede6208399587a0e1ef7eed2661795c2813aeacac675e1588a314208772ed933788561275c316d6df69da7715d2bbda4f5d04a1a967de54b0bf24e58f6854f389a606b353be157c3c984a565c195f7367c3d0db650a774ed3048ca2e4919c40165ca94e90c7b09cb9697944d71bc540b1e54966198c93dd716ae302cbbf692865529cfb9b457ecddc6cecbd78754d175b715ca597aa60bbbaeeb8f494379f0d042edc2f6252c9bcaae44882092990b57cfee70ddb35fc8eb57be8ec3bdae6c73ce0aee96d35247477e15e58e7bd9f9eb0fa9af78f90b1b101b10c37d6003e0e55338cf813ab2a79a40fce91580278221fe945d3c0cf0a63cd417de6e5fd7e9f5d243ea4b5e70c37cd46f58de721a7bdb694d9fa7cf1a6bb319ee66a3e74bb7b143f349f3399fd1cc600757f79d9d707613ceb2c536cbeff1d9845c68d98af0386c830e3be734325dbae3e96d28496bef81af94b50c941da86e3c526e59de783afb965db751c769cebde4a096b7ecf53d31c3b684371bb28a10524ef3467a5cb74634700de9f9886bde5ebc94515a9c048d1e32ea76da8f2b42c74d7e6215907a5e15247e3ee699a4af6bb7c140d76d4e83b7eb34422ce9795b6b666077ee469661bc4921335a8cbad37adc600c5789d1bcda2138106a14703e3838f805d54bf07c4a9a0f9bb2f6a9d32d9e313521f3b6a409b98ed50c03527dd0dcb91b9a90f92dda675590d79e48e3aa63d91dbdea97f2290c6473247519189e8137d3e55358c8bccddb25e45e66ed3df1061b790de47acd65601faeafabb0c540da6b8ec25b8d765a3a61a00baa7edc1429338bc9ec18661f441b3b8265f298bdd3507036ac0ad662a56c5e06a9116740f559c2558e1d1f2e6cd712c24abfd73b21326f42aa1f27bb074ecd080b44241801ab9d5b39e76cccd84302ef3203b907f31a05fe428d2f361feacc5973eae2a0e63fc6958f6f074ae181125278a044114ad0a09f03949041aec04991e161ac60071c84b0032423a66c41e6053f281a020a2b8ca82106576a93304874a0a530c4d45a6b0d03a9c700c38b1c6892deb502b11c4428526bd702a309183af43b46b3161848ba5deb0b2ffa3d73587c91d4ef0f87fb962facb46de78593762d2f741840bb56175f1accc9b5369e2fa034ac4143db90062beb6c50edc776ece86e2345e70aae6b81f9d29b6b7d85d79b9b12010a01b8e3f938b7510ce9a12681874970a5732ef7c4cc93c3e5e9d8031d8f232bd89e0fa20d9bc23713ff9a067140cf6cc4a1c0448787c3d11144f8dec562b158527c9c95f8acc41d72c9afbcf1bc94b71dd36bde56da67de9ec2f269db3165179f6517e3e592b803f2f0ecac564851e7a9d4bd71c807c62b8e87eb78ecb1fa075e69a1a397afe83c2bafe578c8c7c97aac27f4583e3d51273e06d5a6b4e22da836cd403d6036e2ca34fc0ab561de864cd0d7f9389f991fcb273a31fd2eb7da308813f303eaf8f1450ddcca75fce2c8ad5c6fce071d5fabe325d629739d9876bd392074cc82480c95322d008386964f3422082dac5c99410daa18e1b38021a278f9018c135f9af80cc9a087317a904118305b74e1e39830410d4008830b1c6060c2672807124831c31258c45c31f289df893b6a28f1c50d9290a2046168e11385f025081e66c821cc12627ce27be20ee7b3c4da00737063c2075de4604a1357584186c905c6548141134038c183146066d0032348f1828a11acd01eb00bc0b4c0d8002649864d30a7c02c1c82d0858e9b0a2e34fc7d7677c3e62dc2fbf8e0cd2bbcae4060d7256d5f919a47c71f982babb7781924011d33bc096231ab2d2fa234fd94d236662f833fb52742ad0b2b5d24b5fd4cd44a874078348cb9033cea67de03abf6536f5541ecebedeb4c29c876dcea4df874e7780015e1d130778047c3c37c043ec874d34daff74e0b62e3c5d9eb863dcb0e689e5e94629cc3e59cdaab48600e621cb0121e1e7c83b53c191197da2f2c2e64687d1122ba2e36a6c08186a226556021039fec47f81283dee49d10323998b78473b2462f4fb69022021838b183151cb4604b18ca05ab29e5c104247cd0c30f5228090306ff2280762d2f58bc38c145bdbb5ab87e3a865b382272651775ea4f6f016a7fd7e5895c97f0d963167acfaeddf4135897be7ca34efde1cd67ee6f7ea1232232b01379c7b0bf973291d44f59e8f4541e1275ea67b2d0119199bf2cb4136ff24c16ea893af5c22cf4a8532f23d788b39bb0267f9d882c5de85ebe9489c46759e825893af5e59b853e705d59e888c87598851e2b27113a22f20eb3104be88808fccb42da614e21ead40b99eea28e3dcd4ecd9d8f4bda1ecbe6cee755d45f126983858e86a0b2d0f3b99f790d6e01fb751adcc21111ec7a0b27b066f2cd0f29ead4fa1360b8795eb98579e7b33da4ae3f611f0d3b22f8b7450c5b2c69cc41074d3da886d057e0f9ccfb486967c20d8e8839b258728316536ec0be68f1440b56f7002ae24effa83d166c393836bbffc0d53477c07d1e02b93a70757c3c59386908818ac4673c2f8b25b00332cb11ab5d86f34527dfc2e5575491f32adcb1e0e1a9750b22240278aec5a2b674c1228a2eb56b6551830bc06001a6bbf4fc0ed4e15a5cacf47c8e79ecf4ee8302cee7fdcf65a1a321efee2f0b3d9f2144f5563581982ba09a407c3d9198858e88940e1fc3f38959e885e7035fca442570804f7c0ccf07de4a284d3dd8e19da8337f44240b1da926f0ee4ee4dd65a1237a21177588bcdb2cf4f2e3fb09aceb7c9c8f238a49f208f85a5da2b4b4f0c1b5c8c991b202b8054a0c395b7e3841cead90cf426bd7da52842d567adb9964ae486a5d71e50a2bb75deb0a2917f8c176df5deb0a2687e25050e928df9c314a3763bc944e4a299d8b0e462833088dc40cae1c7c3146082184114a079d6a4a28a594b01d6d18e3a98c51ba28a593524ae7a633127bba197f328439c3cbec6276a587156da71b1fbbd8ec3ae79c73ce39e71c640283598c114ed1f2f029e029607b0f9241b6eb83645f3faf4cbf573a16238677743edadbbb8bda57caaa2032dbe2df679c120ac97afa57a7caceabe894703e4bcb74cd5a98cc5867400592be9e5d94d64a6bad95d67929b3476badd96b0c487e6e0a88235a99cd8b6adb7520094ba5286ee91008b3d737949412cb46ddc8579c3261a7931664288a0c657a1b8ac262b50ad15d79932c56d77ca4c56af9a0cb0aab2f54c730accd4961b5cc321e8e887a38e2dd11babe074a1b7723de692877233e0817caf1b81e7f695041ae3b713754df743c75ee062ab60d4ac68561a36c2e6b5e47a154efa2b5a5bdcaaa3055e9ba6a5ef4c97ab9a905a9af5a9454d1a59f2664284a1256ab30940412abaf4bed274261b54462b5cc466218565fd9943d1cb189fbae034d4d441da13a4a379349b823054b4e3abbbcb45e7bef2dddebde8b5ded66d744c4b465a037fb6cc6495eafb7525e97bcae96d8b177954eabd6e31dddeb0e5e19bea694d259a2224a679797746a40689c40845db9d7b143202cdb20d955f25e5a8f7ae18dfebac52afa7a62c54662d74bec5b4627147519c3e8aa91220a298c708a88785f8c1c155a54e1210b24b490e08a1c74b8f06004152040c1c196115841bb30f16284c516464cd860c388d78353d14d0c8c5c17b7680c235c444251038260a485568485110e53e460c40054d10c8a6024a36804482f08cecb124ae603838c7be2065188b085910c8ca2aa688b9c450428f2c2281761792fcc99d19e73ce99d9312a16b7145f2ae59c65bacc502d1ccaa11e75602ada297a55ac783368a1c2c31546618a0083910e8c0e90538415392b84784f94311a6384008963a6e8044462a4f430c5e80da10aa31b3adc0f9c30d229d2c208464ec018b92c460228aa3754c69420892a35481aa308313738616224051438f8d09466c1a484a21bb2307a91109874f18ade0eef8b295cab545483918bc2c888a74807ce0a16231a452a302ac228893382018a28a565c6684ab1684203a31766556482ab62534485d1116e09288c5c13ae073a7c61d4554c1006111064c25062db52849431b454e10409583ba05c6a30a328082ede10ce0ba305f45b92c3ca00142292c80198255550a08329587c40022c288841133e3c1881134db79850a68973ce39e7dc73ce39e79c73ef3b1ecb27e20073391b0e2a8cac35c61a638c31c65af3362505a3c47570f562883a29c8c35ba0fe3fda7eb3f5b122ae9905b87a42f2722d220eae6284ace902cce5b8978083bb2da0e3b76785e6241c00720139f171893b4c78cc5f49517d3b0fbee26e367e5dc78fb7c07be278d45ce7f129c41dabc7b3107708e03100a5c33f262b27253af9b76f4f49e91517e1e9223c8dbd8495ee0a95622f77bb331e8fcdc0db6361ef59c15a5cfb230243a28455e28b9a91b799836ad74cb3145ee11e0b7c800521560d0d7e4a90ee09bf24302b2c8000e014a2ce3b00f0cbc16f49d4793701678c5fa3048c63a373628c3fe006a00e9a02267ab045bb7694bef75e2e41895b3a8de37c7b56548fd9e31f986705fe71795d3afe07cd4578e8b196bbd968a8c12ff95d1e8b852bf488dc8df7127e4ae0ea3dcc1b8371f08b41659f8310420883b69dae416f0c18b87a6701ae5e17cce5c2d7ee48c3c33b74034f3ec09c1621c703031c50e13c81d9b883e8a83a22f047dcf163bb3bd9c49e82e3114df29af02aeabc67e77995669bea81d8853884410885cbae1dfb80e321e46e04a1697cbb3378e20e1e0c0cb1d7b0ad9587d67a93dd7eb4c934435363636f527790be044c027650e726cbc00eae6c322a6fb2ed77f286d3f630a7edcdf599ec6d476a7833e52c0f51e1cfc07107c45b6a984c3970036914523a2bce39e79cbce29cb33d7072a0768c3b608ecb9c938aed11b17989619fd385c159dc2bebac62d4c35e9c21fb75cdecda5b2a1d5b614df64578fac21576ec100575b043ecd9cc8132073ced30cc5a2ce3b1cab3e5d83173aa65a77f0ed4819d7e45a9b5d7329cc23970656d0a8de5a0d9d8afbc822b7be5c395fda954737dc51a8c449895622eee661febb1c2740a63912a5dbe23121e35c3b0306587195816429d152a4cc204d602faa19e794efa49b38703da234056802f7b38cb95b607ce9265b65620f4311e81bd8f31a65d6b0ca4ced1ae35468c361280eb1c8001e03a9c63c2253a92f359422873bef10fb0745a8ab2d47e5a3b6fad95544e7ceb898ea6cd4097e1299873ce8903571888bb65fd4961ac71775280fdbc2e41555170556feb65cd2e2a75e4b5bd8551e64cc2253a9a2f95e6b4a5493fa79db6c612603849c870b9407c4da090d84fd2c32019c8407003c97920f2f035aec0010d2fa4c75a6490c0431b4977b3d1aa998dbc8e3ff23a3ef7f0d5834d602a1a33eea6b5f7ba9cba44471322203eda1f2e8c62eddddedbd5f1723a97bb116dc055fc8e1377b37175bc8d9d1c3c0bb8b901f6f35ac68db7a133bb9f73f6506daecda9887db8d91d52818100c35035d7dd519a9c190238e72e11e7f28900262dbb4e62d7253a82f129ccc106c01d0fe6d27d09c0ec7592521495184b1bdc2d6b0a53f8c86bf9430963bdf34447f110860ca7630e5c6120ee869373e435bc84b9072ae90830dcc49df7e7b59cc1e27592cc95762d32ad2640bb1619254d7f6053145ccd53889f5c89517ce4353dfd735a8f875d8b0c92761abc4447f1f558c5f7b515c7c3e9a09f4d3f067bd7845da223a223e77460ae4a80d2acd6fa9ce6031a61ced9191468f004ae5c6763c0f46bfc8ee8f754880f1fdd0c5371659431c62bef0fbe07df7b6fc77d7763baf483ef1981ab983783f8e52d6b183fe79c0f1e5701658e100b7aba923e6a40e4e5b1392790cc370ec9f774d06408284b601e0200031149556ab0840d59dc10ae6882821964f1c31739a045381973853e1983a535c64a8e0e592d8d708ee9414f31b264920b964a425a018790ad3146d83a8687a9431863c2484189cc0b557010c30f7840854f184dc520030021868a9650a962c30b4d5441c609122f626469420c2b45991852daddd4ae25065267d81263496fb62506927eb7485a63a61083456fd0f449bfbb777bd345125cc24c5102871b681037bc20c2862e3bd8420318e4f0601bb00d3c928c6572c5287291469c9b6a411454ec80c40e869842c30e55bc1082881c6011a28c8f94456859a3a50d5a4a99ba36565ab488f1222ec1de10efd58b81aa6286d05bce082a9812d41fc4481103859896944e88d5116f8f861bdbb5c444e9c78262a4f8e0ec0b2d8dc43869d70a23a5379c9e615ad038af3bec039a34a844ad9595492c19aa11010000003314000020140a8644229150381a11e6a4ee0114000c96a4446a4896c7a21c46511003410020c6104208000018620000c62090d20112f025231cd17cca3aec304d174d2ba2afe627f9d8814b87e87518220d6d71901109b4384a421c6dd529d4ef8ff81119a839b9aca92d6681ae4a99e27cc30ddd07838696aeb53aa9bea4bf0f8d4fe9071d29d2456351f677e05ed34af4ebd82507eee328443a6d0e32893bcabea6350d297b0e22acd2f0b424cd3d1ae0262310698083908548839b10624759d6694c14b2e320c23a0d4f0afaedd370cb041d74d5811074698811a8e018218e76b6a8001da77da3d10f32f201eda774d0912b0e7be390d6f14a8d49718f43adbb688cee44658731e4e0d6d1b5a35e47a5eb20718576a6a511edd3e2904ccc31d29af674799f83afba1ca1f46404451a10254450d0b078298b9286c5c9084a1ad1b2220e1a8f9b3149cd75a4b3a0b29dd8efb2042af4e7448f1fb650c56797e090805a59d24da1bc7db500c82c6f8066cefd445d982abf889973d132b8225ec80bf93aca3ebf9216a732ad837b0d57b8cdab092ea3512eb452702adeb14d3e92c25a59cbc3b15b79ed95534740a2d6c5cf0fd3f5c625c85650c26ac26321114250a02522a9ec188dc5d2c820077a7cdf816b0e7b3ba477bcdec1f53b0e294693510ee8a0371de7efa67deb42083eb43e241f738ce4a22d6b42443f8d8f48c78e6e72b4fe0e92e8b4cf51d861226d0e2281e3550eaecf31428c26a31cd0c14d87ee0efb3b1e4d07092bdad310b5eb28e4551a13d24e2d874410475d75945597f6456464251a22252b3b8a144f3b5354e00e68bfd3f896f4c1f9300707c84913f7697313436cda850f2e867ba205247d13dee4d9a6903db84e46f2a1fd2df3a0e3345cb4674946f6a7fd940e3a72d5b42efae7d8050efa1cd276b8ea586f0e1e8bc390ee34f0598a70a4f11921c70ef473a3010b32829fe6a37c8083ba769c769ff64bc9c80d1a6525371c490d66e1cb6c2fc835b18186fac2274773e190c43e9a2da57db08d8f7c98b2d21f8faf7a2b873601a79014a09d1599011c64bfa5f5218fe668ee1c44ead36c49316b937649b111c7a3e9b091abb4271177e778ddc1753ba62d46035969fe028303ef86b68941447fbaa1b36464a45dda9c2241c7eb71607d1c24251e192973bb865cdb2fe84df4ef5cef3cce4c41e75b36460602738d97c4ea3a85cd032db32f3c6249622d02f671709f5914db97fbd188ed2be30b39dd30d8127e19561accd796fd61d89da5956109e1c2049087a2be6e2fa7118da7c16162b35321e3098a8883017132ebbd3e123cc0368ac73c90189e3290e42cfd29268e0f321f81846fdc0f897ec5d270a209b6640939b3f29829e13a1a520a73d92289dd5c9f804fa085211a66da6e56956243931d6e3dab0415110815f4d7a354aaa4d9dfb7c530fc378df9cc1b6b3849514abbdc93e89a5467d6c59fdb837414718d4853da856b78c1178a6ee63a59ea7b7c0c9a8c650caeef34f3e9618608f5ecad291ff8b74e7f36fc5a9040c5df3fb0be17e1234f6d2dbe8aa49d4e7dce71ab2fbe9e87b82fe4c76b35f09d4cb9f560ba47d439bfe30446f0d0aa987fa5374b9b23c8d0e32d74b343ccc7be61fcea1816d0b823a5a2ae748501ba27df171f1c80d568a07bbd6110a7206c0bf8e9601e22ce61201d9d037405728561aa83e25214a69ea0d107b20920d2b16b1379c4ee6c69bc0bbf944f23809b8feb4efea5b755a18d8033398e0c6762aeec0561ba23a6df6eb84a98400abfb33809567b239b314b52cc72af8c139382a957b840c78c60e0f92ab7f3713ded39c9a0edd447d860deb07d036a21eab127b6bf3637b52961409d2746e768bd69e08028057ffa405f000e75e97ca4c61a9b68cbb756aee060f7357bb2aaaaaca20000b411603600bcdb3319c8ee4152da1944631297ab3ab918df0d62a4a5cdb7b1773539394026e68dca1e357135793241a12731918f537c6d98147011d2c3d53b9166220b9c98b87135cae02e17db9e04fbaa24e46c4d84a85b44f29a8ec2576bb5f73b2ffa80cd3e398156052c11ca6918e6d85cbad1d9d1d7d01bc3e9f18cd5fa3939bcb06586797614b34799eada711704da6c807061ba529a2d34d5e6caeeeb97f6d53ea8636704e0133dc180a0f41f8250905177923053ebcf1402ef683bdc33b2d7c609fa15b69e34679f4471534cbc1472d496ba964dcc9cc4450115453a5fae07fabff9224d41c6bebe5e13041f0d31723541166a69769de6f75370ddb30e9edcebcbb33c4b5086730304edcb22b557265350a3de5625a992706fa1811a491238b741a6f08b7ba653f8c9db7ff162cd9770d039efe099faa5e7e7afe600c8386cf38b663e9380d9c9008288c77f297ab612df9deb74d9a3e14caa0f44affb753f9b28e0836c24efc0792d34fbcc0092f2dcd6b10e003de3d2176bee9f94a481f811fac2da21c978e37f9e67189925cd4041db1bb4e0fc74d3c7a2e9347536b4c8d29c5cd5571e5e1aa7552d1eb5e00f35cbb300eeac3a40812200f554ce3d81b59c6d55e29c53b4bc23432af5c10fa053c8589ccea38483cbc59e98ade4ecb26000f5e30c09b80824b37a037886f3acdab5004c3b55e5f70643e20a06b6f2f844f9fa3405918f0e6e4ecf24c83a477858f64c0dde4fc9c011b3581ad75ae5f5700463f43844997e680e1386348ab6e2bfc68ae577ac988080c0b7c4d711f7b421d2e1cfc4d4f3b98164608098a37b3c965a0baa5a07d4b8810af1bea2edf9b7b08ac8e9a0bf5f5ec82175cf6943073a801c2eb51bdb0d9b82f82bebde1fc7d66d363ad91f3e5a70fbff4176812dc7808c990ce210cbae71ee166f8271263a2e8e3d7d43f6e349643fb91b010629412262160245124a426782b3ce17514ebc1b711dfa25893d66ef9579ebbacc157d2b671f7ab135ad92c8797bb9563a3d73f6daa671ff9c045f4fd9259dc82d8f929e63d4520dc2f0f8177787c64ddffe2e8feaf2727e4f28c233055ac469b1f10bc2d05b6887b3e29326e0ed31c8a5d4184f5b2330360ac18b424620c6dd9e66373e379e6a8701aa3d076fee29aff73cdcbe0ce0a54216fc397bab166b499cc81620c35bfe7249a0212ee05061da1f1cb9bba0f2376b4cd86441e87a8ff99c27c865225fa0748a3f42ea848a0c163c65a5c22229f230c196780a701d0a6485fca18e6642930ebbeb6bea7428710a9d7036428570773031bdfa8382e5dd56b825a6ce752687d256d739077ca0fd54819e3557da5f9b219def147fbd6841969898161be0c6dbe033c6fab206e27c08efd0302d68777b4de616adc9d50f4e7dc3fb43ca2182fb47607a6b461313f68fed5de0efcf288b53a71fc5f6977b257771398fb2d546fadc25959eb304b4d3aee6e7aef90f66453e1355b7635e52bb81d3ec5be56acc7357d2d8ad26439fc2cc430601b6fb470e2a8dc82e134c040ba1ae84b91576c0a6707d4cd9e42e7aa5ebd53380a8bcc47c808a270e54b88b9e9b9800d54489a42edc95edc06acd894aa11a8c0a6eb8aff01500538ac453356e1580f93d07f9a15cffd2a69b3f17224f8c77d47e92d9a564117c2574cbd08f73720116f40092bdb326087dede370456a7a137231716bce008a580bc3f687e2623f4ef0c11b4c1271ea831a2683a2af8d2d6fb23cbae533a33348c160f7dec8db61f3c0e6489795c970e4c548741558b40b532dde65f44681736a442a0f03d19034f0dd0125b1f8786dc4f1b144a71e0abdf04c5bd77c9a052d947032752280758965183e1a243c0b8f498c032a108950768cb0f95230dab3086fbdd9dad518b73acab452b5d0106273b4faf02cd43c5df9bf11ea2bbcf2ac9670d807c3eebbb0f73360e54ccbb269808b5051ca4993df434d768f88cb36bd3304f31f3b9677c264a6da17b55847cc9d0ebf18d9fe2a9aebe51867977f98f83d495f530457afc25a64e556317583b05228d67b7607717ac193ca92f0bed673d4f489a7118b4176d94b6564d35be28abda91e6fd4edfa9227146c830675e1f9c9641b451aa8857762b7b77499feb4c3a3692a20bd80d70102e0670afc174cf98554896a4b03ae5531e9334a71537f18364fa6f09375d9b3a428bbe4aa9444f9bffcd6219ab7c3247eed8f1dbc57fd5a813427a555b8905f193c91339352700958e9f244d9f92717bf9c12cba2f7f7344c725a8c820fd003cf2f4029910d8c20607fb5ef89cee87c64185da3694df063547021fe9ad7065a5238cb15cb5e92483a23dc3876b09a08c23ee995a2515e6dce56eccbb79567d127c97c98e87c052c2afc3326cac0c36f67dd07e6e2e1afa7df2a3fbe33903290e6dfb3e7af9cc5ffebf17542ad0189578566806a621815575f1fcaa79df4b8aa0f9ca6999e595f9e3d3726739dbfedc42085df84bbb8a9428201248d618f4103bdbe378853fdf98cad13f6cc84da980c218454177b78d17fe4a5967ce0812234298181f64a5f27d4c67042705b031caa5eaecb4cd933f4080bb0a81329fe20633b44375b971eb23d16df0670b67aa341973f49d77d0360c293badfc27a93b0a581e3ebe7f5003357379f922ab032f1abc40b13bce7117f3d7b7639e966793d369d84ce7e6fdf56e21270c9809141226ca614e827237eba3f6958aafeba242371f14cbcfeda4fcb7d9f1a25431d0f842052f79668436b563358c9fbe0e1afd6164930ab4f86d6eb804bc7f1e23addb9b961bbf81c2c8772cbb485f5e1d114a17315200db1d4812bd68071bf16918ccd43100e51a057530d0af1653c36bccb07ec3a84f75af8cc074e814ba8a918446ed460381532584add66c514c7313ecd20b1ca0131999e6364076da0daf20eb0b6a44f1d73fc6295826948dce730fb70e8a90efdd800a3991c286af051c34ad7f68def9d7599bdf3768230482912223cf858c55bfac7d1ceee28634fe15b93b7173e11dbab6df3dceccad7e6015ff3626f4c5de857d042395ff0b256a181f8b68cf5fc81089bb371e928054da8ea422d9d882291b17159a5243407296aea1c7ca3090ac5621ca69b623fc6d5b72b10bbec913a8d479fba9378a411acba5d61b3007bc32713b129009f62d8a8b1c1578a1f53ed91c7b72b3c98c492983b60c481133a1ce46760c473717f4d8736c9bb152661d1d2913ebaf757855f405962dad3fc2c8dcfee2c2420543ecb05d30f22baf984ad5c119e71634120e79d6c46b3e454e6f8f3ce1ecdffcd5eef54094c94284b7eff6a118ecd30c5382c9086dd56b018e10b3a3d230b28426f5b8d9c696a3d0b0638e01996c0be9c32a2de999d15e47c8f963ed7076717e713fba7a071e2b50c953772eb9ad10559c1d1e56fdd59f16074989b0a2843c9ec0e4b87035e1e8330c6b79698f9784f4ba013f96ad5de2e961a6cd651d740c84a2667d9bacc0a4e451d903e412631f43bb3c432a275c731b1f21a4da75e5a2ebfc245618f0912414bb40b55696ea80e6031bdd42176982f38de8bf64b05cf4055495af246adddc38638e4468849d569b9841570a76deed0ccf7960d6f254c87d1e62767d8da3c4c0520875a3ca52b84a23db139af6302a3a76ffbe365bb610ceb3f4b89f3165730aeb1f6a74e62b9e7cf10e5f07b0e184e31be417a49ca5bbe8fc4c2ba720902ac032de73e4c3d5869bebd6ebb980cb5941ca7486a8565f85a56cc6b2ff12c7fe8cbc58929c99460aa401fbc693b5af71547d193dfbd52e78d60abb28128070657a1433fa0d31039a610d9e66d1b90757ecede92ed5c324c65196146289340ee74382d08eb86764e20712dab2d17c022b0cdbbec10debc0f0e9f0285f4b1410c11756d6113cd269990ccbbd4216a9908501112525bffb8e6904975b5166ae9211d05340c0e1c75188b5e1ae53830d7c4a09f826e1112e594dd616456280e89275f00ecfb29c129ea8413b77db7dfbd226a8b2ebbc80f4d9446f0532bec693a20bb6243bd17a3d3bdf76faf10b9a4a368d4a1bd1d6cd9e3e9bea9be820aa2681f748687d35682332c419a873d257104474d04ff45cb350f9256c0b6fe64fe6728a2622985987cba8470d42e321ab64de3c73941df17606daf837af3bb6e174e0c6cb90ddd3bc744dc0151fe091e77d09551aca295028f069dcb6e210d3126148bed21392556ac1c5a96fde6c61c7eb4390417ce66ec56a79595cce0706ebe54245bbfdee4b439395c38479582ef696a112cc7aa6055f283f4c7b2254fc7e08dba8a8b68eaa6f209d76da541f85f122ed295de2b1893a574f12792666b2e01053af87210af24974faf63017d040c60f65f301f59251344bab2ad4e8f52a51a59684835275d96758207cae1d532978746f4db2a0d90c16bd57506de8dcb82e9d70aaf680b1607f069da73a53613c06f7daba304a984d624be4a124d12ca04bfa13bf1016e49de7e475bef8f9e34c90387e1f477bd7f87b28e58aed7c5051847c379f9fe7c7d1385824b2d85f952c41ae8594be6ff33542c5fcec0283c5b665842d4439ba238b3248b8d3c717e5a5392021fd56cb7fd6eb118115693090f32fb98f627e82d20ce6b87c3712c1d8b6b016709e02d09438a9876259fb3953b2eafe52b08142b130fa5057ea5499d64bc932622d2eb1927393ba4a032236823fce7b8c024919e1734800a3291e9fb52aa8f48677addedc086ef10c3ea547710b8f71bdc7e3936cad75279d5a9fc8ff28bb1b692172ed89008e82faabaf59ef0cf379e74f4468db3fd59c726baad5493cea32ff1167d45ca0a0eae7ba9a9cb58c1e046651d3471a325ae6f05d509dca3a3fc93c8981c758dc3da3110a3455eabb275a9f9791797e0860741cd2a167971e4e7c16cd8d39a3c42349406f936afa94d669ce0000ddbb5d57a0a51b0d8c2cba92ba16b7ec1ae6b96962774b2afdea4721f1e4536d13f2124a13e29917cc06b25745ba7542a5c758e01e02c5eb4e478cb27ad504476827559fbe74ced118e282bfe6718349004233a00d564648ca56dfa3f7e7afb6a425c64d5a5080f95b704f6bc56f2da67a1bde0c03aa49177d5e4451ff55ad165519ca518c83b09736747a7bcdf72759bd027d6c02409bce0e62a66738d24ecb8e195e097bce8a299bd3673d58d584b7cde0f5a89d8bd9072a9b0f2414747e5efa43aa843e2e3267e8fe0ce9573dd2b3b6520407cd508ee08b2f4e444cc496cf11ff4af2dbf9c05495fffa80963b15438f7d8c4f7f337e7241e38a960a858907f879e8d73b2bdff6ccba6377738f11271aa93413dd79bce3ce08a87b464fdb5e927034f9f76138cbfda1420b0886044ad97a5be1742acc25890ba2818dacf20dfea0ae2b6c96a176879ddc9c191848508884d2c8a900f294d519c9c67d3eac01dfdc9b460671736fa0dfad9347b9216ebd385750d860e0ca57798782d24a563f63104eaa0307224a4f7f4011d421703812c05a894c7c10140b88008c04b8bc91c3e3f291003091e8134a10987402c8d99330d11e05200b37c5035260903f63408c4945f41f8b85b2fee6382801146f9737f48054794d63ff890e221f36dd4fbc8f11e3dbe2894e13ebf3bbd38af07c5d878039281a0d7605094cfc53bfda4d85582fb15c3ce11d4b3b2b239eb70004ca99f7b7b273c1fbca84a85cf0c72db799ef56e20350a401272fc5b778912e65f9954f50b37ab38ece4fe2b4e5bfaba78345524d97d1ec809a0440582025a681b4607247b33b9e904b3b2402a0f409715674c110749e5314da4cb9f5a4ee8e820e5965df00d1957d7764a11ec8e5adad2b89f1efbab3e4f5efba388ae95670c897a10a23f9069a8c4e578ea118ae5b8b6ddeb6dc4e412a8b43c338532e1f703d336c08295224a4b7c2459ef0a10bcb187b0115f8febd85ba4abf5ccccea00aaac9e68956fd9fe0ce593c7602aed6f61dbb2ea96780f87603411f66ee13974b3ccfc2e3b502395df4be6bec829b0baaf35f66f53f2ea51987a7ed760b1866431926d9c8cf694aa6bf505330f3cbe773ec90c3ad86031c0238f01e75a125649b1513cf0b6be2d36698ae291ce57045bf0de0371a90628f98ab98b01943129f2775fb0b05b016e0cea20e7187bf497b6e4ab3e35eb7b56f144338488b1cde2adc46f856948542a350125b3bf42e33393657811c3d6fb7b271c34dde65bda8896514bcc7310116c4dcfb5315f689b87ad2078c39bc41487e8855df6cf09b42dd40707827d18afcc29c607ac2f573fb933a4e43b8d0a592ff20d63207bdd3aaf0ca9318ae6578b970915a452d4df05e119a788879aa813ab5a4734ef24d07b0deb0370cf5ba5f6bfec3ac9c4e2321319463c6fb76ed5e70486a86b26ae416e0ad356c0c1eaf56211be5e00118efe3a03a7b753c8a66f2f34dec8784c9d5ecc1759efe61455f8d7dc1a5a88dacabc735f203e157509f9984f1e259d2f6ba150198cf06aa99df89fde90faff8814437541f1c3422d48f962743386102c56bdfcf18f1e39675500beb8a2e2f181de95baeeac00bc74f945cfa6ffbf5b69fd8c8a7d9dbf90e1ff5d6f4a28be00c9fbc7894717523960b0284aad3b22d0c3f2971870d852b32cdfa51d5b1846c124d824ebfca3300383bf2e053a12e8a63b1001af4344f18535c2510858fe6d2db712098ace7b1ec697230992744f055757e2784dd1e9ab6b55bf2137979a1cb9654eeaf966a788d3cd8eeb9d0f695dd5f4aab5872a2c63d3ae2db0d948ba218893f29391ea99c60b16289d9648722fc5bad38bb236a67c8f32e6f757218b8f53eb40b8304d9b54650dcdd14d07746699bfd127c0d0df715b93b80b8658160ce7bd0802db9a0b0f511ce335d9d2cf10a912a084714c4394282a390ebd3bd7f329c08b0fe88de15798928bd400b77fd8a3604b34cbd7013f5f2bc04f951aa5a99884314405cc7b86d3c9c97b6487429776461d321970e572910ba81f7c7d2ce959e77be42979539a4a1708a40caeaec04bb5fa57d92193050debe2914364346fbbd0bf997066e3ee6a33cdc959068b8787cd8dc168f416a56b3393d1986546f55f74545cf96290357f4358b79f146e722034b14dfb32a4853961989492076b569cd71e177a6ba8963edb38a1c283a03fd0aa80f671d728dbfa35b77475cd59370cf802820433a366739610cf7f6b51f88cc9cdc399e56b8afbda0111625179b097bc963f0c2d353b5018320088d0f977d2b4420a29a4802c7ab70160ed1b9d325cec2e117c468b4abbe2499985612b3fa4af56000d73899b2e4ea35fd3cd59edcd0ed3437284fb85f188d437840e9d7fd138ed301390b21e097f5265d35d56751c482be650dda09c873904349b6ecc99aed4b56068fffd282d905521a66b5f3596ec7fb335c5da2799292a777f634650a0e37abea33df4d351c891696f882ee775f45c4ecf38d5b0c50a3ab1340eb3b3e6083c1316a118cdf79f8b200c457e48c3adf94412bbbabd4af89e88b50f1d555bfe69f12e65606526b6b48cc754e29de4c39c1e06a2972045e5f8d3081608cb89467d936610fc8d307a5b0ec3d04ad80b9b8c4ecc2d023ef2ee0925e36e6acb7a9177b558a3b800fc02d737043332348b9b6300b7f7900e8c6e43d49c6145dd3b8c2e61e49973f0679b62168b70ca6fd602af53bfad76a586aa7d8911f5231f4410e52d02e027995f46b9185dc039a2ba3c13148a5ddc01bf3fc23999d7192adb5fab1adb50dccd68f6482d3047461d4f946ea89743f36a5099b3b0bf7ec9828a37b4dae579f435747c21f7b94633fd7058453472ef80ca5b72e6230a6d132ab73703a7c464f5175538ecf94005979afdc218726558d86eb298ac4999bc00958ae29be35ff7b71903fb68907a8476cdc5b6a06cf9b180dbea925c0b3206593ff4cecba74afed4c270f8b1efda36f82986aedf13edcc3207492b92a0a1896f0a9a26d3372be6ae08d2762a5a2955ebef234b747be20201ab436025fd953eceec51fa1ec107ecd0468c3eb28445db598d8943a426bdcc821a7abbc8fc111a1e9f182cb4785a09330ee72a9c301f2b0ad96a313867fcc1234b4928411153f9a4aa2437bcc020f84a98930abce6ad554ed84ceccd0529d2b84eef63bdc50a28d0ee5788df460685c432e14f5b93026fe0d4e928bb75274ded636f60117d1819f29d646028aee3543f74af04bff946be69fa0bbad0a513a40c4b7b194f4b3e64583676f1b2c421e25946af9a4ec48a1b4c40106a7758577e1a929353ecfd44699f871b96ada12c384652ad9b319c9b3185146b44e149684f59f5a32424838463d435049eb04c571238eb7eab9418cea7ed086d667286405b175a41a480a1ad0586e3160c5fa1e39700a531ffb4e64dbbf79768966232a2b33cbc1198a09f5f75b41026a7562d747cfdb1c1d789bfebb66f09e61bb68d849cf32687be017945aedd9ac5b90c152baf84a7e87a454fed76f677bbb6949305dea35ba267b1deb0e74545792c9b10199038dd34b4bf2f78315def239c8174439f909fb066b28e5284fbef9c10063c9283a9ae85d0318466e109acd06bfe22c39a2dd486bdad6bbbe3a0072afd8f1d44c646a6ffebe26f175ad65be69ec255f87d03123a564a6097872d7c45a096dfcb1197408e5484444107d0cb7f0b691fe22caffb053de4b2afc7e01b77e4414ce2bd286b44d78cf0d9d5715e0d8fb7e58ea1329e0fa481398f87189206071af5ec54e5f604b99fc43272e28a2b4d0ff063157a84a49121e004fb4c952a3a0160ec0e46f7ad91d3bf189542e425251717041b9ee932a6a14df38a526407c06aec5b89d75db153a2ae575b0750a6e370992d4a547ec07e1348f0e55f7e7fc3b5748fe4d2374cc7dd856cdfe637e58a251233e5f4ebad279115fca9a59d9ba9f64335a3a326bbead8ca8c204ea60ee764270e05045828ce4ed001512ca982ced54c8b53677161cced4db004add00600f736dd64f9e2396def65b2ed4fe51476649e67e1f3c8ca625eef6d697c948b41f038d1352a7ac616187615eeab12e3a79064fb3fc1cf939e6a3bcc7445c7d2855f66fd1a307d00d9b93021698807b549b00760462dd4bfb08a05685e9ad6371d9e167436e7f4d182fb47a751fb4f284ec8044dc4d7043a5f058278515ba8043197ba5511566039db0d1abd0259c1a5370b5c500a5695f8136fb84105495d8200f64f1c946424a21b99c8d0c042b43c2b22b129f15cb96d073fc508a47517a366ae62d657bca5135921b11c1545c5f507299129788041d3082667ff9924768b23ee35cf02cec4431e7b6299158f6bae9f09a6e67a2f9f9e03ea6eb893c34410a7389c5a9184be4b3753a9828fb9c4a4d23d84491612ee8fdd9a36e3e8be967c35899dd6b2833c9beb70ccf4e30d23226c0a26ca0583811eab6cfee702bd28189b7b85527cdd48a4def95f39d0ba4c92420795e993e4f56468c7336362176692ca94df00ac2cd523f4dde735f615596f5e8c0cda37f731d9b2407b509afd58407bb4a03e7a101e19748f07c27fc41ec323a488c582cdc6482a9c4ad73b6982c8c3942d2ed450a4dbbfca89689605ec22a50cfd192a8f2f555840d02a4ca6d167381c8e6d184ced95d4c3f38fd1e6f6d7fb835f1590be8547930865acb9ef237f5ff9dfc27c76e20e3f6d87e7cc65d1f75e4d4fe8e0cc5f5ccb0e62021bec245d18a652478b516ec405275bf48edd854d1e2e3595f650e0084aa149d9f91b4955dca90030429b5988a9a41b39fdbdb8f883dd64112d97111888e81d683c09a950ab1ac4778bc90fc88956c7ab07409b0aebd5f980e762c6aa86b478de986a05ea4eb58f44934f165b5e419c946577b2e2d647f5bf0dbef8c456ccc53958d34aed34e1bd9a11a4e7e2256dd86327fa6f29cd590754420ea328b94a5d248359cc6c851e63aec1e21c7ffc28a172d82be6ead7d9256e23cf8a0d9a8bf31c7d02bf854c99a6fc07c1129bb81a37ae483331d95db167888dadbb27018fa9b144e6ec9d0f063a0f6d08d9455a6a3bb01b5d1387fea1f42ec97cd7144cbb0f570b2ee78852638f1f9b2143608a6f7927afe2bd7e6feeb22c0d0d135531176eb40f60d4015a2ba811af000d6c8595d409daa9100c5120e2e0b0281cf8627820204574492be191b1ad9db24dfa0449d4192c272789a2500b83c515bd2576f1f07aa5c1b916a78c6e8686bf8f555dbcbf3508905c08e3179d18fbb2ee6d52e6900056c0b52e2f864b544611470c6a81756ffefbeb7c9d35b7442c85116e7b883948ded276d81fabea9f4d54c86451be502a21d885a4a9156ff75020d83c78566ad9a0848c1e2656ee97038da58db9955842e60cda322a689915a6f47684d8c0a093f4c81f1bd044021c36f031a8d4e1c2e79dd4d57921f23aaff771ba9efb3f4397dda1fb15929a5d92fb9da30c935babc78d58f57fc117a8a3b5796ede2cab78e081a6ed319eca3a4a6b87e618463d437e7825c5a1ca8496c550e6863fbe4a093de72557246496908582d795861a777683c669c3b94505e3bf208a40f933cd96a60ead4eff8fc22501ed5cebe0ed3e91952bfd35678ff6007ebb5fef7183cefe3da8d8ba0ac26ef8c7c73133279671f47b38b2ed5ac6ba45bd16fddd5861324e498dbcc4f198a45ede1414683b233adae93cba355e75ed82ffd90b3b785075eb1aaa76689040b97b17b26830ca00b7c8745200b10abf4e1289b1c07b3b51aa5f03714cf0c3069502ca5404c5444fccafe365cee81b13f479e886299bbdd0b4b364db2f6e240f122708be9ec1209b85c4cecae61ecde190da835f795cd6296e3a624b29649d7c00ee181bb7fe126d89d984c5963c3bbbd60676da50be5db2b85b2b913eac8b1c0689b02b1cdd4dc54ec9fcca0c1cfe4621e366b5512f836ecb750fb6c782a9addf083334759371aa5e9355bfb601235791be596eaf22cfa848db2803068b12635d3c6225b944b209207b4cf398ed1059130065fdc29eb504d0e293110a11f70eddc8a3a28e6ad6184889745282237b011b9bb40ca18cf7b5ecb02e7c2c69e6d44fcf0f4b62ca353270a838b7155b42f257ce85c212250589aac320621c9771863f50c5a6cf5be24647f8fd23ed0a4c5dcc25d65903a8dad0920d594ff48f9a202f7329be4f518092c121985079f42900af6494617476c09437d57440458126b1da94d78e1c036f952987b01403879e444a2354ccc526c193bbe11461ac7c83a4c9e5fd11a8e17460f46baaba67a69e58eba555d6b43229e36b1506adc0f3288e72eee780bccd5996ca1bbed070614d6571797bd8dee835e53d0dd55465a95a536bd7673e1d0f662af232622ffecc9b8fefa4439c9b6c54c9c0c24749ba1b017bc15b54b71f37291c7264813e368faf07af42dc0bd9375a03cfc8d73545623ae3299b823d4cbcf52be973baf62768a6ea1f271c09d44a6ec94d6e196072b38fac80f9d5fcde1efb08b6a6a694dfac4d0691dce3a428f9cbd21b6759228b3cdebdb9810d2d7766d44218ca53bfb1e3a36cc09dae3ccd9ccb815f1aeaee22e1fa5dec0942ac0c3a0d9c28394c07c62744eb9722ee89b2513315fa79491052adb1414ad13661abcd71af0aaf558cabc70873e7127b041dc6edc9d82631b5545851a3ccff124f359c15512febb237f46f949b2bf82b3f0af316ac26abaa5fa07abeee269cc05450c9a2575b8e2df0a3f0799cb935ed4f38cbe7ea1ef9eae351bc7ea9a172c9432c45c24ad554808b52efa897a207860229908c8730964240c6c8b195699786565eaef7e9975e53320e330e6927555bf0ca61d54a51990912e0d817a58989e03417ac967d7e6bf958d6ff94b5612ffc3eded6d5e1f2d2e7a2e13144101c6ee5b6208e810f047e766e3beef0d18c1c7ed8ef49695814b575527409c27eac8f3bd43e991d1060baa30f3157ffea00d2e58dee08cfceec268b52f0c08e39b975445530cddd2f2ad34e940ac4f494923c8e1ffa54dcc8df8987c2bedabc92ecfbe0e31c8659c0ccdd09cf6779e9bf290e6b048972b945c89c6c57ee6673289ab39a3939b68751c063c922ed378f6d7c3e7986e584b7f32ccf34d3e26f8b471c615715eae8a6655cb174c446913be1d87b83bb6ad203c5308cb66d22e619bf24fa74ac2353fc2225edebc54ce54f55212cb71f511492a1b31621fd9efe6ca9e2ea95c2d103249534f892b5ea91a18de0bd9fbc563e7e12263719eaf9d734ac1134302c050aa5c56004081b8244f8996788a790b2b3ba7579bd5a913e0569ed0371ea0ae897e0a608e4def86854c750ec1577ac6a38787b079f5adcf23271e98520f9e144060adde7ebf732cd2fe06af8f7cf14180bc80492ffc982a96c84da9193352aa475724cbe5d24787582d5d2e22588ad8d1e7f6d58b29ca2fdab9e39a8683ffa0ef188b9ace1fecbfb01207164442353eb6bd02ba43a0535d9fe64f42f7b0206240d76fe37557b910ee0f651d3961601d2119b4ac0941244a8bafdc5f18ef510a0bb244be532038fc6b3adbdae578b767941d31c9e18c5caf344e348ed6fcdd0cad169a50f5bba5b613d7b55fcef699623794814c8246f7c77f21e418edd75dd7d273b718bb8960b1993b18a7c782894ee44599c047233bafd48b87294cdc28ec889519dc55199f5a8cdba289cc5a89f85a89d751d9d3317c5ad73e39f8df6d89c9e724ebec9f54655f7f4fc80d28ad615d32202616981688d65eff59d7fb989de139b9a06045ceb5e52be773c098e361446e18118383c67fefec0565f941a973ad1c4d249b6d1173a2c93594372ec33a44e11b1a94e72f19bb56c35443e032ad055b3702a40e3eb995f0325a79e9b7bb816b0da7fb77fb1cf16f6b1a2676f85bef454588df0618029774fbb78c3a73ab5c3d300b6b6fd1aa9bcf9aa1650547fe8dc7c4137e2171366c455617bef9af20de25c264d66c6ffbbabd505418c114ca9717de3694a3eaa6a6192dc02b165fe4376ed6bcb89aaeb5d895843e9754a08aba315ae48a4891b2d4fd44798a63a79ce5a7d97f0675307e4f49b88e14fc6ab7314694c486eb544ee2a098e7a4bfb6f48f48fbdc057700f97918439541b0ff07702cc5315ffd83b312451236c3bf30f590eaa34c2e2ffa5944a923cbddd26d18664f840131382330a45effbce1bcce53c34f5cf11658a8ee951dc92013cb35f110be3cbfe869ad331febc79058587f3531f7293bed1538cab1e10653f2e9c9e40398ed302d22db0d49991698669cce7360fcf5ca5ce3cef00c994b95d45d97d9222f1eba1457924253df0dd8973a56b234ed5c5f95d28907f9793062980bd5e11b3dbf1357c388b5b2f653e3f5efc01c1dc8bcb9479f1649f0645cc62ca70df6b3006b617f33b77b20f74086312d8a644182a2885fcbe4bbb9983ccd3712c2740252799cdd0fa19d7ba9ac71e61f8e6ea16cffd4b088a5008a9d9809b24436a724a3ad32ade98c8475b674be355c17d191a5a389e331238117bd48e4b281e1c4333d520f687335074fedf218216315aa80485724c542c315bb450c5f89cc0d5e238a96d44d49a3683875c535bbe27550dded8209b866964cd83a2126a6018868109da909060a5eb34fa7e68596878af9a2284fc5c187713683cca8a664d7be0729f469bba9f216b82c69bf89d0a86245e6525deef9177a3dea919df1994a3c68c5ac6f234650ea79ae89f949a4eff2602a3fbc1695823df60a8bd449e58b33372d6009a4e5533b097eb98a8bf832430bf912c0109c20ae2c80d22ef5b3492a03dfa508bd02e364f22919e93a4e679e953f662e156883147255384dc628ed6190d110bca3ee6ff43b9315f3df503697ce195a986d9417450eee553ae3c3ec70a368c5964c79ba281b65e37c3bfd1f485eead1f47de46819060e57a8cfe4586232418acd42b855e3444c95b06134bb87002e41d5c106bd29c1882ecfe52a94689218413e410092cdc6fa725c7194adfaa2c5eb61127c9e05944d9e309c8bbd8267a0b2e811be1d2b1af914ec128cb08a2aa07f5b25777238ff89aaf00f1b13ff3232c24c2dfcd1577e264eb6bb911f81e4a32250d9d6c14c71e28c31ec20b75c58e5a63151b8a4213621bb94a6938bbd55423e277b8b9b35a5ebc3939b73aa7df57c02def32bb590e615bfa144103ed78ef54f215a667a4d8800c0e2a7b11acb2a63e3f2c088a468238dd70e007733b61bf9ed3139368d39afd0e6006422f73749bc60e3318e0913043dd115462a478b7e5febaad7d5328cfb941529f0f5d9de462f4f5542a76e39b40efc605ce8612b5cb57a621025db5a44585b73e2564cdaa6b72ce02b684118351e3767bf9bf03612b2cc5a3a54d3483b8f184b081e48144370761c196e735f7ef0a5943fc32fbb52fafaad4a55fda54a71c1175492abaaa32479cd7ab1f1044b05b79f5e8d597209877953dc35db4849383bcbf1646ec0384f78eae1917bfaa10c61ef6f1073b6e858d1f0a44dc7235b6c3c61004e7939f1fc3135861e1386838b2557f9bde39e7964016dc89069a9594f3e959a4de6e6d202c25a923394f96cc2a0597b4d1167cfa9609597eb9cd3717c56f850cabf1d370322a2088763cff3a51a82d66f9d05788f2df9fbf2d41d3aa3f1cb6f073602bdd8c80e7b53a7294dd27b583fdfdf30d40b289f3bc5866cbb4e05cb20f5a71f1da1ec77fc435383c2098b4e32d865fd774ef81a57a5ee997672df4ab825a15916a4a5a7580e7b871d54b1c1c243a8a536dcbf90b8fd66a297d208f01fd757315ea7777e56cff263a4f79a8de73b0d708f92ba0e9cae5ecfc07321ba1f5920161e0ba2f2456eeda2b496fe7ab29e28a19819bb39394d183136195ecbb93550b74c3614f6c8b344a9ae74853c189d31a340886eef9ad7b472c423238ca6e93f81a7e152da2a92e0068154c1f00da8b71524002dc751a2dd523e5cfef51f58f390c4ba58ae1d7176c88c9d31bf650369da5c183f92f00dd3371844fc060a050d79357ee3f127a195772c6776d116790d67070609b333a41a74d9de72a754896eeaea8565484b994aceb47113fe74c6c6942a3dab3b6374688fe50c0ad2d3ef37ca41d774301780c6cbe458889488743102f28fa4b16088cc67814c6c6c573156a123be172138498f8595da004b9fbc6bdffb153da25e9317a977ec44e9fd9760677759dc5582593374be299d4176f0185caafb866d32bd40a888c4ca4d97288bf9e9e5b93542fc66d99229e405e4f7b9213c201f44feb4e564e0b5d0e724bf0007af94249ee32657059a41523c586920817d19f636dfc926025d642aacfec3de4c317f583e4d65ad11185c54dff32dbae0970761ab5d45de1da1455765fe15f65c02e78e7597c392449189f23b9b24d9dc39a033e0aa2b2f276f9d1e761f6d2a1159d10053bb32475f2f3993d7bcde65e7ddf3c60803cdf2aeec9660776ed493056090bae94a95477c902a5f381c0cccea55d7222453a25a570ba9a609ebc217a373508a3f162c134aad15c880f0abc4dbc1edd5e966f9f73aa34c16dc388e182885130483a61c9504dce22321e876096ff76544de37e2aed3ee32307347e5853ec1869398ce4cbd087a991146eb638387a3168c7cf20b4fdd20492855c7f7a3b19c86de60bf108e40ca755d8a2b16fc22101a63edba7f755090cdec8c7e434438201651c09ddfb2f5d7833d4bbc394262fab4290eaa295e2acbd7204e4bedf8cee3f4fe9c74493e626925dec15be876d5b79a86aa96070ea7e579434515d78f034188692f6d08c658eb3ab6f5065cd4e25e014da6fe5feba05a07d6304983da72bf07c12d93907e45272bb034326c6aa0cdf12150b0d0449d5009098165c1ec185c4698c28a65094c74054fcd773f7055434272ec7c472ebba6302ed36c992b26dc7476f6017b21c58ced29eef1f6b67b7b13d581ad4bf6f5878eeffbc9edf9c9f1df84a168a1ef8c9d73c5810910e3c6c3931610622e4306b93f584d7ee734efd06a8bdacaeddca4cdae0f99d65f1ac533931f98062d2da5dfadb7aba8e5a2c721e10104d84777f2db1227dc415adcecfbc398e0dc1c0e3971db26f6cf3b71bb428d44f1d138247ffb929a59b9d4cbdc3d0fa2dfa8033f19b39f1acea9e7bc93235f5d3a8fdacb45a69deee8385888213f0d270e4d9cc339cb7f053cc0e593c0a8af6eff9297d13e8f3bf94a228d6d5618813481e1d0d2dc74a2d0e792e6d1523ab0dda58d090925f7532025ac37381475d49977c7a7b97abd5ab36eeda75c5ef66521e45225d01d8ec246448b96c7b63a23412f58f3e31f52f4cf503fb57ba7dc86388e654db87d75dfd03a63cef9883d371028b3a4f2d4111c4a9e3f0b90db9c283cc5aa7992a602bcd677b9f2fc8ca6657d92a61f87f22c50d937c85cece46b433f42f9b593ad16788fcf7b9ee7b220abdbcfe083a2e03ca969a2b1c762f4f3b85f865b3ec93376e421338acae8d0b9df940f1e65407b57b9e669d19b17f2199890a6af3f9581214e133e503dc9fc1e87e2d6716ce312facdb7dd0c1550afd974ef7fbb865b5872faa704dc72740fa9e929d0068359a45b78b3a1910b7d4604e9a8a79795b62aac1d7789dfdc1f7406f6d61bf311dd8729f4a09ca8e0cbbf68dcec65a81e36f9348f5ba417786a6d8cf97c442f5fe56965cc442944e8fa644550ec7ac9752585869df21017df39b2e8590a1e842f92a0013e0c619c4306c0fd68699964f66751c19ef17cbbacad6caeed6f7e568b55e42c9150e997648db8af31cc9f46bd05c17890e993b4ce9e372de63bed3a9df18269391ddde81d4a5718a07bb510244a2b286c07df865a63c8a8dfb14206388ccb30a8e2825e8c5f2a2b6c934993fd3c3fe1327d9330404980908b3c22bff72b6c610642de5dfb53b33449462d12a7e6e3531e962dd5aef428cdd9ee8785990d0df641d86c840afb81e78348129e0bbb6c8326a0882284bc0370aa031afebec41f70d6085140940bda09bfa0def992b7d39e711a3266e3a71fd3a3253c5a439271c53e7095d2cba8e489e49437191442ec5caa8b64c2b0e1ba001376e37614f30a4c963b34e19b45f7dfd47e26451814d456469b11b132e0394e38613a74dbd4960a186fded771ba449e1795ef2a0b687fda50b1043e9b303403bafbbfe2fd70a792d4239c6240add797fd8fb36e2d628a86f6aabae9662b3758bd6e4ede97f1faf2495b67d9e464ad637277fcaa6d5f25e12a4a4f0260ebb8425ff17c7f5af7999a9df1607b003a01a64c656823bacc4626865d578be76d83da2fcf2b49f0c07850f1abdafc00dee54e55c7e4acb2d3215c2cca6d2d82dc04b1f8c69120f988ee1a5501dae9bb9dcaa558dbbb0a6aa724f0dc98c80cb8a97c7ca7366067ecdc51cb45787ff01a6851e76994d7b99a6005b823284f041621acc3a2b48739d555f9759430b9616003ec63cdee19499ed19705df9818c7f4d6a7731a3317ef707655544445773fac11bf7f4b80041b02c1d8fd08d41eeaff5e8a86da6a0b8198e82c71c537e0cb8ee0d7a7f4ad8735200df348bc5eddde8e7aec1805863493d4e4aa0bc542efbc38837ea55d14be82bb248c90e58c6435c720a308eb7b95b6a6b64f585eaeb5854ab63be6c69c94f3355722e20fb6fe255938c9674ae7591c40e2cf9d5cd07c84f46340108e26ccea0be11d192054d55e053929edfff88bba593bb09b6e0186fe8b43558e86714a4f5f9a1b295de67ae4be84255c60b479ba4ba3d6a6cf8972b6b190a59c53a79090a3215ae129aad656ccee99b52fa827b003d7fb910c3e43d5eafe343338d557c6b0fe029b97c325171b041b2061e34f6cc35b9c4cacc1861d3449404188b06e1449a5052ae7aa7bf7a6b864008a828b88bb04f63b4624390ea100f63e8c46b5db92672654075f2fc2dc6bf8a319f90fff51b5c0ef19d7f9e00b2251fdd6db342f7a8577a699f4d6d54f92ef308562eb04b8cdc7c69ec4f663ae7fab8b2b40ae7c60219b952f36c50cd94aa4739c9aceaf27e98660d6494e601763560d014e7276f73b764d2c672d581c2a2e850bff9443b0dbcebe76203e5eb99a8c97793444c0103b6873b4cd835c9076667014eaeecb9dd8b3f1d0dea86932b8815b3f4d66ae9997d5733791c274d1790ee3dc495360591190afead67aff0c5b927c6c939597419f7afcdad576d20d794ca4b3c73f6a0fe263844d878107a116239c4f95c2b4070820ed36a5105d120b15138d2dd107b399651a4bfd4046891ca18d122506dacb83a3d8ce58118472a3dd5bdccb38756c3e53e816fe3ec42f1b67eb58e24e15426380c98ec8d1b3dafc3386551296a7176c48d07fa046059951b7f058b2b862894315a3c450981cab87c26b930983f678f6047047c46e0151ccc1464557e18b8f8c8facbf8f8e7982650981010bb4901f1c9c0e61ccc9b10eb9321d248143f7dc487d9703735ab4805df31e95cd878c67da8b1eb062be001543715aa4d3c3b2ba6cab6e4cde4e309e038d9c3df278c1e4fee86c966341b35ae1663d029a10ac62c06b0699e4e273e891fb4b4eb41f4635a8ecfd9bb2d78445e5ab42620bcdd01391b73078b1a7d38b8bd8090ef39ac764b04291bfe30365992ae3089ffd9194a703208b40399037c12f1f68bed3f9bc2a135f1e377e670e69c8b5caf30fb054df086b77a635502ab46444d57a4014449206c22a284dfa75fa1cf5349aa1bbe392f3f808ba1f402ef10ff2683b62782f400e72e41d10ae2a0413a7aaa95f5bb903b527e48a86cb6d267114003549032eb296ad2bb8ba1fdf27c3df8b9b08a515880ad65f8a835713ce5cb0c2be0e0884a069e05fe9951516224669a9fcd364e63b1a91af5ecfdd80285ba0e590ba83a21af4e074e32de33e43661773e26c0ab233d4a1aeab73882dbc354d9d379fccf63f80fd848bed6be0c1724f214d28cd2eb283f600c0f7a5cb85c17ce33b214d9f482b3608cbe9d09fff2e3559991955299ec769445d8a41d691b908f28fc286d503e6962af48adf59f08a8f1e35df8b1ced3d11eca46c1c4b0913ee422dfed09e801721151811fb17d428bbf445ed31cb455d4176f1a223b6a4272709a6e822c09c977564e6c1fa54c836c9b2b2a4c3f194d63a749b567814ef741c795b851b60f6d1a1c87a753150141a6237bcd7e0a31865986c640f57046081aaa4855228beeb61dbb8cb7535433dcdab9041c76112ad98f48211f7b061051172732385e0017ec332b7e4407d3a7c29652592b361a7f4b18502ec7b88fcccf483b3f91d6023b079ba46ee7406a2de710ad4d242b577e118c16626cff8434a4b58915ca50415a4b37b24d73fed1da1cac72d03c5a9b8429744743fa699bdfd1da7512e11e06e4365a534c9843e6abd11aa4b4f217bc9ad1daac55448d458dd988ae3e268f395ac3d2502153ed23e511caf7851504096c34f39fd6ee679933eb0b8b2b95111d4bb446c90c5173f3980a750a8f150cea03ca1b78db358f217473b1f26cfc2f4787d6a096a8326530c1eb686a6a3db6469ae82e0b1b5a2bb044f25becb8ca36ad6d605705ff8aa26a57ab50fe94bbf4d6b0143ea149085cc40625c90f156b09e24a0fb4e6d92509c7144b219f35beddc58908c149d01a79a5464c979f0e0cad15c45a6c63614e165a4b61897e2afd23912631165a238e22635600e039e39d5ba22acb58e4a3b58e869727db9e179171dae4f49622610f19aa426b126ceb489fc8da70f89b13b6b28e73f339047c19dfb953cedefaff081427b4a672bb4da6d8e36cb36ee786fb03aa6a021b6f1b5a5bf8c283519b8bd3a854a2008306686d663e05ca365ca9e21cab37df0aedadc69b34252d005fce4ae0b3666ed44cabc9934ecf4d5c19cf5ae35e69aa85ae542d5508b92caeaff0df56a7e6d725a88267cddb9c673feaadf1ae7793aaf2152166f4aca46731c1f4b91814010fde79d65a185261f5ac0d6d91ffd1b33686b8496c928f676d5fb3ceab724977ecc893d0035a94f40db06fd4ed74ed5a3b1f67993a3139f84f269f85c7516f18aa2c9c51153350f481dc893c024e8e440babc9e7d05a7931668a2e06bc5498ad68c51b30bf3a4ed562520be4799fdd1b6003637a18777b04f72d510fdc5afd2107096672fcc8de0f14a4221f26a3804b17ba0fbc65b937169b37cad5ed8ed3013c1692a73dd26a2078c26d51a915579a96428d0b457a4229c3f5c14194c59822a469d85ee81b37935f6842d945bc8a3baa086e60ccdb08118339273bd25868757f71d47d901cce6495f62a430d6f4f198b9d01e0d2345f284c495318473b3c0314589ef1955691502ea2210b1d1151c92d73d9826c26922d3da465c52614ed4566827aaec164e266ebbfa33f0af55644f54b9bc76bebac3a1c209eabb691dfa58345f2490b0330aeeb3e294b8fd36cb476d39b0e7e9a18d0f86c54a232cd5b98b12fb99f73b319a6582cd97a542df95aa8e8363f31b2647591ddfed90c8b44b264530ea93a9cf64f2ae8bc4a7a330c475625c642112392489b60da1ed7f4826124ff9273a5dd5bb2b6e943560d5530b41898faf2baf1d37475854d90e14920aac08b0db0f14002cb8ad5c60627775a50b189204f92354d292c117e43086a36587e36877ab5e76a2bcd2f5f58ad42731c5aac4e9305128bba8f2e43b36a8f5cf4095a81a91f42fd6e6cbb2842b863cd480b658f4e1120846bb1e3578433acf270b02e0630d4af50cbdf1b4c216b84bd3e37718202e60eb0422596c8815c42f4742be11bc77a0baf991db9691b8a6bece9ac107b8267a26c872e19348e322be375f70e577757e8bd1dac629fc8e91e9d05b086415b1982fe6f58c3878a9c18ca8f88543d4151c132ed2df57e2b6746c70e89e3102775cd99e5e804ef7924ba9b0f0995292c2667cb89d72b069b1a18d92f9dfbe5481bc9245053efd31fd1f37508dae36d6f7cb113fba55962fb451af4b4cefccea985ebae40a40295bf54e018daf5a9e2a687601cad5aa578bc90c9c1b04ae877ebe84f56f78f818f4153bc86b2a15ff664975ec4c4aef73ba9c79fe9a3ce69f065867c4d25063dd754d46cdb620bf0e1dbfa88ebaf59bf2a2760fab0a918927cd061ec761bbf312ec132aa2e323b19c336d49b70f563a21ef4bc4da46cf2442ea4cdd59457f167a75232aef08b61dba0a1740ee18b8d17b637019ad7b110a1c8c7c491cd5e9709aa99b32bdb83d30888040615974c7a3865e4a2296da316cfb0278f6e015a7b73bf04b0ce43313fb70afbd9f8ec28d24c169acda6e4040db6eb85706b8e9eff73d8eefa9a68a33c276772aea99729bfeb904927f63e75d04adc9a41e4d658e91b04461a86a7ef58722ed54dfa1378fcedec08f60a136b1845a39a258fb732e0cec8c3cd1cc19d051b4ea6af2e4cce1530be1cafe2ef738deb4d6e1cc24491c2786c2ad76e8d6349f36e1eb8c9c7a705ddfe28cec1fd0a063d92ed2bd3fc8091017b5d061eb7c9bf7206db04c7aee77bb6bc3043a4d6b7c08de129a204896c314c4b9cf08027bbcb54e77b70e850f6da1796320645d6bf4844809ca56ccb489027214f0829579f5031452b669f2a4d99b822d450787022d313c2d0f379e4f995856677703390aef2a4865a757cd20cd74785c4f5197c19c9d11cadbfc6601070f59cdd9d6048bbfeeee0cddc73d9759468e0f14ce6b8acfb0b19ca390a362d012f3998a97bd582ce77d8f5635620196b12c07332918cf219f5189e278849a31c83bf56c0c97f893f608e211c13211c10601bc428cb91b0d608228117dc25513a420302864c143bc43d9c66d1d039fc0ef7845b2d41dbc23df3c16c91ba3cb827b05e13f6c20c9dbd316366a40ffd51b06668641181316b6ecff61c782784fecdfbd49f5e96107fb9f1d5b9aa25eaeef0d71a35fe96a9891813baa5f9bb6e180f1152b20cbbc418879b550a90583ef138496f5636c3d06c3065254c21178766ebfd665512917e6a48d21d4a104fdc198d5aea7bba60bf2a387d12731770ad3bd600b4e8d7081426d7f5ae6a59c05388301e5567fb1bdff1d6b2fe793d3840a2464171369a8c618a32138e4b585b2680eadfdd16b7498d914e50ea3a48380b0dbde00849683af14f220a410f991bc3314d4224db9e7aee16cff75b9f10d816113553e6d5aa754923e83bcc24a8f809584c00963239ffa63230887774cb1ae38a00c907801670dbbf73bea337b8a409bb885dc8c190778afd4715c5e696456e1cf084511a82275d1f0235c0d83bb6d32a3da992c62574213f6aae394917023c6e34bd1889193cc2ffaef1d309d1e1e3c6034206da7fe0adfaf752238cba2c21e6a94f401f05dd646fe059f2e11d748da9b27faefff1ccaf5c1e604960b66f68774b64370a2af69e6257172150efa9e16925b8a14b5736849cdaaed1c5325831108c302f8f2eea5bf5bc10746144bdaa6d284e5dfc1d9a892665b4b708d9a8491878092c79088a72a8642e4e1cfb2ed978660ac68730950cdb4e5de1821750d058005a9d37c6e3fe9f286b569d89391250a857eb3efef7156611bb9764803d44bfd4d505bc399d44953e2ff5efbbaf629532eae8b822a930f14238619cc6dc292f9aca6c408d17153afd142e6e46e9267fd1bf1656ad1bd10ff30931c38d94ecdcaa9d8fdcb9a3e01248e341bbb60473d24deedc485a6efe5934596bb45ac9194ab00bf60cc4c3ca088c88a1e53120f05cc04d207d284f1bcbdf5c3927c162ebcd31add7d295e68d412051c722f98bc57b7e06af86dc28b5c4fd80901e5c08029a934d5a58300edd4e07487fb045d04d939ba6033c200b461718099aa4d6a342f10970c10b414916602da85208b55c4cea64412ed3007510a09bd40353f2de4f90286becacb8bc50ce06fe469b88580f53ee57b7bddbda967b6f29a50cbf0532059c0546463cae0f239bb225c51045e4ecdc9f1ec51d398a48355c1a612e8e56710a868a15ae4e520b42c5209f12491cf74512e6c791220dbca20e1f4b37770acd060dbe197554c53616ee958a38221f20d7aa4807ac48a6580449519eebf503c51b912fadd83756245ade5811f55ab87e4c45bb245e90fb83484491866866abaf889e1288bb07579cb1566c51f6e5e566b540acb7054a8d29dd24a4228ed0de8f6b37a453541b0a31a4cf0dda2b420511d143449b0b341fb122dbd2e571e51a91a25312fb906e088df8293e09e9b83142215c65df9e511062921e666d25d09ac45caea58fab2293149992a804c94fa8c8f5538c4ba1e31e4911c215d2471cb20717a418d6c3441b0f5ab18798fbb4acba2abe49b933943648452721b39f1828745c351421dc157d327b45a52045a01e4d6d6e08341749ac28b62c5a5d6d49c9286f20b948848a7e8a5d2774dca31321f8fa8a7b6e8e20ee4e0fa291b6e2126d895890a50b73e5e249157994c52c2418427d3f7f2674dc33132188f421d9d36ad3203d6dda03c82d2fadacac2804b6b6e55255b5b928ca5076243e734f0425f5bcd33768a8ef37f7defbe1101006a46603047a45a440553c1c084a070562aa398186764c209e9d0d34b3f3c3b7f343c7639a30fc23908e8e5459f1b2d1986304fb63a6b3fe78e5a83f38c1136df1ab755b684f3a1f361ed4874ce7f4c1ea3159b43e43383e3c3b3d486886c33fb21dbf3c6f47aa9cb160ef4f8e1fb31faca7f767e8fdd9797f60f27ce85e1f36950c7882157cf25132d5d767a8e7d787c7070649cf5b48e721477be06c7a6eec983d3f300b0b2f3a656cfeb889ce39e729cb8ab241990d1ebf8e6c8b373c45da3c1ebcb61dbe8e1bcfcba3d691473c156b2a2e20ba123cd9a74dc1bf76de53b08bdf9e1b1dbf3d70c59e2e8ef5d4916952c76f0f10eed9e96ac76f4f4ccfbf8ac06c08c85f922d6b66a9c786161990b9d7666dc6bc31418da01dbf3a6a48e63acc39e79cf3efe823eed84dd162bdd2911bec8ea257f6f0c47a9ba7c975caba6c1378a6ac8b46d5a0caf1d627116802c2af0e57df6c09191ff3677cc41f64f7abeafeedb2e0a0e201e660d47aeda6310495a13e6615e3abd384225521b268edd6b467925c6b1ab96c2db0e357c744776bb4c18e5f1d111d694ce9f8cdd1cba1ebc8e1ded339cd38d5e73651b03ea220d7de66774d3936eeb0b0f02fb3ce794c1330c605cad1f0794c4dcc08748fc50db287c1aef897db8e5f9cb3217089137683b3a4c1c1b239e9f8c5519eb51dd0bdcd8da63c4d795412f148cb3b7e7188da76f8c38e5f1c9a7ea643c529ed062dca90735ec4da1c3aec1bbd9fd6668a737e9a5bb7edf06fe03af2f8f4e7b6a4ce98b386131c3ee75d3fc00e2650eda4bc986cd18edf1b17473d284fcf79737363de84a0d94a6a8cd8bc367a33dc681a755e9ba9fe1dbf3636fa858e5f9bad8e54396369549d9242fac04fddd44df706dca2827e17dc8f1b003ffdd48d41fac07f79007ea3916f60346ed0f36e91e89f6b9699817e39f526a1e69cb9e11787afeb3727a96b15f8df929c57a062adc200eec5b193e992d97a65b0360080102c461ae30c96c391139b734bb209a1f7f2445457038f2808afce04281023945b71098815a739a52941ac281ea018fb81622c2e39c3337091b1e45a2493a9e69224a7e0924b923a8a72122ca42fcf2f093703a3dd14f14a96487270c09b0ca1e8e783a25cb34cc210b1c06a4afc4657231be9ad9a371fa5538a3b29ada4a48d9e11a7165a475a74489358fec36f36b14cf64812a0c826b922d952d4972631ca71f11424e5e63502241d5f345d772a5eaa8ea2794c5ec901140d8bf016a6b34b6a252f1469261bc90e8ae2c8924761c9cc46220986d97efc8dd0599156a44a6be9450a2f6d86998e15d9100c0e5448d3ce4092af1e73c92caeb197177a5e7535667d256a207514c563c26dd9cc0cd729a0082cd995744a8e30405156d267a785d850674292c444a09268918b23c097a7197743b6ce60fe72e02813c283c65f18179e8c137ad704824e8e0efb21a08f1370d3fd26e409e82308d628d6ee3fb18937c6287973606161312e5be4ca87e6e38ddbae47a858bf2da83a7e5b30bd517eaf8ba1b7859fdddbc2ed6d11a63fa778d0dd7c164a807cc1dd05fa38a762ad5de46abafc83a9d3a9b37ef2fcd4e2770aae033fb739841564dddf289e7eae67366a3dd2f4c08d626dfa48e0f9ead9e296b3d5e999ae40e2d9db13bc92b2c0cfac4b0ad04d53feea099cf30d9357c037fa26ce5b9360146bcdcf67c6196bc62de38c15f4aaba5a055df5116f41c084fc6a0b24e2de616f30815027a07854b88e5cc1787ccd7a08baab3e6e2356bbdd552525b69c8832345ee50f4cbe910788800979d5ec04703f3f3dd3471f7866530bf9bf2bc63a72359fe4baf9ad39ec66faa8cba9b316eedc79ba9ebc4cd52bdb04fe07fed2734e53e4f9e17441ac7d7f0ff575c7af4d930d04ee0dcc664a7ce99c68aedd74d537e2165be5d63815afe907d5340b5f15be4a0c0a892eb857c0345fe80adf7ca12b140a858f0a1f7da19beae3bf74f581cf1283df61bffad2814410c39ea244f345cdda0d456fe517061f77164551f47ce2078daa287aa227abe293ffc9b22e52f3f4f357d03db3acea7e78966559e2aaa2af6a6dc29e905fc8ba983cfba65ed119eb9c49c82c4a34f99465f50eab51f4eeadd63b1a886d5dae47e4cc5156a4e6c9e09eb8c816d9667745591f0575534efe7c96e50206f6d1d73b28e7ec9b98fcca9e404466f63564c8af7217e5831aa5bd00dc32219e10452076d047f357dafc3aeb1d9347ff24e66f89ea6be2197c9393bb27c63add1c4ca1ab7e481f7de10b856e0af0cfcf6fb62ccafe7316ad410c390b5ed4d7372350960435c822823e9ae819063bbfa62d27bbaed2f1eb74d59ba2ba013a7e99926ef4b5b7af59a0f769e855cabdcaa957b9f32abb56b90d67a26f56b91cd4da5d7510dfac71ab9c5e09721dd4fbd5f603b059fd5c3f0fc2e9e76b5e47aea059e2870c3f83ae3106ad3386b81c02ff8cd41a5e67780d2e5277e12ad7f305a1ca75d65a73f783f033bcce5aa341e49af741ff0cf607f5cd0a875ce976907d54b8ca75f4397739df7c73a1fb21788173ce6e9dc15d831ae5d1e75aebcfaf6ff44a906591e82357b9cebf65db0c2f6cf9c90e6b77d61a70fdfa3f045d645eb506fb7798e6c1611bd6f7eb9b9505ca40cc441da58ffb51887a4aafb46ad72b5cd7eca3c4fc18d0efb0d90bfb511336fd6c9273664dd6b8bd065fbff0f5b0afee87e0f3671f0962d88569cab2423668f2dc8405ea481d954f0cf11a07020902fb21f54e67dd02ccb420863d3f674160bf9d8eae71acbbc6e504a0bf6a0e62a86fd638391da5a7f4f1d43a6a8ddb701a0851b156b1317d24f2003d7399ae7fd5dfbe50f3bbe466b4d162ccae4293dc57dca273561a75cc77694cc3e1331430803940601fa06f13b79da1c0011158504881031ed80065a857ccfec1b0e377c945df1dbf4b2cfa998a8ea247e426010ab2a453bc5b92290a41229537f3c3edf16622ad3837a6b45cb272d35ab8424c39492291201b152274a89829fef4b94c7a6e1248b1062e6d0d4759d1889718964b26e54239551d11ff4e14eb94487429d5bc296141c41d1284288e040e17edacf802ac38228be8f702ebc9a543729d525c25f5cc24dd1495fcad3032764725e786b5d5b001f3f2d82ac28821054542c96b28eac70d29670e2906089feb4248516bae98a483b8e4c60eb1182e37a7aaa813553cb244dc2b72659470e15ad821d24208629124c514438ee85c203b70a81587c8de2e57c55571cd4571a989c668c8448ba3117747346e7e4af65cb03a17058f620cb6229a99dbf3e5a69051cc314544a2cc6b410f851b288aa2a999f5f475c24985d75c1beeca8bd251f6cc61cd20c093064a13786d5c3e6220e1809223582e905e1e3e4b9ee74a2e19502b8ed8baf08a4000c38708b4afb0175a297762d25a644c48c2b2eaa2d67c48d4488bda79334a9b5660cb8392f2233b723b6186520c10a39fb8bc2894e9379b0f15b97d8dd0667488c4d570090196e451d3676494755a4d944fecccf958536223a4040fa9caebfbf9fba1d903737161c9c882cceb85981fdfb28388f7adc889b12827302414e32de993eb889f0a09acb9c8b9536a31e43482913b311d76304a3874702fb513258d2eb9785213371f18a49a1a20da43d3fbcbd13763a2a7841cddde138d9e2f1b0440daaf578f900438fe8a2879ee7ab8e1f72cb94c6b6bb1a4c62b6582b79426dfb98b8aeca2b5ec828363274ecf4a4846969c138f0d0c56de0d5813b005a6fd069d84a51d58abbbe3199206276447030c2c272ae60f6b09c35c5aa5477c895295dc91a6af9c97242d258db63e19265044a146e632a7a3a790349939e79cef76d8a2e07d728e53b365e1c81217673c706e34e11c7424c4fca658c09475e9c84a9d73deb6ed0795b8726c5e9401c0a373a603c791177d02a8a11461048990a4aaaea7a5f33ccf353d5272a3d503ad6aea46043fa69f9b1b3523992e98fd76119970a2161b4921222d2c256073474670dd88190d31c275d7cf778984f3a1df388e326f34885405798b94a13921e0a67cecdc6c84a9091d6396540ffb6fc9cb120ae25ae0d7f12359b8d25aeb9c73d63a6bad172044be3001bb3a2e018f999580bff23a2e01eb01e9780eabe3df917ceb9bbbc26e4f1de378c365551d9399758c43c75b921c965909a058bd81b003849cf3e442a407af234c569680323d376e002a8e43024053766262004a24a88067c0c4f415f4e7ae5d640a6e982a42a40ab44e8256deba6ad7b1da0e0a912d38e33d4a404b74ec72a6e8b8e3c76c0450a034cd652799e6364d739b7b9be6dedb34cd6de63221b2ef181dbfc956c72d3901990f592d83640a6c190956f1d995d1189aab636166a777828e07d9d9cd03b682a41ca8efbdb74ef40c6a352a7eaaae91ab0a32b2bcb6527cbe5b37af5689a4d33ccdd37c6718edf5ddb21c8d79ebd188b3fcba49c7af56cd12a31019595e28b62bc11d9b446f1c96034306ced052f86531f9a0e1483bb246374494776766a2f19fe53a8cb1229d4ca530cda1699ee7e3997ebe5922b88c2432ec54ab94fb782d69d9f841a2a68bf7e8e4f0d3a369a1c486921f32dcb0ea50ce63a4e33c2949335431c65e152f5e2c201c6e901d01d93a13d2da1dbf587359dbad0d47501f1858961491201dae8496d8f584050959d905ad8c9c70126e1a3a7eb1cefadaf18bd5d5c29bf18d4dbfc6373563dc7bc5f65eb9bd56633c7a94808be0afb9d61ff47a1ae34cb916bf69be51474b8a07fde8af803f1005b704dfe4afc20cba7e733dc12dea9bfabfa74407744ee4a0e3ad9e12f15fe7c4140f2374fd238cb0b74fd513d5950ae67cc44631ee48b9888e1c765dd5d5f59b6f15968a95a975fe539bab06fd7c4d9426e10db8234d3c5095c01b70475de4495c51635aab41c727e859af1af4bc350ce38d1a54343188c490ebd8afe317c64ecf1d08cc0fcc2be8d4041d99923be894ecba401f814117c4b0e3c7bfbed1ab05e2073e4ec1cf3ff829e6eb6607e2fcc0578344e358f0f1af0f62eda9ca895b17e823f039500da604831f4cdf18a345aa60e5a88ca557b672975e09cb63f92c479dcfba48e37a9ee7b9aa7bc5a60acbb22ccbb2b9b3cf591258766d51861be89520664dfefcacf2018b08fa78be90d80102c4d4aa151283cfaeeb1a7cf5390f06553e6009021fd540e09f41adb23887ef0bbf772a4fca4865ac5a31cdad43d0fd437e8c57f223cd3f31d61b6bcd7a306160320c8c5ea24a8df5fcd8a85f29b6aeb58bb1ace5cf1fb9f6e301d03f5114a8d3d43481b91bb9b692c2eaf875d1d591c7d7c553efda44f1de3b1f8fc709e00f26eb726e0fbb7d93a7113efb994db140fb269f42eba6e0a67b838b0bdaf7e33f17137047dd02c80433ff33e79c733e41430737f8b5d65aebcdbaf0aefea6da547474db645dd0aebe6aae26918ece344fd6e53c33fef33c5d4c14453912f3f1a990b22ebaabdf019216f8c107b22eb9abaf0651347dd5453fed28aa9aac9bf5b0ba1823407599fa238ffdc8821238e8e9bb708072d05397adbb4853a333305f54bdce9c30b945cf6f46e116f3b37b72d051d81c4e18bc417f9ab6fbbfe38edc27ce305147b4363ff284d9301801393f6f3fe5916d3ad4f0f8550d440e7883fe0c4407e00dfad3ada28fda037cd4afd16ee66c12d1ee01edfb1d304203708bc9eb1701b7b427afbf05b75c78fd20e0160c28af9f036e01befe15dc127cfd0cf800b7acafdf830528e0370714b60a6e49bf2bc323f1d70819be9b68782171e986e5011ada130d8ff218882cb41df817882c0c3bd05dd2e0a67bc30966407e359f67cf40ccd0330350c88fe142fe935668d2f3b3edee2bdaf30779cf0f4c4d940bf7770d19881c834eeb54f355937801deb699bd00fae79b29a06eeaa67bc35fcfac4bee262fa6ce38156a13cc0217b5ef77514df25fc7ac8bda751e6249bb2a96244625f694c5927afe1405635d798a3fe9211a409bc6cceb67be76afdcdb860a3bc07beac8f5a893828ca9e397ec4447e68ec976cc3ce6d791e9585ec7701d69a667c7ef585bcf6fee31b69eedd40e820055270ee3051e82533583c8dc8e8f34fc56b4031395a45a6362c1340c33abbf18be22312a3086d889f9b851f103d675e16be94451144d4d1445d13357b540f98a73abc8c15f108513a30ded865d5b8714635a693855422ac28abc344099b20733ec4a602d797c7c40add059faba63a154d385de99e78ffc8264b6f396c3472c058c1532ca27b431b2be28962f9b74ea749e67eaf4db6befa2cc5584a24c1180221254d30211974f0953257888b24228b10afb3abb829cb9ea3c43503bbff8c8828c88e1fdc9806fe78e84121c12155892194bac72ea84ca68be7435785160756a2a8e98b448982599a55803a3bbb0d5b46d94b822b2646feac8006ee4c839a3e1456342a8b5b4c55e30a12f462efa9e96868492652d633a267ac01c29bbc2762e6431857175f4ad11dccb97cb60425fb9648033bd9c3520426d71332bf8d2f8443801411186a465699b651a9315f9bd6d6a6865332d50fad2110115d4f58482c564a24b2b0d5dbcf2ea0aa6c9d38b6acd4f6d2364243569dd40dae211e7276326c411e5178be255fe409d91d791dcd4d31a108c144596476a6c865e9a137c239d5acb3cc9e94e0b4993274a7a177114f52aeb68aba5341492113143c0b6aa70289d5ef8e051a3c64d9712146e951ae7f84ad8d40dfda8f1b4bd608ae959a3a90a8bbac0ab98b60aa0548e0c289abcd139c26b5a31939303821a0d0e4e1fdf5ad109d589eaed2be5f2ca2c870820377553703d6b56454abec2eed6ac65bebd508a334b26e96501c0086aeb4d085755727996f2189b73ce7711e79c73ce39e79cb766102050c6799ee79a9e49a094baa51c1a8bd179e1e3832a052c298b06168d97cd0406f61231c4c8da8811468458e044589b5f1d94ddde8bdd12a44429c5d394b49684b796e30396a2ef6f2f65d2a9172c1b5b6b55543b4a3b28e004b30c72639b81d2c1b9e4805205c083c95a7146a74411821d5b457d42e6864c2ced5817e69f3af85681a2288aa2289a9aca269f246240404a00e1a5db8bb322692d84c8328a4e136a69b9830d733acff35c532d209d1d384841c2f48062769079fdd8aac132697172218dc3c8140db023496292884c69657e6e617676613cd60cc484a2289a9a289ad7d1162b3b754f636633363f2fc8316327076d091157570c61d412fa69cc7eb94c9698f46ec0901d5146c696cee45e80d676ec25594a3af180a95de02c9c90553dba96048d80ea3be6789500437183e96bb96372a8a5bc64e32b4e140889c31194d667c3e6a54a064d792724f7da7cf10993049306a844ac580f4aa70cc208000002a3170000200c0a88e33810e4300a876bed14000954c23e524828104b45a1288c821804422006a1000001100080108661100a252a521d06decd6c3ff9791fa6a9bba3b2a478ffd7726006fa3093a99d30b318691373455ad3625567aa0d2038bbb60a56848bcff57c91574fa9394b08e1a206bbd14d392a8dc5e0cf2a5c454da2bbb609d39e91f61ee11450cac83449490daced7e7b5ff3da60132a1f73f722ca3748aa9a951a7b94e2263045b0ac49eaf03ac802067c5555d88dca2818c1ee36ae1a5539d82154c6a4009fb19e5972eff18238266b93b96dca9cd05dc90ec458016a1639fb89eb11e10b249e2e62cab6d16217144ce41eb9da0a21e7b5f9003eb18214062976726bdeb475969730025e8c40615a897852473452f5167b817d6efed22717a3d0000b744e7e34271c61a5267d655d9878ed86e897ef50c4e2f9143593c8a113c3f821652e2b9305e6cd21e5da9c5e5f8b9a74a80b65582c857549765c1e69f7ecea682fd464cd71b2f17b8d51cf33db4b7941df2401b1b869848ba894aa0a39317afe0040ff3ad331a4a3b69725a88b99876f7eb8076615318bef1fc51df027db6e9aab488394ce89bd6e3b8c48cef1bb3a4acf131e4e40c663bee191fc95d44c94c3041f5e4d35f803f6e620b6d0bfc9ff3ecf7437421c505435f9e06a95ba6459de685d23e2baa41e4f5ba314922d9e43868eb022571abf08002b8949a8be8c76bd630d53a74fa5cc99fe249db95f9dcb70a0b1e4a4ba6bf65595a4ee7f8c08dd085dc13ca16de8e809adfeefc376717fe8382af313d765aed0b3cacb2797e41fad15ca04ec44c4d23b3b5cd2573763876215ddf97a3a2137ce7973c16b331d9ae85f6b4d65329b183ea34c4703c737d6ff55b39fa4eb13fc942f75f565ea0e6e215ac3f7d642c0137fde5b6d4d7648012293634a12984cfdca684ff2adf0e9959605d6496f4eae4fea6f7f0b93ee5cd72a0ad314812287b27362d90dba29f3740be0ea4afeab38579fbd828bf24d939ea455b23a8a83dec8427263233342cca6a51b0e8e1d2be97bc9cf5c52bacd662a62176dfad09df53b3aa923e844e08d9dc05618952514a7ca0eece5fd32aa72b9307a17a5bad71e5aca36dde6cd2c4f350d4328dd0909a5895e7c51b23f86295a825d23b601c49f52a1e1911ba74081524cacdbded277f8c303b6e50c16693dfe65e462a3bfc6bfd74d3758c2899cd52a59d7a2a584b8b02542c9f2309bc3674dd900a430d1412ca4adc521814deb69194459eb29b5c899d14a3c6168f0c11822332ed5fd777fe07ea84cf7ef1e100c27c46d659a041e943853ee918a861188f0b64e464f6a4e5809f2b12250ccc4a4a21ba55f7a3b21142507d2fde961b41e0a95046978dd832acad1bc88c412f8d9cac41b8f420712f8376efcf24851955f22c36809409b4a6bc6ab4a6222c2ff5d3abb178e92ad74c00210c6b4d5ed063c4544e8e5fef147b9ff4745bdf83fdd16d24daed101e86e9714070fbbf1299ebdbc3837c417d86950628bc62a28396fe16766e0a519b4f6b1433b10f604d896a04183c8125428b0b3b92c41463383363490b29e1bad3f1b6dad102752824eb6594e36e4c932541f5c3606d340290a206382774966363d0fbd12e3af1146d1acab4958e5cd490c63217c33d1eb4abf3b127d86e45b14488db1e10423c59e9075a0ae0eab622345528124836d6f040746555ccd0604a55ee6884ac22fc93bd91052c61057329b4626ae8cfef39d30a4e437c41d02f2bb7e94dd51cf144a742952004ce7e49a9b568222859127c579bc7e8a4882cabcfb92542eff91c6296740f0d833945c9763c0184c7eb7e75712144b8ec02e48a9d70b901183295c9229d49f804fc8b4bfc5819b978cd5b6d40e6f93eb9890ac31f896b779f43884a3498f93f9042fef5c7cda922558aa8bc7a80c28c7b282ae793b95645ef2f3cb1b2cdf7a7966c0bf63ac9bc1913446d015a133e1834433345cfd0933212e897c4d31ca42a0c5e44fc0191ed67a165698d51071e40dff3228ce27ee0173d2c67a2751ec3f2cb457a00d0139e54b12435f1f4532d133abca7adc668b6ce3b79ad1dbaddc2a2bc9f0938cdf914a5ca71a4012c34f08c1b28739027c493d697ba776c7813905240160b5fa62acd9c49eaca6bd95596042482d49a11bbaf80fce12258a933095835ee57a91a46c45566c884389999df2eb7332da8291a6cf0a8727194757d9f44e4d64e11f914771009d13c614e1f424e0b874eea58a88b4813d2f7e6fe195dbe3d60889116c8218460101f010a4945f1f1989225da55c3192fec2477dc6300ee972490f85789ce595cc70517738dff0d2e783bcd052ec222699a8c9a34c65066fc3825826599ae8e4c1fc49e533cb966435171eb30202ea4bb0aa0bc7a800a8c7b082ae78bb2bc958f23765280cefa93262fc6adb4ea6e1b76aa55cdce42ce623faecbdd40e033958a6652457aa9ac6d5854671193edd6a82b703c974360c087ba68a050a82478264fada719292cf8ec285cf92b35c41558cdc953056fcecee12c3bc4d468eb52e0e30b09712aa5d6a0f017d128e4c38a4054be442981a688e6748f0bbc3fc072847d66e5390840c02466ad58568369a5cf6e10ff7a81ba8babcfc4a3568daa4c6cdf19325a36e5e38560c6fc38492c1f2bbd4e303234e276da0f1ba7b894ac823e233b4719b0e04e81fb422391bfc8e7d0621aaf2990354cdea48d016ce4c156928125369c843b4b9f018a9997009f4edfc3d18f83f9c0a16ed25ece092d913fe767c982be1ff1b5b0e5f0337cc4b151c4e81a2f10bceb86faec9e57ff811a084b5318cc09ae27384e00340641432abcb72ff895f402e7a9e59dd0bbda4d728277b0f81174e97f2816190c59d5ed341eae031ffaaae377c60f8f2c1fdaf28c2ba53cf06b8303e2091dd1fee26d0af8868ade8c23d876d752cdd7ce8d8b176ec5fe62449b64751426505b97d2faaae293e85f2037f08c4981e02b95ee2a902714c6c187929275432a36525f68bdf054aa38c8ba7f83239778a4bc4c80f69190e08baf89d4a9fd101ffe9c1b3d655b2cd2056901280268b410378cb9a164e923eb320d0403e724afeb0554a3fd868f68ec64498269f4ea81e86af014b20016653a5a57c8a4b500d85f71ec88ac686e6de3e265427e1fb9cd5aca43447bf0773fb132c35213b0d3e94b88aeb9106e422f6e2b3cd0c546f331b456ab668436281d96c91e9e0c4cd0faae9e4d67f90786fe24e14f0700f0f729adc98006ee8b5c86be636f11dd2537674ff4d0a2760e3cac2fb0b92039fc54f33320f8e045f570c8f4b0e964e8a0a21251848ab9c897aa65a1dd57a16ebf295f3279224835ef91ccfdd54f64a0f5b678d39e3890e3612fdfbfb414e73a75d140a9cf858d872c7281cc9af21a10255e6c959ab719eb595131a2f78f8f2fd2eed28a1179096fa1b4d4320099377adfa649ded02498cdc4491186731a5af906069b1987e844200c980cc9364072d5e7b5ccb01132817ba6a5251e40813c948a9b38a6ee5da5f60598d5f0226a890e493c2cacafbe266f81834ccc85007a75750d6425a861d3c1f2dc21e3059de0735663e424e6157e519231e6b28ff10b0853e48bfd1dff9a59622490474b72bb48b91278cd4df565a9a11f79dad4ad9904064d54a735c3560669394fbdcfebe846640ce24eb9eb85e288d909863fe025d4ec042196dd2dd3ef872d06717657e75120af6fcc6c0b964f33a494e3b862f675929a058af1418e6237b28041b1843e19f719239fcfb0d278057adee136aae89f5649d3ca4c71cbabf450e47765d0b9140b5902b330498c3c083d260742fc3c3ff2c8679309092344dc2165a7d4ea1e48673083cbb731eb2158a66e5cf5e52029902b82524d6eb4ee021a16c0c704e3b92c7bcb0820e9a7392b05c85cda1afa0206220729c2dd9ffbbcce660b03cf0e284e8a9a4ebcce514832e212e49e448c2c892e8afc80cc0a08cd84b90d084311e41f7180189ca659ca47d153776ab343c735439cfb6c65cfe17d2404e4672a34a6e076690930b76bee4702eedc06cfa1b1aba10b2a6040b656d80cf229481d31224a4ccbc7ff47790258213e61e41a9cec74f78606fb34a637d009fae71dec156c45620d42ed0f4c2719f9a51da63aadfb8302895de36edd7638d921be6d4082fa3d3d00ab0470a7b9e89535da773843679bf981e40beedc6071159b4bc3322fc5798003d35a8b32aeb2d3c696a4f05a3b136fb553e58f248dbefcdefbab27f13391f5d63e9e2c102f4aa3098037cdc0158529e147a04e312c774fc42d97e7a6596a8e881eb1231875e44f2f8e4064ab9b53a77645a2b08143401a9632233c1bee71fab1585373eda48e316dc2f77d5ffa2ebee67fce7f71bc34a19fc5231f90dfbe42e28859dabdc8c4f2d67e0af8fd5ec743b645996f4c6b73ca187b352bcb1dfcc7a58d9f768d058cda7ac82bc4e978eb0d66ea901a43dfcb1b09432ac9787306ca2872ce3b2db7f38837dfe3b509fe5cab51cf71fecf523518b389ff4e0f62025297653c69b92c2f90596be8285601ff8f3379d847ee179e62a0cef7cab723497482ea97c8c883d6c42554ed530dae30ea907628f4779b2f1f9dce040cde18d6874c737324fcf50bf451846059cf795eaa7175c94749a0a36053adc1d6b4ced44505f021f6878461731e6f9886b03f3117fbfa1bada380bb5750d9d2ac46e549f0a87818ba58849a5c02796bd1ee3e10548d901b1433ddd4481e0b08fdcad21a4a2fdab2749af4c9b2ee6f4487dc53c1237b306037c49a85f3f10616daa6b5cd3b0293d82f886aa7a8e58ae7802337fafa096835118f2492808e4378204abf8919ac8a22438c9bd81ebb68889531e54133f591f6677a434a7e9f27c2a92c98fa0215018ca7d84d06865bd555c18e586c777a04c67fbfb420ee111e70cfee2fb6c6d84c955419e5295b9c7a4a4c77d2b8cfc5f3f9f37b19f2560863eca0d05ff5838454c8e79f40107b60e3ace6159fc3dc3e7f0bae7ccf0177ebd6b08a08647f0421806df210c10ec28953485210c3f8ac0cbd98a379e5ca9d65aad072117b5c100b87629bdd6830aa510862ffa663322b4f60182e13ed6df86cbd10887c62e51a314c220619241e9516587daa7c4ee4960135062dae919bcf2b07017bbbba63e21f3a7eeda3529fd36fed3e6006cf5a9673033cd4372aaaafa0a91c28e9117fe5031c8b8511918e25224f64d37bcc1cb8e6d58476a0195c2a0c20ce55ea1b83168aad4839b7b9eb80a8a124848525a53dc69947214dbd9c3d8181823a1b051288f0a5bc031fc6cf72320da02765383d79690ef1b4741f419de4a63ba638f5c3467aac665caba5018c15db93aa62a4afaf5dd2ad8ea14072aac801d105f41f3c981e7f79505d254d582a7d3cd7b3f83197be696afb1471d842f5bdc32eaaafbe6fc7cc3e660ea6c4cebcf63b80101d0704df09d39eb8332795a1daed33b6c045017a74648bbe17bdc2b4c0a5250957dbbffbac451315d8cbf8c390d0bfb85309212c4d09e16591070a29606298c94cc406b53072390771e8777c54d5e6135e445782f873f9b300552c852197d8ac883ed32180f96f2801e60d79ea82b43b7ab2e1d94ac069757aa13fb357575e9c07dc4308191c9f90f68b4244de236e9791ddb0d0caddade33ff479b10e52aa2ea6d16428b2f011d464c109b2d4298fe36473b128b07c29810018b03dbbb12b97dd9f003fad5c6c4cd6b1f1088b1223a4159ad9367c7bb82944ad304322600a6188baea373f4a3ba60c014634c8a26aeed17803b12c12f8fdf460cdc35fa61274095ead46a1e07546bd800a34ad7a6cf033c4b512acf52116080c0a6c614c07ab8ec43100e59479eaf2ed88800c115bce95f17166d76b4c3c12245654378227154ee01fc1ef59b916fb4600ae60519a466a4a8f44c0f4615831a5001475f8554bbdd14b5b27786da434b274bbaacf62ea605350059e25dfc480bc51d4492d615f8f49d7581ff1fcfab9d5883baf70b1aa6eb8cced293688df06359982fddb76ab37c04b6064fade9d25bf010c9566110aa563b7aa4ad714fd3d86e9bc22e05c1099d563f3ad2b5d16e7108d067b961b936082b28e83f6b00b3ed978af2ec70b8f2c2f0ccf9db1576398c120518f4182ce2eec0f6d2e6017f10883c2da30952d1bc2f2a39b77bd0fa2c4d5aeec475b6456f9ef9e67e1c2d0297e7d5f66678091857ddd3b22d3698f6fad114fd414a80626b4463cdb54f305f0fda58a2f60d199ffb29404acf68efece3e52d2426a5ae19399e1072982b91c2164853dd3b478061717ae708bdf050f84cba4d0c808f48d547cae6f244a02a8c2a6d0520f151cd807d51b39d6d75e32d660850d466c6100f13f4164d7f80883ea003a04b42dad1f7248b7e0114f3fcea36031804a511112a62e52b04b89bc03083e343268fd4d05b61db6f06c4ae488f66ce60a3ac3f19bc6dba15f22bb4879bd1102b44043b8c70b4afe49e4741495f79299a95a2d1d44afd433c990e523f2dfb85de92125d9f451054f886149a06c8a6d529d87908151c1fdf9d9193c12f573a63cdb1124ab3b0c3cf1e8a502ebc31833e64c7623fa47ede3cfacf8480f01480c3088360a5b6a84158862478fdc35508010259eb978a63c0df0fa5e4e023ec86e5865bb62b5fbdc7abdd09ae43d77f5a098bc274a9823ef774ad27b9038dbe0240287cf481fae265471f761f834d8d9a3bb5ef1b4c2c10bb2fc19f5cbc1751901da151512758a738a8b72032963cf202d49240a72e5ccdbc059bba7a3791ce5360e6ec477b7435a823e6881522cba58b4d70cd7dc9b11762220c4c2249ae23a6a49721d5be6b96166d66420942b1337664446ebc5ab3509e66b17d137da72daf29978c9a290707ed79d61a9e76160cf4b406c17924d0eb6bbf6c8662a045ddfd5ab06c90e9a520e24b06aba565d986c02aebf67e3c77c5a80d845f386d9267e4b9497671f529237434e3a85f45f9ace27edb51e9b8edb51de0a3ea401d6558186a2f6ee73c3c1dc33f1691f2c648a6b7a3b600aa31540a72adea9f05fb9f8bd506effd5538c57202fc4bb276fdd263f272a1cd9dedfe0870a0dfc836511aee2d74839a71d752b428a83faa22c1d5b858dc9499ee084008f12aef4d9d30f89eaf8b78a5976d58b3fb84347133ea3da9eb2ac0ab46cc4f475ff9c52e0cc556be15a70d0689023d50b0716f21e85821b2168a8fd064ef079dc82eeed535714ec8929620ce92619a5c8681ff0c14cda98691585475da29a15a38ce1ea60d663a028d0c45c0cf0758e00d0ac1190ee278dc5c0083b901917569befa5c07132d7bb1d556e82a47d43b9fc46b30d8602f3b6c4505d1e1e1a412a5cb481061fdd38cd26582c386e1df9754808c03546b41e0640503d1533f75ad1e74b943a5f3f351f9cf8f46e9c343036a6a0a33d2e589fc035f0316853eb8a1dbb1173ae4b6ddfd3d82574e7f7dc3eeed2e4f03ac60de0b14ffec6eebc9197a79411002b91de88dcbc7a426aa6748cb4f2e14830229ba5bd4a505e0b7d2b0ad1fecb2d7d7057cd49ef167baca5d9e1baaeb419cc6891dc96f63d17ca4d7bbbf577f523116ca4e631cb6ee099fed5779996c6f67bb05574c3b1184010e4232e22ca99dd16c9d02fff15975078c3831b602b3de0dca623cf94e6284bbb79210e4d4a772ac2cfd98cfbe34e483efac0e061064d3878800b71ede0f5c2b98850d3e210ac1e7781fa92370c684019f8ce48cd59fdc980536d96d8c6e0e1b71a3eed8132c90cdb931b604c99193cf659a3f41901690478893cea18b2c2aa4818e91449030f3bed48ccf3f121d16a3d5039b1d20de89abcf3adf7e7e3080e83e4670e3edfbe9410d1dc1298358cb6ebb79cfbba3266284aa80cc283bd63bb3f276f5562b03f13f013922da47f4bb8e77a8aa9edead140930b32d8302d876cf0901916cf87dc5f903cd549253d2b35c4e1fdc4a4321e78ff214317b2cea3b1ee149aa23250487811e63d043a2127cb4b1a40055056282ef2a45481d0500df65b6c327f560fbf82ab0a339096380ae393f6d7addd1d2274214be33148084d340f892fd84af3d75799a54ebcc506a1944a42bc7f93453cf12b31ea912b8c754b0847c4b90b5869859805436853498d5a1f635a74e7234be9874848d305861804c84be1b7518fcc0683733611ef08d24ef465005ed38675fa1b1fb672fe96a7e52ba9e4366c4f20168017655afe9693f85c6a08e1c1553e21dfbab9864e449511c56292a6657e7ea388bcd615e97103dfe02ce0e33121634e1c4e6b496180df48a4e2a70bf96a272323ae58e771d6b97546dbcd6aa7e5cced415cb661d7d9469a186aa16dd5a5fb310020cdb079e6afb8e6dd4ce05a13e7c3282b8b9986fa10a8cc74ae7375c94f553a9680172de8308a4c13dd1e39c901de59a502985d10825471aa06182ec743a0decc03fc06ccab448d7f6f52d603fbfc0f15853d1ab42dcf8a227d51d986acf6f7cc10324cac1c3314b9088794b80b73fd91eb2828e46e195844e4c89d1107b895adc06f4ef9f620758224fb6ba30dba71660e8cb68347fd2a614ba1129b0e8b5d6314f371ae82c827b23dd697bbf7d8eda2296b050b453578625928f187ad34bad1afd68ab38e5ccdcc4f3d3708b458dbfa1f1b4e945920bb60833666c08beda7d1ce98ced4cd47dc91e0e0d9a04fcf2a51968078b5352292f16c081cc82b7bd90efc63899ee3afe35c534f9eaf78b1f0b3e1a36153ec493470fb53575da7b559059dd3a5e4dae1ec0b5c8de7922981e2c6cfe2626c664da2307013804c37c153f109c199b147df6b78382c014673e1fdf178fa4e7554294b4530223bdb70b413534c81c5470b6389be1efdaa1f8ef0bc210f84941f9026a71b5b42e026804b21ab81f39351a91c9d10ed4fba95eaa82b27b91c7e458c2979fc26e5b92bcda7a9c9611a0d2c4b69b45eeb366b8ebe27de233b4d90de0de29e83e803b6b9c6bbcd0172a8b00d7e9e07e063c4602ba9c995b90ebc09c86c7ab9d3bff16adf12ac2431928730675c6d0bd16bbc4ed4e51485fb101a5861519e591d2b322b64b2f2749744e94c27062f1f647946212bc86af6b95910e9fc89dc696207014eb496f01c287388825c8d2ffa189258a1990551f1948f77a6024e685c06ec1ed37aa75a3259a8a4880e0579f2aae4c044325838bb598516c280e50682c4c43bfa9633f5a007e1e746bb610547bdc5d69d23ce0c71510ee3a5c6c7e0ac684977cbd83b8955287db7da12f1499df3143d8548579e0f6c7cf44e4f6e4c4cb5f7f56f02299d29016f404cfc18e9423bf9bf641831556c7882bc6bd04cc57d7480ca2be045a70222094b674eae83983cf76415708f299e3ac0ac786e6401ae34d4fb13689ed68dced9059aca56e5c361ce9ffc2dc2880fa02282832a74e8b319162465e985751b0c2513d77cf8b97a0b40f8310da92581982a37af52b626951c29376f85b6b2414f2b152500b9c1704a5610833ab5fe85bda6815bfacf247b0a0b1d926b015addba8e2aece83e05d4e057409e7be38a736269d9f14c133e5eee2dee92116b6609ad4a36b753443cc403bdba6549fdb8e8bf045cbd3838f2c00153f161b3712e6f7c6a81df88a4b6462365680daff0242022c3b5d11ff3285040f66e5372f17725041f6fce1b29ebccdc60c3dd986fd32ae34d6f85e3c9aaf4cf83f866a5252f740537f317e7d5ea4ed5daf5c00b0cf1ad555a728466fe6280db3e5e53548beeb15fa395ebb4d4d075d22d488d91d0e1077743d27122922595763edd1c1bcf8c52706835b91a3a63d10ce21cd2e3e8b217fdea281590c5ed80fd0c1b0045e5e98b074cdbdcea276bacf82eb25e4f34230c56dd2ad7e7ef91940406c772b188a9efd549f5d2d16e8891f81033245931940c25617fdeed82c65a09b61fd327b84415b805a9946e68a83539c9c52840e503ca2c20fe4f6c8b46200118917cd15ac604b6c21771de0a2530cdf62213d124b5e397373f32b6611dd6a6967662d460ee20e50b2f221df4e04d53240510c53b5e296d8e4012bfdca7c3d68b24f374157c52c154eaad0ea408bd68aad00ac3944d1d3e9ad631a0c1dc78d12aad6b4fe73b561a7af226b120a3ea1faecb38bc6820922d57c8f6b35eef4fe342b702a9c20c19dc9c57ce4b8706c05d35b775c0bb6c0a9a0269802b44616b562eb037dac5a76813d7a79237979f344ba3a65bd81cad07c9b4c74195597689be6fb85984279da42e04d77aea927153010b4721fc1944e25486178020810a556dcf554c84beaacde7c4b218cac5d9f9380ed2aa39380090852eeb38bda85dc3d3029b96ed61270d66a6b08d80341efba7b366ad1f5c3aab7daaa076fc119fbe9064c0ae73e8601811ab7de82468ad78d11fae33b0daa935a0d19b3412a62760851c7bcbd5ce6b08d082e1a00b222389e81765d0c2ddd4c961e534cab9f198a69055503c4339623d83acbef86c123b50d873676595ae4f03e3cb5d57833eadb30e4586a999701475cb858d38c91fb6818d2ffa1927b82f2376a82ff25ef987f3d8a96413d650cf2606115aa7a874af433be0cecc51bea99cbef81b462d24db028a7ade516203c9a568022d0e28706ea24a9771b27674ba2efd566881648722e214b28e79423e4611a9f02708826331a2aa6124985585a8af28756e9d8e723d32920ed69ca0ef511fe32f3d75a43cb223ba72475d097d9877e6f3691f31f0b8c8fbdb8863005fa708052080a6515fa814737cfd18415f2d9939caaf00893d193fe47b22e21669865e7dce092180d9028e0019e5e024ad7ac77941fec01662bd48b3d5eb4093917464dd9f5847f7c53b2a31d83b2214f416b7ae459016a0cc35129a0fb7a7a863d47145156d04c4bfe23845052f7af54f3b1578221849bc62dd420fbe99e47b9ebf97dcd129affc7ffa9156cf08ae8a57113959acd1e20e874a915b26e1bd900356d0515f5cdf0f133cbdfd194561864ceb7125aa12d8dadb0585a010c4635764198afc98da252a185b486fdfde5cb05bddf470d0b3aae0f80de4d8104c0b0888c3ad2374033a852f6fa7279990f0ab4b54a3970a678628ddf98ce02d91160adcc4278da1bf8afb656b6843e4a70dd850d909c1f5a0ebba989ea32c5c658cc5e627a31b550d4470a8cc3659af3b108983e16744c2a96ef8aec87aa7f852da6a5958558113cb81ea80aeb5de0a8c6d24ffd341e592c39cc3b7a117ac7326dab52b2e44aa64eca64d9786a6489890f717c62f750ac4ab2c3baa1d5eb7e4c2015a66baa59c77eb22ce8eb0026d4666d8dfdc474cda70b022b2cc8a366ceddfebe4cbafc4329fb893d2f073ed53641536c6f9d84f2f5d646d87212b18cd77fa211311ba78a112ef8e1a12708f39a2c2b191f83ed6683501c9fda597d9825bac133888e5783fdf7462c23e57379d7cba597b914d351f065ebd41d8e4019504094606efa2cf36996f4301a5817d79413f9dced5153f4092b651775440a84bb8b5dc88a2a92e28c38506ec493f7d9ef6237d03680c29f434cf6e64e5619102216300708aba5ed49de04320028fc4e8720136313667aaa539144b5b016a68535d2dd145090ece8703da4efba40f7ef839ed36f74193da6032d847d1cb79bfa5a4c1612c5207589edd03178669e6257ce0800df96048fd192cbf4113d4c03ebe21a58bb9f333ffbd858bb17001861389b778f70df16c0000cc171bb66137109fbb161c1b36ca346740467fe193eb35771432a502d56092569b3cebac99a1b7bda2c0685c6efdbe76cf5f44d6cc45ee4084ba9b26fdd888c5741a4e4da413d0ca0e4d47ad5a2304a3de56a2a0893e27a86df463c2b838c944884fc2cc6d44cacd19d110ff91866e3dad932cfeb714016c76119c86ef92f17e75b3c0c07e5193ecaa18eb765b66dd4105dd2a65885b6b4397685bd7250aac6e2ba40c339d1afaa17a613412246158cf4b0c79a4037b1364c07eb958bfbd887f932ceb0fc80e045c0a00ccae1accf81b91e0f0479ed7213970924ba692e60218b4364073235803e72164eaf0352fda09b2d03dbbc10bf5256287dce189511378f5e183bd4b7dd733d2a9f38eb2d0408d98709b896060f9f5348f5c497b447769c4f129ca95a2b1c5e6556ddec87e7247b44c61f5dfc4c48d1269eb402885766afe0da0f1ebfdb54bd5c1e0532b31403ebc8c24ffe2ae385d075cb0b574e392be7dccb9ba8ca0062fe371148f6f226430af9d79a92acf7a7c1d3d6daa4ef097b5210e0ac4ae11afe44d6edf204e3e7e0cba31b9a2df3ca501a4be3d004c9e67f9680094da1f7db79b9286c257ddeaa604c241b4e8712cc8ca28939b5f167fdda79b9df02d811c54592ba87382f1d3a8a45cc81cf6c4ec41cf3426cf916e88864ed2bf11e70216f6082bd4007ef713ac0ffe31b010aa4e94a5de06e69b3889bb214b14582cfac6744af291a12de9acaac1e07a2aaabc79cd0593137c7fa393d61e476e24099d2e561c1fe8ef19847d7a2cc49aa1098dbd164e39e44188221acbb9defbcb83fbe074d7008a23f215aa7a1e052ca81e3347356d4347c887e3adf37986be6669d29e08f9e58a81fb6fa45c037f1ad428bd549348738a20752061a2fe7ba0af0b5e54121063fb7e5298910e693f8a1a5c7449ab7bf6994620787438109a6db6b657264faf1bfa4d03405811b367e18c7ad50c5fcbc1d8ae79ae6e00cd4f47a4969ed92b96267bb6b7b2d158a9066217befb4c622c0a4a2ffddc2e40a8adcd085a59b1518f30c011b7986ea18629dc78f2efa92465a83f40b2c5d8aa8e299e455c55d81af78779d82ab0fbd5dd7b6ea2d648b2d6431c454513a26db370b291ecb0a52f208769411ab70e67ce1c245d1e066a0461db3f0957fdfc31bd083e5a58c190921683ba80ac0f0e634fee4a06e0554ac495af5be633fe9278d9ff188d2869bf1e18dd33b29a5e41011b08ae21b3710ffbb1fc24c604837ca89d557f0884b524bfa093bb14f2ce95b2ac0f977962d8c550ffd3e1b943ca477ab9622bf2f42d55d855439cb1d911c3dea6184d064ae174e0d44451e462b36516dd753eef62bc4ed1038cbd55a753a6a214f6b69efdab8a1bbbdcd726ec0f43a6ef98e189520ffac0bd22335a0fc73a08aebbced8b065f2a21922602f7d93bd909800dcb49510b911e1ba9ec4683acbf107f0211247d4fc703fe3dec434cc017c14d81fd083a9e27bcc8b28f6bda40502674d0153d8e42661926e80a791c0fd921ee02b0d1cb5baca27daef83003f879321d07a88629fb63261b9d327fd80e0797dd5f829a8899a7acdc9a2fb632ee50d68e61097fb967f10f79ae3f48005303c4b053593ffd74ddea5370475997660df1d99b9713b48e96e49858c8b0c8ba5dbd8f3d3f5ff545c26c5fbc4d9416467aa72a4f970b77434a54fba472ea722dc6647aa6b59f169812e8041ddd9cc44462813268541fb91114fd3a47de6a65a488528fb262c0a8a0232d012103ec7bb96f70e8f69f16f67f8a81a11606769df53d3552b73cb7cc81c7ea5586ecff45c91603d94b0029d44152630952eaf2ecfc77310221d9925f987061018cbc4148154b90c58f936fe66f0a9f44c77c50b20ee66262d3aea8fec277ab51c3fc967153f89aa425202a43887f24d54d9fe9455fb6a9e98fecc4438b782f75d795a41ea998243d842c1d3c4d902e5abf5f64bfa4d335b7232be9a20411a5bceed109b549eb46fe91b0358013be0d7e8ad0cde564da3b2bc3c9794de68d41c2dfcca8c340b7087f8b45f14de888b9cd0da3cd0b59907b312256576c0688fd4d9da9863b1c389c89c7a7674f5c8ec2c06a81be44bf1a898c2785b57860f12661d23ccf20549cefca2aeba1faf7dd09217d1945157ea7bd36313130008941002fb2934c63fc68858209499e2a31e936509de9fdd5d5e374b2700a7b0e5d680b7dc25c1d981002098e783a3501cdddf2979fd7dceee3a962083c2f585197efe876898c4e23728cf545bc0e6d1678a65bb78e2018b0db7cb8cddba3fe52ea860b6c88c745fa698435e80aa8a8e6e0c7bbbe7a99ab0ab6d0e4f19040ce27094df4ad14a996f64271dd2b5dc57e6a171acacee74e52be5b6f1cf7fb1dc5b86894eac67eb82b4beb199b29691bf91c496a244b29be69520fa8c1966ff28610f543014ca244b57e6402663be079942bf83b767e4fb44afc00db2a9dbe62422e1320560d8bedf32a9c6aa6a1131879db25be37e40c22d1f0f0e75549e1bd21409fc8a612ff6a4fd7e4997b55c1f56e8779a874385d8b004be8288665a7dee09124c9a173340528ee73e29fb1b43f51f143db5de5e86869fba89e29c27129dbe757c1aef4a0b4aea2499664348dd455cc6f96876d0bb56e1f520ac4517c689db730059003167b47444485f4aa9c516eddbea31d6e0daa1c109086d92e160067f9089b485fcd882e8668627a8f0f376303b8a9f68630a003df4742bb353c98d880371b3d46120822e7e0ba576cd40d041d1ab572ea601e08e392d135da3a82355eafeea1f3ff31d3c1dafea82a93a315cc823e782b4cf6e8425dc3a99d77e8f02951d80f9be8d689a296303f5a56febc21feec93518e34d0dc353d6c7df01a6e00e19d026b896a96ee1e320f9260705fd4ceb1270743ef38cd9ab639644483c62acce4e0eee07b1d45d2d31425d43a4ed34b93ac52b689062d01b403eebdd3a090a070bc77e0d6217a1deaa7d3148a7a87be1c683aac3a585d07abc7d39458c892a1e1c8462d0b11a68e42ba69fa25235eb4b2652838ca8ed388132bdbc1a23a9aa924ea68d5412f87d81dee737077e8ef4083c38a83de35a4af67428edfa91d13df749f5745430ef438ace300ba0e92b1b42816a991d3641e19d9a0b51568ba5173cef6cb2371b4582023e568b9a28923d0a1e628efaabce66c7b8e0966c40186314b395683a6d9c9489396104446403482a40c8e4adf71fd1e1bb5cabe6448ca6a7071a48c864b72a363249db640ca0a6683de9d4d29fba0a570322248232859d661b68e7652103aaac53547c3a9423cbba37f743465b93e877e07a2d5aea466b965998866a1c30923e448b202475743eaf233708c91458c6b9510751d7a72601a8721d734cd2d245e6b96b6b3aa285563d25464291b4c239620cb41a48e96a685221368cab2be43bf03bdc36a0d5790c638672c346878700dba77ee5a2e244c1a54924174c8efa2490819014e2396321d741c30e6104358ac9bfe4e9ef14252c11922641d48af438d62e33f5634f4dd027a071a6a5e400ec29a0e8af1514c28cec8ce63f38feadafc106de6cb5b99a17d8dc8265b61ffc8691ede2c47ff8eb4756e66846579686f7b197373ff89a6139da89746805cddd41d204c707c55605d43ec356e58da6432d242dade7b6fb9a5942949196a063f06d1062d248ffbd427bdd32fe522e1a5dcf54b837932c2e8598b615a74aa620bbab2a8330d4b273b6708963184725011a3551192b1a04a0b396856e191e7b74c0559936c69cad314a7294d53987a8a6c8a914f299a02a35388a60cd529415370d8249cb4bea1cb0942454c9647b21c79beeca09b73869e23b11b154c919a70124d50601ff0122c252907c6ae47657994c40e7914b5d88d070894c8110394254a2ee0c2d3c3112f40aaa10a275f40d09eb8a01dfd782c9c182d32ebe5a1594db3374b2c3c51e221868820e418211c7010111292c4488e4e33fac1f183e3fe782c1c293e64f608be4f3730a1657924450794a72860a2308181e9c245142633c68f162589a669f4c763e144b1f2b2a903ee88e011d3cd488b0cb73d2ae2894c878517407894b117300c05bff88147fc62086fe1bd3d40b8f75e4d6707c6ae9f591e4101936fb23c8ad203ca531e45fa52ce49fbdea6d23f1b94b664b43aa5c2c8a3547c4617547d46eea35a7daa1955cde8ff8faad936dbc2b448e7db46d2921a29cfbf73faa55be56c5739db69defd34ef7e1b8a4b6d282ed5614fd5614ff5ad5032724e3aa59cab2933e7b3e8fc194ae7cf396773ced89c47e6d0143293104da129e79473ca69829c724e39a79cf435bb9dd6ea3dab6ca7b556ab7956bb57bbdbc6755de7791f2a95f29e29540a7ba9af0656ad54ab95f75cd17c2f1957cdf79ab1b969dddc78cf1bd55763ae3c09ca7caf99658b352438d39a69b5bc67ab86feb4763a6a3c01fca4f44e7f46f3339a1f8d4f8a916ab602ea9eb1aa6661542a6a543f1a94babbce0fec4e93c50ef3d900330d37a79647456e95d367a49af94e8b6854cdf24cf274ec49fb34920ed7f1f414260c18305fbecc9f51b01f40c396b9506b4680295934264b6fed41dde59d281f72ffcd5c9016a28a244f4a28282594129a2d3d5fb07ee99dae4c95a97ee92179fab9a0a1ee196b8fdc41dd3339214e48f78cb3471899599092aee2a8b2a48d8a8a8333ea268bcc19b90fcac977fa3b8843cd646ad8a8c8ad248f2827d44c8648f2f4a3661e24796a2b735238a31639a3165b0a6a6694fb5340dd330b8372423dcdf72b33a3a17b491bfef55ffef56fe439bbddf35ef4ab0dda547a4f8a1a6fd4af2ef76dabdfd5aeb5d63ae545f5bd365ef5032d727defce72366abc91ebf7baf47b5150f2d4ef656f22a0bdfd1d9bfd5ef546d6be1795f26e1cc775dbc6f9085af8f3e33b1b573b97ab2341b3d5dbb65a3f8539c66df4d7ae524a6bd31adeed7b49d9715f37d869d3c3d8fb46d0de7a1f095a685f32d7ffbe1064ae4e29a52fda7d36ea7f35bace03af2ed32ed7308539668ec9f495bbfbd5d872f7c9fbd550854cc3c63eba2e25bb6eac61f398174e580bbbfb734ce67ea449524a29e55694bb7fce39e7eca6dcfddddd7d879adc9d6a4694d2ea54ab1dad92dc2fc6e0fb9ba77d2268d9fbee6a7fb3a63de8fdcd5efdfe5ede77ef9f0dafdf59685c50ee9a943b1c654e0a812ca350613eb79b1b14214a7f7ec0b4eb7460a84f654c20b8983f47c42de186382515491d2277fab925b2a7c620c52ad422924a4335413d528dd42295481daa43b821f7e16075862a43155263a830d42052864aca58714335493d411fa0a5c2a919968cddaec675a8cf6b7130154ecdb064ec7635ae437dde4a8553332c19bb52e114457d5ec76d576bd1b46cde88d88498621c8c83b9cfc8156db014914b29a379f9234e09a58ca48252432d36f782dce9a701391e7287cb21450ea8c517381738205206fe7eee07e7836b41ca90f97eae0717c4f14805b94f05f21d16b81d9c0e2e0757020e07072465544f050929c0c8cd90fb39a13e40ebfb3b4cf3299a57ad687ee60338db97013fe0ca36cc8126ac59e48e152976162976ab7ea94fe4fecad404e8af4061059a016b5255923cfd3260d52279ea96ba54b9a4c0ba040aac5de8075624c9d3ef81f58ae4e9efc08a45f2f45bb066913c5556ab489efe0dac4a489efe0b562b92a75a0da5bdcd34606d81b58bdc692dac5d244eaa32f799b202c928c8225799fb705ce52a57394da3dd5a8852011057274ab4825d499eacee84e8fabb94f46f97abafd6dbe6dffe4dc32b7952393ef38d3c3f1aad1a6b7888432c79be17abfbdb060d41b0bfd7eabef63bbe9b08dcd79e84ab71e1ddc2ebdf4bf59a366638c3c63f3535c225e1863fe18fef58d46bbe7cedb33143aa7d2f4f66edab31d3dd31626c5ff8a20698fb5ee0362fa7d94a5d3687a21f5a15e6984c027aa3b6e644f752e23ccef9a2d95fca2b25751a065e3b77db795a57a9267586f0c8ca7604d9869e27b93ae747c3378f4a19946ede95f128121a58eedff2cd14fc80881653908b8b484d914a82ba826281f342619c2ac80d57305c44ee97a92972bf4c25c9fd127525f74b140bb95f7e2ec8fd52cb148411c3e30ad612923266d3e611e9a070623826ad20b97f32794d5bb882794472ffeca0e4fec989c9fd936392fbe7c625f74f9b29e8628899980bf60ea1cdb41aee0c11b9bf5de86e2ee45ec1ee10b9bf35ad86dcdf5689dcdf355310c7896b667368b509758206b9df3bf6a3cd91fb5d0b57b04a9dc8fd4e67c8fd9e29c812028f2b188ba81d096f27cbaa21f7d3990d1d89dc4fbb75c8fdd452d00b028f2b984cca985a70e47e192029a3ae603255544c9348c5f4e3d492fb6bf5b0528d7e09057095f5ab62ba52c67cba5231e519ae6051f0fc71b56d28a78165d9c18d6db66e702b9066999a9a2a7d400bf08899c0249184f444062b829dc02fe00e83673a6cb23cb26282bc657964454811429dec523de0d95ead763f0668df02fc4a9ed94e9a86dac8c94926d158ce0f393fe4fc40a783f427b8e59c1eb0d768a1501d68e514480094b1bd914968915e5a34410d4c1393f52313ac6d3441fae434bb3f41b73f95f4d29cf64bb01498a367fffb68d849420923aa0163eabbd94eabd552617b65eac0d185b85132cd591e25d33889b49ad303a6df1334a145fa394db064aaf36915c247747200b806e59b692cd3ef727ac0236d80cde38d4c5ba4d49b35c8d3f0c456324dfa26d4099b3090020181de329f4e0d76ee72c4d0bf41b56d732959def934868f6851930fb59153be39e94a6d468b68d12cfb5fa2392d535393bf26ebae2ee443fe1a903b8db5511b39657f0ba3d4674e4e4ab27fad2d9326d154d2d6c1647f2b7dca241b7730ddd3efb1ecaf4919eb9ebef3ef0cc58329fb7757ca903de02dcb0ecab883be07d80ab25c2d7a0e0bf0289bea674093c9b77dbaf7cfe901fb90fd3b973cfe394db0e7db411d986ec32b79bad2c984a5cb119323a6ade8b0023467607a29c98d9ed026b04a74c42af1438920aa5571aa12e656994dd1e5c0ea3c40fd7e17ae1ef65c2e705cc628820433a992822a4bdce6e2097f5085471522982c07153132a7195c9e68810a723401d2c4087468c18f254b6449a20a9725203b400942a905463ea42081022994f81266c9519125ed88bd957aff782c9c2a4f6022628886602b984a182a60a82c51416202e3249ca81ca1e203152646e47cd12328201df583beede4d44ede4e63c7183f70721f24a0a5a02f4260be30df53a78309a781dcd3679443a406e5b1ce5c3a45b568b206724f9c131378ac33eea9ceba87f650f9bd280a484a7713827ffd97bbbf58acf6a477d310a7e64fe956f268ee5ac5f8decd7de75aaf366adddc31aeff92d9bfbe3fadafcf467f8df992ee35ee57c31b1bdb0adc924ebab09ad6755aa775e02866cd7eed728ee056eef79c22b80b47edbbd9badfbabf61a875dd77dc7b524a29a553d6b49f73ce39db286bdfdded75286befee4e9bb2f694d25a9435ed6bb59ad6853935e4d480fabef740fe507f5fa947bd7f36526152d61ea5759f365a25591b3d296be10ab28c82bbbb5027d43e5764028ff8b6485d1ab0b197fdd43efec385f8912459ca981cb2d6badb25b2c7ad92ee7177777777b743ee63dddddddd5a77afd6d65a2bfd4ad3aaf7e975d81fa21552997288e0517421cb4181bd3dcf531170b93ccf59acfba294865e2ae786ef4559ac96b3bf176e516e360c691016cc1982e7091ed422fdd162ce103c7a50a635a945fb63cb6673ced9006d6ca25953acbb9b7e37c5dcbd299629a5b5d68f868f3289863b9863027c7f7e776bd4bfb96afe1ec895860725c0f3bf570d9ebf5a3876586326d7a056ae61cb5aa4e1fc16da883afb5d2a27091e69b6f946b6d659d2a53b97ebf7666fae3fe7e76f43a8d54a2a5fda0897046b3fb7b6dafa79083257b7d37eaffaed59cd82734cfd2ef580fa9a779b1b8a3e75800d3be986fe09e18dd94e6b37ed0eef3bd47f4f02eaf33a4dd334eda67ebd6fff8adad719f4191975777b0f0db9bbd34929ad45b3a8563b8382ac36caa4a41c2398be954fadbdbf7920dbdfb8700b67f2fd1a33337926dfb09d344ddbda4b3293754f2bcb7f6a89bb91da47ba0349190ee3ce649bf9f63d1c69501ab39d56abdd8debbc0f95c2aa950c6ba645e3aab11969d4f0c6c19b1ae2489eb982455e72ffd7d4e5869f91e4e97f61033c72432a2a94727f46b01679862aa71737c0e34a3672aba7dea9afe3ba90dccf24d71f3f21f5476ea89d5a74587ed9e0d9ede079a81f71fed195bbcfdd07b9ebc4163803b2401950fa8ed7a1de9b1985fa198d3ff5ad54dc86c35438273751e0cc9cfd723fc8f7de0ba37d5c62ff65727ddd5cde1e0226b88f2df2225b344a265be4b2455b68997474c0e30cb241f68b55f5668319cce479f3edf4bc8e033d16f0ccddbcf393be5367fe7e6cc3cdc4723db21199f0067ef209dbddc20ef6420c1eb98ea87b9c6a3b714e307aa7d6d8f2168a1dac4bc2d4b59644b441cc27d8d76add8098bbe9554dc3c9dac8ca9accbb8fcc4a15e2907b2fe4c42570ea51ffbd0f76f1382eaffefc68dcf07652a43a7cb194af38198ee3388ee3f0a7be4bedc033639427138e627ed1a842d4d7189cb9e79c42fc473fb5934c7d318f798c0bf10dc71879c4b7c268f2f61ef37b311ebd7bf458eedec2d4500e0d78b4b3d9ccb586567f865f3b4b1dc9fd9a6cb6823339ec863b5185ddb091ad60d3013187c82385848531424ca92269888603164c86846cf882021b805c6084213f4ef0821fc43449216310020c2ce040c41339a4503212c40e43d420c31020bac8190466a00208103f9ad8005300162650207d71818e235aa36200537080a4ca16237ee800827c79819b2b5da0cc40830f2223f9640224848c14e99001952e4d607c450926454909c6ae6f42e9871c2f78bc59e678c1f23b1ce7bbbe37daf3c68697d056b674995b64ed2d27b42a113184f884134dcc765aad7637aef3542b99232c376081a145e3aaa137e8726c80e77b18982e282a620640e00c4e48b628d9d24948be6568550495e1a16e09b25c159a27c5dda2d8b82e9ccd5aa2785a62ac2c8fb43041c96479a48588162058698c4a6906577ec8784858f3bb99241c2dd414341e142e8e4bcd5116249b569647599cdc1c6519b2627ec7c2c3e23493e51116265a1c61b9f2f33b108b1033591e2969e940690a38bf7be149f0e88a979ca32b4857a48828ed852e670678be97a39b43c47a00e1436de43495c8a40c6661221a892daec42f78bef738701079c4b19940787479f70896591e5d39c2816e0ae1c40819cc44e8e677bd35d899abdea5b6dcb514a1cceb966ad56b905b860fa52d5766457030060409ebc1ca0d6690832f47208c18480c358dc4c3d5a563c07243112c3004510a62338526c50d14f4000490189ec44008cc0d2150406181131eb818c1c11625417492b6c4909384c4e3c58c10b41755f02acba3a422927888a1832d412e8455b4004af1e3a3e8d1a24b0b2c94585811c5059c988f1b26426cb41089a1c6b500f9e1521ae3028dd20c845a2f9a242d41f283951444260987d06a0a175450fcc05c5a4821f5403999e1d341062fcb1018ba2c412f704cc8b061b982e58817b008d143498b0c4a53ae5041e48a97a12b4840ae48094a7aca34591e6df141e9471e638850a6ce8e51ccfdf983dc2f6fbf8b892826e08124e43eb675846817ea47a3439a023c7fa45a77adb556dadb4743c70896e148f3c4eec5881c438cc98982a1e0f9120848f22081e74bfa34749f73874e76a96e903a50ce11e168011b74d2c5d892eddddddddddddd4dab6dadbbbbefd6ddddcd755e7fdddddddddddddddddd3de79c73ce39a79c53ce29e79c724e39a79c72cef99e943d3252f41fab8e2cbfe2903db82b504d76d92f655390eb287a826577f77e927d6c0b1de9a12662d24a1ad6b1c909b5e82ffe80bda4d6622dfa670bead8a129955e922a48cae8f757254919f39daa208f5e527615136d09cd9c227037933cfe35a865644ff531d6649f2de43edabd18bb5cff2aa627d9bfa35f0d55926a49a514e4197946ee1965f7aa0fef490dea1e8f08d9d18013e284704fb820b8261c132e09774493a2c5b427bdd32348f654654a2909729f1493d45211124c8a922744410c654f3511caee7dc9ee4f412f69a977fcb50e554192c7352f898b491e7f0be40ebb59d56256d3eedd36aea35de73dbbbb715cd779ded779df8742a5525845552aefa942a53056a9562b99958c0c8bd59a69b568686a6a6c6e6e707056ac60d182b668e13d5bb824385e098ede956087b3820565c1c27bb2689c8bbab171675a2d1a1a97aba6c6c6e6e606c7cb1183b3e2a25a16c8144661b4c58480a6174658053580b1220324a2ac42dffc806315f39cfdfed51067ae33c41da819058765597b07313e4c718115295680b0b2c4458482ef959a36aded5a9d52ea5e3b67110a9e79bcf265f768777fd119a5b5bbd66aed7c2de7e868363b4a618e09ed0e2323a376ea95525b6bb5d6da27f7a391f364368bc568e43cc15f03b6fb92d5269d4cc66a222299554c3585324ea1b2fc9c17b4ac7bbe2c7f5224236a9ded23a90faba96d56b6f9b58f06adb5ce9738228cac7990b7cdbac7c2b6a7cb6b513bb985ae4b492d07dc5d4a7a937a78e527428c068273a4ee77ee79564a299d7af7cadeb6b95554ade1814763b6383f1a29cc2ac48cc92ad09fd94598c99486f6db57c383dc82e39ca3a8fadc57c3834c5ddeeeb17989993e4ebee0ed1d1bba954e5135bcc975876eced9002f42c2307d11670e9ca024a28c19c1d689a4f91fb40bf7b370b2f49e08cae3e3b8c83f598927c10b920464cccb131d2b18e6171c4de429cba326c0e42c8f9a88a2092f4c3835b1d4c415da84cc864e07ca9197264c3e6cf2c5613250972f79be045e0c9151591e75b17243888526805401f264086c00359801092735784296440b54481e3f3f28c0c1693882c869f02364e81e881f1c38948a6490054a0b4848204ad00cb0142c39e2881134a046d4e0352070380d3f382e13429eb0e18921978c7ba2bb654e964871e2048f143431e3871478a101081f3754717bc45cf35c1e667537ee229072b70b16f65c5e67d9ff4e72b7c7f2986860125277c041882342d38791a422745878c1e588e9051fda9323a6168e987474d34a2b0dec752e9c77413bea6115e8c0417429d2c588076c035e22881c5d82f0f084b4450aa01d3964892226831210f9d114030d4438ed4926c1800483199e4ae025073788782032c3e10a0e4e7c1063e4c763e1f4907643220897262e4be449002e397041c285ca6fc15c9e6c796a6579c46589621d57fb09a630c7805daea0940370ba83476b786fa6fe20507003bf771aa7c5c7c92d79fa6f72bfdf641f426749dfebee3f79461f21b318036aad4804cefc2cd664ddccf271f1392b1051f8c9b5c6d8d2752949ad8e126cc3f1c776f76ada4b6b6badd74a297dd1eafe72db9dad7834dbd6e06c87631d43c828fce47eaf425a95b556116aadd5845a43a8b5d6ba7d7d134400b78fe13b9d0029f6cf0065de065cf137208be7c0d5e3802dfe82fe316658ac16275042dffc7c391f46fbe0703fe74fd923e2c07386acf67470c0e394c54880d8627bdf8ab7f91d2cfee6518f3fd4e36f845901b9d3df6b1291627f05a4d8effa9a77fd9c35a1cd3a38e031c6cdfc157f03041bd0e65b3c0936dfe2e7b7b8f915e10a2cfee65758f1367f038418fefd9e0e134cf3feadbfdfac9749618ea1017368f12d30079c6781f349fbb4f8fe89f3333689dc87c5f74d7d06dce7e61b3da35eca47a95eca1e0c808c4370e5da0a67a414591398e14865c016e00afca0c55a7f05285d058e53490726388978edb2df0f80e6b1cf811fb4681f0784d13bf66fc0eb3b7644e1a7c518e07176c9f7bafa0ba26304077941275d883062d4bc7c1728001db9d381145d0208000f0c0078b023ea4819f767e4bc70d14108c65c3f7ee0fab1e700aeefef58322b154d6be676dce67d388572cd88b164562a9ad6ccedb8cdfb700ac592597956d1b4662e4ba6f34a65c19971cda76a1ef57935dfdde7ee6f37cca1c6a5bdad7169a1cd15a4526cf5ad42b7ab71bffd8efb1af7db93c06d57bb776a5a5bebb5524aabbb6d31d66d62b5a1943c3586ddd2e588d1c101cb975a971f591e2d219798794b302d81f4248f942e31449ed8970822dba0d3b96109ccd29725a425294b412c35594ab2746469c796279d1ab820911d7069c22587a51f5c90e4f9d76e40ced9ed4e69add6cad75ac2c812069aa6699ae6c2d968a59556ba8534bc4058660fef0be6cccf6c65ac70bc915930d58fce440529f68fae439e373f7a129c1ffdc88a1f5dc8e83f5c474f5752f3307a667e8c11769080192df063b84f07a11715197502648f47b917b30847bc22c409c70f471104fd41ef22775aba2c8aec712b45a0cd6e45f6b4bedfb3c89e2db2d5fa9befee47e346bba9594ef75a20cd2ef3e99e5d067676590b9cd9b348ef220b20e500469c99fa00069079290bb0d250373fa35b2d50cbe0df84b2b30167be069c99f99aa7a199b133343335df4d2f847bb1ebef267324d0936a404b5404b79efb1a90655403caf4d780aba61a505504e2195403a6b24e113ccaa41a1095758ae0991f5d9669fe669a70f440a6f91af0cb2e902604479125038efe65f427e40d723f76190afcc0b10ad518912c090ade6e652c3a35c59c33854b2bac3fcf1b2a518bdd5721f74185558950ee5a7443dd3a2545bec38552f26cf651a8b0ea14bc597e5eb7a639622a9420c2c4ecaf82066c2875f78237e0b07c82f6f6b5232d3627b9a17aef57f065ff3e0af55ef7a4c23adec855044a7255fd28821c720d47144dfd8cae31edefc5b8c65a64edc71655e5b5c83854397df8bb4efc9501f9fe1c57e0867018428aeb913f5045456e282cd327c43ebd2bee29f7328afbdc6b344b1e6b4c4631a3d4824191fb6bcc7dbe23b9d35f25e64a5f9bd3a8c44db62635858648008000003316000020100c090402912c89b340cd7c0f14800d66884068583618c863a124476114833114639c01860003883104196588ca800060ca2805e4112bdcbf57f8c9e468645a4ebee14164e3a00d88d866473090a756ac0482e8dab7f3c3542de536800d3e8200753b9a5b62c34cfb79b872a498712fa8ba413326f91c484690fb50948dbf73b175740ccd6434f521153fe70c891477c585cb4dc31ed30d723f4a1ee24f432e506fa8698c603f696c934ca0d94f16723f3e29f0b21c39eb48527ffb6f488f45a14ccb3d0723a521ec8deea3a47c0e2ac4c160041e00644e95f8eb3739de147bcb98d16bf7c9f9b9125b88c40f24c90eb96b24d124629b16e65f50c32246214bb1b8336ccc171fc6476991f2bf5beae347dbd88ea3966c3d6d7ba005b68ec1a71ad65d9da9044737a9af686d93974b2f5a55414c4eecb2b650b463115bc9cb0061266e8d288ae54b991df2ef9b9a206c0ebe7dc51ae10213f15f484abb464ca3886dff9b1fe1d2558936060dc6899fddb132b7ac47ab299670e620548aa13cd675d020f4b16ef77c15ee9c37eb5728632f624f051b2c40b18f17db1e92993ef3c04a241959525f44f9c802479c48780cb4153b75ddcfe51093ba308239198424aa32a5b97cea4a6f459136cb5e9dd753fded85c68c1d63fb7dcb6a5c5e6e6b927aa4ceacc042a6d62aaefacff527a7c6ac6830d7cd93a8cd09ad71bdc7ef5be3bb23b439e083d30e3dfb82eb27231804d19799a1319fbd277881354b30bb5093aea290d97a7c5419535d40f3f6631a2aecf3ef4a9191ce860ea44d86581e53a98f059d9de6563359bdd365c1eedf92c9dd241dd06213320324d6927e0c6c54945d620c3bae9e02ffe8a8a8061727e1392524f29e2a05b02fe0949787c64627a6f8d4c6362e0c711419c2d05f7abccdf5c3575ba0811fae739d0a256043c1c716f098e02f7aca805861fa35c897285772276608b30b50ef48ef1ffc07916473620965eb4ab1ec21903365550ad9bc75d6aece520d807b0ef4352e51c10fd5170bdc7df0f3978125d60c065dcc2278a28d6c669d23c97ccc997e97b415a7f558968a32a6d2609fab5b308b7c132a3e9b1ae7adba398f2cb28971c23e79f6d989da5f6cc295cd632bce5d1de96188b0f2115bbb14ef6e9a0152e34e6b38a7bd5855a567cc82d37305feafb432754f428dbe734a685d855133a2d80c5f8c30b6bee08e3df162dd2ff791f41c5b834162013a2c4d2a05ceae3a4318276b06841b0bc46f068b59b24e4b375b95b9693da445457a9429dcbb4f11486f7eb5eaba0616a106918b4df68fa82ae92cd8eaa337ec6c998b2639e079ecbf5adad84609b7fc29d3f0988e746c4835880bf0bea3e121afaca1745016df38c6c3c894b79b1a2d982a37e20ff8a9cd04b7b21ffd78427c352044a59e40942a90b2abb1cf3fcc3d2147b8945100096050afbf2182e550466821e6e220a7a0e0fabeeae8cd8125504084e6f35ca8bf7c08785ceadf88107828157417f88ba03a612e10b840a8bbca9ae0e7c4646a5e168859b6c888aad4fb35d25ff3c23c1666d4681beef2f6b7fc2d0b6dbfc11db072499dcc140db15726c3ac03341c31b1b8522539b652ea667a2ed21351e0a978732e1d03bf2d34cec22e120736fe6de21832450662987e2767544e4a154e465f42a032440977f8176ea24c61081530cceacb8af72c2ea171d3562cdda7a79b866a9424ed64a016354a7d9a6e367e21706768e60cdf8706f885efdfcf204af9db72810811c04cf5ea7d248c4dfd6d007ee14deaba4275793b3121f152e1322a03a29781886c40d4c2a05d98e37f611a446bd687d3afdbc5dbaf3ff56aa47aaf9860cc07613c5e2fde1e9a60504d019350b2e6e63d2a100d178259160d4a218148ca24b5a5263a7917424040f95146730f37d3700838061296ab76a784f35384b4e40c015f29ec320aff1df2deac5d289b6352e66033ce37790dc597fe7fa9b1de02907083cd0a939dc0bfb63b77962b860935445d37a017ec0873218291d8c113843e34e4b41765fff8a30c3f3e29ccd72f05a8f8c6605698e2ddf364abca32e776b3c26e22b92296e334b9d6cc92fdd458c78becc08c351f8b399258940b9450a2d237e5e0510a235e12522f6195b3e99858dabf8e87b7a03424dd5ea09c5e1c71f02d810d774275c09b170c08bae1122790c580688e75453543b9b863f069a9dc45dcfa865c4938218a15558fd0feb78852a6cb20604bb2ca9d0cd1febcc82c9a6db1044aaa101d3aecb8164e4a8137517eb606660753cb1cfd455bb98a19a18c27825d2942bd20da0ea74d4181838121847aec954a4ce82be256b9c4400054d52d941b515e59b4e75a7e7f474aca2d63ce48c3accfa9dab35d2c3f4d9b6a7c62c2e81b882607217df151759ae02882fc891ab0a0f8f5315dce7252bf15db21e530a1099a235e82d5de1c9bcc05c4eebc40c4a724c01316d216ddb899a907a12c9a7ae3cabe52c39eb4a037af2751ac5ea9992c56ac9ad033764cbf6886068bd559f38faeb4128f950e354f10290e94253c0c0ff0061f454f959537f54a06983dae662cc24b8c458fa8cf523465fe7234095220ef1b921bd2d8bf5604a4c98d35b6f287edeee42898fd8387583caecf0ac0e284e5ef9fbcf4b51ba1be82b40cffdfab308f0198c725e0b745b4f5d7a85b5bac36f04443b55ae6bfc7cfb00afd333b5420a4198d3345c290675b2b0d42be96a76d85b33439642d562fac7082cb46702747b92b797a21536d6e3fb05630891c3b13b9698fc65b35ff7ed62683b713b970528dd56dcbd1433d8b10d6aa77f6348849c2bbe076b92083117e3c6e454454c432269017ea95d19bd813242648d62f8585a8fd92059deeb24be44fa6fc1c2136f47d63d9c835ee4bdf53d856b433792cd719960a5880ef29e12020715c46a89f96e06dbd6932712c4a66835df537649e8e2a175c8319cf8b06c6d227c98b6a9f54f9c4105841e6d764949b84101de421e1d6341b95435e221c857358e6c0024e8a5c0628576a97d495d3dca868e30467b88b72e7e2f7772071ae817271ed87ae71c2922e2b815c493e03a4de8d7fee4c2b74a0534bfb90be6eb361285e6fdc263458b770056ae9d5734b83e47d7bb8b7c8e88ac95f7aabdcbb38947d8d706c80a918021a63f48611963cacb7c619b7a92c6b7d55d26c7704579a562260cbbde879dd27e11e4474d5b69156fdce0c8779add42549cc20db318566ca7e02c2aea5417721aa5df10a3c66bb0b1b085d685c42d6d15de38d35888e75cab2eeb26c44c477b973a6ec6a8f84c28311a10ffecb238909916859c916dbda9a86346dc2f97215af99f5c1b3622a916fa9f42dd1f205eb07bc004cc15c4a387981675173571330df3878a6a49d3dd91ed784ef3f07b2fd92e0e4c9e87e579cbad00e16273bca2ec4e40492542482178833251fca483666dd8be8fc69a69d5d196a1186b57440485d5c0a9667bc9cd2673f3ca53d27e1c1380e56515fa04ddd60c11b3320bc094730bb362b56b94488573910cdb5696c9a0eceb31a136f9acccf14aae7057bc64bfff4f238e44c0db77769c4c9365353630f7bb09edf0d2ca49a12b6571d087a09a110b629915767ef6e9c6f5a4dbe4eab70d6dd8b2638583f9353b333d2a3db67cfc93b18d14276f9cf8bbca0b93d4d2af5bfdc8a3eacbff7a650eab897a637365cf319b5e7ef555e28ddf8857f9c0763be559f46d21c6acafeaa6f7dd0c1234364e75ee459ebceda783ecd2ed106810438b56c03d15d8b19daf08cfe1e798355519ea9d08fda10b5182325c1aef1ce2070bbc1fa4ea3a0e7f769685c8b327831b198c7f7a786f204d6be3dd0449e34437094deb7e7ffc5e48abe215f8451c4b26f5b12af45046a85aa879782e89c91ba6e2255496b1205d76ad1730f2bfb5672316be0ce0d69ebd01d88481254326829501104148ad25d41de95ff4e91bc39474446bc2ef38e0f89a2db9ec8563b9869d27d669aa4ad2685bf00bd2ed7af1af28bc5660a938535c99598aaae7bdb2ad2d23c9f708a9bb81ac4c118658ee419f4f4d56e6ef89eaf6c48a8618300171e716f1f74afdea63de8f3219afc00761507e6e620abf4698bebb79aa7bb861efda4230187538a26bc8203735583b5f120060d5cc9552cff2e4b5e4695363d44c154991f7c2bbb0bf9a679b845022b133534ce40aceb2fc8a8ec7d3fd6c4b6044dc9962c24f4024426330830d041c524208e657dc2be75515fd67a49d500677ea8b4cdad10f8c4e00fd07197453fe94a50893a8dcb57879200a82a9b03bd6a4ae118072200796f2e23402bfedec7c3a1c94201779a14d3ee40914534b74c4823677b3e7e3c988789e655d7f35630c4c03fad1f0f7108ccd8c3523a6feea74e6647879c4c9e2a7aaa9554f5121fd6141f10bbb1f0bb9f55efaf5a574897f3181630b177554acf2a669dd008a15501e65f7d90cdd86a8c421349f30f73e9aa658fc2c9c84949f8f39f8275307ef834bd3113918e0048acc37acde63d52e9ba4baf177860d944d4d7dc5248c406ec900f707c7a92df0d4893a80870625ecbc474b66f41adcb864d01a1eee612569de59bfd321c4a3659a948445852ca3409cf782f03559a3a07d32ed68721aa1be375bbd8c77c0acde0e326b622259d14b9ca43de706ee43c47c4b3d0ffd153b45bdfc2ccfd46526c076f2c5aeaa3515433079d0a670596ec48460f1443595510feab00bfc2af85cb590c679a1131069ba0b1b7a3533874f6dce49b9dfab1d2f69202ce4b2fc7a58b6493c9c6396a98ff608499c8e8467f815929c232fabe621a4e39371147cb60a3992e34dad20298f014b9122f357a567a00a568fd75f1623930f0dd1a8c0de27b214200fbdb01587fd87a8ab7c8acb782069b27901bf9feaa15882e8369bdd85a470e1d0c66f98ec2dfc9a7fb1dddc9607445027a8a4c0c5fa9d19719c0ebb2bd9925ce39bc51ba1f7743121ab6f4bd1858b994c83f1588917f396d1d5fabbe66a2da29d5be99a0596ac8fc35d3800b986da0e006e2af0a48b6f8badb517cecc07e83e46c0cb692082387ea285a6c08bb0e8c3b7e483c0559d15a50c7a949b432ebd621b0af5b18220f415e30cd41c41e245b43459da8bc71b89f68f3e81547bbaeac402776b4956546594bd96dd730c9063820bd52e5840b4ba6d60c2fe8383a5b43c23bd08db0a88758192f541a8aabd46d34ec26cf02892002bd69045c32d785debc7548129495d30aa7cbb4514d6f4097369b721d7a03fa8d1a0002d0763bd02a945c181d94b55509d344b12fd22405d224812020953a589c60d17442af5192c0c8ac8115fc6dee807d1af90c2bcc0167eaa5c1f17f7cf1e5bafe2c6905b2c351f86393d034258cccca5401b5ed1822fad18da83f5ba1048737945155f078f8072057c960b777a45554a654543e0c6a9f821d28ef1fb6ab851a2c2557d0301ab1faeda578774dd644cd78f402bbe49f52b2e226da7aec539db427ce842a22f394a25e5c56248204a5c08fb1d39ce2b072c48321c3e3ba04fc062935c8a0bdad95fc83be478bf31035943b86068023e302403c7c41fb7702d21a96530bcff7106ac7c89a02b84b07fdbd80f642e78694bff054e43c6a7590addc3267ed0b3f91733b93ffe800860c63c9144b4fb6e7b53516c56e85a16aa95b019337cb6390f5c6b075fcc9f312385a1319104841bc992550baed9091459126ca61f7706ed9a824ab0c47d9205b19d4377a4596ccdda941222d8b7cff46aadae3f625cdb149b82a8264adb106c24d97ad641c8344589fe0426b2e3be760622dcc5aeba226d587b54152579b84c7e6a42b9ebd29e1f52412df92c410d99ecc00457ae97127a52294dfc79dfeb34cd1e20f5b3e2a184b226805e2173db572ade2232e353f96be06e74df2c8e7edd613ded9e252f9f62c2efae566fb9c8f79cf362bda8928eb2fd716953fcdd068b295cfc96d8ac22fa125244c1346d6e4eca4725c01a75467d90c55039498d75204a41cc86e91594980856185fd82b61e40d8dad25f899b4b6dc5666155375b8967746fcf63e9183b1b2524b1a26559463f061b7a4c0d9a5706992aa05fcefa146a5ced818932f9df63759c7ac2b234f4550ae1125a0333a8d12ce46cd62432a266c105834da3c83af606a43c45f9b5d6627774830219cee0dc10f706b27ee6d469b68560f0248692697836e2076502353f30642bc75a18aaed3b9a9d1e85a629519e4a383c45641146c21e15fb20d6f268346b3871d6205a8a8616496bbf26ff212ab072cd7bb8ac8bf0faf3e51cbdc84b808f5f2478cdf7969ffbbc751fe70a2c5fdb1da3dbe614ef596eae578e2a658d45bfca7e1b59ff7f0b65e99f13807ed25382de052b334a090e4eda2a2cdf7b5d3622db3586643706d657526fe9df489b6dc5bba7bd1a2f2a7dd66b01672ecf5111681a8b3dbe28a4223374e5b23e05f99e9e6dd944420d55aa83a03695048b69160dd8abaf544b389258b95d55870c33780d3f03d793c72079a4c0feff9bdca83d40331bb5d62da21b28badaa818d2681d026dc3a6d0dd6febcd132112a345898d1a4254424a05e0a50185ac635e426dfce2e15e5db14c9366ce9d56e9700637262d637a75cf028d1a3f40ce78a5948c2e94105faf0929b13c57af7c228b73fdb31f5e36a7d83018e50739d883b5349fd285e180a0dc4537162a9bb9a574386670b149ece19d066ba5a20e3eafb0ba8fc50d45157d458b094956e7e0869b35035a6cf822d4510403f7acd08ad0fa66f12d956234c4bbada10cd2619716ab0bedb98c0d93c82842e185d63f06efecf79a9620406c24c4c4680c95ffc3bdad37ed902504456d42fc00589c21aac450d49a652b87eec30d289969064f2f445944142a4927b3c373cd4ece203b096055dc9e37541d877960ae1c82f8d0348ba45633b5782310d3a0d5aa027897d4c3510baeca6ad79be06ccfd7b5d8e1912a46a5f05fd3a07d39f517890276429b77a5c700485e6b16057625331a4a910626d6b271c4110b4e721909a35be82bd5ab55d825a70fcb6e128c870596b0592cef20d3bc12d9f01582acf2b4f342005a5e784c4d57ce084cc5c9562275a545a5e50fc5a7438d23c96d034fd614a89362815eeb4b13f8c74e8c5b8622b0601aee9460b4dda85fac4c13e8afd68c2d3a2b217d8a2e3cb2b92b46f9074b63c74cbc6a7214aca8ed8e09bacc8b25b272b752b35a380ef60213b2564df5248c572c6792d0bc23d0fc6268bf05e65415a337909cd15f706869abbda9033c1473991b99b7db79e14b12d5c50f9698f1cb9f8ddeb637dafedafe17a85cc94340123c1f86975e254d59c2ca910366032eb5f2a323f20ffeb6b21c5edc7c405ee0546d53ad557f97ad11e6c4071254337f9440504d97a9c64c2d8d6c5aa384e9937d8577071a6560a8e5775e2a669a14d8afc0738a7d7491791ba5117ed1e8e7bb56e80e300aad80379fadc749f0861c499e8eb2e27020e4cf406c8f06bcb602016a67c10eed90146fa06d0ac88409ce9ddf1d244ef554d59a81cf751c7f5b04240fd10ed855b132722fc4b9d91b6dcf03828ffd7a197d4cc2bab2030aca6f95bf5eb4393d272407c161858c108c107b9cd85d3337bf43f2a1ae9e350e3a71163a1005a6717a0baac829659be34b354bb718607e4f4d17ae542c0343042793e22dd5ad7b438a913b9aa8ae1503a40013392ba3c5be7d19b596e6318837aac860d8421cd0be9a108f01273c7576dbc526dbca825638a16436551738e1e578b983d297b87789588bdb405a9b7959009d379df6b5fc27ffb0c3f91096a31ced8ddf949541df476f00751983912114705f2504338d56a681a7deafbe4e6a914728e8d681f0ddc8e8d58039dc3489908a6036b324bb7c54985bae8007028b63a788febd15ba83eba3d32be380cf0e4289fc129abe116f299c803b37c04174a2f1e5c17ada2d4b679c4466457a171b880f07870f3a38ea4082fa60781f3d6450bee8382b1391e46ce2a3c0b8c41a54f53f48e759c9785705a125bccefcc8c016d7b51778d765503ca99b0577762b35809240cba8c5d22b0ccaf8b7f933fe6fc5457eb6609450f823c112219a51b041d64d9ab0ab612ae3d6a8525b275b57d8ad808bdef09d1b7b400ae3e3b5480a5ebd662f1f86a32c0f6bb2470006d0c9916a34c02973ea250d6072c3bcdfe39fa51e069015616b23ec98ec9c989f01ca88c32a5cdfd1520b8487c69d9cca554351a3dd376ac1df314e031261b2195424704cad9a5beaa65b59b98210b71266074fe5f8a4e0e7fffc40c2b61c62aa8aa8cefa8fe9e8ca9a9f39eb9982cd5f7ef13335b2655a6a86d0a9f17f8129395098e44770868d9e8e8dcf5552ef0960a864ba8883f1bcdb36682e2b3704e8fa598fdefc3005e09d7b7064649d1f50ef15b51f309babb8b9878556ba961d7c25cc3787fedde98727943e95450d3023f230524911a25538cc9a4e8f6818a814eece236e1875e6696c65ad92bb91ef66b163a670ae3224084077b1ac9195a0466b121c7fc47496a0fe3329c869c3e78a330bba28eb716a1aa67dbd491999b7c86df7261bb3c57bfda69655405b341a37329974b8cb9b377189dc9b38fe1049e9800edaf030562ea5ecde545336ed67ed481b3773f1be58cf62cfc2dd22bd05ea1525aae60c4739202a700d5dea2228ac081dff7ff09e86d3eb20e38801779e15d77a10c16d4e2b5ffb60ae66e2f372d2de55e3e896489db62223b96debd97a357dae1735bbd87d9d65aaa999a91e8d60e0d8bad7348570110c1c81311acf661d489f3277f4b8d7a27cb2b76599104236ebc978a17c2aef97345cf296107edf341e559615d620fdc089b73ee2d317119089b8e2cc96865f9eca2620bf75fd968d8814cdac34f8f3b42c01f2afdbef6c47a4989895165fbbaa7f203342e8ebc9540289192f82869cb287d09e82082ae6b392934e652771a4a1880127bd3f1efdd2f3b94d628bba13314df9d5f5176c26ba4831a5e38be73208d47f5dbf631331459a291d7eef542681e7a78edfb18998e23db53cb1aabe7335b8947a21ff6d0ec8ecae0696aa2fca54da90de4680e6d047be78927123ef0bff5ea0abfe2f6c1a111545241eb9e57b905d21be8c134e9de3a8f4481475aaaafc249ef88851dba52e12a170a644fd7d3813417ec02b471f12e2a56ab882f5a71ed4872c8e35b704367c72ef3bd66c424c0c3eeff45c7ff0ea36f9772a5d9fd4ec53529fba40fc8c9c553460d2652cbbbefb7210362fc441905a31b4e5e108d1ce2e4337b2e7ec2d5ff5e14d531a7039226ad3ae2f7721454b3aa6dc319e052a94b6c8514dfd5be6fb6ec3f600b8bf7bf9e9eff31bf69daa8b7d9fc039989dd2c7ed6a80ec207e37767ca61b23207463a59e36d84d940fa74851e52a1cec19dc5f0d3e79b1118486a985f07aa17eb2d7d49bc897ba753c9a1cd6a61baccf9f10540da614eee0634023b4f9551399f63e912972d2d6837ff866b904232e1771c4eb1a4875f1d7640b0b7d3d01879bfe16f571d80ed7107955c1c9e6a693d5f0629aef5a7163e9eb1729bd334fd5df9552131f80d9e2686b5fa891a3104dbdd7b39d3fb4bc88ad42a57a3554aa5721a57a152ad557a392b312292d68a554185fe9d0c2255467847a3a557df3e3d49946b96db5bf50af40251ffa538d9f5ecf2035d97beb8568052a735780520ff5f4472498b6ceb8da6bb41a29d7ab51897b059510dc9352d519bebec66a140757fba5f82a2aafafa2f27a052b7357400906793aa50af3cbe99a44096bb5dc3b0c6e52c038a4a934c31caadafd19ccdaa7ae2af2b0821635c957516c2a2ff838d02e95f11c52adfdc810265c3bbdf49e04f58d421832d92bb4d8143e621021bc8362be7b26a0ad7b1dc8b4b456336dc28e7d496f2f630f5e9a69ff3dd4f9f0b58d07cbfd6a69601575aa817791d9931e52801f298a656164fef3aa503f3d4d3ecfba32a89e202257ae8c18268808dd56867b1344b4b856c690cd050ec332e2b070335efdbeee6428e2bcb71cbfe8f433df4a7a21843b5e136f7298c2b740a7a0bf00407e70888cf985a4bb1c1eea868398a0ac4061ad6d3652c19b2e01eb97d9894f19dc3d0f8370e99a53c35d83bab486aadbc38bfb0989b6f1400e4b5860f3f1d2090753247db4a6c7fde21b2b16926d4bf099c1063863d79621c74fa3c2c53190906fadd8b08f9740640e037961c546507ebe9c886322c30ed811862a4f8197f4e340326e5af80a85bfe3f3f0e9e672aba1ce947a5de018e31c3d369b8a814f8d28d004801f102916b67f3138fd21ef237354ff5bf9d1a27cccb19be92db9ebc2aed649607a2431c63e473fba9b5df9a286c76e5a03df1e7de8e3cff05329862200f207e52404b0cdd2b9f2a10f268b1af33f3ebde74240e4806571c1392ec7a765b505bfb2801a58c62a26c17b84a1d99d6033795a3a64fe00fdba017e5cc8bb0b023fc3f1cae3b893fd60b613c4bb29c4bc0e0f47c8e6895cd6d88122e881e25cc98b1a2b4ac05feab897185ba3a152716922115f7dab8c58b28242e8b74e3414a3c6d538d7dfe79217a2ecabb74392db331caaf11ca9a4f067b618609f9416f6501a3f3a8643809c38f5f6e519d9084289f6614d7da7f709cb7e32be85e86b3f165fffe3b3eca2e737a8453ef5f812c3591f36461fbca4f85e0fa2155d9ebfccbe48bd4a5f4d5fa3d4cb494fd43df9e22c2657cf8fed0ab0f3ac33b3ed4f9d1a2ec903775156f95900a23d38d47ba13228e4c6dcfec1f45b45b03962896265bbd544b7588e360dcc0159de917f0c59b1d53dc32d727b77c35b8ad24a46cea266e05106b9459d33ffbcd20d8214984ac9780f24d86809e2868b229d5a431c0a114a534f0d1e95be03cb8dbdcba2f5250b00860ce21d08a25c1c5ff0c172efbd9a1f97851ebcefbcfb1dd546389f65a7ff30e9c1b0d7a9687b2b9ae9790b039e10777f68212d4c8e1d3a96ee1f13dea1e01735fd7182367731f849b2c41c20f0bc5146c75352a1468390fb4cefea930a49b37f3617410744608cc37b6bcd2b1ac29061db1a316edb8a6445f87ef75458451efef8538bbd293b21df778c1c3f7325a1be87fa0e0084fb32f452d58e72510b5b6e79fcc454a2c0202d86942bc1261c6b5dbc738b2807def6cf0c963377eb7b5c6a87bbd36a036402e17853830991812a7ac005b351a160a9c9c00e4d1f6f2a73cccc6c5813744fbe2295932fa6c85d0bd349b0160937fa24e0c883117985a76b0da7f26a941e5cc7785e3bbd127a11f3adaa6f7989be12d908c760a0706533a0752f6eb00cf7876c4a57f1166b79445548ba3e9d58e5838eead1d87bec329315b70dcfcd75a6dfd4a59d98773257b8ac245adfd4efaf8cabf4571644fec226c1e4c274020ef4ba180771087062558117f4490814d4716bc7dcbc89a92069d846158e494875c238efec61d875daf571511f3a5ab597ade159d25d504988d0670cafc6282ee2a56d4f189639b2da89bb37a9cc8c62b6d5813f8f64af12bafd48c64daebbc44294a168f5d43ba6809de26236220ec637ca768fba7854f6f1eb72e58071bcdbae1944be2fbbd5d985f909a03a0c4ef51c6cbad78df43ae0e4c3c3a4d2e8189295d5ecd5a447bb49a3ba2b89199b8e4aecd62c3f3310059336b0f57fce5bfdc8d73c55207f94a88672ed024abafc524a041817d3e49ddb1f27f9d660801b5b7844a30aa42ce2f614352df815ccc14cbea1efd0d4811f4b745d11b7b97424d316a03a5ca586af4473b3bfe50a2be93aa5674a0cd5318251f9a4e498fd5b45caa236e11801d907a006e6e82c2f8d86a8ac2d247b0b0cc74a6e845034041a0264c409b8fdc45d3462865bf13284420b2fea8851b9da835382231f7817f6ad458a8270e615ed39611cf39f69fafbb6ff925cf3e2338332c7bf706bc3c602d5ef35b51ca5028a0255736c063685b9f39b0bf8080bd19a8ace99626ae1af0e4d1f095bd94cd753f3cea2514fdf7ea12bee72d35926419554149735dbb6bb9147050fb10a0c60789ad466dfc302128c7e2b9ca5e1b9bda7b1dee47e24ac3b7a296bf98ed5682c14de6c5cbb86405d41efe66b1d8e4bc501f4ed98a0f79fbd3da5311afb266c32dbfa7e567713e8ed2dab354537875cd934e7e05d98b10077e0184e094e848e7ad7d089f9257e11da5dc2d363031d462131cb57414feb2f24b727b7b8a263e8e3c6ddfa40e0a72b4cc0d3e0dd9ea6932c756fd4225a10b5fca2848c778412949233736beb3f6b50dc571b86d49ba4ab0ae588ed390d37a3f1779c7776c48f9bc438c50291544fb02fdf3c4eae66f416bee6d59579c5ab98809ba7440c15c36238aa0315d232d4ca2d78dcb76effda081063eb712a08dc87029f385e04c5a50317b14e6bcf5099e93ffa846b251b52ebff839db862252d0aab4112cb24dd8449bc0cc6f97f123b5a0daa0099b01390039d71331d0ad72818e3a56db3fffc332171668383ceb91a81888cb7f7dadc76c89a7188d3fe72a04c1d4fd178606fb99265af9b43bf9c096f12d0410f61e0ec7ba26b5252986824a8a5fe91cbabe4e2b5a752569951b4dfcce5b5843087026fb934d2a582a0920e7a84f2430a8da7990b9c059a5811e654a30702454b3957e05c31268e70733df2b67163a6e59bb471357cea7d4a71a10d7f8941a1424b0de024b8461689c055a3bb2dc4221e0789d2fecd59ad6d8bc8a23dc741272451bdad84b26f233a7abb50cb73119075bada038f63a167d8f3821f5cc6895a1eae1a997c8e10290ae8667303f33124709b74cc19879c9d80d3b0ca98b65354d28ded24fa996199047d9c2ae0e95c1d08fe286fbb62f7ae34e94d77881488de2839f1d6f4955cd22d7a426ac0162883a5e6a0493c9caedd3785df74d2e3a21ad822f37868eb9eac03bfa819fac61dd4af9b03a6a03b582d520fbe4587bd6cc512e317cc288457b1a1b2689217170a32ac472212e82d6ef3e20d5a89047af3b4f308f44604983b925b089b94315c1edd220e3aabcd45c0341d94cf1da059f0c7827aefd15f9d8ed868dc18327754231a0dfe8aeba9a62987721549116bcbcccf665603e5b43cca7279ce6a83bf660eb7fbdb0d4a9303d1885d2573571ed8c7057ffdc46d37744d113f369070722181d36305fe5a1c45fe3f0e3bda99a59788459005029617564b10fc357ffc591224f19e642c1ab1998c5292413dfe1a572fb4f00483be1a21157f7a4e676efcd5ed29d3c92a6a6e1dbdf9ab2c4b9803d3084600df8a52d6335cb9a8dc1fad8d243f7aa7ae2bd55cdef8365ee7f5b37c3474862fa6882a5ee3bab067cfb2842c8f54d674f824d28036f48282af00e0cfc2399785f3c41142008f29db2f1d0e2cb2c74ad930e783328e0564046254e6fbdd7952782f3a75605a10d3a52d27938033990fc1702dbd069bc8b21cfae0d48c0742a9395b4b2374b271e0076e3f28d418e16556ad49fd455339936682e67b8d660eb804892ac33538c3f005920859920d290191e881c37d35649511cf4f92a62b97127f6ccc247cf938b83e504b8476423e822035c1a018da90cb906d97dac061c706d4b0fa75c42a73ad7dcb4236a4661ea65bbf2ef41864252c3900e80a47865c465894d3a09ac5044c3e1991ba601303f9c4e02b27558224613b11bc8531708de288d6d739829da6f2b5a0c564a887a00d24e40fb9fd23c0d6a8592892a8453a2c225f1964c3eeba098f1950547ac1cb17cb5806dc62c0c41259e252d187d5f4d5c09684d965dbf56d46b7f302f3a49f99164ea04e01b9eccbffa30891ffed7894ae8a50ade354a3b8e5ff7973a520161d249c1ddcb0e5b2495c59d6ebceb477b6b59dcc714f0a8f3c30aff10e82a1a25c1fb7b9dd9c5c7d8f5b3359f1c5c1a7140056bc2a1eb6f0493fda425896559473acd45817a8d4452cb705516659a9354111afe0e9b052830b57b9e0d7e3b4c8443343c31d714779ee599668e25a8fab27ca2cf6f9a2be6df10824118dd799a89830f31820631847fb28adec3c9260167250a9fc60e452ce924ad920d6a4f093f7713538b123d6da307a9609a2067815ca5eb0eb4fe3e94fe3938461be22ca973860ef856e9c725a4e79b99892fa13970ed17902a59a8da722e6d9b2e15d27572bed868247eb2529b7ed98552c8044d6035376aa92d534faae6dc3d3092798fc2232903421df51bbff827e0b4f78f4a8e1e963d064cdc2da875ffb45280bc4829c9e287199574fcbe648e12377217b25b3028557b9810d6461888285c149be703e936588eef99ed0b6dd2b325829b5615f35858497e6318fabf34f18a9ad4b097bb6ee9bc22657d28cbb914bf66904c11fafe75896e98957d3d2c931c86035743a51e0cc33fc37bc76fccb6ac1a4ba8f31b2c2231e1311f1563b16df6e9e7294a4fa7328eb864fa46ac15e5dce233ff22161b361d66886b6789479dc302bc3ffd9b129e5d398f6a4498182f9a5246493d1d18c51fadcc6dda2ed93811db5c684b9a04f1f688c5e498b62d1e638fd0f42d22dc9d8ad6151061a6750f5c349889e8dd3d26884812eb5859a95d4e3c3e359fba43cf0ae145ead09ad59d8d2b30f21df62ed82517dece5b676338632ac576abacff077a50596358915cecb8d9b8843d4e13a9ba53b5c1523a97553412f127cce469f8cfb2227d3e40a0a7a7e2ebf224e242cf100714607449cde5c0b08cc1035e33e1e16af4b28f275194698530f9c9a1937bea03952a25cad9a605b0457a25ab5483f71037396a2614a79948c2199e26486135934aa1134235088494e671a5a49f44174f647a56e93675c96a71d29719bb42212d4d2749155e05c78cbbdb2cb2527e13f6105ce95ab1cd5610af94daf76e54b266e43e7b597bbb96e16624e51a1741f5276892ba283010c125a6596585738755d1c64308940a65d8541207908000b6bb3006d0e50174d14086a263dce8dbd4469379daac2273a29542dc32577f0cbd919a4dc6ab6cd151fc45f0c82f30afc3bb12ec428636679bec8adbff57edc375f5d8211fa15274ee45066f325253d41577cccbf648c3fb60f7d53e8cc3b70dfbdf2edfdea11bd11b96e217a6bd91621f4aa6678986b948e9ffe7de5557d4ef6b6eb8470c1f0ef43db1b6c955a992d77168bf2d292a512144fa59e1c6ad3b2f81e129270d4bc4ab6705dda736df89654380c2af1a586be23dcf5bdbc8ee81d47a7b4af092046fb9c854e815b412ae625101ac9629b480b7597022ea8903d7454e724e332b0d7099741f10f23fa6ee5296a3962b00b0b1211654942ddbf289198a32c71d8d8c8b4ab4a404b1b5280015bff56dd588fff50416a5f45704b648abffd541644e6cdeb5959b462045ce38c1e94693b9dd2fc60a5420e16c85332ff7234993aeb3ee47a1cc2a95cf416500764f520060b9e91f477310b3c0a3da56b474943bf4d3f98fc68faae5732daf19228140000d48f38948fa21a05c36cbfc5555455eba7ab02ad792fee9e48b3ad3db6c2a2c8d6f0d405310c1f49fcfd22b2ebeef533fc0b0589bc30767fae83a835fa09a281adc072578cda1ce38ed0c1b9193750c33278b202f0236a61c13277b01cdabbf1655ee9e063b14f2282f885a2fd47fee865f266a939df1e75f64868235bb4661d2c6c5f48b7aecd565953cf45bfa737738daae583f1a90b6be50c4369e85b25175cc6bf4dc620471de0823d85ca1c5d1d6c1f5602f79ddd49d1864b1c48498b672ef32720942120942e9adadf06a70eb127eb28a141d78bc9de524ef0cdade3e264912b968bec88cf77a373da423537479af0605325b0d76022e51a26e6dfb988ac96e7454b3bc4eb347ceafc13a46196e616d0131711131da20d2eeacf47f08dca2d130c120395711b488a3290fb7c013b890e61cb18563172482e34923047ec48ce8d07ad79fef15bf3b2069ea00edbe74ae95674b8afcc48dd4516b967be5b372f1ca3e1db2f9917f977301eb6a7e3f9ba255b066bed53c1dc7aa66bb1ee3213e27bdaf8889f24a3753000f7a654c2ec8169f643dabfbe76651bbf211cd4ff82a2cfb4796e21c07a1efae07cb527ccad21a814fc935c9b0f6bb76ee2fd67681803440f05f9ec00af2cefdba9dd0cf108ac6c96833aa531f3e54c1e964e9519081b4931ed73094aac6eb31ab46e27525561813060da18ca9bb066b1bd28246a772c4d659c846903c1dfc88e1d610c508e751cd6fc11d38e99b4db6e740418a98d54660822a60d7b7012d11d6c1f2220a79630edc3cadbcb86024fd7b6ad73900c0e3cfe20a6fd5c363bb0a427ebc969176ee5a38b6b91076e0f2671936b05d5f5ef464e586e6647df90befca0c22f2f0b9d3641cdd6768a11fc399ed1e075d058e874c64d551b6f55c074a18c1cb5f76a32633883d83ab6789d9bdeaabda75fcb221db670d506169b08d8b841ee41936111ccd5c280e5202bed4bff64630205e4e0d3d9dc238c2d76a31347efcb3fcfb569e5051670dc29b8c3b9b013096bcb34c0aa39e039fac5832ded03435122034e64a184cae662315777e005c4abe03984426981bde9c4ce21b8dffbf678dfed7bff3eefd3f7dc88837d5a440190f4e7105996bd562668c7adb9a190717b92884f0302d4b265d2d8b31fd1fa094f4066d6a94a516071d9c023e50429d157ec47cc00a350c584445dd773d4d7808343bd8be1d6a9ab7b9f72185c1db20698f70fb176bb2b52ad427d9ed0fa4d43461c538ed3892b517a1470dc735e7c159244aad567670e6a08f7c809b0c775496b6dd186d36b30a838bc5925bb61bff9a7561840bdced404dd2e335759c6a28007ba23aa157f2100dcfa9281deca0a4dff29080407e1d4fe227c41e5741befc58e28b3a819882bb7d7e484bf3a63e9fc46b5ba5bb3e2170c9b5a3568e411d7af8bdfbdc3e3e320a78b58c25926c8b02c0b8f6ad3964e93e92ad69b38708d345bf9f0c5c0920ee04859ab2008985ff939268949490fd345cd22cf232a697744dd712681d6c6a59d70087cf9c3fb67a984ab4d77dcbcbeca48de7fb5165ab045296aadff891ac65d81ef334e6a939c3ff32d5abb9a93222e692a4149dd0c2e462db44492b8e708e983a12f8ca97a9f6119344c84fdd12d91c0a62387f2ad7b0fa88baa8c756b9b3896a4146198cc2022c7ed5d234cae197ad45e5828b751039bf5d21de1aa0fd64e3d38f6af836b17273eb2826cf8299254e4aaf65a21b8d31bdbc0dd5c0eef07f6edd3cfb879088461887e0d2aef4cc7aa7cf6935b0f5515e8528f7ea7bbc00c6b7fefa8144cf126458f7281e9c48423c6f42f5d3cdfc3193d2a23ea422cf67ae2c3898db75c4f742dcc9f91c8fe0fba0b468f488e59406d2a7d995b3219b03ce6bffe04117ef90b4f473cdbe87b8ac364332ffd44d2ea57b06aac0022f7ba3489470efb8152b40f5e075952a9de4fb944b874ee6b65e89f5a5702cffcc476192b726aa406def7714e10bf4cfb009d7592dd887866dd9ef2ce21a72aba49ebec231e70aa0d5f09b4128173443da5ff407424ae5dda1b2dc70e5de12ac1b76d0433da77531dc4e694905764c16574b916aae06e4f40cbd1d9c24c9435d169ab75d2ea9ef35cd676804e47f938da6b69daed9b38f1b18d3b3ea3ce4e3fd4ce16e0a818a6ac13651dbcafbb63c92d2c3173834415dc88e785b7a11ec7ed1745449134cffab7a2352154f3ccd2abf30072c36f434936f324d5e90265c8f7f08337a42962ceea3c0f6308aed94a7db1ca8f5625264b17e80947bdc9023354bd1696214a76f03e64d7055cb3b65900acb75e16d5f01063469b4eb66e2c4c5539f7f6f7ebe621961974811621c9bafc1f4d884b4b04bccdd8a4ceadff3c91f52dd833650dd927cf0e14e4d22193fa634dab0a494b4806873cf5de994e8fb22f935db2b028e239de01874096753ce3c8c4d66194609aa646f5a901bac95607bf36346102c555354e2e337b4412a5d4ce2fc51a069bd254c32a7fdda7ead57ed57898440d6aeb8003eb5653a91afd7eaa8c5827780d0299abbac7fa01ee0d5bd67775d6dc09e9c9633f93b59df5c84a178a55e5c1a0dc93b5cbc70b09025cd9d6b1e9aae188c59634b15bc49ac7cb6fd90b5f6b1caeadafac17ddffc0b196fef5c50d3b1284df26c1999db97599ad77a75a6c380094b3b2ccf70647a5c3821e4c28b5bb3d75fbd8b53495cfe83e5fa267a1ee13f9e4d64d40281f9f7e109b27bf8e79f65ad16bee810349f2479d035215684877bb42038107b88c08001964ec64b52ca1111a276643c0ef2217e9552d77c6aba34be04a06c2a6c6978303470e1d1f7474fcd8b1c3a30e0e1e7574f0d8a1c3a30ec859c824e76a28dd108cf4c390ecffa972604d596bdccadc0603cdc309f9f3f71fd78889d36a16f81f796d0e409faf176c7392b7c77cf28c159cc7fde02d4139a2073a4b1d1b4b11d3201ae7bb7c3d354700a938e8f8c804d469fef96971f573d8f9b54806af1b7b95bbbf003880db8b64b7ba3921072a9838aab50588b425c37473ec8e6d68f29b7a0c685b70033ed3a30cb6c6d4fc160eb0cd1d6829764e86d5b681edcb850fd1c37302ff96418c126155e51ec37eb6f3a940b23dedb7c167564d55d70615167f6283b5c4b6f36da41570bba7360bdef64b4cde8abaa0d6d3eb44cbde8971303ff09f67fe9f660f4c890733249fdd0f46b34bed505307549df091d7b908edc1a94f418b55053d3add81738a443df08f7904e138b66153e79a17400799048d3ddcd1e019afcce43b2fc1628c57509cce3fedf8504924104b3236f2e0d5d0381056fc2cc6b8f554a27f686877e5ad9434af1836c5817013dfb0c36edb9cefde21dd3ac78620ac66a273410813d3041dfb2475be2859a01ceecaf559d7a08833a20f23a5c7dcc9fe2242045eb06275fd6f6e5ec11a5e2fb7c19e29c6c0c9c30e9fe94a9ba4dec96acf1e87104dc54c8fc8e5d61cf13a7c2c95a4f4900cf0a951d0cab657a0fd2d67d153b2135ce0c018cc496ffcd4559b35e2f78884800055a6ee0efa1c268727db93c32e86d5549341da6212289bb800cd0850a6158a5b71d80712c8947b5419768e87d45b4af4ce690361e2ca029c2112dd3547cd125970c751c1202d1eb2726019b27e8979948800fb0b8280996039c61d6d3782135a0995f6fc19059ca84834acedf7d43bd0932edadcf660a31a4b8789d85568c81222098d0d6e4a4e8a6efafc290000b8cd40ca8e33c76a7c6e25f70433e4836120a2c90f1965adf8bac4c05a0ef95f68ec336097263ad0125b26ef3a2ccf881ce1eea2feb3825157eb0dcc1539c31557dfc2c4bee53b4087b5d9680a2decf713d59abfbe7a3bbc856861ad1b5213eea09a81b19a6ab1c9466b4ed4454de0e135b486d4913262f32c5fdf93ae101fc2fc4ab3e6227c1eaf8684141a2595303003ec6d2c517b7480e6117c3bfd3a2492be2412ed94fe9c1ae334deef1e632057ac017ab2393b8c405a3f9ed6c0fab66578a014ea4b9a3bd6da2a3a3bd3cbeebdded32b13f47733ad5bf448bf922094c9f94e743737d95352c5c8f2ec3bcb48292453579689ba34bfc418ebb6ec4fe348ab75d9af9d7e53620a32d637a7fa0376ce26ba3f2b72e3ce40531d5b8ed4e0464c42ed261f81e4cb26f450f4c52a35317b51ddeb0b81f814fb6179449c0a9ed91873ee9dd41f6ee2b7d326d4b058b59c513ba9127464591b3b61191a67d845e32c051c08d85b0224e96f0398a22fca6fa3579af550f5219bd044cf29d37f863f99f96c759c6a4cd347b220a34a1e9f8a1e14349846096af41ae52c344db2400124584300d0da3198b3ef5f73d6d4751c6aa544722590f2aead95e1b06da56a624e9761e6f05ad769b0c4916935fdcd679b4e0e5ee7bc2b46826bd7a067c74cf2016aa1a52b2898d550f17a5e4333073c09a4b662b598e1a320fe444f15d530508f15a5e6f33584345d1a5ebce2c5296b86cc5d1a6631d028eb16ab71165d2dbe0c727d4b45261534a4aa4db68a63d8f5d4a500a94bc332c8671e535c85fc886c1aec50f48ae69b8aa21e254139d93f83284a528a4205321083d2a561790a4fcd6d52a22520c198ce059e895643b84f40144c11db08c067d448f2c2b4cf8cd097fe77629be2ee734b8715822d0e883ddb171d5bff72e82415f6aae58bad854dfcb5138956e0c4b07e86f741fdfb88a47855a7452a35126195fb83223a7681f8bbfcae2085e1f751591006c1c21fc1807230253ab628732901ce883278acfc23a2f4678ed4771db0eabc93da4f824eb9c9c8454bc34a513271841df63d51b8a0ce060a664da38f68a713a44b6e55192e03d72821293f1954054163094905b8beeb0972ec6d1b05f10f71ea62eb7a5cf4e0608827a404a9214ad41973ad480a16ab2d6e0fb1d806719ddd99fdd8f2f103379f14fa7dce35e810b6587b4dd4cf560a5984660e70ce052b2e995392bd2030c15708828a9a4c8dcace7d66ef4d933dc08c1152d2c3201e9ce19d957f29b795981c54a5d2c34883a803e259cb6068f45cb4c963b27f4b0f0fe4341fcaa8047f439872d93874a1689b6e31966b8bfff182d07ab594327e2a4597e84efac093d268e457c65a57ece89f5289e25e468f64d62a2a62564894f86bec576272918eee50f975363c6f93fed081766d9e37a5f4f3bab6a7e4b50a442f84471b336546fd801383c210a236e3fd040b5563d1ae129b98b8f9a74cde545a3938d318460202e89ebbc17f6c401007c7a50850c82b9ecd221232e4ffe6cd92b7b4840a9a401822af9b93a728389f988940e21470b10d7e3a2d40d4c7d4e0f4d1af44d966f757f3a4ea06606859b21b9589fbed608bf37aaea8b007cb9958c87a38053ccb6c171a9da752c836af5674bd72e194773bb0b05239d0716b2fe49dea0ef0de3492618d18d65aa248cfc5f4100b1f8a0a8a00dc436fe7c24a676a740ddbdb0092c5c9ac8ba0ea3b84196f94b5d6c9cdbafc73200f36c4a4620137f9b99386b3ea6773055d66b127e42943705231ff535e0e3e7950e285a2af601cd56b7f7466d0f58905b0d334a93cf20984a3897ace509ff257c6c5870efecf869f95ed8f73889de3539db9a1cec552ce60aa7f90c7c6319200c6e473560e99d57d35abb05d796926464ddaaceba201b6b12e9c21e6208674b4db4de5c2635bd0860e6362b34540ddccc5d2fc8d0dc9e5d5998b4b293d1092f1536d79f64e47b3f5b5b8c46431b6fa4f33a699f3e8a293dee177a7ca44c5a415b35883855b1b02e9e1486234dfc793e7886775b6d1c35db1b4237b8f23b18587c61c997e0bfa4f183266de02d58235acc884523f06f5ffce13151650970ada9f493b8b212b745e19b2d45da9c1910958fb66e462f3d00ecf699b767f10251e2b702098a71b6b7a00cf8e30a3d4ced30c824d761d2eb758a9337759236fa774c30da95c88194fd51bbcaadb782b77c53a6b519eee6beae266cd3b327c9f0696db5c216065ac081cda9aeee84c524cd762b7b85b9d3bc7872b77070eb8893c8866cce8c8738a7287644b62650b7619db4c06f48d940e30c9b428945965e233310937dd2c6c2019b8d57262503543ac9f9142a25e143c5f219cc56eb70d80bf63b08b3cbf9b79001dc9b7abe9e4f51dfb08da07ec99404daa5a4f70b963b745d96dddcfeff4aa6250d6181eb835c7b88c734de58896cb2f124db0e27d45c62c4ba33a9010b1d2e10979a141aa5cd04cffe1513a7d9411ba00cc3308927485b7bf760cd99fa964afcf0d0244521f21780001c14613d2b45c8cc3a6969e235d510693bfbd972676d3f10d817b9f587c1be8214f96402861d9237a4937d4b33cb5dedf76ebe2c16fd599063f718c1d8f9ef3745671489acf8b24f4a66098cd10e9509a4aec897f1471019466a974d2d85a08f47ced0748af8cbf03569280f5d8727c42caa858189aa71c32b67eb4fd9cf78c4301276623ae83045d6cd1f3c3b1e07b5496b319c90cab20b6a01f22426958bd5d44e14eae3c88b797d872f57a5647d2b98760a7fb55d5613637b6aa16f1415f4b4006737c997cec8b04067e00ea03b4aac50e76a55123f2d55609d8db39b6397c9f5cb8bba9a7001ed6b55c7f3d24c87af8ec46f70a38a8eab70421b52643528c3637af232d612dacbca6b9640f9ae63357ecf9152b2c88d330dc6101ea7be5c898dd0bb703e8bf8bb4304446da411e912b33fbf3a939b7a61ce12474a161201102ed5c0304a3b15f64217fdf66dfbc0b0513702658e83f0f17672ca5455756745776c99d3177169cbfe6a107ea12850573da982a2b5da50acac2a1429c659f07b11cb76b62dc1e92cb2849fe0e261f7acb8e25aad23bccd32c7b869870a021871498504fa428cce4151ab2b851a61866a9e36abe82c092bce38e0be9bd9a4485225c510792c96262b6ba84594d5be3c4b8a24c60b1f8b9a62a08e9135a18c1b4a56ae01b31813841010360349040ee060db388d5f45cbeac32437c4c3b19257a2826d7121ffedda13697ea577e73bb8ef0ab98f286d4add176347422b057dbd9fb4db3e460131fec163711949f091679d94ec0854d78c8adb90e33150184a35043f73357f16d636503e81b8c9aab2b3db09f29e41f3f081f6268f8dc2f60b5ce457840f5d10f627fe06a163283ab59e4421c2b6c5f5e4566ab828b952aac2b1579ac6274ee822d9643440e9586a22ca1f8bc76102556b05311f628450449406777fd89982217041d44abac287a627d71eb44a97144215426b8cf7f59c8d1ea842d8722f21a4ee16d371eef36d2aa0ecf6c1e47d2517ad9fd8fa3a658e6ceb76d5a33a4b73c4ab8c6c91482b42101faf9d984036c5570e291e42fd0353a75ed3c1a44edc45c788d993e4fe747d51ff2f858bc6c610bf275e63774295f208019ded05182c570f6ba115b0cf011b93dee452fa96005e3d57135d72efcdc021264c19a53008b3887bacbce2c49cea39d70ca6a08dfb8bf48589d6bca93a5b12bb4b9eaeba8ea3b05aa45578569a6bccd6f66ba7455de61c69962faf947dd69273f9f1c69b14ffa6c93269b7d21190415d161fa2047c15072a16929e3535d6afeccc9ee6d773e95afb0d79da1220614abb0675df431ac72bb4cf37b5eac2c779c0646cc3b8957bca10185ddab63180a8798b64f3b817e2ff2df92ddd8cd9a7bb0506901ddfa887668c5191578d675256f73395991225126b651fd587f99c061e41dc2b7231377c37f076a8c0374102a1b78d4d882607d1ed45f8d4509fc3602004b724dc273b47c03d71c6ac9b8de203db4890e822238e372847fbec42c7f149e9ddb0e5bbaa76e92f1cc2318636b2a9c2da69c00bfc0ab2cdbc8c2849f59f03e6104c3f7b80ca6395039d652b840eb69d2af613268d91252085596393d122dda7b3ce167401f8380ed18aff8da6aeb0c748b5ee75a1bda1e14104791347d0abef308ea850ed1ef5b1b2190c1f05d61acb62421f43b040dd3770fa569acb472034a82967f5c40941da70d0e7da867cd8e79cca79c348fe1448b2d069ba0008b1fe8fc5ac0f5b381b323d8478de064b8c37d8598477110c91c446dbbe726179605d6aab2022eea1c4e35b1d6ceda2d3639d3f283fe9b99d94d24721389eceeeede01370823089f073487e6bc9eb335a5e0d9ba66ebce969dad3a5b06c80638c001103004012e12c07a9180172f64842fe84f7c61baf107f57f3aed1de3c79cebb9cb6d593fa7c7c72007c1e4a8909873a914132323f3c3511b7f240c9a24a6e22f51d2044888c6d6954bd3d09d6ef4a709ddab4d065af8c5788374f835e20b9ac783e4075a1774f834aa6ea625c3c2850c3933d8950a90cee5528c0c0b17b92587584137737ec01595c14bc103aa31e891d2ea8fca8a5351b1e9dc9e52c59d62a5c31fab33c506e67b3ae55c3f12de57da44c88025e2747ad414156c2076141f4851440a2152fc90e226ca14517c446945018af213a58b1284283ea0484841c66006077cc41286c832c413569d068ad091810c6c6670031d4ea7474521a28909a0184187214bf41cd18a22074620c2942b186912854da784472f0786608207258c50c509ddcb0ca8f460052e10f20108c94d72bd2a3c47e8f6e70c0eb7852397b4d6566b6d10d65ef32ffe6230ac5a5b6bc6e3b2b108fc17dee27603dc3123c4d27a39c717718b1140912d1f15644b89653b589dcbf17e3a64b2bdcf5c003adb7e7d39a7d470521a55d7dcc7146e54d7c87f0ff5eec3877bdbafc59d41e5f3d7e23eae796a09dcf0e0a169c0d7423e7c2dee0c7c61185f1746c38c4cc99fc1ae0b6a1ab29ec09329081fc36aeedfd7e272aa7e1f630d2f1ae0639de3d67a0257a6ee475d0361bcd905ff7a8cf1f597a631b16b31ec311d1d63d8c38e6d9c8e7e6df7b5b01b8ef9f32f9fefbd7865757bf4318d9c9bc4a8809f0c175b5da282ec1e28aef4d703058f01faeb8162d57b2210bca3d78ddbb1e247fce545fcf49bbbbcc65b3ee3a6d7bc645bfa7cfd1cece9f2358f41e614000f764e0c72b70864a84b2e02812912bc18b8546fa137ce42a07212898ffe858f465cf42f5cf4272e12f1fdfb5df8fe16ae6daefd0bd7fec4b577e1dab7704d7b4cf30a9efd0bcffec4b377e1d9b7f0ec4d3ccb1ed7bc82eb7fe1fa4f5cbf0bd7dfc2f59bb8fe12d73f39b637cb7ffd0a1eff85c73ff1f82e3c7e0b8f6fe2f14b3c9278fc118f2fe2f1378faff1f8198faff98687b8abb37a3cc5179493b1e1b588dddaaf5fb7d7630c42790492f35a482034326607c02c9db3300ea89dbbdb7300c551b75b04ccbf0eb3cd2db6ee14f04305d9f0317d4ae964a192ec5a6badb5d65a6badb556fa04c6a820fb955041a20e1251188912248a28ae441145141f9789095080de2823adb51ab153b0af9ef844c783adbbd6255bc8c601c8095b89dd832d53c5be74ca080548e7503f4e600ef688511953f7b5e0a81f36fc1db4c7b8edd782f38e838afa9c74f6de120200f4baa2d753af2ebd65011d5f177ed1e9764d9d9b7326e20ea1ae0142d95fe858c618a1c419fcad3f4d23da9b09d0af00fa95e937f200747ce5c8b78eb11cf9f3e9184b29e3c338938f44b79a06e61ddf1cef7db65e74de1e77cc58abb8f6b2f6dafb89101ef7c950eb5efb640538d7dd68224ac6131c20ee131c76b055702a141f6cadb5d62b586b6dbd4e96586b6de54e43d84e88b841e5309fc40093f264054f709ee0e0a48a13284eaee06489139e798b38b901bc9c10d1e1632f93c40ab3db29a262ae4d093e5c4e743e5c9ddd821e55082a9df0b1c3bcf7de5b7bc4a85badf114515dad486c177a6cee843921c5c90f4e6e3aa7c22c7808a305a6e273282cfffb990dc2d8d75f8c6bbc2ea573523a679d3493dfe3c6c08ff11b9c9918d8cfe48bf94d8f9918796ff92f543411c2003f73157ea1c23a8639628927a619db2be516ffda12830f67f3e3c9d431bfc9417dfc2d104685a9b7f231e62f06ae10c68329aec214e6d8f750c5c0af5f4688ba1f5f755dfad210c0e9397156b7d356f9c4a37e71fe5a60fe17e657a676aed7b535b8cbedbe16bc06f7893bd54491e3783f9b08fcc570ffbd6a2642055cff70a9677e63ffba9f318731eec52dc53cc690a59b1e1fc3f410f0341f75cb9f3f18e2571e80878aaf3387f1529101f7de7925dfddf2f95abc1830bf62dc183606be19f31a035f19731a036319f31903e38cb98c81b3cd5856455df32b535b7319036359f3180363f8229ed9d44a3115a36768199f9e59d635c731f249eb0c6b78c317f7cce663be652adedcab86d98bd46fbc3350125f0a52caf85290194096240690a505107490d849402544278014e1840c6a0ba8104ef870a2475015579094fe7a829a042511f4b3b11954a4c39f49e0010c3d61e2c9139efcf4d7f3a47b3284273e78c27a62832742a840c1e95c7e62e889a026fdf53c91a467c627ba278cf4d7f30491cef1fe9e20e28920b3e7091fb9bf9e276c2eed116a01c12af42397908fb04eb0a811ee6646ccdca04e88487f3d4241fa13fa21c483ca0912219b0e3fcf1ae001484101fc0a1cc1086bed1164708bb044cce090841ed6367144ca0a360f7b2341060bed41a7a78921b909204df8904c5ce95cce9309a1cee54c6f0e3cfba7634287891decb0f7e999a8020f1157b07131050f5700f2039ccdbd0e08bb87dd84c80d145408eaf03354d2b9dbd3e4486fa2d3b9d984959b10e1018fcded28ec17ec9cbdc40f8fbd4fdf444814f04928e5841d6e2b5802099c258a007197c8c10e76891ae0d4255ce0035d02053ccc2570789041d8dc89091437354e8f5ac2a773aa1f3cc445026645a2cd81bc3598d805140575091c3b24c5bd9840d1e107713101ea21677250b960a20427e652dea51f5bc564083ac8e430af995c8a61c244e764980041264a60708449c764085307263ae820a512567890c94109272b991c9468d2432687c9c40826423aa7fab136413f8284f4b7e988f09f0b2ff41bfbb83e9e2fc6964c3eac09800fb71c5190457fa82e75cd8a2ee78c2f52fdcde7808cb20818b02b16814989e1d333bc23badc31156501fac5b10c43af5bdefc1453eb43082194158818f22dc1a21d6c265b088d279b921131278f81524a0971806928689c1c04ec04bf80520e23a594d0ca8521b9b05c465c2bd4ba024a2965ecb977658fa851ace52f502691406ca541927b1f6ca2521ed7e32e239b2ea56c61bd163c6cae85e562d3e58f6cdee5a70520fc64b8979f1e3f4339a9a4d5766f567b2f5a5bd4de0baba4959d93d4d90bc359d7b47408217cf04d086bbdaebf6c707a7c7ce3a3c7cf38fac768155171dae89a964e593a458ce8b0783a564445ac6b5af42868d46424340a8223206e2465d41a01c115901f4180ac84e4ace0cfb8ba233c488e74939484f443ea48432429a42ba42152ebc686d482314a59f135e17efdf58bbf79b3bd5cb2ee51be254a00bd18300e240afa7bb97a3160ef63d703a368c27b98f362b0ef25f062a8ff7e70da810b1317215a784c534c4494a0f056cee75e6ce076da418f5f5d98f4f854ba08d1e35f2d98698a3411d1e3c7aaba2528f4f873cab971f187c562b1582c1b1b1b1b1b9b2d1a8d48a492c9c65caf4eca42df418f9bc91642e3c9a66444c4a738e68876b0996c217afcaaf1c46c4a8f0f332268cc19c2d2e98e745dd775dd8ac562b158ac6e6a792ef9d5d7e1eb138382c6c941c04ef00b20d6d250e8f1a5c6e9f1630e02ec143bc12f680d459c5504d2b174464023a011d00868043402ca301796cb082b402b3dfe053b0c498fbf2f2c3dbe7619d1e3c36b85eec88f12a0a0aeebbaae5bad56abd58a85953da246893d17ae32fb9c3da2c77fb15b8dd2235c412030070e61e9745dd7751d005e3a0d7a4c02ed03aa34a83449d06deda193cda3482d0963e672a416a9c5915aa4568fa552a9542a954aa5cb4336513955a73c240c95cce95847744a5d7f4a8e7497fe62f3831effbdd8bc16382f362f3f162022cbf60128065530c2922152a8c26eb293d8568cb022858a1fa8b8992c0814e54ac66eb682a03027882036f77e8208620a2b4c5ad1850c8f07090b5aa00e9f664686850b192490952aa0543132568e58292287583273a4d0a232b0a224c7ca112b3c3f568a58e1811523ac11308a09d5d62a63ada86085552b3df870d52d8b0fd7891e75097a97ec304f5f6b95246aad35d62a4c389d1e65a506476c803d0410f6eb5e9373ef47da802a55979a86193a43d77bd1c898aea181d5ed3d94a5a1c6e27c71a7095c33301de1bb99bdead38828b9ebb6b19c75d635d7c62570c38307ce72d63466d84b84618c31d6b49daf199686ac6b6cd77ac6484f406730cbb22cdbbae6befd7d4539db39c3d2a0e91adbed6352defa224d4ed788a0482412895ebc225d63ffb29b0d7094354d03f7b7358df89ce85a116c51e957986f301b37aa288434db37739fc518c6d9f21afb18d6ba66e62cb3f7b1d7b48dbb61363466ad66b1b53b3aceb2c62ed6b4ae81dc853dd6a2a6699a065fa66bf463f75e36748dc63086bdc52eb616db70cded36c02c7673b063fd980d8d695d53f7ab41b4335d4345f32a6198c90449259dffaa91589bf6ceb0c759cbe9d4b2b7a66b36dc7beffde2cdb0a789bae67acca4f36bad35766d3470c7362cd23551943551c6788bae61941f8f3286bd0b865d74b6e5c725582a954aa5174dba06fb9cbf45eb17692c5ff9adde68e09e47ba066253b6bc067b8ca44bd796f48661e6ef18c18089c9924072d55fec72de4f24c211ec639c05c708a58c394f4cb58d6b397e7a06be3e4e5d03b517d8fbb2183f4d9458d6dc1fbf3fd23e7b1ea2df6f350c0dda67bf6b106d4fa644f56a1b10565db3ed65b509689f3da66bd0b62753d9cce535da46be2e5d932fa66b4cda0c797baf05de6a4abce675fc99aef13ade2e8b3a625f7f1f6b1ca17e12cbf45b1b60961932ec78e374746c83b181751dbdbe9c6f39cc42e7664362111b614505567aa892a5ca1455a0a8e2449525aa2ca99244152654e1e9afa74a912a43aacc40a84a0b5045180a1a3a32c4d35fcf5091a19ca120fdf50cf918ead1a7109ae2a783952589d8295653f4c05d2a429dcb41fdf5505142a5099d4a11d4109c1852326483a19c29ae4c013445478429727ea0724508547858a04ea51d2353639f9eca902a43439d43fd4881e5440cc8911703fc4d81c4eeb58826b9e71681503f983c3047ec225c0005203c58c1ce8f246c296c21f6142b5462107444147a8c00bac18e4f0a499418f0a0040f780881406670b877269762a620e92d2c59c20f8c39b125bb0957f401a182362a68a382f6a342d806c629279d94c628e7a474d6a129859b57e610bda136d89cb4da2924e7ba8ef0203972716e26f9b1f6ce0ba31363fc18736e02993f824c20dc14327330ce5367746a414d8482a4b4565dab6f3d634ed14d44451f3530ea1ac8c91f3d7e49ae4cd36492119af2bffc38c31c753af658e63cb1974038ce7a61ad8d4a2d2f30bc249aa8d84448fe534522aa584465441579dec79cf802c3b87125de441f3ffa030ac21361c0d50a2259c1242bb864d5040af5f7b0833f220cd8c12050089122fd19e9ef371061c0964cc5bf425bcae9ca4d7f0f5737e28bfa4b3ec909c97e3c2c5ee614b35d44183107c3ab9c73cef989b8dd4fff504e167ed1d6322df165ea78baaeeb4aab1fabd56a458a2f6a130d248130d0057431168bc5a2363637363636362c5ab80104d4ad72ce396795aad4552a15964097966959ba2426753c9dec70d78d56125f57c462c9222c9664499664b510800ca9c3d56ab55a7518638cf10dee6ea04baeae96e92c45f7da1d4fd7755787573f56abd56a2581641309248124900492400578215561d7755d775dd7755dabd56ab5bab1b33a4bacd97b753c5dd775ddeac76ab55aad6068015bad39e79c1376dced70d7d9567d9d25beb27a61cec43a9eaeebba4e9561c8a822dbe6989393b38160ce39e79cb0d56aedde92c2c156154273021873767b17fbcffe73f91964ffb93c8d74913f2de7647781efbd8bcb5b2b7fbafcdce47cefed5b5b5ddedad3cc4c6df9fad265e3a0c9daef16656d7679ec5970f91897877171f917973ff1962dc74c376ddc8e0eefee769fba3d3dc6ec35a194724bbc8448fb4fcaadee38817c388364afd05ed892564a7925e6f2b2e54ba3df9fc5f02761f87de14fde1b4d1b77491bb7e529ca8fa82e519153f58dcb31232f39a14c28138a295a1bec20b4034f9c57d61d8af401f4e7b3838f2b1d01fdf9f438d2f1c3f3c9279f7cf2ce2be943fa66ecee8cfb4fbffb77e3f4cb7ff9afdf51f4f6476fbfb4713adebea66d1c34d2b5ad6ddcc5566f3a66b7cfd59779cb91bbc51ed71a6e879c7f3d9783bec401dfda806fe14fb995b458794cb1153b1229c622305e9e833a39eec0cf7ec61731fe7d3d2366773fe418c3e26357fb1b7abca418e167f7331e9dc59d58fa98695f8a3cc64d478cd88643bff6d8bdf672368b39c6a80315101f8b3cf6e62c5aecede3e774448e8b5db7ff39e6fbf7deec332ec7cbc7871a02da76a37e0c6e30dadbc7628c51e7665967b1c7a6871b0e3843dcc1e2cd6132c1bd372ec7ddb0b883c596a6336b37c88aa8b8d92ff1fd2fbce52577f9c94f4fe2793f4d14bd08c2b8331f6ef873e49e618f6139722612dd1c39ff89bb704ec7dcbc85cf1c39eec49db81377762429b9f1d1bf3f9f1c3a1dae74557f3e3a20e93e39f8e020a4d573a71faf4f0f1d9f1e363e3c7e7c780cf1e101d471d777922a8434325e4f35bcae3a2f1d71e366ab5f2fb3e1a0b5d65a6bb5119fbb6810a4412e80582891f9e933c298d9b44cd7705a21cf30ce3f00bcfecc3f005878987f2bfec5e54d2f358dab67ffbe859815a716ba698c3e26441f9b5770d8bfa1d300c0d7f13537a5740e6201d870e8b7320f0340f5dbf8d4851964362e76fb2e70b3c5b970798e850c17d369a9d319659e6e18e7e05bb8c1b8f0d7d78f1b4d844304f05943a55ef4c28f08f01ba53304c517953ec631ca3feb19ea6f4f808d53bd909afb51031000fceb6bbc281669dcb810ecc01b8b4e7f445fb435ba5d9f7f064d28399c431758d753fa57d7f0c768a40ccf3e005c3fe7af6f9c73ce39e7af074514fd99df0030d3c2c6c2a9cf978d7b978d4399364e557a4a6189f419697e9fa739efddfb74fa47a15417e67a6ca6939e44fa80840187c8d4fc39da38154ab471a8df1bf7a79d376e4f289abf70b373cc74fdf4e91afd382cd533e4ae1f0e9130a612f8d3a78c4eee70e372cce8096506e119180e814486c0211b44c1182718a7a2908a820f0e3f7a01faf3b169f291bbbbca5aebbd353aad99d1a3bff5b19c6d4a5fb437fdeff4a2b61a9d3e8d3b56335a9c588650507ab204f9d824c1e9c962e4c5f4a4e76e3ffda9f42bbe050687f6f8b5cf8f352efacc2ff85916223d7b9720597c54b1eab20a215d4a39fa4bf4d76b35304be6dcccbd7b9f4eff2814a7ea7983116dedafd7fefaec479cdbffbe01a517693cfba723007be96962b665d1e3cf78d510c87f6999966999966999f69caa67da06b31f6f1c4c0dccd235fcd7c6c1ec8d06ccd2b58dabd1afe76ad4e8d773fb6bf654d780bdf49873da8bb6176eb6b6cd50fa6cc3517ad186c365f31c339cb6bd883a7d76f9f7309c9bbde5a57600b4e1b2cd883a6dbfa2a5256793c9943f7b9c99b4cf707eed33537e0d679fb3979797972ccbb22c4341d11e76ed737ef8396b3e363c3e36407aaab8b2376e47e65c8d9eaf4cc9cf2b5a4a2316fe4a182d7ccc8a534be99f54f51cb3c16cdcdd3dfb978ddba78d3bf5ec5d36ee94bd69e3beb471a89e3d49b471aa2cd39f39577f7311c0aefdd43662d71e6a0740edefc6e1d77806758dc663d7360e766dbfccbf376ea6e7a7915aa641433f37d3673adeee7e33356660e236c2c5e39180f7f0be1d64d09843a6d344148432e4b06764f04829a594503ef7786a3ca067f3708fe7069b7b3c3ed8dc7621079b7b3c58966091d26f7f3d5884961840139b9bfdc919213721949dce2f017d518f334e6a821bf7d2e59670c2b9d180fd42de616c70546e9c0bfd71b05b0b6f2f62c61720b001669918f51e4fdb2fdce363ccc404405a710ea4ac177f312ecf7c83a181a3ec72ebb2c7fe3acd98bf6ef2dc2fbfc1308c09905b0ea4084edd3e0874dcfe1e0c3a4e1dbe17f6e7ecf2512fc6c5a98deff37f5efdbab74b2a379aa78cd7567855dcbfc62a05dca491686b99ce18bb202f82ad744a58fa01ee00df60a4773deaf437a39c3f6917258536d65a6bada5d6da3869b5b3da7bdd0bc3139b386b2ccfa927076f26cf6eb2241007c99c70d5e34b12735e922844490c12893c2099968c1494d0953e5f47a783870446907c40468f51c68f3e5fd6803ee65309d0c01fb1c90e204b9ed08e1c6ec7aac78751ca39298c52ce49699db4566befbdecbd2e0cc3386335575d334d574dcb75ef5c45a25c4773724e354d1c8b963c5da8ad9cbba149af9c4472d1e797822ae758f4f92653ae9c93a1cf6fb9a1d5637dd8abb5dc0d405c0ef93492ab9078267802188b112c3afdf5601982050610cb0f2c37fdcad0945782ae2c9957905c3132e9152243e69520a57ac5c7951edca562e864a908a2a2497f3d5424a142095474fb52c1a2a20849058c9ac2dfe981edf2e494524a29a512a614948c409242aac12889d10ed3a4842905252390a4906ad0e5c351125d3e1cedd0e54329390b504a197f39b73bf77986fcfab63d22a583940e606cc4975f13b5f8f85a6b6bad94d239a79432c668447cf1099cfa6163b172df89d8f5ed033d808646c2b81153f2bb1b2f490df145842183a6befce73bca215651b551dc8e34f5c3e666ba4c15b1b977a40212c6fe217992115fccc09b9987f18098922f6bf460d3ed49b9575330bd9ebd36e76e545965d541458f453232918c4c242313c9c8443232918c4c242313891ef6ecb1d1939e54a38b7e74a38bbe728ea68b361ab961cfe4bf165e1faba692a8d78bf31951d6a5cb9f5c0795a25879e0f8385e6b6ba5744e29896c08e50e09a30f7c30b5bc7e89f9d3bbacc81e5fbcf419cf316f9c0e1af50cda5f1ba7835e5996e1fcd9e37ba1b5b15649e99c934a5963c4f9caf7b5b87e6ff7b5c8d78f3887ff7d03626238edafed859b7d5dbf02c5c2850ac5c24597a5d7fee2dc0d0864dced17beb0a67db60166b9d1ef85d6c65a25a5734e2a658d314564e7df40d7b0e8f7630e7b44917e6f2fa246a2df22d2b6471b77a36b9fa5e32be6b5d20c317f6d38627e6f3856fcf598eba09cb6e9a03d265be1b2629b11f5b23d7571696979fd34b145b768ad758bd6da6432f9f0377a2e91467f491bb70130128958d041ff533decedeef73780ba8eb92292900481038492540f288452384b8038f2c3159f1f58dbe7879c95cf0f36393e3e80ecd74200bb28d563b4b7f6fbf75f38b42dd56373356af4fd6fb4477ba77080d001c2878f8fd68c548f548f540f2d0bb6f17b5e1100a06b3034d4a75f43dd6a484d4d83d637658434e3766c2dd6c8786fb456d63a29a574ce2a25d535d2c6d86bca880dfb8d3b64a43bec3d1a8d46db7e1c5f4229eaa29a39ef88d7bc3e7aaa6bbc3e9a5f754decf7f1cca396273d0fd397be6a181a5a9ef435b46c4fa6485f8369137de9eff5afdf1f71d8457f1fc3d1e37ba1b5b15649e99c934a5963ec7424fa4bdb5e44895e7bfb3471c46187b78b36d7ff748dd4648e99ae69d07e1f731a928695a22eff051d86e57c2fb436d62a299d7352296b8c7d669e22821fe6ebc24faf5ced5f4f235fcf91bbadf7b590bfe382d2c9bd7b9f4eaf52c9305ba49717d3a251ceb07cb13b338526940a74e08a36ee06a1fe05659950b2c81def11f093c19104b18b281bbb88b213bf9c8fe5fa62ceadd6d979dd381875fadc68549ce72faa8a1d9f2b9de20e4400c4906faf520e69155bd70b548120e7bbef7ad853c9f03aa9d9ed662956a4ed561adadc03da2829360eeda9e8b5a78937e20bbd472f82223ed2ffb4c83ed4569370aba10218a821bea019061eb552a89d52a6784018882f38889262c31b1be8408e0fe820417c914d2810066dd3e477e0ca8d0d084d28da14d2d90cca28a7b70965e624ede78d5361273b7382d80d96e94fa6a41603ecd7945360bea82a9b53a1a26c1cd7d3cea97afeebef8cd4f7ef3f9d59178db49b0ce62816322816f1457dd44ea1164565d7879d53b188a8281baa248d8cb80361807fd364463e9f9b255dbe0b19e20ec576a3989671d7876047b7a5b4f51282523a5b10ba40b1789953cc2e411c99aa6ff3db6d524a21a594525ae9d35e29acb5ce09a5d2c426a921b64dd160db44548543a921b6ddf256712e0cc29130607742a96ade222ba2ea77b2c22199aa5faf4b6edcd3cd6ef7ee7d3afda350a99d5d9f8343bd72b148afdb0b375be6ec1c08218494e28bc6a967502aa59e412184f8aa15524a131f920fe46c9ba2c1e660912e7f3e8dfc402a67db6d421b45ba9a64739075c11f30e7c92f02e3ed033225ffde5d21abcb4f19d9f22fdf5eb8d9f046cc8361ee76ba9d6ea7dbe976206b3e86cdd0ea5a39c355d71d08216ba76bb1e20e8d3a2f76718752c8a27147731731253f731aedc9449171e7a584524a29e38eb438c5b3ab0868c7511fc346803715cc29249b53a594b065c6af4eafebcaf88c298bb27993aaf802671fef49dbc70f39ea7bc5e85b5e1fd2c0b02e59a064ece28e2e02314a8a8da33eedf07db8e92ffdf9f410d471cc759b50e03fbba1a0d8901b019621c5b3e7d34829e5cfa079efdea7d33f0a35c3cc4fc2b87f5954b7f0b52aa3f063a76b4f2894cea02934832694d9a272064da1d98202619841f36ba47c367cee1d99506c68c43cc8a24e4633fa59cd322ccbb2a8836559962bfd9c5fdbaebe32c3f7b5be1f2f1677e24edc615d754429a5238ee3860ea985a391ad17f6d88e138c4623ece23bdaeec53edfcf581e8d9e26eafc18ff1de59b3129da99bea3fc388ae28e5acca28e19fb1bb1eb6e5c7f3251042d156cd25a6b6ac2b4a66f32ddd776b6666b42796d4d26d34f2193b6d6647a6bf56b5a3399346bd27ee3f4af2841280ac10e6ea697461b77e27e6fd7ea8ced8432a1dc234a7c7a20e2d343101f1e703ad69e4cfe4b428ca9458283c3befe0ddd62183f84f4bea5f557bc70835db46bfb186b8fb1488445222c1261912822f98731d6f06b5624ca44af23c66e526dae1061ed491a765d2adab81060fc131ae978d3f0d3cfb8ced7566ddc8130d42defb8238b37076b5f4a3b31aeb83ec616bff71ebfc7f8a3ce93cfda9f3c18e3d8598c71ce183f97d9cbfe9530486f37aef43adb76d44fe2b76bfd26ad7d66f5efb77b97445bdbeea6f98ba88b34c2361db3ef94f22502ce908bcb4b595d7082703a1c563f407f3e3b5c996fdf9b41cf4e5baf0bb741f6773fa36fa854cd374631646a4600000000d316000028140a07c462491025519c16dd0114000f6e8c4c5e523c14ca834990a3400c42c630840c20040888888cccd046088626532e739645693f3d45ec3175f561dd32dec92c20b81a86fad1ad0bb4acda3585dd40b23e8ecdc49a88dd12fe656b8a2dbe2edbb2a4dedf200bb12c28840d1080e55d3e0c79ce045b1a5ee639c1a60690cb9f60d321ca4d146c7b48ab530aa2ede407a8751fded31e37daa2de87557e6187f1e64f3ac55a2602021fa0dc744fafa03d4daa7579a057f0602f4461c6a7ce09d33bbfe076c82ae314bf97cae95de17125892c2092badbc1ae410f45e34a7d7ef973503b470c8f759d5aecfc78ae1b743271adfdb79e8b6750d483009d5f433f02e6787503fff541756c562a71dc0f414e5afd9d520f7e0f2f3d80454243284935996a1fcda2509a671c1e9bca1813ab9327554b5186d0eaf60c89897688cc73ae8577307eb6ca755e4d481e01ad3ca66a90f11fb1b961c4b3ef3eef8b96dfa9a5036fbd5a7255eb17d988793ddc190fe56e4d68b7b10dd6a4ca1b06ec95557666199c770c0bf06741346e2daee31e1cc8a4ab083f1d3975d9fe2965f1638653e6087e2da6fb29365e22d50a7e9d561431dfbc0133942fe2e8b5ea26c6cacf994f3fc3472465e691d82eb3e9827c217ffaa36700cdd17ebfd09d011296a71d3fb7b9a714bd7f332b574f9cf3e272982ef7041a9688b7ec10bc075f25d166f97b624da8d9a04966d2b3c1264698433437d8954668a609e87d55f188ace997f8e9bc312524eb0d6b8a339d06bcb59caa0588e2915c7124dbaabff556c477bb6d61f259b0d9b4a20acc289b9025e1174e232ac05080c3adbd7e646cf2f3b7f3d9e6d9473e75f36effa8cefa34c7e0edbcefd57c530a477238b029596cfd33c699d164de815a7e0d7b8c68a08bbcf787ee5440ac0fd6cc8a68f43b9688b36060917d955599beae9ee1418df8405e58ca61bc9df2d703a5a8e0b5c3861cf9f7ef3868d3f5f7cb3f98aab4f2bcdcb3895f47536e526f119425f06861b34e82de93f382fbd93bec8d196a3e1cacf2c96694cf0bcb5d036ce15a039ddf0b425423b57808af361abd79c7827d8fbaea2abf3b622b21c41fbb8117c40d23a8778b01f70b2268312de1075fc1228203600fe119160134b9899b48f3cd567de088eb8b6e6b435fe12b6ad615352d8d8744d0d1543eff3f4ee8fb3bfb13080f9963febd54ddc2e2ff98843a67c4372591b84b8ce701f013cb80e49cbc0f8288937df241f30de9d2598b4d83901f23904217751c36b27b8d23704f61fc8ca4516dc85f00798de995256246f4b8a79a0e075e24eb34d6818ee737efd65e5df3e2fb003f6320d8518928f322e889024b92bd00251c9c961cefcc90df4574a8212cde1841d3b14932f1d6a40807fc05609476219b2ad06791926b5a66057dca5d43a2d1852ebf4df0c0a5e6f182d206749d13e55ea516a60b9db6240f71a599c8a143f485f174e1b830a7284c6d349ed2a308ccf9bdbc6974a14f53c1094bb66d375dc4e919cca9e75046173a0e2519bbed66e6feab3b696fb69cc39953047586ab950c77eaea05cdab86f54606b468bf29a834441231ed51248ab291b4cd054a3f4850bb96a6462aef61157f4efa41938eb481a118725a659fa82b8eb78934dc76045b131be78c17dfd1fb4287a0217d7ff26f8cad62f0fb02f88940e7417f24006b898864a4ec7fb41aa32e8bac42bcd4a9f343d1027effe85bba2765fc9e6e0b1c283466dddf513a2ef297d6e3750cda8a7aa4787818dbebf8fcb40706be643f63dfc855b422f0999f78e033b77bc1e740eaf9e0f3b57d4f46b32a463137c8ed591b3b20c084b6026aa9ed6ead03e9fd5484bdd84d82219c00a93de454bd968e8cdb0af21886a2a7cb9dcf3a581d7412bc16a38e31e4e59787e223564b20e557533afe2a89925b391d3c53ea9bf8d55c953e80760f15f6a4959c44b6f983d16e38f695d52282c6b9ca97b1188706f8a5964451b25829148b6ff47c35379fd7d0d581ae41b59b8ff23f7586fd18f7319dc63af64cac7cbecef3edf3f2f414e0ffa32d0ff5b58956da5841be467448c4f4c3b8e1e1e2b02ed9bd0670b0095fdf59978640e2eab9062cce5149f06bb5cbf56b1014d3809889807ad73faa83d73d3682af4ef5e4f781a78a87f751078c9dc6450c6cd04f96f691787ff0338950ef5d8680de36766022002763af2377653da1a8c3fc6d7a040028e8a67f5b3d0bd1f459d8cb34379b68ff979a7e6d21c93e982c24cf9a14d374979cf39d8235d9fcf22cc761c177c745b89fca412b127efd2d9e0806e732809bd1c73026f8dc4b7d20ed46f7ee049a46bad20c32d141a8c7e644124e2d3080cd5abeda3d530e5a635b9818362d9d324097c42b91731a3673981584a29aff601d08b4bbe8c224ecca23422fe0c3016512655ecb94d6e0a8953fb8ff0749f82ac37534971cb062fdc0ae32096663d767ee387eff125a6579d3275d07009fd993b785358926cc190f5c7574bab36195f84e7ea6b18421b8889822ed40ed7253d7eda1ae049b5b47f37acaa2db4f907e4a35ef886c7b043504a56195ed97905cb1253f96214ea8524a6b194ff49fb1380dbe3876406c203f2044a9ec2c9f3b3b007a69c7776aca285abb3cd53ee50888c0f92121f4733228a4e46c885be4095f8cec6dfd1ac023d848faf43d5cf6868447cf3ee147abdd3e023e947db49c6164f3862e471fe75c20a6cf79c94721b4482f683b294611445d009bde5e188cf341c146a933bc67d240ed3c5b9bf5bf8df23cab6cb9a66f0131fa4056875c246b18663576107d55c53fc463a8907d6d86bc9fd31d5e97d7f5ee56c85f86a610b89a50e1d871d2e42294eda86bf64d50fc5915060747b0b4642d61a44ae30d2897a657f7447c901e264768baa6d975ff7b4fd1c1f007921019255cada98968263c03d4e2ea3561da1f8906e735be0e4cc7dc08a5818fc5ee2474d0119964c3d20b4efe8338b1635ba375f9e64c856461e19cd438adadde6cde3e6fb1cda5cf969a019a63376811a5f69b20055c7a49b1a7e4fc836666bdbde2481a53f6689f1179a4b4aff6d8387bc4b3c40a85c8ba766632c087351b587d3deff28c86c2b1d0673cfd676392007b2bee97d60a5bd7752f76f3bd2f9e407686e4c7bb7abc7ca41aee76683a557581e2620536cb775cee25753bbf8b2845c7540f91c3e37e61bb700ec21184780db4268a10718cb3f414910899f4fa7889a4365089d8fc0073b5c11f86fbade6a166d636d1978e80dc19088f83900d3ed4c38e62d3a40ba531f8d3e2ee23cc807491fd16de23701806b5266fbea77110845e179c05570a87d86fe8d04b93f419fbfecb6ff1831f1296822aec3977d83ff3ddc148726be67dd93334f5c49966b52aca66d6b9b04abb80369d4f07ccc83b3bf60c51866f564608999d7cdf728c11d44dde3564d7211d002f52528864c6c0eaffa88d3106128b1b743045318531dd178a7dbf017790699366424c5e99d5000cf9c4c81b927bd047760a4b5ab4a86e55f7ecee3d0b41d8e155676a36f60e6e0544e6c38669dcd70e85774dbcd8b5c60d9455c6926a1018f4ac560d70bf606ce40e925a5ef8a8ac8805c01784b839b38f85e01482204a9854e00e39622c7c14cdf5033ab5f190868e7c437f2b688c9b73e1a3850b1969349501e36ad425433ebc45fd19593b9829b688b235bc70241717f9a94d2bae89efc7d40788ff54308e4b77b8f7ca4aa052e1a3d9680dbd7bc247ada49080ac375746a57fcd859fc1760c1df16df34096b080cf447172178a2d056a64cc65d94776ad909bc15067a0960500087dc4278ade938a146b577af9c231d47785bf147f7f6e01e5e82643dcd388dea1ab49ee33f87642f8280f867e2e7b835ab8e3d8e6d2631f1bf34b558d8188259116edd9b01e7c9483f781fdc6dca4f74bc3e64aea0c60f0d1718a16739bd88fa2e9961a1db1577689a08f524c4b3a4580695f85f7267654ee61eacc89deae96a57c6e32301f3be7896070a523c82ea29a22304c7119af973a881e2202e5aed078c53606e3f806500a39ebbd09ff6624968dc70f99ba4c29ea4e76dcd686a9915fcf554b0352aa7462ef2831a35e5428848229dae4d2e3c2a3dc7d40f6ed2bce24b12f7437242f63e2a70a4042514850c882b62872fe4d330b5823064d1e606d623c23be9c872e5c2a1a9af95952f191b31f8000b271c2896441bdb2cea41d111978d064d643b122aaab52a7dd90e68629db716441096cae562f98e8efd2e5328e5117af9896bce71232e0b22917e972e24ee7f03d5206bb02911a4b3ab83915b62f72990d8a9250a99531b56ea3a3d5f3a49df0becb8be6889c3a17695e175f63f3d346c36e5404a974097f6cf7520a1410b09d3cb4afd1f8e4e8609d1e1d458a54ec8b12db0eb77679c79428b5aa7cdf68d450701c20a4025a73de316fe58fbb6ddcd63aba2cffa23f7537306122c69afde008842e545412c6a29311de30088671fa65f3982a991772d8c7758010af2ab956477558e9a7369f81e81cf63b40baa4c815b66db78f30824e32db5c2ffe4dc18a24bfe797d0f26b1d9b4d11d85d3bda46e9b1eb1c88fe21fe173a94d566114a0d2b99eaa8736051c44b042f88fc093707a3e99873b81ae1e9ec2c0d36c3c9e4233586812adbdf52d61d8e0625f5aad209f7dd367c0c72522c74568cd88e9e0897d785a82dfbcac1255a4ac0c760275be002650bc073ac407a74839cedfb8077c90143c491dbd38c261e213e27f51f233f48b4a7a9d657e4e9ab40a7171e7875d1355718610b0ba82e23f44fa657a1cd5f704f1ad1a318a58efeae3114b270d7e4b52cefbfacb187ef9479885e01d053defbb254827a9cdfd29640143511bb170c7d1b3c3a560b3d63e302fced3e932ce4ec94617ec234520053ab8b0c259c75fa4a81141117ee1b73a699d68aa597ad42c27fb6805d9ee1226e6a59c47b568dadc877164aac4bc347389bff7d2178fd9ccd6e51e32309eafc7e840f5ab571f5fb095fea491367bbc8cc4c99862c98d78b580b3e9de9abfe9d6f7818de0757cd70711d45268ce1f1b3727837e8aa74d9bef4a777261aea44d685664bc74c11717a9085d5159632d0eca70b293bd2ceb3afb32b95bc64b0790e73bf38fa46291a55075f9f8044e4d5f4b915776393a184101fe8397b65715f7b40fec480cf94d3c899d091fab8dff8d5649033dd635d23d57f39c035c028b14b10ece2fc7541d5fd7d5dc3c6fa4577519cbd71412fc2802e6df1f75182a2ff70497972c28da851cdb12b1827b047a7cdc066acb179136f55f96d6def4bbc1474036dee6933c579491acfff87c64b1fbf5a5d4dc4775a1393de8214b969999411c265b4c25ef36c0408b3c3409f47f4ac94b3d0bdc067b7265eff4d9a6a22082bae04b93c9f496199b8848b4922c02523e6ab71b431eee27992882167cfd7b75a38f18f916887be28eb61a48406d6df8950d18374e0029cde8ec3cfc0285239c8cbf2f792889cf503230a0dcbb3161c56ce99e37445c8880a6bfe1dbdf7dda660b010aba5f14b13d1225a51056b3b809fae885b570c9870f152a44545b0957cab7d3716a99bb62fbc9435f7137cc0b3b842cd6f3c65d46c7811d323679d06cf24756f9c74eaaea078d65ca0b9f78bdfeaa5e2e2506549f13155445cc2f7e18a728e74f641bb58234269767a78205ce81fde2677b2d368cb1a9166e8188638854279f53c47b2464483978d18dd25bd705771ae86e501b01e6f8b07bab5ced84f5b34786c33d65aa7ecec152dcd0fb43e10b48835c52bcc04602a8cd16f36cfd2c2ce6fc5b64212b1d946b1ba324666d8da3bd2392870eb3591227b92834f39dca497b2209015db0322b16fc1fd1a45c5bb591736c907b7b5e518aed13f3cfb1c5fba7a911294c3144fecc4348e5cc6b9a68f04b5dd682a0295581fd4a42baa079ea5b2a4233b5ebb4f4da98099fbc4878e03eafd08fe7c7f4cbdc2e742960dabe2fc979b7884eb47196df7cc0fef745a0d4097ad87879113393e48ecdd7357bd61d9f6318de47f1ebc95fa52a216ac08ae4904838bf99c9364b838ee45e27f4107bcfb9d5549fa653f66e9bad07824dd04ef0011f4331928ff467cd22fa427d0330c115ff85b794655b39e9717acf5a6508e65a240f54780e0d507b586c8260915b93411a9f1bd38d6925a95133ac20723f2f71160d63ad6a20f9af5ea835227a63a8c71b496a2e6cf1bd105ee08b6c5580a431ab4dd62788b699003e98296824eb17e8d4fd8233c75f4f53725bb7114df4c1da181afa04192a80406c2cb2921f58d1aa6a2004d080f48c2b63913fe02a1a10de875432a678f7b7b7ffc3351d02466621b89a9768c695de26cf1aa196f7ccbdb5b08e5b52ee01c9447cde52132317168fce2d07f2e1d7857857ecc7581be90139a89ef5e002016875a6f31ac523ce1b43b1d8cc5aed75e76fc98102a42d29e00a72521708db3415de275aa47ed08f17390c6157d0f672dbbf95524a046fdbd5941d6536ec3655c1cacd3f99a46ba5e87a8ef8f1709d52f42a8be6877eb7e9045a58e490d3cadd332a093f69139b0a15eaafd60f0c02fe59650fd48aaecb3042b20449a815fc2202d8197089e30a420d8460a03fc11a70ee6d294604b03c780c904d8a1e238d042e475c21720576780e66d077f81d23056ee3ee1bd409b26123249f0fc79480c87399cbc58f7fd85d81b30ae02503ce9059af503508e3201ba8ed3c9d215d170cc5390c63f9446927a42b6362e7c07b963082af51d3e3f3cc8ce5cc0066e4e22249af711328cec47594ab688d1f751a6301b4a3a96d7fc1bad5028571d564ff7a61b15865047ed592e1dcdc08845f389d707f1e1a9af5c4e8e2b75819e84452f7ae70867e8e1e95d783cdcf856094f94f33b7ba348a257201791191cda6debf75ebe323f3527fd915e98a1ce1a06c04a7c8dcf6f92cf23411afaf734485d1521961f966014078a9d6ebc2a2bda02d2c8026aec4b851a74b568705f34cbf6e800089d97fb6826cab5bdffb13497c2e2c00a54bb4acfa3a5ff863053e13b986e146558510e3ed9a7403a479d7714225b9ddcce013f4498e6a8502203200325cb675b8998292b1029d531749d3e756c4b0e9d892840c03f04448b09a664abda0312717621c79ee08d2fcf23e7db4b43564a556e47dca582618a08f79e086476ee732f0f7638f815aca920c2d6498192bf740a571af47666f2b61d021187db18d83af646a67b252e414f8c726af5b45d45601c82f5b99ccdd95da497ca5708bd7297956088d42beaafb117ad230870287a95b8befa83d2ba7d7b6105d231e320d4593791c0b59dfd0627dd2c3ea1e06c98111c2459e5d623de560bffcb96675e238a594abaa1f243e3506197f8688edae88a88cea9fccc836f2a01ee8ced0a159123f83ed2482f392188909c9bbb15e647a552f011f89c0e40372179632e74faa29ca752aaebeb52a146ea65e7ae33615d9a20286060a55f01deac18afafa69cfcde202caf4fef33480899c291d237a582b1e644f43a6a7b11f489427d5aab896a953f0baf1f51cc82dfbad589e33db08cf55c573b3074f6fc59e6ad7f323151d17d8c10340feac1a039ede15eecaacc4c882b886e0bc9c15bda395040c48c84765684422cdec1fbf78d67d74af569797178f5516198d11d1e66699daec98e8bb3b06bc5d08f90b4442c099b3c2323297c88df7116bc5638707cdc50fa650bdd69b902c9bee77a1720cbf9dd9e74c1c50c88c6d68460497dcfed9506efe358fbb5c64ea792dba1146e7d1891708b6d1857ae47c2af7e6aaf913bb1be00d96f278c221de4196a9b6b4f87a6ec7b85610170340e68e0490cad157fc596e08ea275e613cf680cfc67c9c2f112e7d9c5ca811fb2b2555c565628bfd75548efb65c2fb82e3839891b74d1f2915ba06d9ce98eaa0ecb45157993948623745a6d50ed6b6237071efe1fee5eb557592b2993c01a85433e733ec05f999e4c67bcbb9a628cee91b3fdc48bc21e570f8040ec4cafe3de2a1096a9731cef2d59dbd18820bffcfc11bfd03a5ec0f54bea3103c3aa9d1245933cb5af60be8fd2ad706d66362a75b875d993f16b959bc009f4ff1ca5ba31f65e423177b94b5ae0e6b31197da43f8ca7ebd1b5d32ed878211ccfb7aac512222815b34dd753403a3cd673bfad2f8ed53c19e6772e7599606f2dce25a19554a3bf624369fa7dcf4984642836dbdf2912cc81e4701e99307e3f1237d05600e369a4708e0c10c6d969fff6c204cbf9e24154f15403ed6d23bdb18094722f8038a9a06234d2c6dc7c0660757077f53648d49874cce1b6f7249a5ba4ee85d9459e5e89089183c8cb9037bee453d42b44f16aca30c0375f1e14d87bc389e552d2b18c19cbe7e0bba58b8850093e602ac3fcfb9e3a9e74b24c8aaeb6a0ed5ba974c2e73a302f8c54c519c46e81123b1f796206681fdd0ebfba53b41a71040adc31face03a7c747dc3f5596c1ee1b2762ab92d89de6fab402b081eae9b0e2d9fc7e2556d8a688850ca56b43e82deb49170751447e53c494985084229c10803b8f8e0dcf71a4d0c7f69b1de251be75ef6f4eb87d2f5999442880dae6bcb89c2978ee62b77eda21315a6ed043357c7855c01641eab6482baca5dad0a5b1a846998362945ea803e211dc29304d3eea73a405d0a4d280690ae0b5139145d985eb778d4e3026f084c3e52e8b30d617b56f202c0f10b906c143b15bc21822a8a17cb0adf97a7ea642e06bc82a8f28958d1eccea55242a8594744e001a7f5e5993a7365974a09fe1d45547014192c2074fb6961dec4c85ee248ca194036494bfc8115ef35068ed22d1c044124bd318063dd4d02b0228af7972c9fd84cb7f177cb3b39376de1e471b604bcd49a4b47d22e2359044ee893631128de6d55caed94ea12bd356d692d3ad9f079ec75ea904d62834f2297b3463c142cadfb23590bcc5c88710d651f942ac2d2bab2b9b9ea00cd140d96ab07b3c42db50ab5eed460fa1ba42de5cd7644e6310db34f8f5689ff604a103984881cf0bb0ecac86e42c590b62503fc997b25f29c82fdea08551719b9637d056bbf0c7c9d976195d6ac04b5663d1419a8b5255c9973bef4cb5c6b4f5aeb94d1bd3ad9c49e545bbfab2361b50ea441185bd2b7801413b7950fdf59d7f1f151e98f081d8a19fe0b8a381e432cb485a3f550e10363ada10b48a892ecf00f8d7c1307cd722542e3845a17b24de917086390bcef1aadf7b8d3a755e662d01ad08d95188fd7cb652029e80578bb1c7167bd1aa701c0992b2ad9d92d37acd0da8c0717a94e1be5f43285a228629318f064fd4bd93798ea465b2d397151a1b5f93cae42e36679d8355e82da3e96c3e1503655a6bfa624c6fc93dd91e879b814aeb9c13c61fbe0099fc2e49ce86e8ffc4c12144cf713fc93604e6232df3d0e906282124914280a7a3761d5f8e30d0268a2647fd3cd1384661781f6c6772120c42556a18588f0ca539085466d17b98ee36591e47e48e559d1be7b11a456d65b131aac246c611688c23797dfd00872bd8bef382c5214404ea867870909a59caf8b7642b2f32b0b093899b4177650779ceba5e04fd66f52c976fc4608a6e92b947a9e45603364fac4bdebaf274bb0b96288600f93bd9b0af10a8f9c371b6d59378bb6351f0d127663d0c8d9ab08cd0c5eae7fbe2b3e6b7668b55190bc289664c0349254bd891f58385a745431bb96dad01577fd929dcb7636e318602d5ff1152a4149a2087d5b179033d9366a7af3c3eb3fd718ec9ca276fcf0c1158d7cdf8e2ece482f78465aba5a04b55d49de5d68cf8f54d38e615efe9909c1126dc1cba1a584e2b334d924a9ff8c71043584a0b29fcf8fc809cecfcd48d75b4747634ed3bd73a29a4daeb1027d5d3be85613cae2635f9a15f64f18d7eee91fecd335c0ca4b624252a9323654b6d721df8cd02abb7f9e48c1311f63aa329484ba001bfdbe177e0ec15f6e2f4e8fe28ba8de88836eef5914b22882069a7490f96220e3819a09586beb41f87c3913b5ed9296eed7da14ddec110d9b9a04dc95bd471e4938650918611a7b914a980641950ff31eb9cc17aef7998dbed609212b032e2de302bae5187a7e9156f248a6ccd43b127f115922138b06f0beb1165f7ba0251cb858ca0974245912cb0527e70ccce96526ce82ee04e01115ce3772cc85f93499288d91cad6bd97be49d9ef88be4a0debe777e43aef293460b60ec746200e98ca0b2fa06c2152f9e83797417a4a0598fbbb040ccefe8136494d8d8f6fa25eb7dc50cd59961b615153eed0316f34ea29f1ae1829e0b4a976236a979e6123d3b39f757852c89ee2d35c618bf2e6dc21b77caee950c74811836e1305e846c652eaca3c21c4755d0f4fe41b51695da1314ec6b36e5e22f8300b7b6d2c3167771c5ac2793b3e9632094068e03a9018fa2b886532ccba3ce6ffb4232b7646a2be99dd567d394766bea4d69cb5fcbe4d4d4d63db5380e9f4626537213cb91a79181e3e1772ef8063879578d563a037c3bbfaa872223147a0bf9c909c8d676f10df19b17dd7c6b4d7f93982c193199d91c0b10740d2658a0743817a37fa17cdeed91d54ee14d8259cdcd2242e3c6dfda3f78e0b3364cced4dff5b292338fd13190b3edf9a4ee97932e96df046be9491dd4819d93fcac816d965208932a26a28233b6b06ef74ed808ceab19b2bbaaae3dfde7743980c3139a449319343a3c908ee9003db52f01e792b88e86cc7f1720b0108c8c8f3967eb4bc07f4049561604597929523aa2494064a045f731d12680d7091c80281bbc2fbaf1bd5004bbd3e04446f65bca7c63e98dd7d84b51f99b4b759feb4b74684bd65d402eda93234b76136050787b8eb21f64e69a4b1b89e5e881d6d839fa5de2a09a0f53f6a05f559c8bab92d643420fa6df91e19abc731cbe4a3a71d295c00292ac8e7ec397eef4c820d0ff8c1da13470d8fc9a21732a4e5d80540daef06732473dc6b0987e5427f577790eb3d0ac955d999a36b92b0e5cbccc6f87288f59319b03797f0bcf048cf69eb859530685a2b978aff9294a1e51099fe2ed0bcfd786f42a5a311c4088543082150609b4a563b062d356c6546a75e19712ecd394c94e6dc2e68b1e6b33a87be940763d76e7fd892234c1b19def524f48dc14e4e472f57963b2d32ffdaad9b7c660a33a044c4218cdce81c5bef55df19d629f8ade648383df5a19b247f038f4f4813b53cd0feb13a894d945fc23c0665848e8f9dad5adaaad3a9055148d1d7c08efd817037bbde59507346a0ed1a0b138c599583a01ed0d75c8dcb3cefca8e829df1f50cf4831ee0c965b3da1a19705148b94ff23af81095e2c43784aa9c4f731af72f4d6b2c2ba5c163cfa69d512b82d37e2c7de7635bc8cca688a00bab7d34f0e56afbe856b54afaf6e9c48826f7414f09e7524ef7b90f02a3e3e8e587843e1d2067af0a46b3f4fc1a939a95799971267e67d0efdf43871e90de3e69e306d43a9d7c00a19ca9d75c233d36a2f00321bd1ff9573363e638072312e45744a2d4290257c46a8f06f8ce903e106e9cafe86e7abbc9e61d5be734903dbee8eea82b65f1a9882965e8010884c886107104f92267a6842ae2b05480b48335a4de755e0438ebc28e21c3cfaf5a0ded840c8cb66640d5a051dfc9829bea565ce0116539f1248ea510baaa10fc8624c3baf093f8a72b201cdf52108bf3ee754beca54888d9dc113c4cf51fc47f7f3345c57d3d33e22da8764ba16a705095f460f7652881a65ba7e68c3ef0d07f3c4059cbcc376e7560412b5311f9f3bc387bf54e85329739df9858d818b1345e960e59004c2ce0885927e49695b316d497af4817b8e071c623e569baf04cff59cd766db2630d3c13550a16bd45f16894b5d4fae46e6151a580c2289bf356859d3a468db05dfd0a38849af410a717989f191239f1e4bc3299b91b605d39e1c5f9d7bace3650d0fc75069caf412bc744ac3be03d5f0cd8b977e10751ff5495de0549ef8daa731c37579699f6b7220eeb7b50492e29b80cd141c1301481bc1498f04c32c0800ee6e660dec452e70cce6ea5c26b1568cce4abfcc9581dd2306e4b1e002d5235cb12efc32d834775ae7f97a095867594f5fe2fe62f18aaa77e87c8d75f74b3ced29d05cb8f9cf82ae1d0df521c001d42832b7dce4f7c8a5aa032d4b1e0c0e37ad8931da0d627145e44cfb12629661ca1df83ab87a07e973da801ebe4cc1b49df5089a2130cf7890b79fe88a684fcfcd83062b2e426e5211c52fe21fdba135c389e4e1b74c97540ad8ddc599d62e6f3c455983b76a51328bd656044232259f70b8d034ec89e49185e07bb39c500ca495e52f117bb9e227a8d74dcba6bf56d57746bf90fe2521375e8a0d86d7e108f77b533c60b6637ee529cac1c798b638398cc397ee34b641e3388da3b5bee528cc3ed443d8ed15224394717466fccc8651fd1c35f2041ee9e397094400bf1853b2aaa5cc223d96d945597376fc641037a6856b112f0328f83b283412c053bfb95132893606bf36a72f6f663ec3e2de4f13dc78286f94f02f053ef00a0eb9d4c0f35a07309c2388f970aecac146194ef31ca07606db100deef373b742511c7bc33c958504d8f5122788826c7087a98457f9b16d84c03e80274ed513f51d4069bad380ee84cbaf19cc70f426402825ab0c7eabf5a558393ff7b753baa29e4b2092a9be1d2d705acc54427e8acd9e83b48c8ab92bb6a7a20584a3d3294767fce9e0b3c10cd9b94c35e3181fb80f27423efc41d1318a58a667d446895724ba5dddd1e743d0d5586cabf7e3809619993c93acd96054379451504b916f08fb8b98f0cb03a8f358920899e7a0e6a10ebade903d53989fce966f4c75d4443c271516f6a8f5ad7b5ca7faf6d0c2d6089339c5c3551df0e91d3e0cc34527ab356d29af8ee8d2cdcc6d245890d65aa63fb0474ec9c98b214f1715ef20839df7d20d74c6625fd705b705ed96009c5a208fcc15bae122b9aa6d493a73fb6220b431ab27332901b5c35687d95a2874f96c642daa3cfca498a169d8e3483e64c8d742cb460d4c024cbbcc1afa8f6d0df4cd58a8316d78419aa9306693b81145a4ccb726b5dee1e01450612320379b03c3f08b02bfaafacf976d06adc937350806e317228f3e5b3d1352643c46751900686199cbff6e7ffae8200a54c2384cf41c691c699156c99d704d1949fa6f343e34e0b0085ac7b136ff6c0ecbab65454f29c2b3d648c6461fb44bdda28127815d69271568920daa48b2543647cb95e3029bee8144f9a3ae2927179a94963610dad0c19e75ed8302019d28f1cb2eac21cf6685937239f6a4ac76d89f378ad5a4b7d90ae6b5e54815f0cb6c2aac210606603cb4ab13013497444cb69238bfd9a018dcf72973bb0075e2e37b67829f930f9cde0b588011088cf892b4fefb17bbff82783eebd12d362f7148bb001cd182780c0307fc9a081756f3420dcee247d461fbf05f292fc197dfea93e2d9cbfdab9dbc1b3d72274e581898b0face09f103a8965f46ee88e8eb8a2b86aed3cc66882e59d23861b211643c3395ac263409cb792b8b0ecb43014798acb40240e4c18a6a768ff31b14b340d88962c47640ad35758de28f6c2538ec74b80bd8ba9fc74ea61f69553b425bd7ae7d6d919cabcc7332419684946e61a5bb1bc8fc9aa98dd65ea08df055de0d8d8f43f2d1e0ca08fe32c919a7471c9c3718b50e717806a62071f158a23b26b145782baf44b9a6d824e988f9d6065426dea5103cde1ed265424f573871a9a5f49f6c24452cb186b22e2147b1c5b1032887426e08f2a6c196a41c02a02e3cfeea055eed6d6324513f822353e1580c877553046a058fd5c1c629e6e96aeff9496f4e564b8e1d0824f74bd30d7840d1c7ef3d104a3b38eb584d8c91228a9d060b6dd90b2487f38a5dabc71c8f4431f5ea187ab61b29a87188e1fb4a6c703aa5945e3c2f1ccf3da6d41a611541b4b6f804bbf08e21283cf186311b62f86a14a572fc6b2e48b1b8568c4a9a69dc4b4445b900b61a854cd203a11e26472319e03b3d7f48f6151e2cc733505d90a33a5e698f5429d9c28e54fa463ab5257ac3a4e913b7e48c26a210bf18d73b1984ca44e289af872c5f40129d6e446a29b0c967a0a333a3c49c45b9143bb484e63659047d4751c32b612826c8b1de3c194b124ee4b74253724bae4b0dcf359cfe149d21f6619afec7d6b9010512f2f7e0e2d167321543851ec923b817e32598c664d09fb453590e2e849266da5a38c65793a4c244bf14166ca62c62742ac60b238d3d9cb2989a7d7048fbe37d7565eae023c23a1a7d18817c6c8beb020abf1fdff893ef891ef074d343b93533481a8182357de8741aa312e6dc942d0c77fd271a61d4acf7a4d2bb563a45f719c1d0bec0481fe346975051c13396d6fd787680ebd2647b0891e0823a66e07e3af3c92cbc2c842a7daa84a57e31aff28902bc58b23de5a4dbd4164ac441ae800f8e2b527c9a7a500b32c5cccd689c7585196a6dcdfbdd3c2b4fc5201dd498c05c7d8b7b20301cd07905a8281bb595db09e37d152d37587e619c2096ec1b7156de9f6f6afd3680b68d7e879e1c70155f7ecf78e6563c06c0f86ffc619de6406009dc307a306336e66738887af3ab0e28ead1a612ecb5279af9f402af6d6ba1621de764760fd6957a69b8b3f47c273770d477de1540611b8ccd64168171c0371abe2d96fafec79338b1ef5134805fb5b72b83ffbda9d339208b5a9cabe5e64b1bdbd6cb5b27a5b63ea0efd10954f0137b3398cc67b2da488abd11acc980be4c5a9e115cc114b1c75e3bb5ff4399a42ed0c7b9b118466657b233bb0fd0ee9c9844e6189a3f468a023179d9fb91812221c5e934f84ac6c08cbae4ea19a5af7d1690f97775769eddaf105b33892e92ba407397f8ff12f93d6aca08b8278fd06ade1d803455c30069bee2bfe78ef3009ca9900b4c0ca25170b367dd797c3656e143fda7105eed9ff1552ed8a753118fd8d4bf07c94111b4e8c83d77cd60925f10498de31650d899f2dcef45b5355c72e864fcb8e8b032f2596498db71632759fddbe7ddf65780d3cf67671ea5d3463e9f0e6dc3321d12fc83ef71be043c3e3cf3308946e889f84c3cab7bccb01fd0a99c2a3a176ccd1c33f93696933d55a5b5ae9fb4d03ea5660019e748e747eec046fd416c85d8a3011ceb1d589bfc1eb446168b9fb524b6c9f9183cf3bfe837abdd787295612fab6584d2beb97ed4cff2e1f39325ece4c11ea7499d7a7eb15aa1c40804853446918b32b58f10d7cd29cb0818304eb4800eb6696b69ae2572be199f16d8a4c72fb3e32ce52e874729bb6434de1d6b862073fadd74b09fa38f4392ae703b5503b069764d925f3aa4bebed48f4b5f9db30aae48cc850d52bcc6e975652ae8e8a47747e7e61a8f4af6ebf77f44f10b69a9b2cd1b2a91156661ee8df53e036fc241eecddd9ec8c69746ed6a33690b77f1e9f34150df7b7c08dffc6b7874bfa007014d2d3aa6d3dc20692ad20b2f61f16b9428f49ebede116774f64883f269c6a8c614876156c877e0dc67c4e03d958165ac6de439a886a62930ae80db9063f1f01e79ba30df92b7d887f42adfd15cd39597488bedeff78ad309e30d609caf50af3274250f200b764514b627135e2d18337c082df38578506355ae113f17594b12637974fd6575a5ae52d756de1263c852412ef6cee6ac054b2b63d8e34b9b978b036a5d56a1d4ea8f72d6d19708145ab82771b6656deaba3579ca4e0a36131fa67b84d814ac435b104131de643964e30ed45f870b2cf68bd3b55a3c65df3d31fcdcf919d5a8f7e92f65d900c39d67b64b114ed80cc464c1130b109c874441ebf390df58f11c9cff82ab1d4d560fb792d1b6e3cdf53debb5ad9fce39c0f62522668472a0d5bf683b457fcf1762486e2a3d48050c51f8d5561286a5624c9b0bd3213862d073b4dae0ce5f4d592af1e63a6f5c0a562e9755529fd1e15af008d3647acbadc295c3e9650c2ea3786b59eec94505c8fbe426de566d435d6c085f00b50babf58623b1ad3fdd1086c2d7093fbe9dcf40199c23cbbbb12b0b94c64c7b60a97e40c302aa427959a1c2afdfd0f100c05f8180de9d06fe808d861214b8759e19d48a914ed482ae11fa5844bd2c08b34fb6b30e9d3adb6a00bf0efb5b6ff8ac29ca5c426694e7d4d717afb9b11e5eb86f622555133a993ae56c93683be914d728ac46badbd8cfa896dd7ff347bd659f6c7a166aaa264b486acb248cede20c9a1e7c16588f9b0831783ca17f0656493ef03613e0dd6315e202cea5be726b1398c284c3d9a12110f78c0a72e640876f8891781ac35d106c30e8d80714c4c1657b99dd640c4033e107beb40b00fbfe24db3e481914b695357c183a2fae78c85b687fd6f6de8dd3e284e2b8308d37766c3a3e7b48376dc0da3adc09876b0e30862a1c0ba8692f359ed1ff366e8a8061624588bc079babc0665fb54ace8ee6babe374309adc4c13218d2e6eca37fc9ac69efb03c121ff779cfafe83b05dbff61e088e9378e836cf5d8be9d000cde194e8e2a38f617dff093b65eb62fc0f943581eef14d9a35bb794f5d0ce638aa85c4bb7e4e48c09ddc0a869b64251f8658b32e864edc7001dad3d5b34ec65b902842031e7aa8e811e1fe27f559bce3909762d8444e4a5f7bfe24b66a62ce07ed9ced1f93db5f78db1c0677063d71825bb18587247ebb996b583aa1f4bbf26fadd19d0bb307e7bb7239ebefbd628c09aa2eaefb7ac68223626f35e426dd889b3952b41f28c1daff50f6a123bd703483cba177b512fca26f57ce0c00efcacbc540c9c175943b24338f8164e4c866d472f05fe8bd8e48f8fd3eedc6371b7f12ca27e3bd698fc4935dc6bc6d94b1df0997f129b8fa7983b090bb5a80c2b84a52308a297edcd55ecda6ed9976f51e42ea29828adcfc83a9abe9344dbcc159efdc8ec83da1436ad0f2a6719d8356dd832c00e5c1ca941a9f3f8e3af7edcedb4cbab94a506ca224af4f2210ee97f47ebf430edd5965378d03daa7a79b9f262a7f1bf4b34d2482dbbdb50e20114e2590ab4b8b59e3aa551825b9c664fd8803a0b25c6aa5f74e42f0969780c9bba427cb67c92d17a817b5f68990d6fcae15871460a2c50968af40e503ef12d0a2d39543af2c6ddef81ca3eb6daefcbc85697726030a99181e94e4f30a04d03152af7d12bf9249288dc5150652c0926889299aedacb1451e390a9187fb9207f1359b9a40cbf35055bd008761124f15ba5c88a13dedc14063b03c004f3646bcdae0704db6822e1281fca624057d0b1bff4e688996482d1be8ddf6644dca643ead447a027c1a8abe0dc32fd682eab1849a052138fa33803ab1e3e1a5dcc1ade818c48933398747c9dafe2fadd8e5df69a40f4b1c8871e5a13cfb00e5cd15b44124cb2b7114071ebedb29ab39c28b5c0eda36e014222885d147990b0727507fb4f0ce27b4b449840da2196d63b48e80febb89205e88dcdce1bf91f3408336237330dacb8c3fea2341b6e3842c18ef5ff3256ca838a204494e284fe8c960d226920a27b7424405275c660671fbcc7aa6f8c388e812d39fd3b1f83d44a97daa9e0f48ef27bd6dc75cbd787fa2ad8db22f0ce84627944684d737cae47531a654333dfe6879bf1cd43e7ccffd622100d537e6bde30f41d627d77e52e237edf25353dd68897adbecd7723a2453b8524583cdc5c4474a0ed93daa0e68222808c11dfa258aeef6442d0f4dd78fec2202d6245c5124fbbd923d971ee6ce697eca9a7aec79877243f08a115555a393152d406719d6ffe0b718099a26c0e79e8583120be824cf48ad466e51fdca8a503625e8827c0057a0b423826e900c548062514c7e441a49cbc7778c6d4d8d8a29a1fbc8989d35073f2e8b984a3d41822796b208378ccdf58bcccdb1a700f28bd86bc9c196390e8075d1c288319074dcf9e070f3bed41935a032d9aa1e14dbbc1e25f37001ba1e37f05af8610855d28ccc6cafc2f8d5706f9f37e927786c2e6e56dc666b7b7a543e8bfbe0f6c7332e64a7ab2e9321f1191dcce22bfd798527758e45984389b63b4bb215b28e0d6bc21ceb46b7a8be0f0359afbe6dfdeaa00e192b919da44eadee1e187da209dddcbd5d9dfa0bfa71307a93c30229773b19a152aa9e67054d2c47c018a15697603940e9ebd63467bbf4134bae0ef7469a62d09782c4480a54179e3d99fa77d562f2ba1952d6ef8588a190ab0e44c1d044a720f3305372348f35bfc627a70780a12be49d52c1a582f922b21cbfc567b773dd718156a238e968c370614b06313908c1d736d72984f503c999c92ceb0e93a975de977c6e4aef5eb938516d538f4e93bd2f7006fbc6d008fdd397faaa9abe2c87cde26296e83c17501195233af77bb580cfd3efe12aab0e0960386e961fb99cb76546be11aaa68b842ad6ee28f2a05f7c559aab95662ae999a075831929086e088e8b0acad246a63fdfbe4c205d37dc993cbf9be9f20ce525e4f8638e721bf2d02d07d535e3d8addd9cb993b2c1fc979d56f56158da24aeab22f59c386fe536b58e3fc5d37f3f1e860d41d9c88e0c012ebfb2d08657785084a35aad7343305732ea6a3e736dcb112717c2580fe0207125896a7efb6a1a24b1d5b8c007505af8384c6850fb76ddf5590a8502ab8fefd4211232521e75f20a91c2e09125e0f35a39918c8bf127f1509282d20905467393d3422bc7fa8b97bc9519202bb1adfefbc86cbe3633d4f9257b4cf1c5fc927726c3ccc8f06e9e983a10951a329ea55a0ac989737ded7230470b07c2931f42dc235924b9e441066bff5d562b3400f9a5d94b30117ec87569037b128986b064711e72224409cf0bb87c76fa7beebcf3057ace118522c5de1665957f7bcb51cf64000a68a9ea3f242670ed8149b2585f35448b4acee0c4ac27a104ccd0a65d76443c2f1fab64f089cd1426c52c7c95999271af496bed4decab8b9293671fc108b7456769fd388df1e439560508c68e751c9e20f31bb8745bd234c2fbb57f8ebb562396836e54f848e0eec3e2c30df4d09ea29290a5871a47878bcf79aa46049ef9844254f2d9142fcaa665c4a0716cd6ef5e894aa5505639eef7c442d105968859e273456415678a91dae2d8982905d95e33aa20067aa5d7fe2708590d9dbd0618504ed02c618a8fc3f61a77fa496c4c8ce1f822f21fe06b8bbcf801dcedd340c3267b8d1b0f7ab93721f6870629fc5ed5a0c3629b48c5ce5e133bf2e2de7adb143ec4b296c5a2f2c98339ba8e29eb6b25a5ba23b1964941a372db6f800310b35f91355f28dc93fb3833fcfa40e394a8f33c9c69a29190a7cd13992412df6e40af78ee050689296b02c34ca21ee04499b9fe7e2de8d6accd0aceac3f8baa1e82340b16da21907f4cc9b629d9dc70bda2b09edfff8c59937f0775b6b5d2425c53efd0fd59e616a4940f0bc09d4e0e6f25fc0e432a13a7c1dba0fb1a1c2c6240103f6d23f8d6a0d6261e26a53e9aa6d08696fb0d0282e8f8ab4eea83396f7e444428f2180d863a7dda88838f8d1a76270ed0756ac6c0cfc9d27b36942937738658135b44ecc16e867ce572a8b8d1e7f9a12b6cb957c4cca8cc77f322aabf3005920f44ea72d40d5d8b904cb847e7ccca8424500954c7570971ab02bef8c698e8e2b06caacffd98fc01017a5360608ec8387d4dee18123b72292c00629c3972e0d6f242d118792dfcc981c0f2c64977c236800b948a83e34f65f429ccf13ee4579da761f17b1a653f33245e8cdf140c46d9442e3b565785998051e01a6e88e941731e66526cb0b25ae72abf8bcd3b7eafd1192a56cc857bf803190cf8cfcbd2972cc6916e2ba3a3985fe79a0a4e47bd25d4f9edf461382eafbdd25dec00b621e631a6272c9788d3b3bcffaedd516c9e0c8587a031356ab2e291705f4b4978c2ac2486333ec7703868becec1fbc31dffd2f3a4ce1302ec0fef624c675e604da9df3961ac3591ca2e553a8c09180efbbb53ae2c670eac7dd06361077f510617eccfa5feda64eff84158f446f171d70cf217e338c8e420351d8bbbdf54efa3855bb2834880e25e98b6be534dd726e462b4994d29d21755d7a753dd47c684c21643b74e6a73d09fe9fd87b5b587ae8dc39a0710fcf626718ea621b6e42d7eaef248c3601e1f5b298fc9cdc8b4d449ee3f3cac7a078f0de460f8ccdf222e4e97401d119795aaf13714929f4cdce3cff21e89cd652e10ddd813f0533f99d8169ab90dad4f7dd43c9e054fa8b3c250df7b7a22dde21d45802466b50d7cd15ed31179022721ae843218fa0725d66309b1e049de7f289e94142398214db6d48b84d245c535fac978d2819680790d7794d1bbbcf7c98a4d54d7de2f6278a60b5ac63313ce14032765f35cb263f069a8eb3dd5289b722157ad89b4f3245c4b0568b0061d29359f493ed6f754a399018f06118a57d609b86ce067dff15860c506c8a2e8bfc2a3cb33103ed4c30a37d941f8ec5050d52612ce86e33522661a9b998e284789f33535b541cd9018fdd33e3ac5da2d7805f83ac388b833c07a97fdc17850abcf2340c721faf3e19765abafefa586faab3985ae107bcf82e43785e293c159fcb7fa485498bc9a0541f5363a3358cfea017b6c7f8702fc46cbeed55638d75c0bdfc305a2240373e4f6f779e464fbbf625cf7ab3905ebc89c77ca2ce8466fdf6c5fe5d49cfcc7e4dd462eb51c1fd6b66265a660dfc610f899d25874c321aa027196c7ac5fcd193214fd143dfe13acde2a7d131b6ca1ab61c5dc7ba047d1b578cfe80e01a6912c0663e40e63dc88b160ed2cd2f67058233946aab2382b667618db01e40c6019f7deca76be51e94bb8ea6824bfa979b8c7c3c4d971d8f28d65cffa40b33648acabf33ad3acf1275dced5f643ee50fc4f68900eebb80eb9c2a116960c6d593af8d492c1744b33444d14be5c9d91413f0fd5d8cbeb701d148fc33fc97a0adb31cfce25b0e069a90d88e575c622445d73b587c85074e31e3078af669bad6999ce81042f767f6fec41cad6436ffc4407c1b5136a62b660b67bfbcc151233dc76f4bffd1a29d2e9a74654b3c01ae1d8a3870123c45908b1e0e83c67b7a62969b05f8d442bc45dd3a0e897091f8f907305d1ece25826709f3b8cc37158078345ea27a1f6ea34885184f280150921194963468803b1e6dff3d0caac48605e093fec160b674180cf085b3e0025ed5ef0e3e40c99a8ea31801e96e3d6d58224130ebc123e951f4bac9fb2ffc8e6aefbf503724f0fa52b2a322bda77d421e3b7068abbfefaf8d530db634c7bcf3f6546f54bc3d9ea341c688faf9dd6349b2a4aef5934e23e36b79cc974a1c42d544d711183dda1eaddd6b7a9dc26fc4b254136e1e72f0c2f50759535cd2ad0031316522cbb6cdd1cbfc0f53c40b25db2fc5335a7d4dd2f919599c497dc65af4aed56accddd0a78c0656012074d37dc692b2ab936edb7460a3becba6fc390b856fbc2ccb16042e5ac6432aed6d742834a2d851a494d7bb4e585db33a539c014ce55bd25b41fca4eba0308468b4b26000c2f2ba76e3e69cd2f311952c524afea669c793c5f11db925b40696364aee4d5e3a21a7757eb292b2fdac653aea8ea1c996ada9afcdacab6c97d85576324fa44f82dd49eb917768bdac12d087efb24321f4b02c7e46ee4b7cc60e4ff85e113774eb982de7fbc1ce40d07f6257cc2abd5363561259a8f08fa4786365c9c6c19bfda419fa510518c4cd866ec7892765c2701cbec65f474c8feced9c19d5bf4fc2e6fb2b5eac8cb4704613ae49dcbd2e8467f650fa094313289861e6e16cd1109c93b6f445e92c81a1bc63cf53128ca27f4d36f0c39d171800a472f9e29c2f90e0179c4c159e56ae229e7f23896bc9787304c39797e87fec20478601da575bf8af0f7bb0948a35960642dd9efa36f42e98097c3ea9120c8cea0fa8dbaae33799ce31a90a86613f6a30dbf0dbd517e9878d860d2d4eb314923081fa25d9c8c1227dfaab583f0a327bbe7a223049ca879c5730543f22851e3d797978f180d4d426c89cae0d6015843e21ee53ee6b2ad45e3a49aacfcac3b0625ddac4e8a7833faec8903122448487c48b244dbaa55aa8ac77124b463facdc8d43651a25dd7271cb08b3d0801b146c01fc46d5679d22dbdc70aaf5403e9bed3f4bfe3248f005589d6e45bb1fe2200752b04dc69535c04862b0ec965d15fa930db24e7b997a6849dc48d8c52d4047637b3a0417a128c9a2a0947dd6505b3d0ef09dd2da7362fd6320b09384aab771e2673f104528d04f7de7b2d9e68b63d184620d41d111f2c1d2df88410f317e2de4cd75fffb5d3f0c7a2abb2b781462460e0c8d8f108f04cb4729608c9646587449cc557379cfc595003472fbeb42f39cb7181afd5f5e6037a410f394f93a4566d262887a2d49333746235f4ff8012dcb6213a0592b352de66e832b2bf2ef2916b32746aea0fe2ea6a9ed8e9812ead0acc98a255bd2b92b3f2211a59841db0d8d5b42141fd96e6064c610da6729327ee53f75904bac1de6d5ac4f59ec6d804a6fe8c2da74c5900246f1e2dddcb07cddc8b33296811f43ad59a1a6f7a8feaf4c6857606950afb28097e709694101fa2bae2c1562fac3b6667c8bf4bcebf06e811f6107dad93b2651122f85e0a2e67dc7aab0216b22dad1c29f588426c568a775ef4a0b6f95b905067a5f810bb0a24809197704d14bc34198ae6b31fe5815551424f139b2c2b25db0c44c32c72e93ebfbb529bfb2eb879735db21786a20eae5484c7b48363047e2d95166f9972c46421ce0ca5284d4d0e8883ed89c7852d9769cd5b121c62ebb46b1b8c51dbd2b118767bf12f7b20f27d77f19ebefdaf6750994f1c411aba46cb3797092349a962691220dedf112dcdc1dcfafe3cc17afb485489651129fa6a33f8f0a9942869af4025e6b2ef638a1618c781fabab403619a2798e6e4465aa1aa8640cb30759fb194a96e48fec4edd9d91735cdf2ab6adc0410e7749c5624f97b7283347241c4b9e1f52628cbc541942c8f3a02a837d1e0e4a7fd5951a4b01c8892ee4ad9ae68d5321f3f0f8c80c6d03862888c43df8edbb0832b99e42431de0a92a7d5afad99249ff07921d5d44c1186c50cf97e10acfd48630bc6448f2044fdc57a02f33c7ddf1c4cc02810f983d149d17a27471efdda8b4645a6a54e88937cc0471d73c83730e02f264e5815d00426986302386439212fe37c1eb136bccba89eb596666cbd3b6c9599b9b2fdbc0b6232ef02abcd0f7dbb7ecb5c570aa3770d17396b412efd6d595b90e394e72958af7db572cd6f456b7b0ee8159359bea94bfa2ccec54f179cf353da35ea2236926a19c007eb9fed7a695d8d11d9c2ed917a345019a4e19c78742d2e73064893e3306d1adcb3f1da300cbb76402eaf17f5c63b1a39a9f51ad6d102d7c12d8d9a5da47b60e79908af0b850288736469f10a204b25e0f35bb0c78749a41359b88a8c65bddfd99876e5e2602c810acb9808d4282cb8427f14343bc8588973f6830b52b8dae1c4974fd914ec1f7ca9caaa309b4e03ec8c4e68bfa8e87498155559e1c1f56eead94f27f375ecb912042fb9d4acb7a30191801063506231ad7703eaf6242f2c2e6228173486d22f5c1304155f5461e6fcbc78950e6f63f4ed27561709bee260492bea521dea9ab0e047f1c0b692fd6947075003f2c82515a74c9bb937ce0d9133b7daada0b28cd82ecab155c0935ba6f4d93fd3239009fe632445e5d11cdf37e5db226c87bd0a58cc521e70e9007bf87222cedbf0c4d348bc9577bdf3c1800716aa5428639b0a676071ddf9d0b83564717e79f07946bba589a5048f8c25c12555b6dbbc26604168b905a68a049d4fe115428db9f2035afd2518f22901c5d1c021dc6f2e6182d7917d22307ea24dd5cce1de314903b6ab943c87c5009ef2b13c1fe08451ad6e235839827b20e7d32f8139cea17c7e20eeb5cab4df606eafe54a7a83a7388bb77841aa44e3af95d06331f5c503dbf07c592ffda235768cab126035623065ecb61569efe04235cc0cfce41c9dc702868eb1e0567cdee8ec583a9a5336d8ade4408eb7da2e0b35fbdf79d1146c737dc99ced3410a70bf4cd9c0b22d89db42e6dda319d54b5b39f6ed79f92c27394bf2feceb8868197f21dcf03528f20bbc18ae2370071c11b995e68e28cb296881d1271952222a942b8814051425c542c59272c909a2b57e8213a9c1a59903116726e9ec160814f20865cfaa182856ec5add8702ad1fb39d0230c250ecf9921103fc43afd59aa5cd52169832994bb4eb63ced7f1cfeba71f2d33301b59fd411a0e6f42866b8179e45a8948d6af323cc5c117480b707a3e3bca0e767873554dcbf6f69beb8582c9daa2adba874012fe32473d68a0325e6fee09589329f06d625566e765832d9b3883bd3400b20a0daa2843fdd2b680e9b4dd4ff30eaa1284a95c95b717b7f7b3eabb9c6c76b6b70e8e8ef59394de011f042ab9818f5d0e51da2b4f374bc45d827f79dc0a9715913c895114e4e79ab3b2b938b885e028c5865999adda14b14be1a73c8c4bfcb374877176d425b13d18fdf9c9573a739fe9b9263c364f2a5d6298b4a6f7833366403cd1882cc63be781e9d844efc9e781e6ae354c2a73482cbf0c28037bd3325d7e373ebc6cb6080d257cf7659da597f7b536131787485292662278560e00609f85fe2b202bd7b25185b1675ca5970934463265a6fd42a2235c41dc57ec6f66ae900162737bd599299d2e0b93eedd215b53fe7eabfda6a0b6ec6e0d6c32c4a686c547d87e750a42f05829b66db1ecc9a86e2f5aecbbba99210689edb3549ea5014871000fb6ac679d9f51ba883b0c42812a4935fc2e5d2c29fa52048524cadd0d3b3f45a151de2551e195c7356b179a2858391291ce9a13924eb119dadbc60d5084907ebacf7be0410671a8735fe8a995c57d96e8b616a199aedacd789ea1cedf3bebf39febb23608e37e14ea02aad9790d0bbee2f7fbf6c2c01d606570c5822159a305672138f4b4c163b256d98fba83135410810fc412ad95aadc9fd4cde58d316097b1e0ea92d26585b4bd157286429ea7a339d78ed688e575f31d14dcfa65c64f8afc46efcc2ece9e3378c40b56fac0f191c80c0aea909033c516236ebd6f178d9d349539af26305d734ab1081c93f83d8b65925b1e02c9190d659466dfcc1bc9f843ffcde46d39dbd424ad073ee404d6243e5a8c60d7f9221c401157ed18336239cdb9a3eecc6698e1df6bfe49c0972c00534fdebe32bd809ea00a058f5920485863ef16260daf45f63af01ff010bfc016346b3ad0717d1e1cd2161161b21bb8d53890672668dbfca03bb2972ed43387859fe06e66a9a7067c3b64ac8961ab2d9bb7d72677152848cb8d83a8309337474b6aadc8de58676afc37e20c9726cfd6d4621a1193eae82d6eea9b782787cbd323d3fad579529311ceb400013737eef17851c63e69d3c508f522d38d5ede79c50cd62172206014d4048573796cc3ddcaaf8643931be0a42518eb4472400d18872fb5980006c5691aa05209abaac0f81d25c96485f65cbaea3c2d64e2b3a9a79a7cef657dd58ad29c17590296d15e5ac4b5c6a5ead364688c7eb16ead48e90f4983f90b318f0f3b8972f91afc454f98838d4d33100637b20fd1b175d821e12c9473a80a3c6ecdea56d3bd62e6c7dcfaf72d387d30f1172f6808341131861a031b61d3faea438c867b5b02a98a1cee764b7e96fdaae10e18503a5aadaf066bcd18081996a6faf3c557437c34c6b6850d228e33917b966e8809440d0858e22e90134c8da8e10c1a530ba9c846619c066dc63f6e340c6796d1055cafaae00f88cda1f1a43db52860579bebddaf634cf77c96a6557ce4a30d87702b722919ad809f9adb47b54e841f18cc16badd8e298a67545fbe3acb4156647d4aa6d345e576d236988e4a5893b794d40643c527f055801864bd44041180ba044b9e90abe833077316dfe081650560e4ac1e0e35e57684b9c00229c478ecae732da8d49614b7f15a8c8552d025aeb45e2c3b9ce08ed6f3f8027bb8ac14d064d20fd10d6b82d3f5fc40bdac7d89a919a329f985519869f72ebf07cd401fd714b67dc1525a8088f558a7546ff549e7649f22c45ebf28eebbc0126ef372380d8d7fb02b51f50165bef3eb0d1a96383c807ed58c592f4ec71f5477d25d148f99bf54746476ce4437cbe8f37429f58a7718a442268f4c17c50c02af42c0a716da4db31ebe45540cb6b48a8300d58a414f999e05b2d2ecc39e46d0842048f3abd91ec057afb1677c2e36fbed3a9322035256ca195b273658eb36a1d8ede3cb3519da39eb13179cc1ca2911074c42bb21fdace13bae95775f0f62d78e08a8aa80ea58ba9ff5a2f4d6aab18f03829b761fd7cb4f71ee477d762a4d368b674b37757114c0ea03881bb0efa161aa2b736a1bdbd0dc5eba4610a1b7dc063478bf08aa562c65f6ff05de9dcf9a5b901d0ba47c8377cbe89c52d1904be2d91f069acf43c6c9823ba3e0ece612127ac5cc42fb56b72bd6e2d9562a3e4028e6bf35707443c1f9bdc6e970081104bc304349abfd2762e4918f59fa8646925e6c254239bddf2a9b2eed9d8f2b1fa7d3fbf5580f66c513c5b557d7bba07534026d479723e3032d60a97777cd918dc05a95102173bd1ae3e3fefa0db81eab02db14bbf62e2d6e993b61c345039e3c3a1c88bd73fd0712e8df51c7c015d4899c6f0da6520cdf003904769a8b65beb19c997824bcc67f1ea48f838400cb506cce5513a4adace6bc9c50aa4224b17df90a9b1ecf0ca558c6cc311b7378c6a8884c1203303b1c6ebf6691712fade8dd23be1d2ea5d61b656c26878382e37c99147ad858f9cf5023ac2f26f8b996f44108db8f9dbfa161f37bae2ac8dfc2fddaa9a85e8af6295d24794df7715882a58d392ce84fa07f0d4fbe865e0c61fc6f810dc389fb84d36b78caeff8cbef123402a45b5974408c1c48f75fb03bb36933f600ea69016546ad9b16784d4a1b6574e61582fc2add3afd520f81b3922fd3c7d0584a6cda3dc1aac1a0dabf915d45424a7bf4d0a66e74eafea7802065f4c75b4897f203a042467eae1c17fb3d36673e1009071b0aa098dd8677cc0b0df4913357679e34529b23a413a0033b5a51039a301db31f472f9f515cd5e3af74baf6e2b28cc50ac082f4a6fa0441544eb04e244cc9a96901bd44de00087edc804396c4c63c80213eb45dd0214f8ac1bf0eb728af0e13b5e21e4a6dafb2b650fdc0171d2bb9a55209655a975b7b8523e2ee9cf82ed0d774fd523696026c07e411a67415c8fd81a7e955f726d47f847018fa2c2bad287b87b2485d37d0621401eb1603ae3f3da0aff945c05eda3302b2dbe591cf14db01e5a82fb203f7a0e9e7f96258db36d3520adb007dce5696cbe03a37111e30643e11bdf316ee7e939bbe7b861436df39b4bf456ec351ba05ba061cd1fe546d4a6ccb7802b61d5078702240c2d63cb3f868f4ce883572130c8f8537787593146dadd7f1993bf0bc55a8eb0d6064f59d4e3996b4c98b8fdf7b16c6c234bb365e2e9b08ac5d4822146bf0580576ea2938385599302baa469094d0c8f708d1028bf92ee0abc698dc54cf6aa7b6a6851410e44e348abf0edae237359565e195f89425342bc6655fbec79a60d421a603dea021b1dd1b519a60f9102dfbaf68f63ab312d16b95c6a28a95e0300d7deeb3660eab2b8831e4d68e5651ad63ee55144cbddcc0780fb33ce3dc31de15c06ce97d60c01f54d3fa1c381f0d8a37aae6aa40cef3a82d3606ef96a3f338521196192c8e81bfeeaf08b96a1137cb93d462a4d96eff3bd49a8bd552e32085a35802e42592158e893eee4b02a80b55c99fdc75896a82effbdacf3d5184f383bb4eac9661a6940c06c66e4ba3f237d55ad707db8c3c612962e3aafb0a45291299ce6a29f539e5c30815de15ca668d9c0e0355ba19ad08a2fd2ff58a3971db4062c206e860039037d820867f433a2547e83cc94e2b406c63e3f8f7963c6ec2ced04b060777b3892ac3aceed635f1a05ddc4f8ffbff63a80bb13c5b08f879fb0cf4ab0241fd44b3dc6ee47e24a75e9da0297500c262040f3d61edaf5ccc92bc78d3b07ab4dbf4c4e662c4af6975920e6761b818fa4cfa42f0edc7c66c3cad433bf8080fdb9424e233255800f2d3e0ef99282bc6f0f0681c7c3a1cad5152a7bd552bfd5ab5012846a4b7be0ec79409f883b6741d8e562efa3f6c38cca2051e5f453612581050e9481d025f829c71c379904f0374e8a5b3e7d8e8a5f880fab3fb0188818c809e2649233aa3c84aed20b2b9116b84c8dd943829d34b430c7a5875c47ffada7d58fc47ecf4503ab4faeb3f7de87ff8975f5a237b4b99026212e813ca10557cb4af01560e398059b444512585b17e0ee02b8a2a298cdffb97f16b21562604ff57f53d88d57259b0d55aad1e746501bfb502bd857ae124493d4a29f572a2671ff572a2f77d0ae0ccd7196b5b2ef02d8d1168bfba66607d055bd685a5c995430a41dfcfb8b268a941dfe7904210f8f583ac3da95e4ddfd7562bcbeab57cd0ccab3e68e62bebd5f465998186ef675e4d5f961c3ea8f596e685966b061abe5fbd9abeb7ff217d46332e2d3568e6572e2d3568f52c57961c52089a792d3588f52ceb6a3dd86abd666065511d7950eb35431448acaf3fc3cc5bd7ca954314555218515f83ca18512f25277af69de8816f64bfd2e0ac00be7d2423f07f0b0bcc39b9401538dad6abea7fa7faca41a11e7425497972828dd68411b54f9526090a95d6cf654be00b07f5f55d202c85a3fa136c845958adcf04cb2d12d5bdda776badad469c58b0048c191d4c13628c49aa26c28caa5616e38f0ec6092846d6d704cbb3bed68e13b284a857d94fbd05df4fae6a539f7af04f453ed224b19ffa93cb698862b5c298d8efd3a1b6ecbbecf42714cec985737af0744a724a3d2b857a925a9dbed3fb09f52825d40b07f5a7878da717cc7b7c57b0bc47924aa5c2824955f9f8d110d593aa7542a1bea2be72e112a68af9522b93eae54454676aad33af4ac3e453a550a82d5b9abe4f7da94fa45cf8fed40497f1f4281b1a3636df8387b3fc0bcb5f49a92c51249dde2aa16a50a857b97caca1213aad4eab941d5b373d78882c41a29d4c59b620d1c58ee0b36cb46e589a56536ba5c2d13aa9deaadeae6898d426bc8cdfa7524f43a4fad43b4d68612922d40bb430f0ab6e4f33687e9084e51685aa19bf476174304b6c71022d6c4868bf2e6942893108e832fa27611995404011e387002de3f7eeb22510e74382f3bd68fcab0bf5ee6252c7ba3f158d1327a857d20bc4327e2fff643e26a1bef220dca093d37bce831b1c3f548ac649759284654459f0fbbe57cef8a4befdcf55dffe2909168b656d0af6d917cef7604e924ac9fec7258cd172f962f4d1eb6861e0db3fbd70c01c4f52557b0296db95f515eb6b75b9b538acbab27683e30aa55abd96ea08e230a94a2898fd7114a4ea7f8f42e1a050d6a65c38a9f7c749a1520f1bbfb7a94f29f5b131a16af5e0ab94503ff32b57959ad55757d2cc6bf524f5a814eac1127c317eff8919517fb262f4f1f445701945181d0c114c8c4eec30da8c0e260165c65dc7ef1db572e1d49ff955ea51a917d8fad4ea53a89ff915ead452a1c0577dac6f091c699c9c1ef5c2a9af8a4252ebf7a84fc251aa8fc2398138a7d59f50b13042140a85026988beafaf541f47f5b011f547ec56bd98c046d4a35eb0d5e9853a9d7050ef38a88a3aa16acd58732ccc554db0ece748c1c4e8a38f0610625cfd49a6faa4efe4c2a9abffea4ae5dae0f8adff6890b0686ac625704cfd0647f0fbbeef67beef7b9026098dbb2cfd5ca7f5c26102f37755a96392fdef6756bf7202ae5e382a96559d7ea53aa9be24587d7f7dffbd60df2bc7c25c044888199d95c3c20171c01713d8e8dfd32001ff737d39348c35954aa594525f55abb7384c604a49af5f384c6063fd5aa58e27d797f30d000c12568cafd1c120c16554e2a3fd2570ac52c954a91957b59e4017cee9c1d3c346d5af4e95ccf881a7c7f9fc05b3306b8f60e5e4c8d2faee3a58c6241cfb38f6c504063bc578103a4ec5a90fc24670b439aee33fc6adea95a41e7c2cab5712165b5f89bf50335f5f1febc9e9ddb25cf5224a3da8f4d520ac6a92a0360d8dad5247150ecdea67bebafc695c55aa93d5a75e4bf57b3141bda7725ad58a80f51d61c5c87a55925dc7fab1158449389ffd5e4c602b55129cd5cce32c81a37f959ad1bf55a5aa5e4befafef95a43eca7156afc259bd98c046d50b966361d559d572a00a17a0c862b4b55626d64b0d687d945a34d61fc072eba3f4d9131223f89f113b8ce07f556a46779d27a06be9546b036ce07501628cf6595c8cdf8305c862b4cf428139c016e3e9534a3d51386afb2c96d330a6583549a7df757ce1107dcffaefa5e42202ff54a566d4efaef33db1cf7ad7525daa23f8ac1ad52b61a57ef53855eae8bf048ef5abd48c95e609ea53afa5fae4f4f5b5f4bdf5718628f5dfa75e4ae0ef3aa25ea092fd5dc753953ada179880ea2e809faac205b00050802a5518dedcc0fc84c30436e68caaf1fb2376470c076195fa7d5f9da141824aa1689e9cc0d6077efd0fc6047cfb5aaae3097c150d123036d69712ea556f5d49a86702beea513444a857fd4753a52ed93f3dcab5549dd8ef34a6a64a1d3f1bb11d8449a7af9f048e3667b45f992cd5f17ba932c0f21e7e9a71e1d49ff11ec472d5d4b47ec66b8619df0adf8366603dcdb330f3e16b869a9f799ad70c5120d5fccccf60f32c960ba7be7ec6d79ff1ba12457dcdf8d60ba73ecd6309bad2fa9a17eb6b1e89f5355fbf66e6695e576a7ee6afd83cebb1046109729a1baea37a9cfa58825a2e9cfa4a915a1faa6ea078d08c0f5f57ae788825c8c675250a249baf795d8922c9899a67a1e22002609a826a6abee645c30c47c2b779f17cb1ef5bfff22fa60a5fa10da2fa195ff3493c4d335efec56a5e465fec041c68bef5342e2c412d1796a0afaea5cae473d5a6d6d3bcae5cd17db1ef692fa62ff67d0ac583705fec7b9ad627d5a616cdd7caa56ee1520417223be35bae9a67b140577d2dd52a76fcf2a548353fe375e5ca8c9ff1aa5ebed837a3e66bde83667c52f5327ef64157b53f569a1ae43aaa570a077c0fa23981b494552920081822880043440f6088c802668830c68c0e66882dc00c118211353a9821b000338405c00c11458ed1c10c31c4589f950233c40d2a3004588121c00cc6fa3dca005eed079e5061c010e08b14a383210013a31360887166743004d8618c6511fac7b2081d071361fd568c025aa5f29a4a558b42d9ef74fa4010044fdf7742598b8a3520ac63922a497d7729b156d867551a1c6ec2f103c790068a7bec7b1b57f29d6894b8c3beb77198fdf059a7cf56074fa1ebd40f6336b01a9ff4e3cdcf8d1f1c391efc1c8f23fc1b61f835c2a711be8d2b7c966dd5d711eb13fee9c3e7b1aa0f5da807623dd0f793a366c6d3dcc0f1ac1c385caa97fb84af2420d51fb1b5c6a54ac1136833569598a6fa05046b172eac576dd1be988d3980b6aa5c9a7a08932a171a9ad657bb24ddd4a6ca85e78a8b01551f589bec572e9687078887874b0f618ae6a7f59606f592c2b1e0e16952dd8025458918071e10e30058c1fffca65625c2ef95d4a3de845c621c08550fa85e58960d306764f5e031b2de59ad91f5e02bf680b08ea9daf4d99645a17846af64a480856f43a3d6af537c3f365e355a2a1a36420bc476a964a4e83126799830616ebe6781a8946a75aa2d1b3c926e926a52250323135b22b4b11dc224db65b45d6656eff67bd577fa1ef4626176e6e64faf141cbd4bb5493dac1734b64585ca35c57802bf9cd1bfd563eca13a559eaf4c095e6cc08030432b6d9c021026391836b4b058077800460821c008a165548d0e4688262264c004e102304184b16082b0e20313040f37dfcfa74ea9d47bfd4755952a0c6f6ec21b87fdffa79ea7c90f71a9cf92e205bb79d8a752a914f08c817901e4eeee2c2230209f73d383c714e10a41a02b0547283608e53afd0c96fd53fd420baa401004938058af62bdea9158af7aad5eab25ae631f7c39f88a5520b42716d0177ec5bf7c40dfe7840a082809080808685b0b6461f60b141ba4b241345a8011428c1c304140d1054c104cc4bcc4a2883d1144961baa882da0e67b2c6c05c78064dc2a711dfbbec4c29a88c11306cc066f6dac8630c93bb045c996ef07080890d3eb83410a5583624b84493c29205f68ed971d958ac7c280d86f67fc7ec765cec30b1e16f69d829aa8636c89b0b27064c2241fa3a56a51a9c2f0e6e69fc9ba0dca54d60c9e9fa1a2095b37ac9f81ad784615eed47d3fab1f9fd4a392545fa84696ca5577e051b5dc10d64f59588eb5299bba80cabf1f2752cf8a2d119e2c2c076152c873e43bf1d8184f1ee4a8d357296ceaa687859d5ee572fb1676fa180ea13d59fb89d1244608bec372788000113932b4a48911929429a7a5a22987ca658cd006a18cac4f7d5a89fb53b799ac4f6af55292c5fa68a93bf8f8ad56558552f9d7d7890b0f2a0b0b4298646366b40f74aafb64a315ba4001844937a316310f8449372a5518de7c03204306073600c78063be7c0142cb0f63bee810c60f5b6c00c40148e687324014f1e50b1553542f547c01b3a50a305b9ea8191dcc1624ec1428abfaafd65a6badb5d65a6badb5ca137046ca468dd5aa06c7cccc2b35e365c39542d1b86ab892c2715557b5d6d56a3503f542bd4559313313ba4e10426cc9626439cba6a5040d122590acb01faa89857d340bfba458d83705eabfd1a25e43b127425b5bf6a74eb18010b4b0df620a8d45a3c68d1ca8d60dcaa274f4b0495ab92cf5200a85b261c3860d1b366cd8b061c3860d1b366cd8b0b152b98eb5afd801c224df02f59282632ab78ff675d600750aeb63abf862857d29f111e513a68ac141bd3c655faa978dd697f0082b6c398d926a6bfd5e4b2553c980d5d67ae36badb556f0860543b8f1095184857d27974d615343a386c6874b542b2cac561182dd62b7d8174e874be77a552b7210b6926c93dd6285b045d8a6ef63358d4786a4b0d6da6ac5f7a562918565d970d12cac0a2949fe658aab7eb1b1d812d5fa90857defa30d17cde2d8c7f91d7fe3c2b1bf438af50171fcf7382e1d365e491bdce162edc8910327470e1e3972849023870839728c9023c7e7c8e1ca91a3a615e3a14ee15bd4903285e632f03f95ea716e5c2c009c70e3c6cb6dbc56aad50c1047ada25a4153a7b021045f49b0191fd22099f14a427dea51610d1abec5163663529d0236c395545d27d0488304f502ed67554b2c179818168dfd2336c6439874135340e82ad5cdc7033eabb66c8038a07ef538a45e354314a79f21f52a9c1550bf7a24d4af5ea71752ea552f1e37388429fbb1542ec6c1b7d6be8af5b52a8d12d5db174bc78d0e11fee686c7df54119e078d1c56846f845a47a84c65be9f5ac686061336063e0d1e8cb288f03c9e15eb521fe77b293a1ee7a5ecf89b19a240e2f1373f83082f1c9ac7791d8ff333f078e1d0bc70bed70a38afe39170743cd2eff89b97bfb25818accc5726ba7c7ff3588250df0b67051d7ff3483afee675258aefafdcbc8ed7f742daf13a5ec7eb8a8edff1b2597210daf89bd7f1d60a2cbcd0789006921410f5ddf870fcf77ddf97c5fae040fd8d077f427810c78bc9c2c45cb9e1aa4d5a5c56e6fba95f74d408c14f7dd28f65aa18368b85811f82cb36d998140b031f458362fa827ad530ae037edd62464c016152fd72c4d62d3e9415358ccbbe4f52b15833686c120e033f44c2c2c0afb971e5d898fd1d23ea05ab4920617daac3ac75cdfc8c6fac7925d9c0429b1aae24980d57526ba431f32a57d209c472d6d7fa52bf58170efc4aab1fe3a188d1353a982c618c37afe393dc06624e9dfdd9f1e0db5abdec7055315c3ac0bf71811f6b0a93ac97117cebc5653e82cf046631d62f388428558c8730c982654e362c1f9a07df36b9ecabf9243bcef05277409a3465adf8f22c2c5ca7068d99d6e7a271815eea9095efd80747fb35ac1a34665a5fea183b26592fb58c0dea69becf7ea171b90db0857259d7b1dfcf8d8e771dae96db586c8910e56558a75aa696b979f0ffe6a686f66b2ceb6f5ce02be9c78065ca3069f95cac2b59ea0e758bb56161d5821f4b40a8e36f3ea97e517d12cec2c0afffc5fab01efc6a85fd71fb3df8c52a161606d62fb58c9622ac0f0bf5594f9da83e09f55285532c0c7c319ab2589f1daccf162b84f5a92f298e14bb22848d3330202a5518dedce4d81fcb848da12c1722c047d17c3fe302ed67ab0567a09e956a7d1f3803f54a6a8d4853ec8f07812a2c362cec072c67d57888fb7e6afe53a96c84618d9b1b1aff362f1f53f3f22f07667d5830ebb31a1dd5ca12feccccab5aa1cb5aff25dd8c200d97cbe562d58460abc6a96583a6090ea779c1582dd6ccaab59ac17a5924d6b6b0ef4f9c857dff4a9aa9f5e4e2d2b22b2958ae1a911cc9127aeb86e7fb55ce0baad70baa2fe6311bc29305a760790f2594f8e2add60b04df9b802038f2c4101002b950366e78f480e58029d809045390e459c0a4e0c211e4f9923c0bd8e954eb176322045fb126c2fa6e4fefa7d70f21f8dfe9671e4b90eaf4c25961b53afd15950a69e55f2cf5ab179620141016063e0f0b8b251126791637df2389b0c99493f5b9eaf8192195160694c343e408482695c5862a56cc8a1096c475aaaf0f1f4b1048f3c25981c6878f44e3c3d7952868fe4af8345e2a241a6ff336af2b364fe3852508a4f9ff1e3c40df8fcddb1935ef35af574e0ec2d5876ff3493e0647f3b606fc9a9a9a9a9a9a1c9a1935ac19ae2b3db685a96ab86036165b224cf2307ae47c0c8730c9c3807d8d13347e86cb092d1f44e39d86e6a5dad607a4f1f69dc6a682de93d40a335cebdd9c7bcfcd3c2fb662eabdcbbddbc4c934d13c954b39e86091ea292eb53cd9d494d7d4138e3aa3aa7c803ffe09018a90b22ad509fc6af51c5674eb75053085eaa92127af4155afb59e4e402ccb7aadf5b34b6a4d555beb87b262abad298b034aada89a725b69c4cfa250b099afa0b5e0960ad66a672a0f6c5df9a982f6c3b526d95aad2a8ac5b1d5a2405b6b606b45d9ba42cd51eb67551b387da9191587107b43f55503545b51b656fbcdaa056756406cab1a51d5538faf484d590bf67c33d6d6588d4f9501ec6125f98cac836e9ba8e007034fb67e7e2240754175eb61187af50a565b715055f6845aedc9daafd61f75a7aa6acb5a6b5142d5046b415b793e91a5435542a5a1b1c312514f564705eb57dd1ad99fa9a05b13e54fab3c7ceeda40f52357d8afa22a98aa34f52bc25a95ecab405fb5167cdb5ac1eaa9d6140fd833024fb53328954dd52aabd6aae043d59505bfa5fab2bb5a3f9dba62d9aa4a557bc48a6045b0217cfe79ada9286b2b0d187ea0d561adada80adaeaaa47659d6c3dd5193f389628c55ad95a53b552b6ae5055b57eb68275490dc10ab13c2ccba6eca97ed5565b653504cbb229b07ea7afd69ffa55585dd556ad754815c1ce7ca9aa02abad55562b0a87b551415b4f60156259f5b322d4efb316b46015626ddd6167eaaaaa405b6b95d510ec4ceaaba00aacb5fe7cbd394145e443e154bfbaaae04d5dad642c187044a80000abb5289bc235bcc1c35a52abadb6d6aae329d7f90b582a191770e0ef821263c2b8e0fac2062d5c1730204a0bbc7024570afc480911e0a3ab854351a20a034071e5272b289144c6e80239d244091176b0e4f2e011a2c4cd8e903be3899f16d0f4f871cd549f16d4317c68651cc0e7c9709116041174685d6c8e1709c839cf73020a5c72c01881f6ad113e070de752838ad34e3ff88337b87feeee3cb3bc67baddac34cfbb94e63445e2ee3b4e02cee5238ce6229e37f229c6ed0ce489bcdee6cd2c335aa17077113c1c01c8fd66d676723bd4bd3682cadd65d84dd1a9887597d4788abb5128c2179d8a77df724653f3e17c1768027968029ba04ef89ae2410d61029a4ea756aa8414d4002ad103e66831f1046a004d6093158e191e373734ad5c005ff844606d544b954405849af986dccc9c3ed0a49aa2c9c6941a563f9f0174d0eaa2e95446d3a9b5c3044dadfdba40d3ea66864d0d39ed9c84d07283a583081bc01d9a6a5c35ae4fc76647756353860d2714544029225fcd4744c544d3e7a46707358382a2e963a1768039ac9eaf822d306726c90985940ba81da8195452cb46cbc6ea668523e5c237860da81d9f171b4e5834919004e67e464208a0ac5583b201eba7f3098146ad1c289b6a2185932a3add985151acef04b6beefb35fea537dab191ee0978a92a2516334639342a5ea970281803b6055e9f8706a588d707aa269061435d8a0401cd5900d601736bc66ef65902103146c2182301ec062773bfa610b92a0148afc64140c1cec9810d6a85230bcf0a4a88c108819c1083ef01441c41123ba3881161dc0c0041ae0c48e58c210bbed834e799003325c94400c072280858618a6bc20e54991922423889003471515c0d20006d030c32c041e191d6146172ca8926b2a830c1ff4600a0c3970d89ca00357640003139080037ce84100b3185c68e14911911621b80204162862890a52a045073880810b2480091d70b82107644e50020c5ca08a076469c22511121b1a3230f8a20b0f70a0025448a1801f78c0e52c862930b4408464882c6643a345083c6080237ec882cb1854204a826488c3e00b2d4200e68a0a502185031400440f59a8a840546488ec07484f8c860de865c0e00b1680f1c0151ca800150e5000103ff4c0431617cca84c4961471423084d98d4cc58018f2d3be820a5051e04f0a0438f298a55191f19768c53102c10544f800bb00ab04e541fb6e7e3a9224be743e17b1c23581e1527b5e3d3516fc01c15c7aa060d1a5f08d6b46684343b5a3a583c666c5629152a6551a8d3e9ab8eca3243c2079a52abd40a9ca1f249adbe105a483514bd5430d48c0a086cd554b0859a81bc8fe6b301b7b8c18826d40c9b5a813934210031a06986855609e6cca8c102c13945012b8a88069a8a3419b2b9c182336093980f9a6260c309616aa82799cd08476ab0e08e4f47575d464e2894a009851ac128cb8d9a201c3e253504a049c7aa85968d960d2b496ee8547aa6074d44f64a090d8830b5fa684e4aa00076a84105ce4085506b7ed4200304ac4e3041165519226658d6e9884d4a08c804c3e0c5861a27d84c9299125053c01352426ca080124a6c58800f38429e2c3464930158d1c4dad98eb881c6474d6581c73724a5c3a786999410d48c6ac6f743a4e40b6126490f9a6652443447aa25384892ccac96b48e4a221468ca01e6f8cca064356850332c24af1812d034a35a22424d87a6d3179e2a6a05d4cc6908ea042341acddca04d512d44c4a07cdd0aa0758b4ca618347093b709ca042810994126a985189a91f343f7e888c522d30b5e324fb7c562dd0843f925aa566c09d131310e8483de17cae130e9e958afc84201972a39ac1b1faa941a888054405037b803d500b683a6106387442e124c2aa07c8a3a6e70bc1862671a77eb64f07fc4e32bc6208e202196d0003c27cf1d280053031002c333069251b2669314c79410a0b518e8c9aa8b04406f4035602090078f00a0e9401860d64908211125e3b74a4b880200b2712b00292146421dc68b15056544145145d9c60620925b818200acc841df10823908eca10238cda0b60e00003b36c03840fa6cdc8909954971fb6fcac50b08502bac884f8e4b0c19a51a578e04c40025370f9a44805a2244864407a62346c66d08007e8410001a0e145100b3480010bc0d2020b3f3e3736401184d9010b468af8ac522807e440c503103044103ac890c4010ee0c3932223434c68d5207c40b06540328f033b0694816dc1c98b9a027b026b8255095a62ac08ac16b60aeb80af0156094caa3dea08aa104e3c6874d81cf646b56153e344c3dad4109c6159a719bb52a96c2a75b260fd6a45b9fb8c0f091ede88e167ed6ed44c753bb8cca489eeea7713c66fb868f3511ede54096f4c772fc1c31ba1f006c8696fcb1f7bd83f2e4d8d9aafcddfe60fe9a537bd38f2aff9bb57bbc971930a6fbe30070f68b4bfa126c6f13ef645883cac089147cd1bae511145118692440581f92928ccd1e43a15d114ef7d753be9d60e7ed66b88a3080e186a6e8dcbff9dd1d738971f836132dd658d63e646185ea278dfd737c494280e6f20e0c696c7ed1b8acfb7e5c7a479ea4fb32dbd5baf60ab1dbc4b37d6e7b5b983eeb1540adc7d04f7930dace0a181bb909e37f269ba234f10220448c88f101f2141840011f243880f213d42788408010202fa01f2010a020404e807900fa01e201e20213f403f3f3f3e3f417e80fcfcf8f1f1d3f3c3f323c407c8e7c7c7c727880f109f1f3e3e7c7a7c787c8404010af213c4274890204082fc08e223484f109e2042800001f901e20324081020407e00f101a407080f10213f807efcfcf0f911e407901f3f7ef8f8d1f383e787101f403e7e7cf8f808e203888f1f3e7cf8e8f1c1e343480f50cf4f8f4f4f901e203d3f7a7cf4f4f4f0f408e101e2f9e1f1e109c20384e7078f0f9e1e1e1e1e261e77b38608742ae6762815771767726660b0197e86999c1919fe735e86ffff77771d77146235aebccca8c611f797853544a8910a69f8c05f36f3b26dc3e7ff0c6de36e66fabf6df8a4611cb96fae88ab4811773f21364548a308f7d7e6ded5feb5f9283e65ba4477b9f6b6fc7b97dfdd6126b8cfc87edf2fb11269a25747630a0c321a3c7ed6eedee568dcf09795b8f6bdf2e2f4bc7be724cd698a8497d33407d97049d6ae10209b2edc5d1477ce66f34468c3c429277632c2dd713cb4610a6d807c89eeb2ed759e46c5e7c7e7f88081f6f886def4316e3f6a3e36cfdf7a977bd946cd199359de74966e3dcbe5d466b1a0f864ba391e1b6a16dd221474441ef10240f44eafce02ee264ce131614aed8d3c151e186cbb5a15ee0e000f4324cf4205770b867d813dad8ffd31c408307ee2410bdc8b18a2c96b828e78cd818bbb09a1fb37c6dd4b16aca07281d15c447b349b5bf72406eb6d5d0ecfb429da76351714511ca93439c556be577b5c9a4b66f979ffd6e5f0deb7ce3420d6e3f344887c0fec89fca3c0802716a08019dc5df490a6cc4e9be9ad0958538321308052d1050f05431f0f0ea043054048f1021c0510f95220e6470e0320b1c3142390ef4b0f37247662182ac3879caf090cb8be38f241b1029d1e9f0e4d434c62b0e2841638f0f87450c01e05b52161c46c7c5164101e110425906819a0f50d392264020633f8a12756c1efc38c0046988016b2e488f1a17478a20730247004891d61d81a5460a949132798180a6d60c304e1882b2860c28921225f5809744181088ea6bc00024370618f700197087041c4083c3231b6862270bcb003195c475d64616d597c088e20c114a626acb04db488b1831c3a788d2ea8c2f64c800b0c1c21cde0022190c2e2e8c11546a44b1491c41428aa184d1ca101202a10b203094cd416b020491216280097d90b90a81d20c009524c0102115c20204485028b20471cc062082a4576a840e400430e40c07004073490a5f2a440fa4289de0a6e7857ea141dac9864906206251c760d42406e89021801064f85b39a90828a8372878e071a9495060827664e02706420658aebc00a2a21fc20a84a084620f916377440d5c38e27b00adc2de085051868072ca2e832e408b80189801e315604c10422ae258927269490c3881712209e2bc10880987862064db81c3ff281061f219081065374ee405f8808810c1e48dd8080bb0835a42084a98c10ab2cee5f144c35e00014b5561963c68869222c2304481c11a30c0888600239a4b84007ce09a38c02ec504516ab6ca4250b1b9441431530509540d8eca8c1176590630420023ab8c1c1cce0a20ca205f4e85100530341023165885f4c09ad38018521a82ccab05180145c70451819b0406105193f00811712a2e09e1e09544146170350912983819a1b4a5290610505867441f8d0e5082da0204301651430d342cb9e410826c8f021015d582089296030850f4890b1bbf801af872e4683058420e385218a70d8e1072a4a88b203192978a08a32684032c07394850c1202509b9dce2b2ae870858c990844208a2e0b28a3698a3d06183b7041992058b0811c94708e5182259eb049a199a5a007e51854a8008ab3c70cb526b24c19834b104a4984a00224786008a43170e0c00a864cd841021050d1640ca52c5888e9620457a43064680ca30700dd8270429007f440648c206000992922c70950c000c818385c72d00204446080883072c6f0136c1c3e40820db20ef41023065b86a041065a52c4131e627c4003a1103e4e82c0c28f0d311c6003111a3d2a1208410b2d3186604016443f1c613aca95018a21030d9078f10080031d3e208618d70055a0f0218a0478200261889184042b4c81f54431e2061b8891c3439811a2d882450c225f88617301167e00635432418b8b20f4a00c9e03c4b840155c3c1113042e9ed09191a303465c01c6dd9d8c2c82908118ecd0e22bb2034917eeee34332a938a6f68c1bd2ef570af555aac3ac3042bcbdb8bc1702eeb9936c518acb6d3b3122b9118478a1bbdb53a103260e508894809d1d04c09d1d14ccae8e48b18f9180cc5a768dbd578a76ec9f50e357de7ee3b1ea276709e37f21bbd39b1d4a988e6db4dcb9dde0def9b6ebd43e2d2c73e6da7231fccb800230461a037e0a2898b0ef8204a15301de01f8091238b28fa0b5906d20c2241247821841b3e3da2b8c2e6a5840754414b40802d6ab45001d529b1c0e80a1a377602b0050a92482f408200c0508478a5ba2d9ac108257c09f88145471520f092022b402e5424d082073600c0fe62a7e606d0185f17055889043052fde6c93783147e10460a9c20e20628d00d4a0c248d501dc4814e6e84010728c0a8010039e82067c09d17440867d540035e7b74dc45c8d2e41fcd11f7a2774f8571772c6c51137777797822da379fb659cf2c77723b14a799e4f92246feee1397f865fa6a7797e2219801af99e74e73ed86205217772624dc79b6b87b16f7cde49e4e39ddd12920cddd5f2188e4feaab9eb702772076dc0ef73bfe15ec3dd69b887ee5ee3ee3380883d3a1aefde79dedc51ce4829b6d9764155f78287d60b5c6612973c62109147072888aeedd87a787882f4dc5acd878ff2a7c7e6a3934d51e37d5352eca55b9b379ceee45b7ac99d1497a7b9abede05cc6edb83b0d1220db8e92cb69127767b90a674bdfe6a9d34fdb9786c3c3eac5dd69786881dccfbb9473383d95a076c0ddab87f50a77cfe161f581bbdbf0b0bec0bd08132e5133c51a35752a9639b743e2a5d86b13f6283e9fc8e3da97e72ee3f4c7dcdd877b45dd5d8787358bbbeb5424d19e9ec1bbf32e3d2d4d91d01ebd8fe6a7c560ba9bf2d09d4cb6cf9dc650685fe2f3bca4bbbfbbadb9fb8d87f5752aee9c6de5ee2a4f739ae247ef97184d771ba71bc5397cea72e66ff3a6fb6fa8b9f7cda5d9f6b7005e8f70f71d1ebacedd693cf424dcfd86873e80129fe6b5bdc6bb57fbb7e547b3b9eff7d29cc3399d8a1687bbf3f0d061ee6ee3a10fb93b2f9fb6142fe5ef6d93bcba4bea5424f1d28c77d31d32d53b643ecfbbd34b6f5a334f774fb93bcadd4fad0f74773be304172cffd2d434fa37f3041996ca634110234646ad2e2d5ac02c5ac0570eaaefe7ca151aec7f4f437df0af448194fa99bf9245cb079d90507f7a1a56ffba92c3079d5e576858bd4e8f7ad1807ad54bcb077d9f7ad1807a9d5edffbd380aa282b3686b5f5fb98b0bc0acbfee95465b1a106fb16ac0f825f8d00cbb1b894ea2ba1aa7ce30a0441d0053ef8bd4af5f54bfa6a7df0fbae24d547815796ecabf6f7aa577daa2b29d56bd32ca949a9ff9450ab97120afc93eac1d7a7b2af847a3968df5fa99ebcb0bcd624d5afdeb258be7a3fbdd20d3eeab5648f7ca0abcacda8847a1f675e55ae54b91951affd2da9a3eaabaf2a57c6d4eb747af015657a496d962f80192de599d1d75d9c6aa169b3c418d51aa7b79cea1ecde8a805e601e0c2fd16002f017821003c8ed3dd46f1d289750ee3764e89f1466f7a77b7df19cdc191bb2374a7cd1ccaf80eefaabc367360c25c4ab17e8ce2de69a637cdba1cde3908e5a072176fa8d94bb70e4ebf57dbd996ceac715aa277df4b6eb344efd5ed705881fbed1ae1dbd5e1dbd5612be6914c86840393a77829cf7080e2e9124e75d88aa96fd7c8881322453adde51aee666274d62b2f4eb7bea71123d88a79f439d88a79a4bb7809111f3fa2e48d127d0ed04e77310e5b318feebe43e5c54bca8b8b96cc7af7c4e952d6cd986ece0812918d8f304e9182b2a8442742526e00e3862f4e65ca3b11927283016e38dda94cf99cd27c18a688657a79282f67273219122fa3378c58df50f3869a387d979ce715b2210c9a712e6b1bb8b868834e44b10d47dcdd867cf26ad8c2c534bf8fc7b51a9adcc71a7886a4b84c73d318f78c8e4d45b8d8bbbc1497e82ee7735113cec58fe134e760df43ef36a189c779d8f6396f2c5eb8d77e9b803e162ddf3bd12746a7c626969bf3bc42348c1169586267f466eaadb199e6194e5fdc0c657a66e599711aa7b83d9b010bc7337099cdc0e4e63e77b999be3823e3799772aad3dd341b218273265279e65c4e6d3c8ce6ad67338c535b182fe215da11b1bcf262897917b765f0c25d8c5d191a20034de7f3f72ee70c21795e3e71edf7ae26c34dde64ac7c41cd9c152dd70acd734ebf57fb8dada850b327a6d6d3a107a4ebeddd2dbd2f966826b1662a23c64abc615f3271a9d570f939341a13ce5dc438b531bd184bb3b97471b8a6cddca7d9c60b93e27dcfad61af6fc8f3c263ea9de7ce4674de9d9168bc25ee222d89158c531bcf71f9e735378a97b07017699ae93ac1b98b2e1581bb99b81a0b4b46ee22cd4879e62548446c4fd06ba69705da9767c62d85dabc2dfdb81b93536c65d7c5ef6b349bdb2ccd5d15f3fc5d93bb8877282f9f3b20b1dce4c5a5894d9b59e6dc4ea583535dd02e81bbfb799a4a3b4818a7b6190fa3431bc5b911a766698408895990c990743ba59c9bec23fb468f71f7999ec2f7c5e56ca69b765a9bb3d9d6bba4f26aa3da6c63ad612e52a1a54038ef4c87b1d20c4a490445a3595f9c2a91b94969a2d84a4e6d254e6dfa76cf2437dd4c48f4ed9eb6d406f737a2653224224c39485fa61ce4d3b33bcf4b9271c76d9357058bf3bc332eee5598964c5cceaa18dd2a3c3872df5a15550f2b41d16d31445416e9b4b88b39f3b509dbfcac3f072f99e76facbf8799e87062d6017177715f93cc5a5fddc34a9f8b740f3391c9906c39a73a5ddec2dd7b5869b6b1ce5c3216f3a33dc836948bf330fada447369163212e3e1f1f909627ba2777a8d3e67c4291ae6c2b8e78ac8e95cccd9b897b8779e62dccf254e28a78b354ca23897cba4d217b134cb9df334794a4c4a40ca9b536a255d2089c95d8cf54e9d2e63f34caf8eedc4fa3c4d5e1290ce49eea2364d2c4af49a5bdc455e46cd9a8b38b74d5eec73609a87511c0f5cdc24b6d9f063a5bb4d1c4e8abb8bb8d0dd71edf6455f1e5279e6db16b1bcf9bc49b9c15c44b295b185b1f56ea8a9cdcd83bdadf6a8f94844d29cc4b6e3ee1ac7c0ddfdbc3b6fdc347a887f44a36f52b2a0dc1213cf7c4f8c3e11f1be8f7729059339d5e697efee9ecb413c24bdd82922491c5923e32ee2c8f4625dc3c25d4c917858dbda3cb3c6e9d55ba748b59a4a3c73be53f8ad8295ee3efa9dcbab7466a3c7b87d63b42ddcc5cd84d18ca2e6f3f0d18bbdf373ce13ebcb7bcca3797117695a441a4d9b34203f75656658ccb4cc8c66b01c7a33cb18ac7017b5b943cd8d667233211961c2a816e76134065a0c412e0f2986eaee62799667a642021753ccc3686f671ccfdd651e52e1c1451a4e334943cd1b8db6ef631c121523f1bca899cb2815176928c6f16829bea1f9fc2961dc457df7142e8f5e52e74c4e619a72a3b3a3a4ef7e9ce6dca7f9319a3fef110632230c5c60c031f1108610ca0f0f5f08e3be6ff9c27e01002e608c7eefe6943cefe682961b6adaf2bb407301a674ee82de96a578f15d44257da5e8c4129f2726d13b4a81e9a0196d81cca7f7dc91e6d8c2177711dddd6ea849b6c0452c51fcb9765f9b630b52ce9c8dcaf2b6f0a9cec4e914a3bc272c8c71e76116b4b86f33bde74e6b1c79f1eb1b6aea74f7ccbc9dc91f43168cfcbe2d4729b3519ceb5ddd794933ca14ee62695e5d0c35bf77a2f961463c8ca273d4cce5ccd7e6cd6994253c8c8e5152a430ee48e65dbaff19c5a9908748524a143fb6dd4f3312eedda3303b3cdae2aeb1be484740eeeeb5abd15d69e625285becd23493af4db8a70e0a93fbc69b34d3adff7e9a6d38857d120fa1c0fcccd9088abb3bc9845f9bffbfc21747c715b6b8bbd83b6fa8b9024ecce16dfe631c52b80213a3322e92e62d9ff7f5fd231e1a79116fa8896ed4cc3a2326f7dfb8f73ba346372e626d428951f36e349337d454d237f78f71484fcc53a7bb45687d75bdd4d431e12734bdb5c9847fe7a227404f542ef6769117628971e47d7cdea22a448c66a534172d51d4049f576f268c3ece6512f6452138b9c2c5126332a73abdc36d949751a58f6ddc836533c5bad7263eefd1e3340bbdde658cde8ddead51a2c738a43387b7a9996eeec4282fcf7818358244c4f6a44c3389a1a018c7db79c9d4e13493f8dc9518471e95379f4a69e69544504a9348495f24257d7792de36cf8b9ab630f89c6dac9b78d182ee9ad0b6b9d3ab6bc2e3bd2661ce3a2663d21dc9040b17a9d0987061c2e4cec4a897e6ad4d1c13d86ea64299990a6154e82252a16db3c42939c3fae2c874a753a1490529e45581c7ddcfab672ae8725a12b10097bb33eb72aa9b299dbbdaac774f0c05939844ef52798dccced3aca5d84897dbd566e7e561b444f10c35cb8bcfad53d356e6193eaf9eed5d3e4fac6768366f38c569162acfac671aa7999c9d179766695e5d89e21cdebaa7b719a4a4af139c66a15dcd4c379ac919de77c94c75467438672261dcbb3a4ca2f7bc419834539ddeedbb8f84d06c9eb797e67d4bf4e690ce9b4b339a6d28d1904c86a4c40b39864a9adcdd95d07497372a0172acd35ddceba0f9d1274a6edcfd96ba1d0d979994d1929071777d7949c2f8a363121dd617a7242e79f93c833c4c5263888748b6707731cd4f4bb3d0795ed24442de7433e1cffb9320e9e2ee222e33b9cd5c0d89d12ddde9fe869ab8f6b99c7e4eb1151d344412a278c806435d441e464bf4a63b1263dec6b527b14ee72e9a8287433417f13675d6e532f93a68464b8c4b933477474345dcff739111bc3b2f0b39bccd1e6662a48799f4b0122e33a97b58a9b6d3425bb84885a6f1edea66ba8b71b38db5d0142e52a1096d61326d38d50919b90b7d50190fc1c3a030e7692a057599ed2026910a4dcff62ee3b6c99b6dac8396cc94d29bc369186483cb9bde74bb5989ad9869c6eddd9df54e9deee2f45d229321e132934690747923d9285ec2585f9c11d617a7c3249a51d2b4d976faee3b74f72d37bacb42360c45a7374582493417c964489777d312b74dde6c9b491bbd3c23b1cff1f103e72e8a73179de17357e65c9a5173869ab96c4389b20d3567256a2acd6644454a69e66d8ca639e9e666b8cc42b8d6bb4e54c0b7f46e23b844b1de283675268953bc64deb6ceb9d9be33cd7473256a32c1bade9e21c1676d9787cef3921b2b91e6c6564c3d9b31dd1c109f1dd3cde9349b29de285112739f3b273992c9c82edd1a25224262167ef858229223a5c8644096508cf7dd1aa72f6eb6519c5eddd0d6f866967ba7c3e9bb64e79cced025292e2fc619414284c42c68d2d4a8996e266c04684784c42c50e1f15132e112251aa9f8f8f143807630b83fc0dd691e16998197a7b9e3e9117de8641b6aeae0f392bac4e8cdd4fae2f6357a22936d8df73d65b21cc9847399dcbb9cde50b37775e7dd6df2c6604472a4148db16deb4cfa04f1b104a72f0ea7ef921c29a53467b319d3cd9de7258176335d8e9492e634c5255169ce88f8400428a3b41956ba9bf637d454babdf20e1143888743ba0c8132c4cf5d8937be95bbdc2e6732dddc5fdcfe14ef8bd3db6bf36557c87462ef3c7736ad314996fae2803c948520444c0c4d730df6dbd448223a0ab109097d5fa026770732729c3651d3f6681e8142f8c1c2c5f3bce4fdd1e2e585f263a4bbe97e14e7cc7b92b97ce4ee4a3cf4e9810f17f7dd49a2a6cee4eb6de6306e9b6836517314b7f9254e339a713cbdd317e7837347efdb32121f180fa39feef2e7bd6f7a3373416810448820475ca4c53ea724fa1c180da7bb7dd19ba9fffe0d35972e8e4477b65d3984769e5788f6f7f346cd477738725f9d36cb256d069901648ae7e5d79777bfbcb811c8520804e62ee69e34f7cde5bdbbe87ddc6d9753dcc6ddcc12e37eece047123f96b88b68d6edee97e8ade5fd399f93e27dcfd738974f3cf441e64b14fba880bb47f1d087cd47e8e2dee52fd3fc39785fd23c75bbf2afb9cdcf49f112466fa88923f7cd5d5cfbdecdbd7857e809e3ee2c78d863a5c7049e13f09cc0dd8f3ce4c912f2f0b858e2126314d73ee75b2da7bad7268a9752bcd18ba67829dffebc3bf43a79b1c43a5d4ecfd3e4f5ce9aa975d63dc66dbdcb29bea1b7fc12bd1fcbfbd36ca6baf2e2f486de47cd87a1bbd7e66b1387249638c5af51f3e6300ee9c5b277ea5d369770aafbf4b589dbdfab3dbedd346f8d9a5f62f29e3a5ce225139338fd5e8a7755bec49bc43a26243b5bc46839524a89e223bdc3db966137c5bcd71827d9a140b8a373519bf8865e1ca977af7579eb5be2adf1ae0a4e710b3b462e6e14eb7107266e21c69c0849d138d531e16d8a3711c3442e252671fae3a14873b1c43bc54b252ecda59cea9e4613558e7369ded7dc266ae24813c7fbd2bcba5d159c22e98411d1fc5a89cce77e7d71a10e530fbd9f66dbcdc4295ecada7c74a3bb4c92f751bc64de1ee390748c5cc41b9fba5c2651d38990943f2f999be8c0dcc52739633ce78be3944433a9836634a70871a3586ba41c2347818c1299cf3f4f73ebc7e92d312649f492e86e89872870114bbc71aa4bf146cdc7b5cffbf1592bb1de3ded310e0985008428f0b8bbb8cdcfdb96bf77799fd1bfafcdc7a9de5d12d7be779e37c528be7d0e3e6b17475e9ca2bbd79757e2d4d4b87c8c430a4ff062f7b99cdafeefeb8bfb6d3e265153e33c3cc18b8b29dea769d368361f8a87271879891fc5b8f678e9e25e7f0fbdb9cf19c9dd9d78182be3369cde93c4e5e79d661c895e1d9c16f130e6c5ddc5bb6ff937d44c33f918b795c87c8e616c8abb889a17476e9d7584c2d80d16ee35f2eaf4dbf22b91f7fcfb5a77712936124b14eb47cd8fdd5073ef722a62d1843dde696de25cd6af2fef718a7148214c27a239c5ba9c71dae47defe2366e9fe7853dcacb8f7148210cc8ddc512a3662ec51b978f6bbf334afe6b131ee390dc7d050f4d4881c6d8f61bc529b6d9ccf271dbe4bd7ebc730ea7bfd3acd3edf4ef8c7e2e3fe751a21297468cc460449872d036736693991123e7798570cedce80e8a4c66e466dad02cf4fa3e12112239520abe5dad71ce8891b1858dbb99983763bab9ad719923a530e5a05e7a4dd2b46114d77cfcd8e5f0366718dbc212b6ec73776db82c4157a2589770a4849b9d661d3ef126618ca358a7779a842f371e92c045a442c37b4762264c028e0420f71cc944822aec1146a442d31b6b7d6729b669f4a67b869752ac713a2bf13673e619f608c2dd5da4425b9ae19a9992bab6d3e86e86c934db64b28dcff31ad160788c8f528cf232908f9edd467739778d68a6ebe47362403e7a769f9362d3666e1497444230222466a1c425bacb413ac5b99d4633996225329f67ce35bc646ef2ceb499e2120ad668d6699cee6b2406b4fb1ca01dac6733774651f366a639c5b5dcae4889cc67d0de659c33b791262546b3a953cc0291149b29de55990538bd24fae477644cbf2d8b5468b627286ec2749dd060f85ead77eaf3e6a4a60e978f7739df7e7c71a358e74c7cbbb9e7c574d08cc2b43904c5280a52998bf0ed1ae522283b17d9d8d009d9d85862a24a506c6a78d143efdf7447e2749b35b8b87befd2683635ce5e794f9cc669129b1a4464a91cd4086d5237363450e0b848a7226ea631b6c96439dc86860a363486d0987177b1f7328c6de92ee8c597a5394d314d264b33ad8799e84ca4750b78ebdb44df7d87d29c4429e720bd82ee61269b091745b109a3b009a7b8ff545cbd29b1a921e3ee3b9f486c6aacd066ce6535575c2967dc8ccc3adb763ef5c569897755dc1dc86d66c02e2e65e0ee363469ba2b79f9b4bdac49b6a136343436ad226c5a5adc6bb06919ed0059da21536d737755c525aef2438e8a9e1021091545516126657492d128473a26ddb8f1518af191de9dba747704a5b70bbaa16679e6257833218132945e7ce65368d4e5d22528d63d11e2e1225d2e5d8234e4634926cb91526c667e6c6672dc73249383516c5654d8ac6a50e6584e0f2bc16c5655dc7f5fa567c2688e64b25179e17e4b2f4e284d91283d4182348018dcdd749b9416152ca7d8ca797edeafb7597b9b89d33a3a15331944f4117fe8e890daccedec90daccc9641a5504ea8a0dea8aabc70565859e6a51b58295550203b815f72a5cd89c409b938f1791b8cc68f5012a42648857991020f7fa537dbac4604af9afc4669fa361255cf91c580f2bcd7ab5d9ac975ed4ac891a3541191429f2e98eb4f9c4f80d3587dcd0b7f9906cbe232308e3fe3270872136193d7d36b68bbb8d8d8dc17d6774a3f868684c22de7dcbc7f888f6b6acc91f87306e672129bc12bd3c2327516ae526af2dcac65a7c3193a8a9d3f492af4dbc74f597e82d6f3e6ffab913a719a77517d5b56b9eb5bbaf7813f1e7e420d56a57f7f8bc2f6eac71db7c8d5e9c3b6f8a7318a733737fc95d99532a341a0c5fa2f76a333f3abe48c356cc14be8517b199ee1225d1bcb1a642a3c1304333ede293dc28de55c11acde4e74b9ae82e97cbe4eb4cf230bacff334a920197a222493e91e569acdce13f36432994ca761a0028399f2ced3cc799d7cdbbdce59bf1e5fccd11b356fba49acd338e56134ca8ba7d661ac4485a694f312bdd328d66816a2c1f058ebd4f2d6ba4c33ef51221d26c97b4b14931a97dfe4cb9d8bc69d8b6e6650ce48bda0121be927b31d48e1eeae149e369b6d7cab07a841dc1d04e2fe75e5eaa578093f6abe0ec294e8ce76840e02a0039abfac4477369c12d1418f0e68fc659b09e7fce7bc6cd6dbd564322d74434d1da5c4649a9320a1d84a4e9394514aac54a226a93114a2124a5089376a3a29314edff3a88512ef6ba6fbea3094281b1f6d9d9b6cbd1b2a312f972812a21ca4e0e27977a89933b7c68fe2ef9dbf73d18b2e8c66a59b4b7779e9dafebeedc43a0fbd0ca3e6f9b9bc770e7a31636d7ebafb8d6fbd9bd38f77b947f4e2511efabfafdb3d8a7559a6a4cd34dde59efe5ca67809f3f2921769259ee17447628d9a34fce82573728aad9827a427fc2ef7de46f4ae275090bcf045e312a487820469440245c923097aa4a3284e5e44b12e7f3070fd952b5fe22f62e4af5cf9184c9b22c6a9ade8c512cda91de91d8df6f735d6bb1c5a2fbdb834f50dcde77d1aed758eb6d9322e6fba73414fa3edb20b33fcdf7d873ea74c8d3ee78848cec41de9ae137cbb45feff65f834dbfe334aa3d1903c00fed4e52e13be5bef5d7e5bd6db44773308c10c6e104d30e165a539cbd1369c7e4ef10b779f7868a83cf3928b876ea859bb258a754c485022dd44a7a24e8e64dac9914c3b37d4bcddad65b21cc934c6c8fd65d98612e95404b22493c964ee7e3d94810d0e64e9f37e7ca6d99662dd794bdc2b2f86a2cb21349b37a1d2bc4639bc89d0dd0d07e5cc7b0a1d21c1e57502e5ccd9a8c42551898d4a9c96184a6904833130f8226acd749d885f128925ded908bf58e22fd3cbc3e9f9e979434dadefc6375bcee563de2ba599174377b0174dbdcd1c7c5ebd7159dbe9f3c4a436736fcbaf718fbc377cc6f4cd29e9bb61af5353c784e4bc3c8c2ec945e769ee2322349b4279282395689471e7a2dd93f2cc47689432c54b4f72510b42a599596042d23bd38b04ef9b974ca328ee164a89cfd364c2c345252eb3d0511730e8c2025d289de71532020a7274246e25d4c4385e46955eeced14eb72aafb5712a0205abf1e28c8d1117a7bd104252dd48644ac949750536f9d9abb54f75be3f2ccb0d761ac947b27df448b5aa64bf8379f8673f988f6224e8753dcb6a13ba36f333f067baccf9be4459a8f1f3bda6bf369b4dfb7dca5484fc3b98b9258a7692f6e9dcf8c7e264ddc7eda2e6d262d96437baceb6d8d53bccd73639b2d6b13bd3852e3257c9a27a9b37137f37c4d9a5b9ba4a91b89d8325efafbbdda6b9cea700afbbf4e9e66048988ce9517a7585f52ef926c5967eff2e7db7ea61cf4629a7338a7839a7f59d8f7b4a1e6636df2ae0c09d293a2175f4c71ce8b4b5ea4d18e3eb699709983bd7e51639cbe387d9de4dcf2febdd39d37869afac521a29dad445113b7735189cff30a0da199cc484419499718179158778473b788c4ba2322d40c4270e35e7f541fb8abbfa80436628280031b884181982cdc3de5a1180e88a9428c13629a10c384ebf2c74880fdcec748f8cf21e165bafc39243cec73f4538101979914838a418ac1f6fd9e2ea71bc5b39b6ed49461a414a7d8ca0ccd280996acc2117881cf5a0fcda1c5981138616ad4fcaf091100b9fb967927a1e6ebdee59d57e76e7a753f3f7ef498baa7455003112c89c09653fc029a8bcef386a1e1facc59e7a723ee1f8f1b29b14e67a65bcb72faf288b8d799ba3aaf7b55b9bb2ae5eeee4edc95782d62a5c7c45bda6d9d56d16534a79464e26e2fb820a50516a2201d4159c1a8c84913262a2c519204c99050d0b823eae494514619376cd4a0615346b5652144deba5e4a2e6561e43a1567d84cb799ee9d0f9071473fcd36327771baf56333dd2fc3a2e903577ca0cbcbf0ce79190cefa30f0cf181268fc1ca2099ec869a6789de251ae3246ee4fee4035e12e1349355ae70011829eeeeeaa548454b7c9664b2d9d6a63e6be60ddd2529b112999b40c1682e3ada3943e15d28b3141b798009b12cef97f83c470f5cf10026d1ab93620fecf040e8eeff211640c06205eefe46fe6548901a80c502b0d8f2b2870016a5bb77712dd1811df866c23a37dd5dd79f17ebbf5076236ada22f0329d8a3b3b4a24c6913299de4cb80325b8fbcb4aaca3609c904ec59cbe3cf2da7476345e32b79933539d6e3321b9e9ee1a651b4a74748591e6b9e9ee5ef1ba87993c07c4b87b89f58e68367b590e7cc0831ef0200c1dec400739d0410ec8801184155270e0eee00dc20d9471f72d7c0355d036104446f7e76c409734da9727366ddacc6d40c90680dc3fe765be4242035cb84ec51b6aa65bf7cede3d75da1cfaebee3670f71ab83b0d66e0ee22b89f44d8e130ee6f7a75a71334ee73b609a8bebc4faf4e676000ae5331c54ae44d9196e8d94e269b91e8e895852f62b8eb94e635c2380992a8f3d6995b97336de6a9cb5dcca3d14a5d6e57fb9c7cf462d6e77dad778f794fa3d17e480c851ff2273c0a8fb16d06fb22af33f76ce373484c676e18795e7256e47fe333cd497e67e773b6dea5341aed459db9bf57fb9c98cedc9f51d85b31b54eef4cef69e6d05daab3d14bd2ce9b4bf5b923cf4ba25967eebf77d768a5369fd6db26ed5353e7fcd2993b35975e8ff74e97cb24edbc4f68d8f6e37f2c0bdce88c717795bb0cbcc4557e4889378a73b5e6eea887554c71f721f2e8e894b88a17959e5461c35d295740087771f34e8cbe4c4911511194b1850a34b97b055ce348bc7bdb4caf6e279749b1b6c36df3b6b323d3babd71bfefa7ba1f52e214df6e66ba7778c9d428b6e1f26f48c5170c80c2fd653aba1cc9b4a377a8e0b9fe5196680ed22115b25c49a47b58e9ba7b0c60408114b83bfe9e57f2daddbfc8359408a75908dbee918f1f51363e2acd21ddc34cf4d6b74979f1127cb435be11ed7c1ef17091e6e5a292284a690e193541893414a1f284a2cb9152f4d0d67989eea5782993da1cc24df4798e1a9bdb093e75668a9491caad4d243952ca4671ee868fd02825def786d3db6dd4293eef5169a6295e7aa2cb0d9550304ed24bf19279e2a1f14897e65089e620a11b6a6ef42ee11343d9bb27ba5cba64ebdb4428c5465a974b97949844771945c79dcf239cbe4b8c6c39a74678df7d8451a2a3149ba70ee3249b091795172f21ab38a9921bdafa36c165163212cae5ad77422de872e992bbef109acd17089598878ba4b881bb3bed310e490a0bb8bb98dba1f86934296e17b7f4f7b510d2795e21a6eb44fc346ff226b9a1a68f1fe56f13dd7d8a758ff50d127dfce861255a2cf6399f0383d9320a0f8466c5d47fdef29627c6a5d9763fcd36d296f5ad6914ebf2dbf2ef235e6e9233520b4cd749941b9ad31672d1ce4525bacb49762e42898e525ca64f6c4ff6ee490fbd4e72463ae2e124392315e5a2128f4e64b7b6d33b3ddd59e69ccb0b173a1553ac3b316e96e299363546f1cd052d70b1c4555e544ab34eb2629ed74cb1f6d2e42f2b7a72a482175bd8801c889ff76754c76bd8801a0694e12fb3e112e3f2267a91878bbe892d4990c1e9bb442623cd14a3f8a6d35e74e1e016078d70f7183c64008ef7f4f4883c628f0e9a75d20c9729c6fabc78979ee74e278a243ecd3820e18231a280edecd4767ac7f6b8fbcc4328a6d8f7662edd8a8b78183d1d31033a2527a78891221f632a4dd8b6e1263228e9936dc34dfeffd129323c5369cef0adc43325f2a63b8712b242a9fcf40330458cd8f0e98122445078149fb35979e66f0520172012291e5b975fa40899eada8d028eb83b2e332a43f1cbb820d1f33ab613eb2f52e4457cb33eb83b0c1e76c982ba804424341a8d424fe4994a53e7440ebc976e14efe86e6e07e374d776f499c91d1f3e42807c7a786c3f808290d7a7a7f603fbf8f8d87a4a5b8de727080f9010d2a7e7470816f2b3436ebd4b77c88de2a58de2a5d946f1526d37d3e54826ad67ba34330b32d96c363323674664b219ceddd49662a59c06f5b6799a3b8ade9dbbdc4e28474ac13bbc5b419723a5688d8f4e7c24a4b30d25d2e5ee36f23944d29ce43cafd0798564b219990ce766999c695cce505c96266e66eaee4ca76532db89b54c668434cfdace48a71b33924cd6e3f5fd9bee462237dddd2ab912352f4e28b743673323387d971880a7446f5a22414644628bbe48487117ff1f1d91f84f8ff0c275ba23b6e86ea83986475439e24574977e3679dabca5f7fc5a3e6b7f9aba5c268df0c25d2cb5998b8ce86284d1d6195700327a9b35139753dd17808b8be82efd9d59803417dd7d877028519402dcb897e9e5e976b312c57a96cb22bcf04d5e1417e180d9c65a29bdb914efcb9be972292ea8c43a0a6e9726af446f6d5662bd33525e8c1bb3922832d97967f9362b49234bca8b71b39b5e1d115f10d1838bb48ce3d1be57cbc1d8f6349db969b6fc39348c6d33da8f18db66e7d5fa9e425adf93c4d836c3d836b3cdb0be359db98d609c8408db986e6ec6c36889e6da105ee453cf86f0b2b11e42cb1052dcbd2cef10b38d3501cab8e7daac4712000bf79c234011face0870fa46cd195ebaf89ccd4a34d7ccd29c11e02627bd105eb8eb2984d8e2eea210383407097144f370511065eef76a414420089a8b1bebdecd3d79b3d441047103c41820a670206840c0dc1d2fe5dc0f5eb8bb889a3c1e2efaa10b6ef20393c9c20f4b5cdc42469bf018b787b67cd9b2c5dd7d0bcedd7d0bd096d045bcaf0f5ffcbcbb2af8b559fa5084a7183d774b28d1a33e1cd9f9d4e799c9abc3279a6bdf236f6996282f9f423e843d6ce1ee3d74f1598e64ea81a987a1194e5f5c0f2edef4ea6aa636720265c9a3230f6178e0e29edb699cf280a46dfb482623f1924c566e3dd3691e7e87277608c2dd757ad3c1a8697b9c66272fe25d95abcbdfdb1b9764c638a41d8434b9cb3d2f2f29b1decd76b8d1818c0e4be860a4c33700070cc0077717f5c58f6b680f1dbf443389d3bd82138d5e9cfb137a273eb33ee137d18bbd13e39d8b448c6b610051dc457cbbba01c06e5700387d714ff309e263e6032bddb346130016dec56f02d022801eae77b0a7a5d98816a9fda8d4aface5a11c069942ce08c00820000000731200203024128d874432b164d77410f20114000580be627c529c886194e314328c186300000000000000000110006407e2caaf031ba6634736565d9eaf727125db8d6258742d94fbe8064855b1de6f1eac49e287ebc0ca6c829b5b6a97b61b3f1ecacef8b17a64852dfaabaa48c366a4c2fe21d3fadaa2685f737317afe8a1cbe88a9b0f314ea6859c8c17ba8e30cfa2805557720680a991d7fd1c6a13b182f0bb669f5c05860f100d58e95a647cde5f8abe79e65caf443ae83bdfd90aafd8b1b5a3aa47b4ffb34b143468c197626f303e2e5abd3f1b291becce09bc42292109c488bfc5837f366673c3b430c71d2ebb960463819a945409d89987475ca92f306ec17801f328ac89b57f1faf8ee43ea75f59af68fa570515fa190003bf31ee1b62a73cb782dea5c0e3efab7349e692979f1fb3b9ff2d580c19b2c4439614772c4bd95cd6b62714ef657493dcc60ccd7e5f6d9f043f5f4d072624df28798e0c17ac95e146ef98221b551ad98815dc33b8b8ef1d5d292a65df9298a2c8a2a89b7932f344ae3e762aa6fb86f7a1bf8b32029f8ef768305c5e4618c89e70f70785b28ea32b873686a12907a49e54fd1c3a6ab284471e2606a4c530b190c87858baa485ce404af3eadc618e22595c14b1fdd1edd1af04a42f60d93f640b83a5f0a9b923c9e0a631be86639df42d2f201dede038624f3706fb4b36cb271ecf40d46fa74520ac4d7e832f21a78493d91395bf7df274139f4d0af3bb215a27a6148d6544b64d6c519ec5e10d8701dec82b7ad8c2fc0c3720c95a03d3d3a1de82a4d61d9c179ca6ce324ba6dd25d5aec54182cd071d2b807e174ef43e0c5261f56f384efeb3719f9cc1a700182a3ac6032dc2ceba4107c470a7af23621c1eef0625a4fe57643df9dd4ea01932edf83738ea80eb10f1f557c42ff0731c02e6ea01c353bdab132020ac074eaa41fef1cbe4e9dbc72fd3a5979cd94883f4a5ea7255746ae3db5d73ad9a4b699f82e7ab8c40f53b06a54f66c617cfcb501d04eaba3fbbe9a79f4aad5ddd83ad98c5f6a4b68272b7dcdc52e1a9ef6c82d08accd673694c6112b7b5a71f97dcdbb2fe9808a7f6a008ee552eb37f09670c4af6d98d3ce3bcbb0d94b13552dadc715e7e3a93f10c505b8623ae51e82a3f0ba6dd68128e5571d6f9dd6003f9e85cdec46724a31f431c832ae32604d05f83362ec6499aa6403b29bd933ad5005c9eb48688fa3048d338632187a2b91ccd57d271e8a00aa3ed5026c810917062913d99eb4e9fb92477949ea10f520b95071f7ec095a3254deeee3477ea918bdbe020a8236e974ba44b1ef95a1b198d5992a0d7b210639afd09dcfdfcdcc206c6febd22bd7e7d189ecd498e69a40dff71e4d3fa480cc479b52685634e9379ace687ed5385ae738260afbf15dae8e0833120e8636639cb7320820cb75d158e151b8ccbefb284162cbca3a8511c6ddc3f1a77ad087c1e06e6ca3f9168125bb5fd5f34143e3470023ff2a65ffa76f317dd5b8d25038c7023e7cb3da98fb42738e8d16306aa89c40ad71281f1fee8231df702c9e9b81e01a00d736a32088e91407c9520bdef5dbed5965268f5e706dea53c22242b1f88ea19e5a17ef3ba1e35abe9d0d7fd276711595decb6c535c691baea15f0a0542b33309721fad985f90c9607811e7c701446e109ef0228869f80b64d90fb7d092b739ac3ed5921f05d32ee9a94db5a0d34e954785ab7f8dcf06e497b90e6ffd3a4fed53e584d2e39be1397397e45224ea4ee1f3fb97110c791852e688140feaeb759cd9e6e4c9518a6cc313b848c2ea65f68f6a289fe88217ba04a430ed8d1dabc9ac16dc13b44d42bc4eb0187f6d7adf4fd943fb5b04f93d99b7dfee3d68c2a5101bd4e55507fef2f6f767af335bef360e51945caad42a1e11b87eb0b60736fd92c164a09c9f1f7b6935e5c9587bf494b39323e482c122708b02576bd4b27931875bcff50c0a832c1d6a97bdd7b7bf9e8894a82141c2b89dd4de7ef0a9597b2578ede724bd0cc38fc5c44a5e928b9a657d09b6a006c31da424a70959110cf93bc18eb0e76a020980300d8132d6bae1d38bccf8b24cc3909d988804dfeabddddbc04c0e965e33e3b97f52584a04d8b157f0b17612da09d8562a04d67c477b30972c4e38fb99734e7bad051ed1f9b19ab67c3f54ca8771d4925c3c84bb31d602b45c3a2f856227fc4ef766392f4ae2257ee582982114ded8ebb835f16818429f95c0ee25605285a1f66149a1f5a86e8f48ba1245b867eb87c2740d2238cc0489204e594349fd7a23f8500947f39591590087724453ba763bab0159f9dee7602183f3bdcaf0229a6e54099300babba0fb70ccb65c30da9b046296b8f99002c02439307acb842368e79e931a3c0b6f56b88818ae7151fe6383aaeb4a697d281119f4490e05be701d8191e9219412b46349df28cfc8a529dcb14dc9ec85d0333e46533b98c8d280e982bf0ddbcd5c6d94a20983ea58aeccb56bdd6dec1d259a7e6a871070b6ccc9e248d482e1c0c9bd0d7d466695f9a0022806b3b7adb34054cb03a679179cdf481246aa549ed47f4ae2a2a612e4578a2782f96ff401f5f1c538f9cca58affb4a705e43070ef77671f7f4f3e3ccf1cad001424074b780907119f68e5028a061bda5d03a7d77c623593224314b7ee2394259940185a20eac9859edc0161f442f98a0679638f8c1191106f6453358c95f1200c38f313e15f3f4ddb46d36c2d8c8495b06ec95c125bbef2eb3018306f2bbd0085aec18506ce598b7f36f86226debc3ac1a2541c6c64e74553f50da19629100b219f5b591ba95b914b260c8b145edc3cde32c5a520d84ced4d5994990a3e15bc4d9b765ef9625b01814c6f9b1db5865651d3fc602f735cee3cc1ac1650b22dc91a0f315c1937beb9f41f477e12bd96a1a85ee7af8ecbc8f412cdc1705b8892c095ecf0cbe14296a39e78513f06de6a541b251ea8bf702f9aa01bab145351f95782c750cd8a9bc9cab59d36db1007b2ced8d2de39e387524044e558664c5ea1170d6e0026ad1aa61509255ea61fbfeb50f841dd1a82905522e10d985a44cb718bdff56deccf72a3f222688a2b0597010a431c2bdb9b5ec540bb4d510cff9ac9ab331000148601a5e4e609d5033aeb7371bd5c5ed1b3368e499d43acac0444dd9225f011c1ffd0a8b9aaa6b6eafefb66d870ad85cba06d725e72e17d4f21d84a9cd6e38a9b4fa37d6f8b0225c8cbd8772f9dadcd6222dcae3aa0b41f1f0813fde01f6b42d33f3a832b9314c42b0b14da85a1b02309d37cebb3717505443e1349208e5a2610113615cc7f0312cb096c0ff78a7c0d25b9fd649fd90c3c941bc7537caf3cb6f443915fef25c78f4422226666a526fb47378bbf721b405c9f29e4c2d74cfa47bb06d7f01a0d77083ab37db4907ab044296d5f5bc944ec1dabb727c90312eda037657ebf60d6b502b932d656b299e987bc78b5f2f10f089f8733194843ebbdcb2d2cf769158b88deb005e8b6949887302e91573a12a0861a474fb36fa4e1ebd772d361eebe9b7794ec25a52e3b4b3d6a333fc6db4098fc4b4cee99fad061ab46530af220c98877876884a4a66cc1488e454c4ed5ce798fcc3e7f1242d16c232be8dadee82ddc0102ee61e35c6c12f13bc2386bb88ce16c7252638484108e37e36b3cda8b4fbf9748422ee946e52ec2008831b36068d3ee242ec2eb1eeec3d0c93fe5dec409b566763247a5d3dfa34f6ba3366339016232a1ec8d145ec1a8aaf769caf4684a727635c561a5e901a5f4967d40e39be9858c858397b20176771d8e3e18851be0d9be95b0e85a930e0b609dfd1b45272049bb3ae3716067cf8c803ba51c5bd81c4b6ed674add669314844836fb765607718290bdd854331491757dffb54bcdc85c598dbc84f17b0a836ffe3c5d5805312eb2cf0060556b1401e304dd5f44f63bbf036e77f6349cd46ce0cd5a055785a4084b8323e690014ee0dee9933df2772ebf48eb187e47a998c16efa79ae8295f96e3115234073e6987a77527286a02e8db556a3b62cb284973209ffd228ec70be782e88d7e151de25961e3ea21990deed12780c89fa7638aeab257f727c1a7744715b8e257bebdb98b26c5d4c60838a728e62a94d9a98959ee2c77bab6b19a61dc828a149d7e48bc73b408582910dad47f41b428bbea64c06fa79da63384c98f637e5d2182d4f90a289cb1efa06b4cd72e546526255547cff3262d7dc99a6827d574d17421b042a1e0ea5c895845f31f216c062e7407e15d967d4b6570ddb868d5502e5ca0b7b47b38a9b5b1e1dd2d6bbeced2f5718d08fbea9ed1fdf9709048faf583d00757888e76f9619e4117c235f143c598bf41a3a96133358d823ca1cfaadfd29238772a2b68622f8b93c4f6f64ff0f9e7978a3942c73199b66be3fbf5f42b87ecac610e8a13de2b4e62e6db7f3d9be1095637742d649f68bfbf0567eca032c8c04373709b1add181085c07d20f47e313035c43c7d436579d5af57f3a5555456e4c6148050b1a4aac5d25c3a74162eb054e1e0e9913e4348c3b6f21836b0ecd4e2ed8722247f8acd83508453e85dc338ce5d35f8a2d433eb2d4e288ab60b62f291686c047cd9b738857442f3923e92aae754aa1fae01a6980bd31cbf587cab95340211bc49b35649db9a3eccad6138aaf5ca979e5286a89986e4c51de27edffafd6bb623a8ee932c91dbe8289b7f9b5ca23833314ae7c975b04c87622b9ed8fd56220fdbbd03cd2c1d00f95dd4fd3e289a9ae52be864f1eb58816a00df43372c1299cb1fb91ebd940c00417599aab3c3633880e29757c1210b746dd20b8d28104b8b5512f9ff9b0ca5265aa1514823ff3f6dc10306033292dd0c9c73331a2d373c8272c04e8b64d352ccec4075d10b837191950e85a39d20bb28d50f59bab514b50faa5aa18c5854d3c411dfa5559b1a2d15cacf82b38da102479553f69e96bbf8178bf6973cd86b4f4a32a6528577640b1f0f2ea9b568e18257ce5743b3d0d2ca345fef43e78d72623a49e83965d458088c2224d8dcf833d2a453242f476fb9882786e12405f2b6aeb5ae8520889a51b4fa7afc79c0125481519da95b1bdcc9eb3a66164a10deb8d86aff31d7cab170001449301378d33ad786565993973131f592ed9cade581f6d14b9ae7018db3725b0c0423e9fcecb2ae8b8651d669f6e2b3bf30011cd65e2a710a711dc9af4522e8fcd8e168e33d354602ea68e25142343e0b49402617ae20616d2ffeadcc99b5c38f82b880dac2a9a72b0c4387863a3a34d1488451b4bf84fbb2f760fa077bfaa7f3b0638c863ed4016a88c9e28f6f4cebde257439b7518484148f662f45c9a319177cf0ffc4e94168a3f43e49c82074f63a811138b9aad95c32eefe4dbb3e1685b746ac75e145ed14fb98ea7d70a64f22501b6dc817ba70ccc7cfcd15eb2f1fda3f08c0f1307329a0c821d642168b40926d45035453c8067c048fd09cb61a630de9574b798b4f41cc438d5a3a62b76a6e633622e312a49f8f14b88794c6879660d48e4809c4274bd7870c8eceaf596035119be0df4956a77556054e803126babcef28b868a0188aa39b0448b1d836028b859537a75ffc6110baf7177be5cc0418a9068feb50be2d2163d12084ea9c94ef75e6d3f1b2991002d92af44a6404b96e1906e20b2a5c55facb9db4e7f51009caa89a28a58412fa9b232a6069e0d1fecd79ee4f138ef48166704a89c056a007a705533fe6cecbd98a808c1fd371bb020e5c7644da226eef725c611ab783ab29d189cfa66671248b0ff8fe8f053c5c02ff3c48c689ad7893d9e87a5a4c2cf19d189571b03c9da32d0e6274f30925bcfe3688163e28db85fc06bd2677189c643192ef3e51a0c73ede5cb169b5215788119452881271901a10ebf4c4c12ce4a0a62bcd3dde7839ff93bc20eb23bb24645439cf130d399588ad7ec5bc2db5a2ef7ce2e4bddd7262de2477cd58ea50127dd6c2ee8c88374662a75432f1f549fef6912d3de79a11cedf5b48ad878e3ac1490593649438f4ccfd414cc4c1787c34baf134cab0a11c96836ef7be67c5a9b4f4c06aa23ed75125fe5cd506c8225b980d645016aeeb83eeaa84d02fa2bf5559c8386b99045d35cf301d4fd88499450d8dc73d4a440c0ef4500fea80e81064f392253cb6c11a89b3386112e70db68bb15980de23136061392f41d2520c48b5b1d593871f74f5936ba801996a34faf1d276c51b45d17063583e7e60ae0c5bf97b50573d14b93146a31b214ee55fa7514d0919f46440ec8208fdefaea0000d9d3a49069e9508c7390cb6a0a181fe1a2aa519367704a9cfc987fbd25794e04b3cd7a63debde0c4faf1d360348dff6797835cfd269b66bdd4be98fea721df16d11ac9e8bbd7070cee7bea8ef1c60586dad4dd30d91d6e3b5d4bba980987af72b40b971f54e3f1dd9fc6a4af7da6925ffa916d2b6093341a45573b44f8b55dac3c64dad150ffbad45ef8bc7e63bf7df00d7141066785da4e67e4eafb1e15f4fde9319f99c86b70d18188ecbbb587ef51ab5135a221b27e95a4d937a832dd40cdef13426f2e7ffd09be5fad4dc9a8965a624774af96667c183cce84ae9d88a1ed5713226f07e889a52c88c2d8f7d742291d2c80ad74b5de371e74bcaa4b47d7d5120762e620fb466e2c434982935a483c572d7bec392ba73dc4837881a93f7e220cdcfad8630ef84e903f3b2104fe7ec3b494f2e98673401f614211bd094649110e38b2a081f960fd33614e50ef84080d29e07523565ae9bf1b6cb9c0d8de8026ed4f18a812d40550ae685c7e292d7a649dcd4b6bb7bb8c763f7f4d8ad85b4875cfb11662dcf6aed0cce86229e0c538f88a72996cd4828b3145ad7d61130f2e40d4d83bec8b7f8fd4eb796b36c085bab346e3f17b704a5a70a4839d194cfac3ef4eb67cca27592f823beae1398e2bae5d3c70385e1ae208b66b8c93b6c6b03549686b488452bf40c55bfd10447e60e54e404b5d183a9079cf84bf18c7793b270b1507e8d426e0274aba20da3c5596219dfd64b162214b06701a0d44f3a1715360de7fde8e6211fc3febd22984abfbe3b5f2fcbe48282ef62d273c754f9df09359f288874a8c2b788d49093afe8247926952b46de86ce593ee9ed9f6f8bf389bd94f37918f22fbadc8e94e415839d75243138139e77fdc3f6bdca8d1ad589bed6a11049793d7c5863c3a55445c2e59a1732a765cd2c180092c8e903f12cd8237395ad6133036d35bd7039d4be1381f4b59914dfb9da543f0dfa2db4e558cd9e035059c03c9fb746ebeecb6f14b48df879aed2a0e8a5a9e4d07669a9eee3d358d0b68bbe2f8ed91bd03db8fbffe869586f7fc12f2737c7377956ce9c5b7602c8da18d0f01fbac6410f24645d80c791c8939dbc64213f78b1ff2f12db4e41df0367adfceaab5ce22cda3f601fe7516a29027f49937df86cd578d9a5002dc8d5d976704cce1dc22ff55ca1039e518380445d6fd996b8c22636eaa8dc7274fa0901a3651d5eae18b3219c88101d913ab986c823b7e682447a4e7523a02a4e13ed10e068421446faec6bb26aea908a2d40625aa8120858394aa20983a83de38bc8d013577710daef6eb1f6e415118b117dcee0d38495f0bab6671b08ddd7e800d328ce8d272fac236eb168cb89c93177ddccef51edec077f34168178dae2422c2200b890b3d983298b11bcb3071ae02e1f960f075e27c03f9f1ebda58cdf87b7035981363f713a1341ef16091cb06f1f6df5dba3ceba095f2e301f1684cd022831928ff719e2d60d3246f52a5cd0b66a460192a132e7f57ba808990fda86789b1fde6602b393bbfe20219680f5c453248513621da0410613c1fe80aab56a024a1d39869875aa3e52f17fae8b97bfb1e491c1321c5c88abd046908ff8d920182a26fb4d90f414e27228a9c5938dcaf47ee2d3122cfecbdc12beed13c5e6005cdd46ee3f10915d005b38c0289522ef4cf42ec6fe4282f0d71a26d9a6f09e85fdc2954618afa579a3c217f6fb73192b4add011288987c3d778a90c8a96e0c52210964eb31cab192a262a8e9d0618d621885fdc26800e8e31185b724ab3ab0665ab0b2b62dc17e97adb4660ef325a67fe0c4dfa18ed38c353d8e919251140cb62a68a0418d64d5c8846cfcd1916de30013263ea701c9f0325c492c0291e5df55f750c81f57ca159bc1cdf8623d41e0a600754f60d62ad32d7fbd84ec1f749f91e9235b4bcf759d76324991ffeea6648e4113131c5b068ef8e602f53c842ee28912787fb10efe73b673bb26c18464ee47ffc01761aa2757bee8fd218a1918f8994462a5ffa444cf061322f78969f0f606f6aef921f1784ac9ef54621807c76e7976693657d504c89de63e1b10ed3fc0f3054850a58c9024913dfeb29a20d4227e05a8dcef1d6bcbdb6c552fffb27a7e25fcb0c9277103cf03bd0f8a99817a0253772a4e393b0078e81af9241982a40c7647f4b7296f1d117428e247c3df1d394030b548fca5bc51e9909b3a4d3c81618a6f9ac02a9c10cf08b0423f9009f8e3b575e954c9f689a7903e89658d0659fe82cf1b53c78c73a3aabf7b44f1e648aa1c3f71548f77e7eef9ebebfcf68fc9a10471c90cf3df56f55b5c948688b897f0aa8a26d3cbf1f50a7a0b0000a91831e413dc148c74ec0af135b7f845933e0ea00856dfad0b5e1d3fc240bb98000b8ca20539d3ff7be2ed069b660c9117d288e226ec0623b0033212a365f21c4dee2b9e79aa03f4f0ebff6878112770a0fde1173ec2cb6d9fbaf4fdf5c24e52ec1523a1152b643943e268c940e053d0d7ca0c5838425a35c39206f0fd98ee101a5482541a0789a6ed4a82e0d2877ce8500baf95b3e802ae71b69dc4b971a2fa3fe7dbbdbe60e68143110d912928e8a678ebd0f5a76f564ba486d5cacfdc066bb38424db58ce1ad71e2eb9a33a2ca674aaabb903712568722fabc9216c4f22ac1893ab41d617277a969d51f236408990a7eac066fe52824e312c5039dfc19221cf0c3bf549a67d377c502ff38339587693f61ca77eb65103a43dacce003cebce6334e5dd583a2e22c67e15053c54ebcc4c4c8440a2a194f2f8f94afabde8bb23112d7eef08b8b132b8d0191cc5904adbc7057ea1686aede73bfc315d1022092a15aa6ba6566e496e56e464eec2950304cc15c28438d3543160cb505f31c8131aaea642f2664060cf39953a2c08fbc88d0b240aeeb77d464384004320363a9d41c0cb11ae207b3f11c3967cb8f561dfb138d72b31013d0b7fe2489b38ff51e77d17bed0daba5a9015b1bddaf42779f6524fd93e5e10bff95f0fc6df1d5f9ceb5ae88764a439ab97831c841ed67bcc39d626f00bc9fbd207299528a319065c2cff7a2315c2a48174ddc0df9d5b14c2730e9264d9a17b973b93d51545baea7e812e50f1f19d96baf73ebf4888f26f7b389b8ffe523017aa1cbf764f38b19a502f2bd04d008ddb4cf975edacb66f69c137b3a53b09b7a8f2aec954bc10e5a96c207d650e0de6813741409bf8e10fc5e7016bdb04c1d5f71177329b4d262aef03d50038bfb7e8768c85d97b4193f811fa333bffa0b2267a98e6078865efe1ed5fa08bffcc35ecc2e5306ffc9190f6a71787b8aed45e4ab329a648c544aefa8314f3bc86eb961dd9cef48d698eef63e94bc71473d9d8ab67395733d89c93cf9ee52f1bc0334bc040663378c191bb2bbdd1e86c76bf7e91f21aedf7e443e14b5faebd9c63e98171cefcf80e86a869636d4478c1bd185db1e4acdc1140f803252da6bd8bdd7fe3ebd54e279d559ec0d593d0e190d1df3fc56289892272a5f361403e21e91919b7fd3bfa75b5140394f93a130764539b6c5774b45c7df0f767954ad557cf03920c4afc5dc713c4e46cd19ca9de214e63a9fa9e3d11ca8a592e94d58aafd6741fc2ea85d70170de8523f83ff241303ec08fd413eccf47d4021bde6e1db271f3977b07acc4b2214179b3051778313dba9d0817c0896e3909069669f5b2ca38837c6e46fb712cfec4f29758c89abfb144047105d8a0ee2e4cf29f89142f606e56e9759d021fe994306e23467578cec04f824be3496e94bee4fcb61231850902d0cdca51d4b0a62f17e827b935ec1313d0e48ffdd2ea0f18977ba9efd03f79433f386c270857cd1e03df0dc59fcae8045c02a7912a681e2c97b395356626197fd22975e40ccad39f9b486887faf2b2fea55e418612f6729e28859c0dfd9009781a8632fb1ca4eb455724177f4b57e0cd0153dbf8c937918442646c89958da3438420e4cb9173800a442fd94eddbe1e19384eb2ec79fbc5daa6ad0190241909abf94a0b681e513428cadafa9922f2c0d074892984bbcee65258897ecbc3f74d8a0ec315d035ac323fe285eed5c47ae6b54a39f6d8889887e49338158a559f1e58e0acfc86a5946dc6462af203eb482f47149de2882dd94e8374ce2dd53eebb0b6ee58f1f4794efc494b0be94f1b5f380468256eb14d0a41b21693e93d87b7145f32689789b625e1bbe08e1d7cdb19bbe9ad73a4c7f2416163c85490818afa4c0e85cc9a963b79e944d2be1d1b58e9b37f0e3a62344d3393955801a207746dbb38afc63b6de8354591acfb8591b56151ce9c8226fb156deea9c432530ffdbfb22ad542d0aa1fcbc9f799a8786730ad4dc2fee6e30400aabe8c849985b6f4910bb8185cca86a188aa628614c78daa82afed3d99e9d190f72bdf929c3f7e6b2dffd0b5aa9216d317feb98bde8f079441f9745335471b9c06f2f53f371f37fc0374925ad88f63d62267087e364622cf5bc63328a653c7bb88cbe86036640637821771535dc6e962334bfb1efc8c10141e10407feaa98af17e48c288a93065bf3d8d6f54e747e9d1abef8f1ab804eee28fe0bfddc89de8d13f3fbc636f5b4e5f8d8286316d2960d5bed149b3214575ec59e44b70ac2cce4388c85e1143616e21858729af9d66ea88109f0332de6e209a55cc0dfeb912df47eb2499e7e126e544981884c6538d6192aef4eb1854207d0e2a22f9382f966369e4558f0eeae6bcff3bfa992cbe821d3f63db3bbeb6a58ace1bd590a3a927448bb9438aa99786e35c7fcdd9af099b673c76022e39143bf938236b0dac440639e16184979bb676a1db4c99a10cf561aa741ad9958a2608e7dd0296e6219e632125f800313a240c81fa4d5bb1ec400134dffbd39909ce37fdff8791bf3a2567600abe0b81220f6804e067242d28e732abfb650c8c3da28641c8cf0e0cfd2acb7fe1fa1aee8a324c615239923d67692b4c227b717c8046a5836839a8298fd372be6b696664a2981816603b459adb0ab13882c31fc33a19fb208587b8bb34ed9cc8f6e213b102c482528e602ecff81fe1960b6a3bea738cfdf5a8e21a9fdfd204ff981dfb7a0e00416237e4947739455dd41d062ccc39ef54f69d0af45db356087d7eaa7a98ced08726871d1f0220385dfe6f2bc7fb5edc55822c5c24e5aa2c9d44b3c7a3890522af291d7e7493a27528218de70433f30883212f6f9543d3c960bd06720df1ce984bfb06a64b661bab5ff3cb249f8a352c9cd95613fd1eb9ecb0c7c60d20e32c737c779a5954a0f9e02448213c9cccd57b52938880b4f6e9e677a910d8402158832b2638ea27b3d64e63bb8bbde7743091ded6455b95acffdb516ca0532ea04837977a689b93c8d46f14e4a237014f83951c1b117e461c11f87cb2226c597078e6ad2c82bfb0cafb6b3cc2c4ecf0e8deb0b3ac14c3edd43411ac63a5dc9564a9fb66916c9d9297be4dd35452a1f2673895c837347083bb57509f8be23216dd02e5a1a653884ccdcc57aeeaabeaecc6669288ede3e49c2307b5f4f64cfa17c886413f1d62fb103366609b712cc7b1d2708107ce70571c26de126fcfddd3a5de2538d7fb8b7cb3d3749e067222712ea20568848d2f2ee6df0513d2959d65c3167472552be590516969d27b812ebc32628fc074d5caf2f608ea1b1800428bd5067970f6d897ec8902ec296bf6c3d27212c789da199f5982356fc32c0e8704ec55860d2309d0abdc2457f627170837f58e143ac24508685e0997cfb5ee7db2832edcba553b8df27af62fada09893084c330998e693dfb70d7a160a72737a076fd8b0b738b6dbfd2c7a1dc06ec44a6c9fa872382512e713bfd4470dd1341131f092abcddf56452195f466ae4e24861e766589c0482d47cabc6038db39ccc2801b51f851a3355305c4731d1658129cedcde3c8ff916a2c7e68b5af38d097ddba1d3cfde4f1acef85276d684ec6b04c810059af2cb5f9a19181827349c685e5c3e3a7d62d472f5465842387c6a2dd8d672492a2e1c9f5bf708c695fdf1c2f3e14068947077b4c9aed241dea65a66f70123ac5c736c4a72540300bf4fa62e3dc28c3700fc2654b143ea50606b334841df790d1ba3ff5675898317d71f8c87133d03094ee462d6986d8c0c2f2770077914e2f3dd7ad08285f7d42a5cbbd71c72600434d8098348ce15038ec93cb64b9d9f17d08ac2e2877a3203d98ae89678ebe4e145a5dfd01fc9195ea1b69d0be952f5c164283c82d97dedaf40749f9906d48293bbd46b0f7e8523d620dc018ba28828715333a8cdbbb166d54b9668168ebdd5575688732b22d2fab82af4ed4b32630309ad96cd51706f172243daef337e42926763c8b7adddbbc25d31c53d99ebb907b220d9f8ca535527b309b72b2d2b3a9222b9796ca6cc8eaaf3233233a95b1c05e9282e7ef06fa5c106549d40743865ac1bfc25e6d26389e27c3a3db05814a6ffb89a637e8d0a29cd30ee843132a7e6fe17537312cf8c9410ef07211d9a72d979534cb389907b9a3cae80b19c96996f960266d1f0a8fd60238e91c4bc89a29ba5b0da0e5fc7aa1495f63728b4636998e9c4761440561b360ad59b62ac6a8661ea7d139c65c586983e69b6b80c56665e6f1fdd13e494b4275bf9847d5ec244cb4f188847069bbe8997f9aee1950c5457c1f220a46bd6983fd8052e5c96636fb6e13d257c87b8911a595e54baaa1e1e3e8d1263160cc31bd254354e8590db70a7b081260c8c0458348d8a6097a0007a164ade31eeed31974af34eff84e0156c697cf1486dce507f76d371609b7f4ad9cd682e189f35f942501af47626c11786b4053ca45121bdf1a035bd71a69c640517932c3227bdc4a139ce0511f57a3268c80db9928cc724ea41ef2a90bdbd296c12c58bcd706a63fc612aa3977ebb01c8e4ae912e5c71e3009d71014acde4c68d15a8a040947048459cfcb399a4eece80668c212e306accd7ee6eac95bae64989be891f5bc02db207d0200213e8e1c9779c661239a70e48d38bdaa35f1cb87e25f5c71d04061e6dfe8639461a75cb856a659f80275b4f7d44c61820a25ca210c0f0f001aa09010924434dabbb41ae4900c38618f1061b23af3e0b40689764e2a32549ece2109bc82d04e748026214f6dd2bb6dd743b1133f1af2d3eb43ceceb083c9fe3ab1c60c4ef61d4d8df30b30b3a372ea09a91e6f63cd0e2c8a04b7ad2214c41000996abe58bf46e9be7cc737da0f44e8b19a73a0658241341c0176e0f467a5b66647cac0b872ac62c011302152ce7de3d41e7d2908cbbb45d99e4ccd153887f6a1f2f1b044e336521f2ab5dd77a4aa46057d22379038198981ad9bbf5ab420b8f20495a30f3486037d51f003b09688eba8e199e3a3fab572d856caee18da523303f2cefbead8c41bf813cf53b78dc5b9509ffbfdc8813f69a572ab3fee51cf60f4c7eb6ff02ef68697b57cfa601f225286f4a63d9d7180e1d4e42a3911924dc795bd640cd3df41d4c0fb761802287e7e4be599b0a9c54f229308804aefaa5f676b7652b96c67192b585c1ee4e7e3f37a3955c0b1f15772bf80d0cb1e457840eada1054e6a81e793cad3c384bff38bc44e5350dc66df52630ad00e00b0a77f86c2e65fc01b49b1eeaec794667c1967618f3fc54f389481272369cf8fc2627c8f4e4f8765781eba21a02e3231a3d0170613a70046384b71c7e686ad2ddfe2199f4bcf338f2ce293bf0c38b3a026ad90d7a099f89c684b9cd0241fd46a1ba05aff32b9b49cae86d2198c775d2327d9e4672596f52f8dbf1bc63b479c45f8b98bdf94c961039ec4dea2b541897cb839ebd8fa64a7878d60c680fb0cedae9d458d35796aefc62809e379006cc59892be1658c55aeadb1b4eb52443ae63ba474abf8cee13dba2e0c9b4847c37b1d00f53e6fb6591d31f3d5ab3854abf585da9b10789dcbec83d6ea60d93cee23c2379148fd9d02f15e585002b50dd77caf93bb86eacc82cf0186f59215d758be0986a66b8be0f2da35bd5602a136702b06d42d1b0a5e8082001807c341ca961be5fbbee2923688c5066d4f297ec28c6cd82caa4735b1763d3f7ae3df1f8d8de14898e51db45dc3e19e4ffa601aaf270fa670a14ac55309b55723ac2d624b7e21d78a015d4c7f0cce722a3b8fda35bd605ef41855c85c93743e1fcbcb9f7a9c63310c0fee503e03490c6d3ed93b854d2b3b9d8710569ca9d7ce09bf1fbd60485a78f3b39785f5b72dafdc174a444434a3032b326da3d9fbe619a89c3745b258c3bbada45bfdeffffa8ec887788f9c330ae9587b137e2109c4ad40d5c84fd266833b7fb4f8ba94a6fc1ba7f43f95de37afe7f3dda23b1e2f496ab60086dde0d840231a871428afb7d730c3590ab230cc7420f0d78b4c8643206cd6a16860af399f25e9451933b5f5de13a97ce8b9890c4bd6043132d5e8dc1b7ce25ba140ac26ef72247328470f26b5b593058757ec4f8eebea0fbc401acd8567da8cdd58eb653b7e4038a8a2a386427265c36ab9d9f77a4f7d7abf9cdac04e2d49113bce36c605aa03b14ab8c6d5264667106c880043960d2a3ab73d1af6b8d034bcee55fbbcb9a6c29180a19ad883a1f90eff4e9bf76acc1247bc22d8cfa50750b15f4a5f8b1b12ed23aad0821ec5f4aaed07d385d20c04f4e61d22ddb153abd923590cdbf87dc02f86d4f591a4f407d24df8c2643b10067ecfabc7323d7dafba3129dc8df2f7039b65ac368514839351aaae561e85010ac246ee9d9617e87bc839a0d2a4af5368485fdae795251bb148215e85ed3ad659a3cc6f485c3f99a8b8a2c96b249cf61d0d960c45b61bbac47a63c25650362c914459a1c0fab2fe51cb656d1bce901acb6d26fbfbb4b2e340df7c4739b2e0ceef1a2f91e4efc029667e27263300050219715755ca1bbcff112516b50a547ec87773cee98dafc9268be23140c2e064fde056ce2d0c93d1d16e42c17e55dbae6dd5a105b1921e93541fce243a1bb9af4eddb151aef20e81ea0ca2daaad77cd071bd8e054febb640b8b7858c9078a527cd449fe1903fb2023dc6fc7744974d7060d07fb3b4beb9c82a1bfacfbc6485b3de6f585de94fdfffa1666d8abe750c6c035bc073b19663a7f69fded9e8584e5b6d56fb32c235cf93c1b91cdcf02f47fa1a8003bfae69cfb242ec3d52676183eba40b4eaf13624b3c9bbeba42037e84a497f7c9a77df69e3afd59cd9388739bb07c567f828c50875b17a81474a637c1075cc8b16c857e42b52c3a780e30134ade1880117d76b9e2ca7255322c2ecda9c13e54343a2ff516274f2eff11ddfc6f130f24e7017479b55889ab378cef755cee1fcecb0e2861793350eeab61b611b7a84706852a217aabcebfb1fdda6db49a6f74c3753784029763fed634ae5e5822f6bda39589958437f484ec7ac413b4c15e5d9fa5ddd17378acdab5a6767ef9b9f298ec3b798a50276a9b6f05d3d2a39e31d3c90d90ab96d2f1c9fa8a56942bf0ad46ce0a4596fe7ccd8aaa5b0baba0cf52afd00dd0cb856937059f93fa688030fb86b6b72b9c179d15f2761345ee4c656b6b854aee0d90f78044f5cf231729ad9630fbbbd132add9a2c1d41e29dc3989c12161988d388026820521721a3565183a6eb786af617858d83f7a5b667db65d9a3303dce98086273de78a8adf15963917c55ca8d2d2ef39dd706cc4cb6aa913317c33091671bcebf7e0ac55b20491e0ca5f9f8347b90cca84c7a99756ce46de55d5d3416b1ec713c602869e725635901b7889993db076809d5b46a459fc92e696c4daee0a2b6f89c0c8086b9bc1e80c1545cc76a4acf972fe7557ddada4d38a28ca1fc1dbb13abdf2e28b1b5d031f7c7ce8a150dbdb2179fb592970b299355194d219d88341c8b55f5566a728cbf3a064548a4d03032fe31b35f560e4bbfd27d7001bd730015454cea410a4a4bc129428e751994f19db35d5e5eb7d49188677f6b99768e5c53720c391de33a41bb04b28d1740458ecfd948665f40a4739031bf0caaa61ac6e0fa8bbf0c421cfbaa8f78913381b8a9757d7be7907da18c1fdc257aaab0e6478affaf39fddede71f44ec6ac47717ddea8ab52fbd1000685c3a65662dda1bca58c0b7fbcf693c3fedb2023037e148af309450f97ac44ae6602940cc5d75d5e0e814b2f79a90da468aa631c10b2710d2dfb0a456943a5dbd88cd5249c9f4a1eff7201c0456e26f0684a5fa9482c991c8aa4fdc62c7421c00c023d2d5d50b90c38176ceb06667de3f3b62d12f6a2e1548368784cf382bdc50f1cc1008ea764b2eae2638531179f4e23242f229d201e95333fd42e58174a46821d556f02b07a50eb539a89bf7c49b462e9ef4d4372ad1f4441ff886e1306783322333c92d73430450651bd94c49b61577e68d67670fb5e5e24ba40b7358034013e49bb5dfffc1ecf92d58a592fea7e01bf0581d23a767c54ea86a580e6313f7cec95650535ffb085bc47ad54dc0c6c6969f61775d4d892f94ffd9d8c9c65920830c9de8b8da7acfda7999934c636630ab999e947268c84d5c022596b430814d0b4ffec25dc687e581ce8480e472c73769c71f7149650d8c49b90f7fde16f11298678bf312f84bea618382f1d87ba285125de840c6f12b1b774704202d5b8277c314bacead8e2e22de62c2210e868fcb6449feb2b3a4e9d2c2176355fab8145ef01174f97b4cce0a4d3bdc47b580741a9eb74fab22d85558117ef20b16749b18c9ae864cea4eb8445e1ae18c7c2b2cf5b460a178ddf486c1b1db8a17d1473bebd4773dd65fbc471a8f8ae8ee75d224c413f6b057e42f11ea972c431d7dfb010edadfc88498fb40fe5995eeed57c609d24083662786addb062ea88a05d8a4a8ebe4b0320e32e213c55c966eb0cbe6d7fa067ed403c18ab93861f20e19b0368c3ce99b708a92356b55c230638b108338063ee004c55ef3bb1d14edeb291a49d41a486004722e463bc3f7712a2a7e53d0f6403f9d7afde9b39b36e5d848b4a6d9cd9e5a781f62688fe83f78f7188d86af6c110d9dd2534daa51d01fb081cfa4810db22898fcc06c328d60aec9e64603f33b0cf33dcd68eee1fe81678f4edc232e1008617c5fa3a99540a4f310837291d4907c1c3e45e38975c460fd2652a4803c75b31725de415bd72fa0b3e0d7486999dd199e828ae64451d2d8ab673ef8c3399f68f780c4c80c26f1fc1dc31c798133539efecebe49cd305a9e5dc8076d7ce01f7e44a5d39757a0e7d45bdaab9151c61c6a31a23377a1e00e015cb127bcafda349c2995efc735d3e4cb2f475954ded60bd11b61af5f758de7626ea71ff517c32b6067e4304dca4c2358d4d902c47289cf27a9c046e1b10192a3662587cb960f39a7487eeca53b190fc7c0e036a984025511c3d3a1c967018328010903b9a307fec4aa8fb211af79e68dc4f7f1db82e1d8e6a63bea43fe924e0133ec390d24167e409788500264443834c6bc575c964583cc75dc835bc52b5128c1cbac52843e60438e521f6add0605d6ce08971cb67159d7606e6911cb85315c3babb69ec6a8929ef62a0d6117b2e64e98d89b9078298f503f20299d80203634e89687b006378e069626f806ba2f76e49891f421ec6df476e5b7b942a3461e220e7f346c7d2b0788f1708ca601581faa82cceecde70a42a13ab3d946796d89c3d51d09a488323d7311888dd5acd63d3f0dbc791555655e3769c1a36217ad63163f5c6ccdf1cdc1d3424db24c539322b411f275dbe9fbf706ade17626c2736ce4885bf80e031b6cc9a6914349a185c626df827fafa4ed25930d284acd579de2a02e12e84065adf34c6888307b6b9f419bda9b661136292718f482ceb85878a8749ecac0c7bc6761ab346a4b9b6e33a3d7a5ac3018261f7b29e22e44a3c67ef5bf95cc0ce709853857b410195d180b3719682c98e60d135fe4a3a5fdc4660801dae7f1665671eb4890e36e119d857e15735b5614fef0c0d334cb8efd74595132cb528d4e55786beafca5f72e252c1ffca284be399c26106d887cc8689f5b6bf8ebbf4e532db9e5ed09ff253007b85bc424420de0444d6b0b0ef3857825ac61e4efae3760e20de095c5153986d13fc5c73b891287e8dec78412f560dc0afbe65fb2f9fcc782414c23258f93377d91e03321cc870e0e0571ae114e3693a22099c8f93b05b70a6e00320a16cbd473c63b12889d8c037e4589a78990ae9c10fdb7ef0c88e65cd0812408f08fd4b62c2bc951a5bbf072311b8a806ac8b5fab948373f0efc37d1c0cf5d6f07f25c37b7e9541cfe9abf1cb8b34c369eb93a86959e1827a57fb4be26bc35b2ec6b4a8172795c45e71f03580dd90c16876ac49761562c2138684b6953fe8a22a90977901a6fcfd4ad900a8358a75734801b4fa8f38b5505bb703675b7cd979d75b40b273fa0b33e3ed3f567025051ceb9578feb5fc044d8f853722471a479e667633059c34b8ef6bee3a74bc4d2306fe69e57131f2f25935ba6a52f51795ed77aa3006b9eacd7d4323fee62e9d8162c1ec53c3efe517cfa968a6af832f3963f0df43e2935aaf8d906b352264d3e811fde1a9d205afc915d3e08e598edd7d1e7827a13b8738fcda57efdfff9923b65c7b30b647ca094f1bbd8e27047f030be446fdf49741143042d9cd3b09b526c7f1e2cf1c21ec8a2fd66540c7ca804550fd5e3037ded21a4a56cb3f9d67325ff4da37cf551a8f5c6dc81f5bbf53e7d39ef64caa09aa786067da34f276e69517d362614a880f791da1b37e872cf7906efa44262ab31bc638efbc186e02c51307799c23cc73d0ed77e22405c00bff94df884890fbd5648537572315538be45dff9ef6f8672debcb69ffa7e491a5cfd862ccc7809cf181690e88449e570f14544cc3476dcd29346f10b7e5d2e1afe8f1bc448ab23b06ef9e896bf9d1b668351af4d9d1d0400c010a5a3b513b2b208efb16543e4d585212032a062dcdac51fe112ac0b3b0efc52ecd9c52a956105d084da55c1c00fd54472784f30f491a7a8a21ba78109832bd7f692b9e27a9d588c1b3560049efb4c37935d90af980b5315156fa976c6963ebbfb7ba48ef9762f00719865ce8d6a2bff7706bbd34474646dbebdb4a3e3c342e0ad0a17525be0fb3c045ec3e91df48fefbd179baf6c5bb0216b35b66415597af59e92ec821419c882fa4f6faefc57a739dec20228b7681ae9c33cbc4b20c081f483f033edeb35895c9b7e8ff2e7426cc8b3069dfb342c1eb6fb79f052136d8205c9c063729c2f7c01ec921eb9a206d6772c435dc83304cf898f75cbdd700c9ebd66c00dd234c6d109df9c3eeeadebdd12f2e555e22141e337ee1b0568489b3d4a21d31be6e477ee86087b919c8eb38de7ff3c98cfa41e3791cbe2f2be3b25bb1b3c1e4e55d6d02a81c0a40c6b15e3b992e274c7286e4a3434f3aff695aac05a6159418ecc40c149f69a759a0aec7049dad1ed812a3f4f957dfdc6f7285c840489d44a6fbb29eb488eedcec0e6636f0531b33935d9db36c2648eac3487ac3b5e91fea57e63bdb43dc78a71561764a52b6b036d003739b52df8f8e1467cbe6cb2cfa41216fddc107076882056a30b22c01baf96923bcd3525dd9dffc76f3f8a32ea3060d4120faef43b4077d5077297320f4bc1fba7be26453296077ae162972adecb730ebf06088dc2e1adc08d3457d3c65d5f43cc80f1cde8b6b59bb4b8df3198d48b904d857bdd1902047ba9738a287ce9e829e1faee1ad25a17c37ca690b6d4855a53112fd72449599090380b4886aa5faf0a101d14f10e433201acf9cf4f7d2ff5bda94349ac8e6535696973bdcf144b6667106c6484cf87a60fa180035b25db2a0074730576bc00459d1c08e1f9269c5a6a4f8aff32e33992d74449d679597b8309ed101b9fb081bd203512cd3d14ed3cf9cdcc8d8442df69da05579a3458185467ab52f08d8cd8c5b03fae7ba383c0c364c4f6e0006a30f049d049b7e69498394ba018e898715ab048ad0b703ac240c2bc89471509feff161a7b1d31573eef347e09abf83dd8ee79e24737fbcad8cb7f3e193c525b0c59181cef806b9983c756c07c03be6ddbaaff91662ad7c73f077e79d61212815559df61dc9ecd3fab715a1f3905ae01ffcc027d6334a5f1ebf00993f317cbc35f970541fe8114a0c69c6d4cebdcc3019303a76b09e72773e92ba10fd2de90f2be97eadb3fd8450ef0dfdfebc46e614f66158ef77ccfbb72b652f9a549cdd447487ce55b71994d6189d10d01e70676fa6668dedca9f0270a984a7cd2bdcb6b1c0c973d7f697dfbc024bb88fe5f0a9bdf4153f33e873691e05ff71f2f5efca4bf4990c1e44fa4dfc9a7a9da667ebad287dcb7fb8529fc2320d5f256ef82a60132c0dc11ea955266f7ef14d1d1fc092b487cd5903f530f2dbeed647ca58f623577469dc3ad04fe0d97c13049b21c6cf13c335c04567bc4cf6031834a929b9fd79fafd9caf5ff6bb4de4fb289d4bd95f45a46d4dbc97c47eddb74ae9783806155655a8fd0fd10e48c73183c809b2f73cc4e07c7ea2d710420033aa3b7cfcccc85fe34b5cb97a8dcedfb5f39978a85ceb141d2d6c5ef2efb7b69af6d472a36c0edaf1cfe316c91140d0620bcf74c7afc3309ceef49847d6d45c1b7f9bbdb6e1ed815be4a3b05750bdaf6f14b73e91bb1863ff10c5bfc5f58bce1ee3366bdd0715cba579cd67067a110e33a15f92ae4bafe43a191cf966be57c6efe3c604aa238c602dcfc4e3b4003b952d7c3e4db66af665e8759f4b185223fd87db7e627efcd2643899a5cebdd36e0cd6c5f4d70cf73eed4bccf25ee19d92f4d1f02eddb57ed1dace6f96115e054529d4c63eb3e0c7aa2df6845306f332a9da2ebd0ab7d0a85bf7b9ffdd7f0072a644b6f979130d8f5789ca0414cfa596861deeda3bf3baa24f1dc7d5752281d72bf623bcd328ddd8154d9c3ba5edfc820f6f4f60b2b8c8cf443932ac7c192d7bc694d59973c5bec309ba973ed3e5cef0f267bcec195f7666973cf34bcff4d267ba9cce3c782cd0aff46f73cce8278e95fccb98cd99fac24c29c038231e5f6262fb25b7d1bc3c19294bc694911925c99c5232a5349928478694272365c9983232a32499534aa69426135a3a5c2abe9f710ded51ea199be1037ac78063c89f89d63873623cdc85c45d39d2f819c550bf7c838288fa5ed1d26572df9132893bd673eaa2a848eb2d4e06931bca4ef2da9afaed68e67dc89687b66f4c154705325491bd273afb2b4944a3e9b0e5ad13bdffdcf503689f7fa91ff86bd61ae0f8c14d086214163f93090b8b276911538adb030fb4d214ebb1522eaa4816c39ab92280ea4be52d7a4744cbebcdc961eda166837c51addfc3845f359dba7692109ec7716feff17af0dc9037679f3cca7f01fcd43fc8794ac0a0d32e9e8017d8002893398cf317a52018556689177d0ec48c9d2f12a6b3a0965659f936fbadcf5f901e59f6de52c44a09a46448aa37f80f2d13031017056791b93326a0ff0505e8a5c4f7618b6276f8e251a1d90561c69900ff1a9339987e47d9dded209a5c40998bb42a431f626e149d0f690d1499736bbe6d3a719ba486e7e87d00a8da453652477f7a8b86fe72587ea6635a09bb074e696ccd552780ccf312e5628b400010e1e6ccc3193a11ac7b4d8cc8b18f17cf2ea53f85d078a412ae8cc6e78a3540cfa25f3121bc2461da57d3fc875dff6f78de755117d210ea18e3469bd0840ec70cded065b78fa47b53aa3c8426294ae505174a362a03753a0293d1f96eee57c85fbd4fe80e52c1bdb689409aed5cd2df04ed9eb1718d671b1caff6369a3f28c4b606874004e7fdb50c1664c90e0e84eec20a548743a7fee038b8fb04ff182208e8b61e0406f220eb2f1fe39c0be4a0b970b3cf0480b6ed82f76ab6d34ef88572744d8c618d4a6f8883a09864b096ef7512e21b2e8d420fa3952fb46369ac1fe8645927b8c0ed8129b636ca70df76787e5f8e93c96913ebc67b6c826c6ab9dc90ef3782613b2285e180195510412af084a47abf12c8274551780f7446974c4c9c0d4905b067c2728328d82a37cccf6413a301ca2e9bc0482ef97c02fcb9031ded25eca9d51d1cf91c88851ce49a1201cafa1130ab12e3cc1c1dc4f176a51b729643dd1967156242e628c731f8d6f0950a0af093435f6ca6b0b3018bf68e82bf3a19d89bb66f41ee1578bc8f1c3d8cf967a57e904d1bc7984a52fa7136aa54f3297006b3b9ecc19c4ef12c68fffbac81c024aba7066f38ce07efe6cbe076353d93ce1bf7c05cda5a998f1483f22523c1a1e0fc9a894c68f00a5b7b5ba1be9c9c7be001aed206edfd2999af30f1c49f5ca47594370800ce382d1cd065d7d36c2878cc2dd5c83519b46dfb149a105254352cd45e8b2862777bc536197cae151d19931fef239965a5e65e347325eed2616f8117323612af702e2403062fd65cc45435968afa1e349c2b72e16c657472f0bd79f47f375b8beb0792b6a6ba811ce1c1a10ef64513220e27e95cd98a8d785f28aca6db745dfbb1b0799caae79e4ffdae5a24715f5054cc21a72c102d44f2ea770eb1a21086a2e501e00b3ca71e3617b62c5ca0f96fe97cfc7b18bf255ce36d93f6c6562c37bd9d8c60f1e590e274bde581f0585304a035d19d744f63f83c6ec4411403dfa7453c6e10fd72fbf7801b29f58e7e4131063ab1f19874d3383c3d374b3dad4a0a735040a024e7fca586b56ad7d4e39711cda9ee89944366d82c8b6d5f33e497fe474146a2c90da8c95af0c5f88c5db5b96d725b4ab02a461e6613d48e260089d0d8a3b0857ebf706f71f5cc4361d8ee0974800fba6b76e78ed8f039f5746c0a0f47792f9d021424007a19f0b34f84d14bf8a0a724109496ca546b742e10c6ec72fc8abd32f0b76abe682bf46ba7870afe2aab1c090b260a1c0a20a0a4c0b27f0fffb190c2832eb30aaa53a7bc1d6f4c82de8ca53d0817e0ba77e80672d22859a7a8924876d1f1a0c0a4dae120fa435ac8bb0c4fa81f9dc5484704c433c7a76171a65e8622b6fd626a3ac56cd63dde855707c5d04e784d9c24e5ac4ffc39f10486299a6c10ebc28926cfa3a0ed06ba52bb7e8746d27086c9f21b3e7932ea18321ae0c531e7c5738786d0106faa29e1a836e4a285c69854510fc85c2eff36be03b6e9ff3cb9b28e0eb16ce077e50ad265e6dda249b3de252ba15c839e57d44f4f04ebb2264e80454543d08160dfa1f3a9031e0c85b6e3ee3eed77c809aca7d65992e51ec3e427ad12c310f33c3971763b5261d1ba127d03a0c26fe2e9c060f176329776d96a3b3a8f2f7f3bd329ca77afd75caa2a0b56df74f2ae2cc1d291157ca6e255fa3053b5b5256e708a8179126035bb68fb8ec5ec347b9daa121f9062711c0fd5138a4e7871139d6100bdacf7828329b2e56b99be197c86f229e164014749c323a6f072f6e9f00561f895bc7ae80eb9e670207b4fa5289b3e17747df29aec0ef610c2e1b915a57440742cdd2445c5178366483056165e9f1adf2c7c9780f45e8e7bedd9314ff886ffc994ac44532130cb087374d48f353170ebdb2af188661a3fd8904e7f25d799479b04475b327ccbac646c72941625986155f064bd5fec4ad59c1602a6cb459a1de1cbec2162ff8400deb4aa7cd0f715194ae4f253bf36a9186d383cdf13b9be78040e0088e33f669d625cbcc1716acc6ef2a60acae6d623616b9d89962a4c1e2ad44165ef2f627cd818bc95092529faabeb5338cac761b7aec4c574ff205881b10fe9587eb6ad5346a93f3cba8a947f43321e9a2fee451a67658fe53890cc33bc534f001554c307716a0f58bf251afb0610d1de56d3dc9063392acd3fbcd02793c516cac3e55a1449c689c7f8a4df75d67ce7009a5c47a9fc9904149f4fb06d00f97ad35d1d9f3746ff0a7b53e1aa856d90eadffea5d55fdc20c607182ffac7128f9152f55c6bb76cc60a0203b347344b3d700b7dc0a27e170b77e09db32d5bfc09207b5e126ab26a7d50f23293a1013c1414013005e5310497c51c30bec27be1f2219d9c54b8444622eab2e3751960ba59efa329fa78a1413c2900fe2a4bc0c9fd33d3ab872c8f20590808d25c75a6a0d85a15c498926fa4712a98bd304cf5baae436237d35ea97ee099965db01f6f18af59d44537bcb0222fd6bb538c30d8d73533d02efb25daf8e3faed00b90f948cfd3788389f1fcfa38c819c010e414ae87231709fc4e462762aecaf8506e2d5b43c984a013f3979076b3a9f3ce7f0875da62b9dbda339f0938e60a7b0d3159c19dfcf5ee17e02ff0dac1c17991655e856e649281a1deeede86d2c3c679a42fc4e7d3c8a7def669787f0e872e219a64b49c6c4c05101c48aa8e53e9608e8bfe8d126db45a5bef2a25ba97cf1657467aeaed3554e9d70ddaeb9222182ce475c49a5dd940d0ece9d5044cd843907f56c02ffe993318c9ff92bba948a88dcb0bac0c7fa0ef757dc67b63d13f4004de08345e78ef13ebd895c84f59033dc05d12e21c885d147eaff538b6b71ab77713e0a24885316ea0ee672a2f94db1683908c9081f6c5058989daf0ed8cf22df1f1e6815c6e58f1a671339a46a52ef24571d2d75c098a60c4767cddc1988d8a60e1f3a1a8df49106511b71d34ec44aeee2510cea68ff8a5b612c4ee00e01077dbe7e64c663a1a53dfd8cb8ee99f462c5824a8d1d59a4b049042124feddd4dc83cf884392d085af94602ca8ff95b313c2ed03488dd9ace860beb6e5a9171ad6fe27b457a27ca18fdc367b9e63c4e6977cb4c7c62912a10c9654587ab35bc2184cbbefd3dae8db46e7beec5465c6ae1adb4cf8e0040eeb1a8e22af6a68ad216470533115fb37833004ab7c47ddf7091ace7964471b3ccdd87308acac50b20479709e16ac5a9aef8784137f80481d5b76512e531439bbdf14202ce24e70e833de396596375ec630e51a6db212248ac01af6c209b0a2603b7574ac10470ba3ae42676ddc86adee6de4ea85428e83a4be28f5afbb68caae068508e5b434abf2d381fdb02d85a680a44e3d638b3dddce36be318394ef910f1ebfa7db53e142b288fb2eab16703b22126cb0c696418bcb48e546c2d2b15877aef80442fb892977a69f995f77483daa071f9a1af0e801f4b95f158da219ec513c845a023a6a557c4d492cbd53ba0751f3c44b4bb29e74c6282c8d55e767e04e72336de674cb55330ec72612717dfe43721c0db05c0dbf0e29b8f01c18519d6d4b2a64cae89879c41071ce1ed7864b38ba1b7b05b0d06f555f85f8b02458ba44ae33bae106abdf3a652c681973c2772a50f9a319059966ed275d31dffcce48c438aa8c1b9350ccec3333c7cf518eb3b66f8b46f2280a334ba74e1b7776e8dd53ae18c7ee4c48352d3780bfe45c733e49b4266d36d3a11595462e4c12e3d1859c83d6fb8883527b9251ce0443a5a2db4bdd68c8d79c8ca5c1dee879e4706e05318ce3955dc5e20fcff1b784add7eba3ca0aaa2b8a79c34ddb836a145cb244f0adf1b910a0c759c6ea2b8c2beda2e62e927216857f74d6a193f0028fa4f978526d6ca24c3e39ac7dc7c1887487249ee5b8c104a089e4d8118ba283c15179a04ce7aa6cfaf54f574a3c1d9218e85cfee774c054ca6d0defaee075070bfa863d79f470282e716c0c9c54a40a235f5e94510b4e4205910275905c95a2750f9ebfcbb24c6590164cbaa58049705c010695d1ddc6157f9d4432ef44cc348dc3f472b43cde94617484d6a3ccb8974d94636ce3b4468e59170e418db7dcbcff5b5b0695461cb1845147968faa49013ccca7d3b519e525fb00721ba7214f10465649a7aaeb4a2d6e0a897d880d870674d8ba7503390ec2ce91b9c39f3e36ece79de2945e7d760f9c5d4caa010a47e083700f921ee2af2f3617e1e995aac64f76e6b9ad55f97604b4c2083da1305732f13d09fbab4521b85363d6d69508e3fc9ba7382a65e9a566f28f2a6ecf510266255570849d15eb4a392d4368e0a4d5042be00287fa7a744efa3471748d4cfe8e1e826efcfc80343e3790defec4017832518aafc198a8a2139e733a0354aae63bb7eacb54dac962b7ae0d513a7e619868d7806f5d96a05765a4650acfc538d0ab6a30f239520d37a6c5b8348b63334bc0e4eba81650dff0b56c8047469edbb36e304bba7b267000b0188f14b782b3d97ac00ea0186c2710bf742a2efc32c0c981fa97900120c5e392faed2366c5f1726088a214e38354b79a5f35568db81e861054cd66144d14d7a612fd0ca32786c8e8cb79d6f62a53a5bde209cd3f912070d786258b81410a1c04574f1b9abeb0fe68c1f38cdd34d50ee682a6f0865dd3916f11ce15111293d5842623b0af41e915a857ae7704b44e6edb300b318f49ebf0e8d0bd5c021f0c7531ae05850660cde6fad0090540ebe023264cd6ad47889a345a01274e216b6eb09bc211de2526dc20d0d33956510787365a88dcccfe876203ff8040fe81ce86552d751beb6260ad5257500a716ad0bb09bda58437c1f9e31b443a435e210f2747e533a4dbc8613c26dc4324c235041f2f45327b99096002bfb354b762e2bd139d010d4508a4f93d7ccddda3514176990cf238ae1c5cd426967e3d7231152e7ca1815971a3d8c7bb3e0b6828c3e6db1d2749eb06828162c0a08f799519f2e0ea7b2e4304cf2204b243abe3a38db3fd085b2357f069843b28a14f30f3883d8c7d6c2aea57abea3bd3ae884f7d5ce2a694114893f3fae44038e5462cd33ec98faf653aa36ead81e076889e2a7e29d4de4667a71f240ce338180768a3c3928256d6ab026d2aa5a94cf4b53f62c87666c412690c730d2f7628a0b20d95b707af009dcbe4080ed81b7ac07112ba067a78e4dc477c98e631721b503cdae9745c128b240c87a8dacd7d4f6269facd7c49deaa732a2feae42e66db8b35acb6a9c9903f90d9977d5d90652381a7eac5159808e71cc6f3dfe5e7fa29d31d297d8868edbc6c4478148c519a862816e85cbcc56fe79f9e260be215c8c021727b5dcb165a60b422cc579af49ddd7589d0c1381617a2b7ef242f800ae518c55a748201975c1207d4be72e3768d088109ba469af207f7ce1bd21c53d93a692184addd9fe91eb2021e5240ff6455313d2881436407c0ac723c7fb7753ba2f395d1cfb9b79479124c345fda1d82fa19f12c08d7903f3a857bd316dc149bc1e6a6033f70a69b969b88f0bd2d8cc1d7a14541e05afffa973181871cfd28a09111e27e985978332cb1edd1ed1a5a0ada114dff0b5822cb971061119f98fe4ec5d84e97e93f0ea6022f2308f9dfe0fa12f38101f14d07b9ab6fe4ea7770d88b527aded7873e02e59f7633c662f26ac78bb4445275c4e52c2cb61f5fd917ed066c91ec959076c06f6544e3dc410fdbe7d45bc581164ad3596efd9c90b12ca7280b280963a11c381f7f09ff994b438df59b1cac088afdad482cc73b5f5b70aea394593a4cce9370334114b475b73583dd3d10224b7b997adc4aff2b7ff9f54da974d11699258b6029ca28f0ce023bf5a9c2a10aa11601dbdaa54c8ffa200411c0ad0560ca7adf145d6fc81d4eb71574dbd905657d1c5287b52612c2bae40c2a63dd484254386b1ec8036ad5b7731b15d05ffb4d6df151f504542bf504ae5ed7dc8642dcfa8ffa04f523846b312f5ba0c913716a31675c913049c3fb3518bab1aaf0bd5f0037611c286a87e2edd221d48cc7273b47b7eda2c6a593c89cf654d7f05416d0c9b9caa953ab30f0ad7c7d63f6375e8b837088e0b3d4c1145d417f112d7249e6026bfd61a5205f5489deebee5e982b8f1e8a76a561a5ac9237f2106d96da116fa104aa47e706459e7dac6d578a32df3fa250b8d54c74ab019453bdca8b8dff693912e06a5b9e9f5d156a104b1da89c80321328b1818c08cd9a14a25cdd8ce4397621069b0baeee4f16b5c42c9c6248c05d945ce8682c9ad74572215943985726b06b40ed6448b3b2c5913d0f9518a1c138f3af53fe55d136da4b22d001233edffb95a37f6c3549f4730be9ed1f49627c350202450b5b422d2d677d3eeb3accadc2e5042901954e6a81a1fd5ab38fd27f0429aa57d42c24ba08905df8d2f144c299507da7c31fd0d84dd63200e0ec69289e4d32b08fc12bf4789f10a66ca3d87f518ec8e096a62dfce5a9dac39c0c07c601d1f3f28a80309a7293517be3a9216ce073010e198ed0816641bb62dc19ed8fd028fd69b131598cd5b91e86be333bf74d73ecd627dc7746b6042e40236252384723024b384c23e243385223a2cf26ee64d262ef97eb7b64b83f49eb7d686255d92891436bf258c23ac31403e3cce61c04c9d27159de8951003d8f9afcc5f36a8d248b2a3aac68dbdc087ef64680e13a8dc41933d79fff4e71f67e232cb942397d23a782b2da229e110c388f9f9c429f01f0c998c99f3dd0604d5bce0bfdeca11149f49e099b2522fa589c1b7c0f2c42d1f6409c0a545770ab53f64f9e7b487cd74ef435ebf9960f489146b6d40840d2a313a630c6c8bc00ae8e36ee8b104a0d52421a77b734af66d6a9ef5520c29fb66c16921d929141371bbd266b90fcf7ba69d20027e659b5699d91a66f512b58181f8034a9187224d85fe578ca9741dba413e33b289c523ed3666ddd3c886b8c92251532a6d3118903c4c8544326a2db7d768c7c8483e99c24952592269a494cd651b552b438b50a9aa0877347da965258623198dd48ef9e3275647dd55271ca4f54c74ffb620af5d6c86ff1bd3b1672da4930cde99c52b80f5b993e2681b64dca5d5de618fbbe4a5d96f61918b612dba8f76a24682e54f606d6cb04b692da83e477af15d0d5aadbbaa8f5377729292c0cfabf4f030e08149d81d5d3dafd4401dcbf3433451ce2a56cddaf8911ce30fb43c366f1a7056dbe7f79d452edad244fb51a0be90ab9b6a05f7ac3e332a3fc7babc48f983dbba005fa3b8120eb1ad08c0c2e1e8df077939fbbbfe175275b37b70d8e2791a7147725ade70d2e13688ab44a8ab321060a2aae7712dc1656d05094ecd4b81d26a12862470b4f4f349cbf927084b2e7f4943087b8481281f95d2983f1e9c16613bb1bb65a692016414d3e5b75adc228a35c6010f84661ac9f3e941f1cecc620cc52652a4b9520510b32d77f30895688d27d1ca33a5c05085eb727555dc1458dc1601e819d44e8106c7cea2f824bac1c918be08ad060af31bae4c91f9a138ca08f56d572739f16a3653ee219d1cc8fa183e257ff537c9ec7f6a40ac49af701f521601004e4c4af668f1daa0431972b1dc9eda601d57b45665ab786ad428b18f41b612c15e2ec7f4296c24a154e64e1c7e79fc6f684289e36619ba664bc1bfe1508c95b79fd558d561f2d78731be863dc385364dcff4861d9f6689d16f4e131684e6178f1df6d9d258ea4d73c93470ea871d6beae631b6446aa49814cbe76521707c2759faaf2548b1b279a4810ba4618b2014034268a19d4345a2929d52159644170af35d4364a0d144e85a7dd35c28646ecd5a2d6dc2908a2e58380678f88c67563053a016556123be69728bbf16b166b2730ab6257fca41a479afbe76fee8cf50e61f72f8d2219d0a6ef062bcd55ffe07e5f83b59e725f661e16c33009c884dcdf30c628073e2f2e8e8af6a3cae6ae2c099fa7a9d89cf5ec99719782dc6b0a8a4490727b95a18688813886735ddf1233ea82bee467965533e34745b85dc0eef7bbc888adcf93fb2bafcd9e196b7dfcc5f7d34c593f5b97691a40d2413b672f2c446ff468be24831ad9c5235d96328047f825b50fdd1ee6e847d1853acfead050b8d6a0fa776caa8ac47edf5240ba00c4997ad4de94d58e0b08a99b10fe2e7f6489d997f919bc3db689aa60e3fab1c16a9b15698b0ed9359fc9f054db65aed01fbd449d780a19bb014b0b2023d3c7272e278c0eaa00689df3f382c13717640991dd5a7a866aa11d408f93782088cbffc9ee1a077c431c87e4546407fbad82774412b75b1e72d8572b6d4f4805f95d6c6431089c24c4fa8f22fca2b59b05af85877764ce994ea05674b84eb057cb47313800de70be7f59efd46e7b6d6e96f960703c6edfb5367ea4f78fd827521adc6593df997f7258cdc3dbd8af922debbb3985d90d8c8eaf36a2b1a8f5d2f1ba3b35d8d3299955389fbeda64599deb43ad5eac8874793d787786f1398a01dd8feeb3f5010143b6106b2630ed707b2f2c3f4859ad8a2632f2966f16d17457436e1da542857907b6d1a1bbb6a456c6372d39363803fcc093b66d15559fe13fc6938e33c8dae1450c26465a90dbe05ace8f94f5ba454901c97ced60558a0a7001acad3e6f487499138234b414ddc1845f5f3f08a0e7b195653e8e1f7882a19c137ccc5788b46504142c9f20edeab3e6580021858120c50147579822556a432bb7794fbb250456856ab668fcd477d33cce7642f393bdc73d5c9a3fdc88bb460feac433778c816b7232e11c1af111a5b4f7cb4f1bf322e6a9baadc34f0144b2bd1cf6200e1c6934d586bd8e1ab56ee8ddf22f82e49849d9bc0a9ac0d53f6a15ee0fdc149eeb1f050327a694f1fa2e1dfdf84ed950b1c54071d512032a9c78a9e7bcde4c4cc0f5ef731a7c34283e61c2594131bfef0ae03f68ca211b35bae01faee7eafeef2a5c303589daf9b5972e4c22640a9f992524b04393084f4b5d19127289e1ca25ae45a5725c029a2a9c8d610d8a943193f5bc4d70b0350f790a02f935d28eb7eba1d961b53a86fce7e4cdc4ba27d2bad64595f4171848d57f012fb4688bb1b27a971a487ae8ffbed70d22c8754609a8ae14a016264a8793deeadc0cee9878ed067b82f3d9c77f867f2c78a18dba947573cb3e4c76d0ce794c755c6bb7611c54734382ba1c3d8b383f3a6baace6d2b3d3ef308d0e211d8ea551f84836eb5b080c134edc6e3d9c0483eb6d20d2e0aefc255c86d581eeba295916d5710fba55511de560ec3c56b91ddb808b305eb23ddb630a6e56a22bfb128d6cbea21b87929a60b5721b661798c8b5646b45949cc9756457a1bbfc84e377e4d99fc4de9721e804676b24e50f7f1fd2b6e62657407a44a6f99211c7f0832a23d65dd5b4eabcc7d76f75ea8dd57981cd9ec15e43209d71379d126e831c372628ff5fe518ff633d94f5b76c2e8f1ff51b4ab7a2a4bec118eff4ed13e5ebfa76eb8a85233f855737fc17ceff98b2a771705ec80dc619fe22eb0fe079db268b5307074d61a61a2d585df7289dcac9d914c56fd69085615ada4b7950fa8b095effbb0b7b7c54d5d2ca3b296474115cfd4ab6edcc15bc5804f24e6df2d477833c6170d5968abde4ba6f110b7e6413e3ac103da08b2b4b37c3e0913acc2aade2107067c18b74c540b4b68c57feeb7cc21ffca23a86d1a884d69f4a5e7ad79803a3b8241e400bd649f525046e1060817cea20b01e02c97ea1a70394e7323eedd947ca579e48592358b09e4f6d4d032006eccec5b0573287e1d93f6a6a2c16c05b4390e5f89381c51b589f369b5ece87c631342d1028017357862ce7eef8330afecd0dde8c8b72336ede30133ce192ea9ad6af2fa5d1f7994302cff9145f9b73977cd4398f5147d646e73d3bdbf9af82d30ace0b338fb19b4cbc13112865af520d9f7efd4f4fd4e78fa9cdc127ff84ecc529e4051c6c8e04f446c34d771877d41d2c9c0571e301d6c98b402e207d585e339ab8b7a3526676b7a36856d0a1308ba945a17501d06f909a5a246afa874826c3d4798e5f34efc7ecdb6a69e71914abd1901127bababe9af558b7fda969011c9433c70830d75e5adaa37cd0090d09a0e02d12e2b00231b0d137617dd2cdb963ba024b36e28da7056c6cae001448271cfc6efa310d75116b50049a892804460b9bf5ececa73ac055dbd271b3e52b7f51dd510a08c8b37e410ec0d56d4843381019ec396e6bd241da0739d889400bcfda8b9a5147e0e617ff2ab32779cd0c850d4ab051c7cd804ca046ecfc78ae87e5b85b88ce4e589229c68c735d2adf097b717c03bf1b56f62b5951fe5dc8620d63dc597c636c9ed25c96815aa2170d580962792d8a1a9406b6f96998ecbd9a0e2ee3681bae3c6dc98dd03826cab043f10007d9ae100bc9ae368295e18cb50945fb1161d14bb4d4ff45a80324a0b2a8b219bbdd00f0dcb76e391a8290c7faa5ccdc3a0e0efceeef827daa1fc2b3ddb284e10ca8329c1f46fd989dc621873b9baa0a1a692ed42654a6f92bd9b14c3c58a2d56e3276541ad1540120afc4879902a44958d81eba7bde56d2ed0259cd44019c3459b23da76b2190a1ca506f6771b68b7228e07880fcf41f942aa8348e0a052789c5e08c9cae225ed6d224e8bd356a8e75a2eccd5f46d0024f795524229d943928c0ba7e177558b062498e07cfd9435fd7b77d7d1b1a5a74ebd3b8d85a01cec24f49b3433efdd48a526efc7b8bf3750649c40782593cfa1acce07926cf49ffcf48a4578e01985b3b190fdf0930e10c8a35ec995fb282b4f42ac674cb5d8a9a1b175222a1e295fbdd5da6b127a83b7057e7466141435027826514af24740898036cd3dd97a6bffa051f636267c07c455533849b08b34f1fcdf4216f2cfec3c01011d478c76ed1848acf25d2c448ba5fcac4de1d7b2b3015ff8e1deaafec6496daca7adbc206d7073afcdd6308f095f52f4458abfc48982abd6bb4d18185c48cb173141a08672fdc6818b0b5995eb3dc3f79bfe106a6e422f2dd43b36b65173c3caec29fbc357e4927ec2d3fd47b0b74edfcb49003fd3308c3d1fef8bfd13f57ade3a5589349f8ebd804f7c7ffd95ec1c4a6cad03f75008d1f4016a9b84caa6c448f3e38e345cffc1df3bc4cf82b42a7a3e5dafa8d87b46b8fabe0a6e07c4bf9018e65feea4aad9a33a67f80659ee6ff91719ac67a6bdff0f19f4f56df17cc274aafd9ff117f83ef457d50ba63fe84619f7c9f5de71977fd7dfa6593764e18033478384e658cdddf8f24225b9ff5a4da8e8dff46b07fc50edc965bb823a0140f32b0330fed57372f9f890fd8f46139dc5639cffcdf505ad4c07282d93ba9df1735c23c209a7c274fb8dd7dc5989cff62cb4ebcebf66904e8cdbf4338f8e85b7dbc4dc1fa486cbcaf0596362e33e7e7226f1eb792176fb97b38ed66090789cb5094b907fa3e7547c41dd3e31504a32a3f2af1f6e1e3fae9869ae51b2a6a1e8a6a9f3035aad11bb378ace4e3ee1635a64b22875c808f7c2ff04021820d4f55136e3032d57abac1759eb9654930edab9b031997f0727ec4e1e22bc089196641b4e3412151d3cc868976eaf997f9aba219792063d8c412e87b373db63170a1e05303092032c89e3738ef62983f6a57544907cf9a4d3a9fbc259b88b8313675e9f55bf88b8a2fa90a6192bd998024cd3aba2fe3526a7173b75e9718db3d759572f532b4b373a3f5cbf24ed0fe1ee1bb2ba51a0b88161d759de596419257bf5dccceb321edf23e95e9a8f299818ac907edefcf2b9b1b10b7862d3662f45e2bd6cccb6a33c344faae5e3104c59e7c6261070080cdba013e8db27a706a05abb493996e0229d8a4f5a61ac374b388b11d68d9cf078204eb363b7bd5f4827c5cd83316ac2986369fe0a88a33db5a43b050f16ccfc2d2be790880004f582a389e8e63d0d5dfdf4e327967bb6f1199d5c450d5c6576d21cb9b5cb5467b9d30b77adcad6683e69177933377961f4c470ce2859d3abef737683fa7c2459845dfb403d49ffc2d2398e466a4aa215795cec02761b71ed9a670032b6891633dfae92f74aa70dd2431ea809000440b284fa98b1a6ae2740012781dd33e691257e6ea5b02a9554d9fedcf73c65578de8266e0e88f189b259908f0597280991dc239879c88b2a7b1a199bd34e539a62857c36014e65004f0d64f328594f58707b6314073c991f82dad19fecbaf471d159d65aa7a667ee996675321bf3d16be98e6b2b0e7a3c15a045f142c2fffd3e8625c9e8c17a6b2ad40466aff5082453ec74fa399fa3fb17d6a95cb90ff50e85b038264002d7419c9412295e228a4703e2bfcef5ba5a675154408ae198da0f561af7f7bbf215d4786adbb4cf2b8ec579d143f3eefb7f3f3a5c7b6ecf82b28ea9edbdbd9f8cfcea66f9554657d1529392d85b0511413d8da13e42958ebfa7772f991caa7311d3c993634ce2ecd9dee35f89ebc6f623a401f7b451748bb703407955e4a3dfae2e4e0aa5415bf6d7eb69359a541b8bc268d233a7fe512047c1ce6de6ef54efe5a2344e13df91429666acf02f2e3853921a172c354cc3fadce9b4aab453d6b70ef34514c51ca74c4c5100a1616755f2747cd34545df5c8c74b9caa5af87e81fd591b488f559605adda23b4f354743b8378e6435e143e51d491adfc7680104e4dd792a6c638a1f51d4001f010745e36f8f5a785ba6b36b29a33a6d32187e2f8b225c80a979ec0d2c281916d115b270619d0dfe35076188cb8ea841b199b7764d87bd69109cbe9ebdccad4c6170332a95e34970e9acf1e29dea6fffba3ec0645a3b866df1170be3bb303a267e19fdffcee35480ff6f109a58917dbd598b0c99d1ecb935250a84c40808d70269e924f79b06b34eb57930f535864e8a358aec458db04f9df7dcf0fefc58bb0aac700decc2f4da6dea340d83ea6e234935425226045403d2ac54c85a174cb1b91bdf9c76213e1d291c274b9a06c43c2d3ec32ed856f22502a5b3eef5f0d24af4f407169abc50f50a78da68bc473e4811bb50d064b0da00f8171c37fffab641eb5ae79faa5f8986854e6fbd2efbb56df570befafa3f8c024dfefb26b870473dd36b7e11abac16b132c5fcfad69f54b57e1583616c6d67e2f7171d606fae64b687d526677339fa49ac198c22eae667d96b59fcb09fbe34aec55e8ff5c378a24c22f497c09978680bb98a10b5639057c48e4deced7063205baba066e11f88f0c5b50f40d3cfc05b70d8d896061b81a62bcfde8f64877c1c912b39bf0c4e21c60f33058990ddee52cb4b1a91bc3689a59a110015f11e8c515af2a4400ac02ea68ef25afa15459d869d8a74df2eb4463dff5b54650426790e11916b8e60522b87ecee03a9e773df92e1f2e34e6231296d7ce386e2f9b0bd1f7aecb659272d640bc25995842eb51a36c0949779d1cc604dc3bc36b5bc54bd3ad97cf13dad09fb61c8fded303c37091e99f554cfb2d107f8e33fa0f2614e8ff4c665b83fc59dc7552b5900e57a69d098b6954ec5bbc8e6861bf33c68d31bd2fd60066a4fc2bdc7819615aa6aed73c1b5ddba870aa77d9b48c6528694304c0db7595828c421c71f27a4689759c0d483fede24a6e4098ee3bc5405fae91bbc97eafddb4c898f9f629d581bab017a34c37ecbda14739c5abad7696c1c66a0d2c2dbc1c62610d0acd868eb80182c4096f431096fc1181f8e8628b1c9f1990a4897a5a24a316730bebdc0d3be93b9dc0aba4c9fe1375d84339527bc6e7786ed2697a6029a10a4f0d6d7224ebc73bd8e88284b7de287bafff6edb4afd013e8340bf502452f958e53fb255df63facfb021908b5fbb1deb1e23600ad116e2716291ab9534fa80b71ac088cac8d464ae837d76e1b2bf7b36449f7bf2b551e10d7341bbdec080c7d1e2e2ef23d2a38d3cbb954422983a8e4601e663e991f37db3cf3e751050c11af2b3e5217907c7f3e0cb919575aa2035c9161ff541438029560b7b4570d3cece0393395cd599e48d37a06e9c6a269350dbbc1ec9012e2de84c87b43affb2014498deb07da02a48f77031dd7233e7fd896f48866d68d864162de8527e7ff9ee7c290b00a678a6e2c0642591f2f1fa2e365e410e86a4d5e69e8315df70c8d388a59c767aa25b69b5d8e19c64b741491e4f23e2bb8a050a4c3e9330b274aa34b376d1b2da884b8489499df08296a4182a6ff02ec877ec6f2af6ddcad755df8aa8e4c9c5c9bc1cd06f44642c8cb501ffab8c20e878b5a7f560d13f132693b2570ca1433391b578606f4dd5e0030122aeef186859ca5791f8c7b5a5a83c10258d309f969c3a07d526dce822969133c100b524a03f9fd48cf850cfe94b4a8a148dd298a0f8866ecdc65fabe4c66b734ad71568472406f391ca439bd4e7919525359fca3c1da3474ace85fb8f41551bb8d0efcd09c08d2bfa87548868c16da4762d872d3c49454254ce9f98b09ec4f4174c310484252403dc739a6d892647f1337b5d58434e5abaae4df3f0db60614766c3b299c5a2d9155986629a2239976bb67e5c635924fcf599670a80d1ea147ce1dadd41cb2367b52c3820b16d3190d57eb132e501d4220d3f31082adda399eec2bcb9cc843f8297f2a5dfe0a2038000c092ad97835ec2ccf0d1a6fb3be41cd522c3369131e95ce6cc2b8fbf9da08dd7b65a5a4820aca36f3361ee825b7fa89e85ab767e51ce811ad340b7722a186a31ccc6091411073d4165d94278179fe1fde8f9aee95ed28a4b0c42d63127cd7ddab72d80b554d08587028633477a53df14441ef3c2cd2ec8870f8b804ffb4070c057662c45f5e7ae16e656db34b889b0846bb036bc100bd70d5f45d6c2fa325deb839c3bab9952a0a7bf175aec3b1c16997df2295d884a42625f1ca1b1c01338aa48c42353181ceabd9e2411236b56849e86c029dba9d7d75f1a0f6888e277d3c882da0e10bb2ef9fd6dcfd9f7e047767d27f477fc1bd5b60d396fd74a566368f694b5ca1b34707cdd47cea10d308b386c3574938133904d5c3e4d7f9e20afd00ed5b9eed4f219c9b3247b795c1ccce936a67b7fabc91715e7ccf0826fb85a0a52e94843d608623d7df4ea9077f5c13102919f2d765a7bd808061c03808b1b51dd8ddbafe2980ac826bd141ff063c70c5164a5798f2046a7ec2146751255af8b5d506dadfb5aa1587188c0b907a14c91e3956031f7c620a23c5c2ce025895328a0cea5751ffa9d7648d98720c0df574830a533a01b1c590811e0db5c0b7ea77f4fd44b699bf7e76c04d96ad1135dea01bab177d233bd0c3857aaba95e00192b867ff054cd9e62ab997823a0841fd9d69d067a710d362ed20d98ef634ee39ce7a57c406b053d1e0ecddf97ae452c0781cf2b673a264300eb93deb956eff30d9a9a27a2282cdb3783a8ba5f0764b51717cad5463f6bc7906b1d7fe88446c4f01d043fd722c2d9b35b0bac942b53d38fb86e367b8aadec1cab6e38d8b9d9870b54e58885238b17f4c15e16ee2a39c85566c4cca61011df4bce2e472c8d911918601013cfba2baa1456e6bb3009cf5bdc1e6fbc010f6977a1546246fec9cb86daf49a4c9e27228616894edbf49720044dbf031cd1209c1529cbf65fd17ac4a545e2a84f536905a9c3c94b899e59db7bd64318fefb6ba36e580fa6e6273e00c6db83704ca64e742a444a4a6ae89003239310d7e33f8b168e191224ccdad34566d24c10c5b1f4569f98ff836ed667249ce12627a3312cf18b7ea47c35318e1bb27c655bbb4501fc699252213840672aa53aeae15fd04f3216eb6278e7762ee21edaadd8285a0a50e6b5ea48edc55eb2b7fc2694e53e54537d46c3f9387a3d3ea64b3af12a04c9e746653f56d40330f0e14de211ba892174bdfac5661d45d5dcb455a5deed1a35cd7101f1ba9f9aa2c23fefb99848b165e51175246536a29bce56c34b98d38d64f98d9fc7359cbc61c8aa97574f384a762dbc0448269a29064652b00a0d017dd444d1a584684c64897ed5adbe88409614869bfb00d3511d7bea49e7be27d3b93b93bfddd3ac83e6d6d10bc5bda0a080d1bada78ff932206e73840e98a554be66a9ea1513c080e8d3512a9c958d410348d4308c33bd7787b3708dc1016382d3f0cc85137e84c57c1fffa93b156d06b3eb3fb1cdbf97a54d537e41164c011cda65e4464d803666f071800e62a58d4941a2eea85c196194f4f9ca69e8c72f3d84b11f96f0019903433d0c552b6aa035a3ec79c1fc82273b7cb419fdcd96d63c055c7f4e71c48374a552bcbef5da795ea1203289b1d1731c212f4c94f976df98d3ae0f83202c682dc53b114679308163a584b4a57daeaf15bcff21cabbb9183381202182dfbc07168dec49905bc2a683a6b583d002157a3d5ffca3814d84b8baffad0c77123af596b50a2408a7a91275807bd96ebcf6774e2105d9bf226abdee11468110fab3c17ce37eccd08f984b184c1b52b3306dedffbbd144968ea57cd7a8473daf0dc967ec1d4b61f8f2f08c4865116ea41f60abacb6526ed25f5637f11e223e28f77165d370077efae6720b3cb9f0b86fb7c52f33de0ecc9627f4336ab87bfe524363e4900bc4021b30f4633c5f546d740d07f04524a42c8d5138bcd3222208b6e8349af4966b427ce46b82e9718201b914ca19623d11a7bb26b7c0fccd92e0df2046faa4e54429870c36673d8a0f8d6a8fafca0b4cef67ac79b467b8e229c8e5fedea2ff120d447c0717000bc92628a80a8c5e7275c92daf615562d2c304f5193ddb079de14e3d61e02f6ecaad1f367b6a745567361992757927cea022e1f39e4cb8de711a7ade97603758606d99e20d382be754643ffd90ebafaa1430f8dead3da5f49e4ec7ccc36fa98d0aaa7106ea6882f25da0a2ccb04be5845f9114c1028b2b66d0b0b82aee8298920b2e149aa59abfc4b2a156081412a808f2ce90711d12881759be07e5cd9edf5a1298a856016d019169b918d64365ad9ed956deb53a70baf57f16225fa81dfa6bd124f1581105eeaa5d96461a3b139e1ff3757b1f228aad860e49f876cc4c1c60430d528822e3646363c36b0bc8a953f2f046243c3526c34a9640d0cfc7f142c85c252247ca0c777d6105a03cd1a40582a8e323ad31a4c7856a347e685d0fc7f94ff2d6f52638d18a2b8178e2b0c6990d5a981e5ffc5af08fc5c5043843412790c1c313144a54194864f1a5dd24099d228e151d898a95c99826158134d40c1c8dfa071c7ffe8698fe532e2d050a247d411fa3c9697432034ba3c181627e25d5c20101affff62ce30434ca9543e5f7ac2fc7063549c169d9f2f406154aa1409263c07fd4d6738f9174356d6e08b016f85110230636b2889925358190c3da28f9b51862065cc21862855194960a2985d62880ab91786b9339511011992907188898c399e7b29d11bca402632942083e7d5d302c72fafc0a854580ae8111c3ee791ee731ed9f2398fec7cce23a8cf79e4032626333a6f3223df6426843799b1e04d651e79539942de54c68d379581c09bca30f1a6323bbca98cf8a632416f2ad3e54d655a785399ec4d653a78539926399f63c1071b38d920c78bd29bbae0c09bba18e44d1aa0dea481096fd28082373991e44d4e1c79931341dee4e4026f7272c79b9cb441c1298782085cf0395a5cf2395a28f2395af8f1395ad8f1395abcf1395aa0f1395a64f1395a38f1395a04f1395a187d8e16429fa34599cfd1620b064d4e181ca2e6730e11fa9c43cc7cce215e3ee7902b9f7308fd9c4340f89c4330f81c432af91c4310f91c43f0f81c43d8c0608393063fac79d30f3bbce987d79b7e88e14d3ffc30d90090097c0e20567c0e2007f81c4086f81c4076f81c408c3e0790fd3980bcf03980f07c0e20f6730031e17300e1e07300c9f91c406e3ea78d249fd38691cf6973c8e7b4f1e373dadcf1396d2af0396d28f0396db4f89c36547c4e1b273ea78d119fd36687cf69a3e673dab44e135c9041930922980003092c68928797cfc9a3cae7e4917d4e1e247c4e1e177c0e1e8d7c0e1e7a7c0e1e6cfebf820a32780fa214e04d5180785314ef4d51bebc290a7e5314faa62829bc294a086f8a32c19ba058f226288fbc098a1f6f825281374121e34d50b87813942ade04e5006f8282c49ba0ecf0262836bc090a7f1394306f82e2c29ba0b4f0262815030f20c860021305165cc04193a7400449c018fa92134dfc9798f82f19a05480ff1201fe4b4afc9706b066cd1a01ac4962cd1a12046b48376bd6207184116bd6ac5983d3d2462423d614b1660d116bd60c214429883552a4f0ff6c6c5032438717405354f02207832ea8e8e962f5637411001eb890c0ffe73163f9d1c963c6c262fd135c70f0ff2512b6e0e349502ce026842d58da034c59b490cd498bf2cfee31e2fbcb3fc60557f602f44fba02841a4fe4a1211070f2ff432cd7d0ff8f1f27da1e3886e701288c5005cf03387840045840828506b06883051d58bcf1ff5aec5f8f4e0e5f3a3a2d5d66c7061bfe4b35fc97685073f45f322afa2f11558104066998f87f521539fc7f1e8b68d16302456a4cf2ffa5ceb3023622c80010f9ff1b33ae1f2bf070728923ff8f4385140e009341186ceeff935810000c5f9008e20062fc3f6988444688124250c58aff2f75e1582064881486f0c0ffdf6870c41c1b58c20062d4f1ff4c9a204024a43b5296b4f0ffa5412049a2064a9610e4fe3f8e13411130b17a43863ffe9fc42d702394628f31f4f87fd21ddd54034d1133f43105e505151434e6f10562fbf3d2048941306052bca03c725498201e823c288e42792e1d162bf3a0c697eb0be23c4bd0cb35be7807fbe7a178c73c97ce6a140247958af37e14b246a397e7d2e1fa43f115102aa8831fd7d2bf1e9e1f950a15821d0b0acae14b8777de6acce16bcca210c8ca181fb39431045722dfb925965002167a2fa129620f189daf07431d812eac078c0e90eacb1ad5595c1c3d8c8b9e988b44504ad098312b56b0202fb33e50b3c491e5bdba2962c678ebb58538cb43857cec4242192808f5650f95c5a020f10b5fe21766ce0241d71048c48dc69087a3ce211f47d62b4bc91f180c150a81ac2d7a524496977b0862e3cb85ed2ff31d82475fc63e509441a54205056179ece1d8feb2377e3908e3c13c974e0e5f3aa81cbe32068a22d7fcc37ac0e860aa116489286ccc528e58397ce9609e2b63413b431a64ed0489a8cf1b8fc24c8412b94b07f35c3a64bea03c57c6f8500816a942b0f70e6228cf9551dc753406002bcaa178c487502eae8b0e4f184cfcc1b020dcc7575087ca1e11b6b908ba8c3876c487b898b5609b73d186ff2ff36bde28fb274170030987920e3faffb2fe556fe488afc9782545f8a214d098dc879e744212fc1c0caad2f1771224fe8bf74c64c99fd79432532a531623ee41e698212d03fc92b85f929bdb0bdecfac4648fa5a33d17c8c3f00d7a1139cf32f2309cd5653ea4c1310459590c3991f789093367f18c9abb8cb8f0b543b53174cc1ca34aa58e008fd8a52e3825174a5c2088c364c4201ff2d1d3311961d4a627024b8c90e0ffa340492208531157fcf311fcc214d14311658a98520407ff44443208115efc7fe0474407449886a0840e91c310744c4b97090a6ae932e3104f5c3c74094189108208c185144f881ade24041493101f8422538248230809fc3fd6d265b8ce13e36abcd7886553104888477c2808feffa6204cff8f0a0016b47bb8eb08e888bb1034048aaa0f0cc28a46171fd29c08e31bebe0111f125318377f792bde61429fc73dedb5c00fd45c047d8eb80bfb070efe1f13fabe091ff8f8f7810bd187285ee41e2a101f7048d85c8df78394b634f9ef210794d0e7e53087afdc03971ea0fc4b898287438282c090ab113d226f877c8b39f020c1835282422e94bfec05f419834442498bce63879772e400a403174f42a603133a3c31e9e02487397ce51c8ec8219126c1811231448d469c892b982b6b5511ffe2d0f97951f92f8d70431a429f97e5150261297da5cc248918ca30c9bcee61ac8f0914d4f8f1228cb7c030184aec5ee24a7f39dc61d280d38d08388f1cf12115092511fe4b21348900ccd19737f88de28bcb7f0984ffd207a50e2ab9a28635461c2be250d4f079accf1b038689864750472cad83e697f072385261652f1c31be02b1aef50a359631916ff05381e3e7a97600435c8d61c63811d885600fdfa0cf0e16ee8540d8fe722ad5b55e21cf02585eee41e3aba51ac5cce24429f022354ec41015825cc0d17394c33fabebbcafc4c17f69035225a5398ea0fc632934de6484e68fbe9c41d65187f1f0681cf3e6afa0546af3afe80bdf429a93296950094901598abab080f0769ec449654ae0a10bdbe06ae42deca893a274818948ff7f2a95fa2f39f92f65f0ff3827473800c88de14daf25264a4a949ca239d11732c2f13c3c2987332202fec7a0ff0ff45c99afb094d846ac800c543c96e26abc3060c410158e1132f1a8cd31ee02b5887d5e18cd89544399170d654e06cb360c75a319d22899fe4b39ff250cfe4b17fc972cf82f5550a2e0bf34c17f49829c5293ff52041fc57f8949024c333879fd7151e42a1247853904bbe849914002092498e0cb3b186ae44763e8ed306320a6930168084afcb80bf4728805015a84e18502c02e628812b304137c20f68147d8a7930a527da0a7c61b7bf441f20191e7e166792bbd88a9d5c2bfc88536efa104818b8fe250efa00b042265613d8112b10fdc397ce94861759ef871918be04a63e10b3483a1c430bb5c19db2aa8207a612eca18dfc15022d683611fe87a6141fc158e4118383a000b9cffd2cd7fa9f45f225df24fb2845409181e161f1fd2b9033fee612b2b564ebcb712571470f1854c424afcbf5adde65e38a600c5ca3f8992ff274d72a58bb1f906351fc12f73e5516c796357a2affe7bf61f093862bc0c2cb53f2ef21eb896c752a118a2547b0d38625fa2e1028698f423623851d9946e9320b979a4044738d008238b6c40032445d4b0424ae48c09c041c793e630e5b124812943792c51744a7ca80492562530ffefc29b547b3c2605f4e951150003853c1014443ae49f64c83fa9907f5206fe49849004f92705426af34ffae39fe407898f7f1206fe4917f82759e09fb4c73f498f7f521eff243cfe4977fc93ecf827d5f14fa2e39f34c73f498e7f521cffa40afc93e0f827bdf14f72e39fd4c63f89cd3f898d7fd21a6a04bd4e8328869c47759e95290d1762885a21cd12ff2b31af324fe3c1eee95fcf50980fdc29e23e45dc676f9d22ee8326041836f00f6482410af17b8554ae6046b9853a0ac2c48fafc8e4cd8dbc2c186ad43c0cd30879fd13396b7b9b87de9198bb60a823d651e7891e91117fb582443108438951a41c8d50c4cd3f30e42e4c8aa7c59efd813b2d30ccf2338a5e1710680c7908f6e8803e23e8237a2c8e8c1b6390c9e27310e79d4ad018822e23ee6dde6a794141118c89448231628c63f6bfe85da9f279ff0fc19bc6741963c2ff9b808d19c35a5c14731891877beba85e9b7f625c99af5262aa8891422a91d03883740314462a0534c90b200069518561644413a2f9d074341d1a34684a40d3848426282614987ea8783144855cfc29c34d3f26fc7c806152542fe0f0c2eb05d60b31bc40e60530270ac59fe89a3f51d7ffe770f0272d41fc494b0c7fd202e54f5a487fca52c89fb2b0f1a72c0ff85396a23f6519f3a72c3a01f814b0abc19a67d2410459bcf1c5430009203742a62f81ec8f8f222f9ac25bde880a3a21019f80277541a4232a2d44f9ff346ff281e3ffb144655346100ca7702f1c4d5eca90e2e89f948028ba6cd145897fac0a86a1386b7baa0fc442b07fe922f4433a7718d8bf9e1f2c9c67193f1ee667e71da3ec0535a6090a8201fb3cbe7b07a71ce52130cb32090503573c186a7c8147b9c5f272178f58ac57cb133bd10b4f196fc450da6be5ef6883622e1abb29990affc0b0d25a6d11180a6162eb45064305056141435f82beecb1f26b06b0a807e31dd6418cb358b9254ae153424e048e01c1607ccc20eb28bbf290c87b10f7c5ffb35819e31895ed4ddcf8ff42e2176ecb202bf1e5a292c2973516365894f8f0d5312a54b00861014385c57a752c188f2122cf17cf595dfec4f0acd9fc7b75206bc7c4b3850a4fceffdf98b95d7e0709b07fde4e99ff29d8e7a9014d3b50fe9f0b6557d7a1e45f47902741c7c80b4f190c3bea44209d2eff2d6d840214a14fd5d2462dc0d10204501f8861a83c06041372220c1c370b04bd2211e345230ff3e7612b9d3526664ce444210f83b1e0e4ff15b9c2e60a15586a7c81578ab862f45256d046a9d407b65aa056895614792cd502c32c56f6f8dd63650a2cd5257b63c41015f2d1957756f52a94fc5771234c98918baa546af32a413f6915edb1149137661f51470c51262a397c6a144314e889aa14074ca93dbca1908baf90bb5e61449d1d15be84d4f8ff190b41cc0353aa051418284ca97f2c0d306d69a0b6d779e1145b0f2308864bfc7f00deb46d79226f85cd82476d2e8a2c56e651a144168b44a1f87fa3b1c5f5e31c51324cd7e89f85201282b0cf13fac0b008b37bd83922306252b0540b0cbbca64856c8f65520f0157452317c5f1059aea1462880ac110fc3c95eacb3a95d224d116d1f6c8ab222ca58da16d2101a259f02f1ef1214c62a31157e5f0954df38b69b230a4b911d090e6ab3104bdb8725864924f3c9672e5b0884b1f5ecc6044ceb37c628e429697b300897c280371f1e7681fedccc3e8aca0c60a0378717f5c44fda0421063e50e6469c1509b8719431d7d52b8909873c8a560c15045e03734e4b1781186ea20d6e21a6cb158bc08133326450c5f212862e20bf4c24cd4258b5fefc1501dc4505158acec617273972b875ee86517162548c4886c9d1877017b94f8813c23e8c345315fcf9006bb8cdccb08fa889c670933823ee290068bc02ee3ebcb0e03fae49dbcd323f21f9ea3d1d5e238abf37a46d0070b6775f91393657f3c8c989636823281090ace8b7cf3a1c5a4c00576421714b4a4b06a6923d5feb26a84143040e1122c25625254e07e151fc10f851754e03e4110d30916309d3087e98433c2309dc0c53f8649c18cb63785f38e4991826152b051e41b93824d390127abb2d85e498c0f282e822c8d198d227f09612e1064617c359291600294886163ce22c10428f1e32e570bd439ccad95fe78f7758c95bd6c264d0f456097b12312100b849207ff8e90a43c89e7494cfefbf877c384f17f120f3b80a3e7040a2860196685046ce462ef200417051450c0ac5cc1f6c71f278cc7c1020788c7e1c1d9791c1d1ccd84311182e20a62889a321af1548a7fde4ae7968a8f997be188618ff1d11343d4f74aa58cb211163002128fa58282466e1a61fc1b9c26a7196efee4fac09f5c88fcc935c84bc0a494c53f298b2a388c7c487be33fe9061b4835889c771ad41cfd938cf43fa9e89f44348a7cff935edd3f69fc2789e10c2ef06bb1866420793851a0fc7f0affa54b40d8ffef71d3078afcf30f14327d50c6a78ed4e42e1f24f1c118a5a5cbf031eb0fe4c146f083827d802595dadcf4c11321af4b6dee81121eb014f9ff29260fd6782cf582170c1c37a7260f380f3af87f51486c6152bc74e0c4ff83b9957744a02351e442194c185197f9e142190cf7050c07833cea881524a652e20b3c3a62714f88b3c4fdf110ec513c28ac3c6e7e24e5f3c4537a69f5983971f9e2ff73c857d05e78e232e64f5c7afec465fb1317d49fb840f9131710fec425e74f5c70fed413c99f7a0cf9ff08722ad89c05fa6c16b8e5e36a8a4016df39627d5fc470ff3738b0f20d3736bc08fad4b0f3cecdeb8f7217d0e767f45a5e97ff1b1ad4fccd11ceff8dd14dd1ff67716b2e0c07823f5cf4c93baed710287ab90562afee25f2a2eeed2c9b7f45d925f2a3ccc258798b61651e868760b6ce8967007fe2f9f9138fe9ff37782a8fc206db69e7037fdae1e24f3b477fda39f3a79dec4f3b13fc4927913fe9dcf1271d2cfea433fe4907e84fb48c3fd12ffe4421f0ff1748d013e668f4c688017dc29d7776de11f98fc8adc6d0dbd9e1ac3c86e1e16b7c6519bdef25e489a84dc5c35062c6baccca2b23be1a43afc332f67558142898c8793ffa7afe6f5e23962f3c3e9ceae7cbcf0fa7e2ba88c1f2c58baa8c8e97546acc42d90586ae2e4457843210988f0f8140acd706bde02b2d3ef60881acddc33f4fe8e358a0e149ff4fa21f5271a50c31441d752a51ccae1b305f3e7f5ecb0bb5e86db125e6a2f00aebffa60a95ff312e882a561e731f02454c4a1ef3165de2e6ac3ce62cff24bafd67c1f27f83efbf6805849dc5ad792ac5c3df1e38e64b95321e85429daa80b9c926dd3b048b443183598dd9c8ebbcf5126fa648f91f732b04b3e02a86d97907572ee69d9d77be54860aa522ffffa3a050282818f7734a653cfcff349ae5cef4845161e1cef474d1e9f9e1c2a8b81f31403a3e5a7ac2685b9affbf4101735846901546b3afff9b139e8c202bcc8d42e572e5546a93b5ce504ca5542e4bc73f9ef2f5e564bd0e4fa9122b1f11583955ed9ff5ff2788214a5485dc55a1fc3faa62ff8fa71413459322fe7f4ba5302c043b5544abe1b532ff27ed8457b5c050e51275ce1ced88f1b07c3ae14b6bf0a60412fe5961c86990c5d2c1fe6f46b811e112096e1840fad295120a243c9e24c71ba4351290812086a89d79f8a7d30aa087e615f6d737762f520738704820243fa688719a8280294884f0a729abff67b15e1f96e2aea3710a9629a939458a142950a64830e5a328d27ab1408d61fcf33e50ccad1668c457426018be44fe81ac28fdf3a6ac10002c04319fec838da010148c8fdee7754ce423c8878ef850942c32cb5e68a6645996bdd040c158a0d097c3a0126c4823252815a4b90c1d887d39ccae2c5fb821fc88f241390ab32acc2bcde2963099208a22a72848dc847003c2ffcd07ff371edc748003207038e243226ca2c0e10a1a46a872c54871206243881b26201105879dd40bdf0e160003070b54f860109c2390b8410f2041409823bcc00d5254f1854b0b30047243ab0f17aaf801dcdc7007a9b2e65f4fdc700342251b131ec8c28638946083260a115d6c304011932c48b032810d5a00436578b004151b5600734547a291486a90c482315f888fb051431a1358b1061a2ae01a906812c4901c401fa8c14c0376b2700044076a78e2431c0850c3444503234314683109ee42031858fee021004564a1c1879b0c9482b052070d60e448a4a696c0000d1e648023c10366625043880f381f48d182831a2daeadc104165743c3104204612c40355924a092c3143244a83145414917e20ad7111f1a1b1314a9f172c40024a0a0220036568e420bbaac404514f2a84a2019e030d21d8e22f860070e341d2019d5514375718941c8e8000358b34515d91446420e48450172e40ba3a9013624e49c214991253d2d688520004d119b141368287243164503e89c3c31c644a14875033465121e5c4550e4201a628527ce10396281004841840d1a109161c61f32a8c96110052144c806d8f8ac400414468432515c218208dbb9018b2e96e4f142e4a692409cb8d1c88b0b392cf1296a52c62b0706700a04d0127a7151c01d7f808100052f0dbef4818348469511900ab498675ca2472bb4e880081d0640c0f8aa230e31a31a0e469dd70c7d74808d939182454028001906fc20e65146102b8e7e70c404b4f1a20436c63944561363e084403a8836906c0e18882a20967c8a106b50511056800b0d897c405a112ef1b51184128f041176644490009e0edc114eb12474028a46c2cce0014bce00400745f031031a53f3438d1e82cc6084176054928499a119ca086005a9e364cc0c2650718219df87c9b588083aa12971886b025150d0008d2a805c3d60896079620d8f0b8c0762e6b06193c3d5011a62e4c0060d0ee0204f14a0022d00c00166610337c3939315504dd7a40b263c2801721fa454187a8208cc0944890d886183940f033824d8f081fcc737c513852c31890e387c3370f9f9831221263e2a558840a784477c4c48d0e20c21cea8a045071746542a71b85a4f0001200c01089281567780156dec7c49a435491893724234815549c9042422f9e2b2d8d00e69610d49d660090009309ac06cd0c14ac3451a348ca86007560a68dc6029b052871c29bd1103b85518a2800c7e548203932a86d688c141cea13086c21419e0112863b2a1114e30e3070630d24506431221611f8a9840862d16d1a6dc053491010742b02d66988832f4f4d0811d6a868e90c189f7801d36632af0da000db18a024b1e5e15d81f165420d5883716c2811e7a7467bc16be6873c5153e10f0263043480d165cb458e121e4c32463e0716695801110d0598265cb6a88bb712b4959b0aa893491e286127aac486bec20d3a4280321382e10a191063c4944a8003344e08c22210421941f3102022670b943480a1836100201961f7a0726590211190e80fb19dd1f1b08230b497a11325c32884a87233a993570781181382ae825d8914724475060856f60040a9cb9c128f32f3ae01a48490ce13c68e921e7113614e13e7bd8e103243ae11c60f1da83e7089e2dc8181e68632bb01b020530d3c56833661f714e7eb22d8c3696cb333a72c61a3b474af540941514da026dc694d969c112bd802d8cb2382134b5eb88010c41c00733740a871f8e1029e4d0104c2a2e22864cd1cd014918d522580f9d1325887009217f47c7b92084891ede019d4cd3839a391e883c091b3b3cb08556415e23c523e5083479e424d8d43158b0c128a3118340bd31c923198533ee3801a4048d200e54a21ecc2c510a1aa3043229288d1c2008089f2b5040a4a045d0cf14638680e2e791a010f020c3bd21010da80ae9e38f2109548da8b6d8809045525ba4a0ba8108057090269150b5c5b5c3d12062c0a0caa0888a02530008c4f0c716310028840c0e3138804915461338c111c3088198294118c823861670b03cf1528315314810458b4920f994e68e1cc8e02e3c78a589a25f3125cd03d248238395365b0830482b8d668917267e802193e6df70d5e1827884c68d3f3c40e4f403031a02e0b0250c1d0cd48026cf280810474f8626003d682508428517183a7083c6102f302b3098f104973069646009188898c233012a131001c318219e5062052a0a80a1842636f094a16487338a5ca083008629083823010d3eb8353cb9e1cc0e455b24c9429867bc0cd100483a60f3e5cc0652289286932858301388216378557400879907e8ac8001d111589831d24e982292b011333c681049640a1433cc5c3089c9688b4e2db3079b0bac1185a6421905d81108ce214a1865c009788ffc8e1a65b64c02125f87cae078e142a469162133c79528909ca105116498a80483450e60481b32db0d11850d349003992c01907c91c1933ee6034f8861e68b9495316a70c9b4aca1842563926882021475e4bc31068616acc0c183cf69cc09705862a5ee718198465c6fec0064c08298300ab1c20e2311dc10f3c3cf227c04712085981730e00800b6c862881810062082105fcc200265800f0e3e491e410314811e2c4e50020d1b806cd879801440408102d2b21aa28badcb094027302448c3864b84307d74e0d5edb1850ed38048d21882059a2f61c4291b68808c0d1584b9f200221ec0818c4598264328800c283e4f7eec90e2103e813d42f88162080309a29861e3c72b216c81f180ed47fbc0080aa01a61e3e70140c11b65cc60bdd086187f58614655f382124b7430465381cd0b41468098d010d37a410518485e40208606309068d0442438583a3065f8a1c100ec013e002304258bbcc0c8242a30629638010329ac80031812380904e203194c7c49440a32e6c0e31218be78f1011c0d303101802f3a40200f452e7062fad2a5cb1019f44ca08b2f00508014af3b9448c227101074f0401f3c0df0b9e2031e1104d82af029428191471f6c58f1d919828d158340b17d2cb862cc923200145ef418230a1d6cd474e0458a4ac2b8609b448b97af4b4390232209bde02f3787b02009245e6e420f889e93e8224708af295c4f7cd0c50083c41082235968d0451f32c820673882a5cb0a7c24e0c3f9a2e58224367869e40041645c48635f393388970c5c40028c0c048c1507b870a6834364e880121d179e0002c41a276dc4c185112e58ac3ebe2b5cc000438b1302d89071f121d741d44725657079e1830bd4b86137c1e583186e68e246ea881e4208915124808dd8a3450f296cc14514687a6a6032852240748d9e2c43126084070d027a4c8bac61460e1bba6ce123027974800336475b180089511a6da2c85bc2341fb81e7450c8162b3a4a2368a099624b043b00f1c8135c42d052471c76a800800468a105011b7cc143c6fb40cbea24891c4798205ae84e0ed9f0b243164be67002913d6ab8c9c28601829490a58d27b20ce08b2eba80e0db208baa8845d634c9e249962857cc6c51108108f7886cf3810ce8410257460a85ac30c249072e080bcc3088253d9438202c1e91c0bca91c36840a52a09492c0828811cf91050ec005962ea694d800844b07b0e4c0881c4cbce021002c2e7830481e812c02068b061008c1a80b225ae001a4cc20414958791e2bcc6809f9b0791e228d8c0f7b44f13c3a681cdd36393c4f054390a0a0fdefe421461a2220f1bf2345f604212dfcefb43c50428abb85c890ffdf2945a1c22a5001be841e3de8d31c3aa81e7288440634d61cd182996fe1c9b3c0c8a4af1158ff989411d0fc69842a41df8490ff4ff32711285037be43ce0d70122187ff9308ab073a89b0a5f5faf849842aefcaad9308524e2238f92fe2df490445fe4f2194398570c763a710be789dc3bcd2a7100c1084855c888f9f770a61e814421714847d99b340b03bca61984f2090f17f838105ef05091040f800e8c33f73fac000ab31bb56381a6f2eb8b140fcc1566376612c964e2af56f42584619659481731b4002045b9c3cc84e1c0c72e2204c9a4937c0c2d6b9e5b4c1b8c1f8ffa25136c46903281ee8526d6ee475ed8dbcb51abd30af70da00e7ff65c0030791c9881b300460bb4a59c2a0810376686025e88d3cfa50e38495422069a10c251040481523ae082730848c03a85145933416c1c14b05175884028e5cf91191e0c34a6800223ca0b132a4b8dae081ab3c864c395a63001ad962064b046a8865403083142db280a4831b8215521c4da8c18027c8b0f009b1c3255d82bca8a1e3001210682ab018193031059a282c902175650455133c5849ccb863043df22064e8f8c0004e907281cb494ef603217cc871830306091a4458fc20c4ca974b8cd823ca1b2b9c50e5032512a046070538faf8b9b102354646c10c1548a54e1ae09313362727588c21d8e980b144a9d4ff959598c1ece8ef48d4115b429fa7bf23311f6516df5f11b85920a855add7b7c18fb35447a16af3495fabd1c5f76905fada3da994e9052c4e395ffc09a79c2ea79c7acab15205c3524141d8286617868de077c2600d8ba5f37f03c1dfe0dcdc7c4b97b9c2fa748ebac73d3e86b9a0e74f1674395950c64de9268252044c989c2a08d2395590a3e54f1494f1281696f9e8e99c2858f3ff28f1d59d28e0b2277d9d28b8e0ffc5fc698209a0c48c49e9c1504722177536e7e26af4c84c702568628e193feee94f478ee13f4d10519d9aac3935493d6a14b990d04b94c2c5bcf23935b9f927e22278fd90985b975c3224e691e58ddf6b48cca14e93c92b10d4d1e2630fd813827af78069f1b187953fd01387c40cc40241309cb57b54ad304058f0942f2d7a5e38cf7223c9bfe9e6e5b9b22a9b280d954d11025941e2f752110d05617c357ae194233ef45ffac07f4992ff52241e38732a295194432a51d994af080cbb959857a7920b5b8979cb9f4a3b4c2aa5f906f5a4af2baa90bb8634c8aa62945b57267d5531caadd35f2266d67371fa26ef51095285a02a28ec4009927fb07f3d625e81e161968f0f81e36bcca318a25899952d39f38f42a1b011e42c91c589522c4ec459aad44acc2b4b9880e098e262c889788885a8959857e20634f05f894e255378d260f12883e1bcabc4234a86d82cee99f9c4e41db07f3d5ec4a30c06f411b9190abe4c1244e5038c7caa908f9e4a7397b882e6441fb8e3ff254123490b1f852912ec81a2ffcfcbab2b57aea452dc0b47954bfc40954a486c7dafac1a3f2e4efa820482312e4cfabac237c873a58ae663542abe415dc43f95b87b78c8b770d087c57a65c963de1c98a274812f59608fcf63c662e58b05829d4a1cfab27b267d355285111918c9b2089845d82c12c206b0060ca0c8218a78ff4928d2e47f911d940213a644705ee56a852b4458ff5f9ec40535a4730786a00f9343b8281d62f4433a04cbff7f6688212317b9ffd21dff253b6af82fd5f15fa2630e394a7114a208bf1245687b61a703a58ae663547a86966a86d6c6a4ec9e1c663055c617a872b5c295cad552b95aaf495f4262cb9481179e01842ce0ff7fde44481e24881f38821fd8fa71a30d423810248a17a407419a047204c81c8010d1a68cd21aff25359ca4f15f42e38c3fae30fd31c49bfef0e14d7fe4f0ff4c7432df92c30ce69fd4fd0b71ae56b885a7c7d50ab78c202b0c2befcc7ffe4b6590f147e1f8713bf31f2f2308fe8451a952299e1f0d4c91011f78b020c52184b4418505aac0a001131c9a743181a90b3992c0c25053fa1cf102041f04f9e2040c7ce8c204094858300970002eb898c2010e0ac0411c783800cb0d75000961c50f267dd4c00725260bf460da83cd1e388226f478630426ff4df4c0ab37e5c18688c7527980792c950708586a102c85c715580a8ff11f4be181e5b1141e39ff58ea8e3db0d41d4ffc63a93b56584a758714d08b044bd9510696b203e8ffedc0b0d47e531d5cd451039632d5c1011d6de8a0630b1d4e1e4bcd71c53f29037300c9a1084a0cf9c85be087a576de793970d068e159ac179938c6080a7a1d06c90830c64ca0f485042ca0a60a601105cac75998952ad8f65a51a04480b492c03f1bff252fbaf837e080430c515c6cf15d74807cbe9ce9f9f9b265fc40355e08ae82bc88f151715a74c284e1bca8b0fce8900123465546c74b10e7fd0d40dea8e38d32dee0024be5964af4302cd579a81aca6f44f158eae7cbcf0f87914002096fc0f0c699375a5085aa155678a3c93f6fbdbeac553c7c891f77631037e0f87fce52ad545ccc60911b59fc833e6eece0c60c2856de9f3784e1ff770373e3db98038eff1f73876146d94b1b54fcb751c3ff07f5bc46166b3cd1460bff6d3c51b5f198152b56d818c2268d2f02599df502c9087d01b77659c6d9d4369ae515155cc6956e7e7795946f7763520338ed6a9de59d595679ef775b198e222531809b956a95f38eeb6675a6f3284ec1699d55ad665ce20d04bb057038eb99b67a9b59b7e1cbbbc7caa402b8db71d574dbab7559eea616a5e0343c29ddbdf3deb1bd1aad09e0b44ab5d53a9bb5e67b33ae45c169d556ab7395566ef86a4da1e028ef28e5da669ea5dc349f08e0a4e4bc5f7ea5e4da866d9d07e06cb67d629a6d93f29b59bdba52ca4b7a82d3aca6d6e68ecbae65cfb4e804d7c99df3d69a4f8da7969336c1719e6bb633aa55d9b5aeddc904d7d96dee3dbbc63b4da7c62a959d06e0e8cd329debb5f7decd62b9ba72090e6b9cf7cc5a7c7957e5365dae5701389aabe4b3ebbe75186323be52a92401b86a73ed9c576cafd497d2d5957c646525382d25df36dd342dd36edfe40038da4d2dcfc9b39ae746e9a69104c0d56aab96dd6d579da7e5564e1d52125cd63bd39e332af7ed3deb5657eeec4282ebb0ccb28db9edeac6e5241dc175da6a58e3aa61aebb66edea4a11dc9aace1285a92115cde3793b3d66e937dde22fe5114a9082eeb785f49efdef9cecb2789088e6ed966bb5cb36c777b66beba9295c33944cf1dafb7726b27b799b6ba124ff9528dad8e49427077eb24e75ad6b65d35ef1d9e9256152908ddf1b6698ab76dafd6b9665f2a2e86d9a5c9d6eba33ea4355c46f7c67bd77177b74de23ae91612101cdf34ad67b2db7925d5c431cc2ed5e6a36a67d726433e6e2c907ee0faad16db8d4bca33bde1ed035bad96b7cdca917ce07ade66a7b7d6fba65be26c14bd2e1ba9072e5f4dd3b6ceadf54ceb3a3e728c493cdc296fd775f9da6e6eb766ab2b6bc8bfaf470c6907aef22a35bfd9e676632de78ca403a7bb4dcb79f7cdb3bc75bd9ce57a0165a41c3899755ddbbe37d67ac5545b5d69ade0c0496dd334cd769db3a45d0d23251e5b9ddec065fb6aa9c999fbf56ce06cc7dbd4b2aed9c4d996759d9dc1a0506287adcf1995500d5cefd26a5dee586a79bbbc73e5b0e87b5169270d5c5773d7699a6619573c3915b7ea734655468ddd2a9f984ed93bc65ab7f311d771e614638db5dae1cce28d8a91ee322c65763b4aaddef44b11b7d52e6f1dd62ad7b68d65df9f57f4bdc08f88ebb89e35677dadcd5a530cf6af477b5f06834281fdf354d7e78caabf66bd9adadbf16c6e5b27b9a6f99c51e991ab986f5bb659d749aeb56ea9b453e42cc6b7ebeaae9a7653d3737555a237e5167252ef7ab74c77b452dbf3b6bad2aa722854e5947706aeef3cef9d1bc69add7be7d595a31157a96c5e4df1867915c6c5751dc7595bbba736b37bfbea4a554675408e4b6efb9c5df7bed9cab3d5952ad59c2c16d7dac765db5dd969d6cd6b37cc2fb53e6754685a1ca5b2ab9d76a5a6aba6558942b1585c9b61717d5bed623aab9557f7a9adaedc9e8abb8ec6a34f07853afa3210f539a3e286b85ab37db5aceb33cbd3561464a894d3badd7ef5de72db7656893cceee6d6f926a5d9f12679d35da3d425ffe41a15028d105aae4f539a3da2b4e6f8cb1a55bc5145b9aef960971b6eebe49aeb7ed6a2deb74d2d7acae96475baf8f8eadde75cca9c6b7ccb9eb249796afaed42417ce6995eb2cf3ababd6b7dab7e65b058eaa2ba96c2e5f9d65946bdc333cb5beab2bf7f70243d591664673f86e5c52b9b7d45657cc6dc76575669a6b33e3d3de6df69ab99b2fd7b36add7618e7d105aa3659bb0471badbb4cb68be16e3ac8d3a1bf19945c5553a67bd1dbd9766de757775659512039737e536cbb6a6699b96f35d5d39f19686cb584a9d6787f9762bd6f8eaca51e455a2e1b2662dbdd84a6d9b36abdbea4a15ebd5ca64a6194d2ae4ed60db7a7d307059cd6abd9d96694b6f27f3ea4a114ba1cf1bdace70b6cf8e6bb9ab92f70c6f7275e5c759fbe32a6dd66a86b39ad6d17eebb53dd3b3eed595992c025d2ad6abb5597c5baf6fa70c97f5dcb0a6d19d37ad77aab590b1724e29379cdd2cbbf8ce39a7ec6eb6f1a639d572d737de211f7b7850a8cd3d17a8512854969f27990c4717490163389d4d6b7b77bbac93b472fd811bd7df972f8bc5a20b4c89e1b6bdb3db4ddbb46ddabee9d595630876d904206ed3b6e35ac6bacb3a3933dcf98fc8c7a39dfe249b2f96abe55d2bf4eaf87685d93d6f7d67ac799dfc5ad9f3832bc65dcd5cc31ae769575752175e98b4ce29b78a6f96596ca7a458676cbbbbf56bf9b6199d920b182eb31d979aa6f96a8eb5c67b839bc45f38d965ce70ef5b97554a6b5f5db9c1940f87a79e5ae6aab1d66dbaeebdc16cf3c2ed8c761befb0c5b26b5a73b675e1b62e534eb1d6bb8aa9e5747525cbd5f2549b877925e2eb0297b36dd2ae7bb75d9bedbc7352e1c2e56d675d36f3bdb69bfde695786d0f87b59678935daebdebbdf38f137115d80243979ca92d5cd7b56673ce7ae75db77b5d5de902c32d332d5cde92d62cc3586b736779aeaed49c48058e7466e13acef9b515df8ee79c7559a5bd318fe294d5e78c4a721cefb49a6937674d6b9f1685a2351c5d64b0703cbb9ada8e4a896dae1b0a85abd8d9ea7346258687db986f9b6bb65549afdce8ea4a292dae62a7f99c51653b1cbd99cce4cd19cf89335c5757621e823c611ed3ed68f2ea70b9d36d65ee995abd7558b6c065bbbb5be3bd3ba75a66b75a9f33aa1858e0baaee2dd6d3b77ba35bd67efa06aeb7285ab925bbbc9ae75adf2669d15aedb3acb9c6fdbcc33a393aeae545169add49c88f654e1f0963399d56d6f576e5defea4a950ef3a4fa3b12352c5438af5def36b65b959a56f1eaca30af74268d525bcbd5ca2da33acb3a4dabab2bc351c4d5e78c8a68e370ede4d6499be9cab3a47b7565fd40160f0ac53f90a533eb73460503e632aee9d6aebd73cfda51bbba5235a51d5b9ddacb751367dec98d5e7deb26efeaca4cf20d7e5a9552c7b64050c5daa14a2541e5aaac7ae7cdafd45bc392afae1c43dc82c66dd99dd9c699d669b867bd5757aec4974b1582ddca2e94eb1ab67b4fad9bd8e6abe1d595aa8b2747ef95dbde74ebb9d3b66b5757627925a7f58cd2ab5d8ebbedb2de56571681a1904ace8ce3dd6ebca9ee9addb89e7775e5feb29cf7099096273a4f789e0015e59f4ddeea73466566050e63dc3bbd718d37c6d7da27405a9e60cdc7a0509a135930289dddcc2fa538c35a76bca15028d4d4f814b951be697aef9c72525957575e1a2485ab5db65a96bcdfbad98ce3d5954f80b43ce16a3cf1f504a8cb13d5e7d9198eae2a01d8f0c5b3d2bb4d2aef866a11b158284e4f592bdedde6beedcc32d5c6472f2453c756a73c04758f0a9c96d9cd3dcbb7539dd16d47e1b68eb7e41df76cd377676d75e5d8eaf40990962742af8e6341a1c65647a178086a313fc9e6eb09d0932c3f4f9e007579a29a9acf199516282af115aa541ea4208d726b0414a40a640981ac0e4ea0d993144c8052021412a460298ca0820859085140c03e28c183199ad081ea040e660bd42a1eaa5472c8d6e9d25cbc1b1ca95426006073950a1ab49ca84270cc1948cd867032028b46114cb64e2c674a954ae8f356625e6118947001eee32b040b8cf84aa5d2a2d702a1821428103b98608260e88104433a772c16a842939d79e841042230912a2ed4010452c4915eab0542b9992594c2cc59fa0392541971105e851fa030d10589b7f287038589442aa0e0ddb0828dce77381b4e079d6fdde520550c69d0c070c64c193263c40085f979c1c74b1717b8f46cd19285c3c2b3a373d3c20d0b57fe66febf0a97fce9a6c99f6eb0446e14a1e0dd68001f3a3f800a469881b4812aff240d5c803406490c013c49e39a800f2651926025b1e594c4161deafc3f1620b4dc80c31a247ac86982e584c44760c5e988054c80039e8c78040a04fc3f01c496f761cb187aef6527f3eff3302a133b01fb38ebe3ac7a2a020d51071ec1e22120ff9940e288310fe63f90e14f44644c3630c419ff3c0bcf3fced77a1cd6d08f21c883238387b37a30ff3842fd1f8777f9ff26385b85a33fffe3043dd862fde3a87062380501654d114e1a34ff8f04107ce0c0f0ff4d70cebcd0e7f1a13caa58f907ec079c930f4a9c7600e1a443d0e720c7090729271c72e60d7adc0087993264fe710000040404043406470c90680368c3fec709f3f3ff02982f2ee470e1e2e385cb23727471e1b9fcff8bb8cc2d63cbd4325a195a6696f9c7e9996ad85023c6162d59381c2c3cff383bff8ff338f57f7b2a9c1658e069e932ff3791e05cd184b032a50a08537022d06ef4f080ca3f4eca4802461130c2c2480a23041831914a6918e7fee3d87a2abae31f070a9d325be11f073505070356ee4096967f1c2963985dff38016812be586036cb5bf11cb1be2f79ccfb1f47852847dc859b37fe71a0a470c487b279c435ebfde3a08063c20925c011f221ef03bd8cde278612a552632363065ada68e42cd66bc703f5e83dd27a7164400d6af087cc3fce1313fe874230cbd1ceff8d1c25fcffd1ce4d2424e08cf08f83e18cf08f23c23f4e08205c60ffe37c40ff713cb0238e36420a84609cc22e6e1ed97cf34f0c0e071f58088bf5f2f9b21730a398799751e71f678316f88559c68f772dee856b0f1c7314bec4cc43a00ff4bccf6b6d1dceca9ef6f68b0b27f284789795e6409c488fd1fbc4e456165f2ee000e08f3e9d39836906262d6df48fa381930cfe714e38a61c3930b8b9248ce6448f73018e05ff381550f0ff4d2ac189a0121c2638105482835309ce8d8853aa0487b4bd918be225bf2d49a5b44a2aa9a4924afeb3e8d0219dc730917056973f3160401f56e658401f238eb7321759390b8bf5cae2d219419f2f932895621db13e574b8c2b87409cc813411048e43c8bd0e7f9f09697592f30fcc48c21e852e38511370bdcc2595d1e419fff1b0fb058af2ce22b1c3f319b7f62fe6f3a00891e378f38f2ff250ce6186f0d2f8cff6f69236d0c1d23ca904a6944a9d4ff4d239891bb88dd40d580a6084d6496f9bf41e4907f598687dc90423240881f83f821c89aff9b407e7b807c9b29b48410117f74206bc70f3ffcf0c30f0c6c9647e6ffe6021ccbff8d05f6d8fc0b8ba5c7e62c561efd0b8ba58387f87f73c7f7eaff3776dcd4f1dbeba1e3ff668e0ff419b92852a213173a713437724c1a879515c0706847397cc38dffffc488622aa551a2546a6a9428959a3da914254a83afad1a9d57d2488c0a0c5574a85345f33157c0fef588573ede25043faf158232e4d6958f77e1adec6394bdb4f297c7bcafec9eeda942deed9e542ae4ae97d8023fbe5be0278ae2667964ae54d17c4c96efd5778ffeacc46398c11c6d70670cb36bf71c6d70e7ca9549ab4c2a66143f900793825f55f0942ffc4a93cd233ea4d9d7f6267d050172d304137cf4c2a29d79f87f638025fe6f0a704300cdbe26912ae8064509e2200a96ea60e721141503be135d227e693e46f45c3aa2e7ca421f6fe54fc572b53c31061a1ea808e451894f8a2406094e6980f82a22dfe0774ac381962b68d440d3e5e3ae2fa0cf098635679cc02f336dccc081e571be9801225122fec55319ecbf34c210efc3894c14aa1c74a0a1063250fef3281a9dc6f0f1e018d61829ff46fbcb406d80be0055f07f23c4ff4d10ff376b80f8bff9e1ffc687ff9b1e78f8bfd12187ff1cf21c72b5d65a6bd5344dd3344dd3344a29a594524ae79c73ce39e794524a29a594329bd9cc6636b399cd6c66339bd9dcb66ddbb66ddb368c31c618638cefbdf7de7befb5d65a6badb5b6d65a6badb5564dd3344dd3344da394524a29a574ce39e79c734e29a59452ca2ccbb22ccbb22c93dbb66ddbb66ddb8631c618638cf1bdf7de7befbdd65a6badb5d6d65a6badb5d6aa699aa6699aa66994524a29a594ce39e79c73ce29a594524a2933b9e16bab460318e066cebabd7d76d5ca2969be00a7b3ecba677aa3db9669335b80eb366d67797b27bb89e9cc7b705da699a69abeb5c3bdcbac07577bb6592bbbdd76955ce63cb84ceb5a6e3777adf9b6c98c0797e9ddb1ccb6ac4a2aadcc777059dd5bd6f149f5bdfd66d90e4e5bdd65df6cef757079ab39e72d35d9f1ad753a3839f3b619b7ddd2de6d3e07473b9ab37c6bc7efc6319783d3b6bcd90e57cda5ee57c7c16d5b57ae5d9e6939a5a6b70a707267be69b2ab75eb4dbb0d0e4eb395529dd5a9352c69dedee028cd7ccbb8ad9aad58db3637b87927c51b9e33bbd972bcb5c1e16ecbeecd5d6633d326ded8709a524cb1b59b6eb7db7763839b58dada5dae499be9aedb1adcdcb6ce566bf56e586edaa6069731963667ddb6b5de39ddd2e0f0ecb69c699657aa75463734b8de6599dc74b75aeb8ccfed0c6ecb6cdd74df14f77bf7dccce030a67deea975dbd5369d5b199ca5dc72dae14d37dcb9dcc8e0e6a6f54de74cd22cdbb0dc28c0ddd9b156edd554cb3096db189cdeb2945ab6d53ae5ec5d0c8e629c6dd56aa71be5b887c155bbbbcb73d637eb7ddb60701ab5945ad9dd7b6fa57b025cb76592f2cb35df1867fb0b4eee3bb9964dabcdec728d25c0757ceb3ad34dd2cbb5d4d80b6e4aabfbcd73eb364c7787bbe0e8e4396b936a92ef6c76980b2e6fbdbb3cf7cc55e76ec35b7055db9cf55a75ddf4de174780db946f9c49cdefdc38be580b4eca0cd79bafcc53dacce22c382d6f9d627a7bd7f5de2a8600a759bc352df339b5dde18a1fc06d9bc6f5a6946ab3e64b31169cd6376f2d4f9d759a6d135fc1cd5b719658df8dbba94d6c05b7e94dbb399bbbd6ac3789abe07495f2f22a65ef7ab3123b809372e20d6fb74b9bd99e612ab86d2bed7766bbd352c3196e006737def1ae6bdd96bb4deb0ce0b6b933dae7bd35eb6ade53709ac6a5ae35bbd2dab9ed057035eb7ae3cd6b26bbad6e05705477b6f78d73cb6d9e5b0a0e6f934eda6d7a37cfae4e00c771c57c6a7a37af9deca2e0f4cd726f5a3631be5ddda0e0b896d9deb3dd689731dd10c0d1ae719bfbee5dcecaf13d0037a5ddd7f22d6b999df6de27b84edb79ebba6d5e27b8dcf54def5d7967e5c66d131cc69ace73a39273d9676582b355d335eb6eaef8d2cd009cce7a5eaa6935bbf95e6d090e671995176f38d3b6566901386977766f3771be1ded04e0e8bcf5ca5e2fef56cfa904276fed1defb2da5d4efb00389e31b7b4ead94d9eb500388ebbbe1aaf99f76e7649703d9b5be5936fdde16c4382db99ca6d9399b6b599a93c829b96decdb73bb5a95d6d044731cd18732de79cb599dd2238ab759dde2eef1c5bd989e032baada5fce23bf3d64370b7bb1c4bac717b2304d7ed2ea5dd7a6e4dcb346e6f82e0b66d2dd65db6ddd6f1bbedcd1aaea398667ae76c4b7dbbb63740709de5527659b651bbb3adedcd0fdc9db672dd499ce7e4b7b3373e705d66f7d2aab5cedef4c0ed6ccb72a737dea7b43ddb1b1eb89975726bf9d29a6daa657bb303b76d384bddf3ce36dad9cddee8c0f59d3bad4a6dcf8c5b6db337397033d31bcfa89dd26e3a377bc9dd64b6b186b58d2de1a886b194dd6eed56acb54a38492fe61bdeb4c3bb7694128e565dbbbcd672996d9f84b339ab96669ba6f52bf5fc0077336d6bb6f6562d379d92703debac4dbd377d71ed32126ecb6c77e636eb9b67951ee0b68eb36cca4eb74b67ef00a73bbced59bb2d2def1b245cefe89675d69dec12cbcc3ec2557bf9de68a7ad9659965947b89e513e6f969de33e39073889a7ccb863ace13d7123dca41c5339f5a4bb4adc19e16a96dcf29aed964969fb221cb795f32a3b29b7e67b039c9d536e1deedbaeb7db34c0cd99713c69d5b44cdb4d11aed3ba27af55eb368d529e08d7ef9552eabd5daee7e48870d86ed66a54cf3aa9d60fe16c9675bc5a3ee9cdba6e43b829a5e5d66e1bbd999cbb10ae67ddeeabb3a9b33abbce00a779cedb36358df1d66d1d219ceeb8b4d9be5bd7b3a6dd20dcd5dbce9a9cb367dba66d827056b35ad536cdb4a6d5b905c25d9ceddb6d7bb39ae70d03c2e9d95d3cb3ade3d9a5196ec36df66ab3cba9f3b59dfe83cbec9e77cb769e7552ed075771dfe6cd7857b5aedddb07d775c6b85e4bf14635bd7c7032ebb34b4a71c615530c7012d36e4e39355e6996f6025cdd5c6b9d77b5f7ad336b018e4e9e4d5e379bedc9376d0f4ee69cf3cd7ddb9c655a0faec3b94f5e6f96f39e95e6c1ddae6bde32de328b6946f1e0ba6dcbdde6bcb37df67e07a7e58df699354e33cbb71ddcad53d36ecf32d7cce6590797abb6cddaf79c950e8e6b5a97cd6c536ceb95b2cec1758d354b73d559958393756eb36b33935d27b7acc6c1c92cb336ebe49654e3b75780a338ebdc527d67957d6e38b89a7bdebacb6f3625dddd1b9ca6b5cc25de9276ba6ad90dae6f5aee76ee2df5ec66d6dae076b73bca7bdd9da4546e1a1bce624baba6b7ba33aa69acb1c1d92ddb8d6b58cb8ede8bb535b8ca6d2737aa77c6ddcd575383d31ddd709dbd6f3ae3d86a697099cdb8a6a5961acd19b61a1a9cc6edc455673df194d56a67703ce32b33dad13c3395553383cbfa7633e3b777195359b532b839338bb3a665536b8d4f8d0c8e675a5727bf39a35d66a546018ed739795779c65cf32ab531b84badadd652aa6ded32d3c4e0322d27a677cbb0ddd9ee61705c739bcdbbe96aed963b181cc77cd3a6beb76a5bdff804b8aafbc4dacc38be5bbf9b7ec1d53df196f1ed5aefa4d554025ce61c671dc699d6b74c3bea05277b97d9a9efc59a67bcd12eb8aecbae7667d76f8775b6512eb89b6d9ed999ed5a33db31dd82e3ba6ab9eb2d67d52cc63402dc262da7db9452db8db74bb5e028be5b675cdf2eabc49666c16dbdd92ceb6637e9d6ed4a21c06dd4eedbb5b6dd9a71d7e803b86933596bd57066afc627c582cbf26af3d69cb3997597f40aaed3aadda89639ab97ee8c5ac169ddb74ceeda751dd6ba57c1757de20df79dedae5edd1dc0653d93b3e22df32ebbec5470d25e796f2625dd5ad6f106709572996d5bedac26b78d3380a399d5f8e59a66e726279f82dbb2e34967edbaacab782f80b372eabecdcd62ad6f762b80cbb56f586ab8a3b566754bc1d94c6ff2ce7df3b47cee0470d26afdced96d996f36eb28b8aabb59b58d6b7df3d67550707a5e2aa59675dda4951d02b86eeba6be99ef3c3b29bb037056cbb6eb18f3dbd5aee627b8aef2aa75daada59d9ed9096eebeebdd856ce35d6786b82dbd9ae76579bd1ce4ebb31c1610dcf69bbd4dad6e1ba1980bb7bdeda75d699d6f2dc96e07836abac1ace3aeb756e05e064b7946a3cbb6eab966d04e02ecd36c59dc637d678632538aab9d6b36df3eeb9673c00aef2d95dad6d6dd6db2f1600a775b4da8bf5cdb3e3dd9d497059a632677a6b7c6f9bbd13094e5bce65a775eb78b7dbce23b86badbef96eb976dded751ac175deb7c41bd72e6f18d7592a82e373eb137756726bb756678908aecaae4b69b34c6ab94f3a4b4370ba6a8bb9de3aaddad6739684e076e7b3ab946e5965a7e52c05c1c9de6f87b78d377af52667690dd7b36ccecd6a6d6fde59394b407072db9dec5dc519b67cca59fa81eb34e318d7aca35b777b364b3e7052f73975cf324b336ab359ea81d3b6acf14d777b6696e35ee281e3bdab756a56df3cf9eca51d38adf1a6dbeeaef596b39774e0b2ae756dea9a6d97edca4b39705b9d9df2a969dd66adf525dca5566695de4d77b7c39d25dca5f556dcf5bcdd3d6d5709b7a7cd7096f3a43c9bb5a384b31adea4d66bc59d76ad9b84db5ad355e65deb366dcf1fe0b46de39d4a8d6b2dd32e4bc2651ddf4d5e8ef7a6379b23e17637b7bed979ebcc3abd7980cbbdb3759392caaeceb9c90e70dbe476d68cdb9d6d77af8484ab53bbf56edaf9ec32bbf2112e937377bde16c5ed9bb958e705aa3dbbcdbcdeea69a57c9012e6b3cd3f8eacc52acdd2a1be13aedac56ebce58d7de51c9085737cdaac45ad357634be5225cddf2deb64a8d67adbb2937c0dd3c79363bab7937bb3ba50638ba51dabb9e657eaba64da908a7e14de9ec66ae9d96d9948970d46e35e3184f8e2bb7994484cbae86ad76f3a438d33293877012ebc9b70cd78b75b7dc102ebb7dcbb49ce1d9bb4e79219ccd327badae74e35b963c035cd6b3db517b6ba51ade9b106edb6dcb95d6aeeb8beb1e84d39ddcd4de9b6d5addb42d0887b73e27cf78a5dae64e07c2f5dd513bbbb6f5d4eca601e1a4b69ddb9a7bd786ebeca5b7d73a2db55beffee0f2cc946b75675a26b399fde06697338b279fdb66b96d7d7073f7db651bad739bbb6e7c70b6663ce34edbac96718b31c0f5acd36ebbdd33d592e20b7074b3fad2abf7ce5d66d8025c86b9d5baa376ef8daddd83ebb5de2eafb4fbcece563db85c69c73467b8c37367350fce729a352d77de6456b58607c76b97498ab3d69aec92dec16d566fb593b8dadd6d46ede0fad6328a6fcd7570f46eac7515535cb3bc493a38dbe56ce26d66b6dacde7e0b8deb66a69e63a6b9d66d9eaca2c4f80ba3c11c75c5955999483937ba3575a2db59d99c63d0e8ed3ab51a9bbed76dbe67aab0057e7ecf8ec776a9b6f9673144ab33e6754694870f48977c76bd6abd639bfc1e54ae9ae5a6a56d32496d80d2eebf4cdd9ccf8a5bdeb6a6d83e359ae1c7775674eaf76d964594729be75d3f76a6c27890d8ecac937be353e2bd619add5e78cea87b40667bbadab755259b7a651cc5f6a709b9c985fbce53dabb6694f83a3597627ed7aefa8b4f26a121a5c97e93d71b5156b9c35953293cee09bdb3e77966dd9d6bab6ba52b3976446df19df55cbf2cebd0cae6e724a3e33bd3b5b69af1a195cef7abbf7e69cafbe15570a7092f7cd6eb2d24ce22a311e83b313dfed7619576eebed5c0cee66dddcb4e376cb1c5fad85c171adcbf36a6bb76cf19e6070b6cf69a7ceb8f78ef9ee564e80c3b493bce3986ab6ebb674b9c47cc151cd52ad4dde3b35e25b425e047699319024c061b9d15da7d6e5966baeb50791bce02aee996b2de70ccbadab952b52179ced59bd9d9c5aef9bd6d5cc0527ebecdb66bbae62dbb5a9b7e0aad62dae33d39abc55667475257e02a4e58966bd302d30cc8242a150e1285a2152043899c96c3bab2f973a5f2d06850243aee6033f14aaf5faaccf195547d282cbf26eadcdcee6daed9a0537b7aa69b961ab67a62b95aa4d561204382debf6a6bbec5abbd169b330e11846ca1b8e22253d80db2e9f966a1c4f8dd2be65ab2b711f5f9b88c351a4948405b777c6bb3c67b66972bbf3aa3ecebaf2c805eabaebeb09d093aebe9e6c937405b7ddda517cb77d6ba75da6cd1648567059e25ef9c66d576d77a5b658485570fb76f4f63cb72d778aab740097e9bc03a074a864f0aaa6a198a41432840000a8361200900003130030482c188c0583d1a0585dda071480024f966eb646984ca4d130475110c430c810630000000040000186a0b41100a84f064edb105d0b793131399a8b74cc223ae3d69f0073ec8df9cbf13bdecf59cd26d2ded26125f727564e1f444f85e031698ef8445a593a5909fbe4e34405d1a4d02d2ede7eaafa48ce6dc1fd6d43a12429448be9e7e84a2488256d25be4f2b4e271061857c3151399a8874b3c45b49f58b24b86dbfbffa50e724c1d1f6fbd577750e1298e6883db17481b467da271eee4f8cdbe69eb5fafec70c41ba775badf13b680a907ccfadb6bf83288e2435323b50a13bd0faaa2141072be38b87cacd442ca7b191b0702cffccf8e8d0109779465761ec25be97a0dc9bb0d73ab973a6e0c8f7db6afb3b880a50e28826d28fc0ab3a21e7b4c0f8765cd57872120bceb71b559d9373b7e078fba9ea2339b705f7b71faa3ec9315a80bf3dafea831cd382e4db6f55dfc9312c48df7e54b54d0ede82c4b76f91d15f5a1fa2725198a2c89d9b594434abf8e70ac17def67ade689b46469be92f6898fd30aa29342584c3e4754224d2cdd56e27d52714552df76ee2f3094238948344bbf95ae3e41386910f1155ac574e20813c967896aa5c9af5b70bcfd54f5919cdb82fbdb0f559fe41c2db8df7e57f541ce69c1f1edb7aaefe41c169c6f3faafa26e76ec1f1f653d547726e0beccf114a248925da4abf3f577c20d06865f8e259b9391107b3e35b87eacb84d30d225e21554c24ee6de7fe8243ed27a98f76ee17dcd57e906a9a487c96562b9d7cc238f920a22a3489e9e6882792ca12c94adba73fae50f549ced182fbed77551fe49c161c7b5bf9d3aa92f8a58713475c5ff3dc5b70fe7e86fab6cf5d83f3f663aa6f7eee161cbefdb0131139003d2777c22cae4be51bed9ad641f7dbd4558c26063351566cccdb684295b3c67d4b1a972bf42e6628b50823d7a1741067cbc0f0b06a51a871d6cc88fdd55d977ac1bcaf45aba283c4dbd4aa220f0c48ceff83289e91a71fa2339f6cbb2c05375468382182ee1591245004ddced938dd257acf72511b06b42dbcd7cc5c9757b97017b623c10020db63ec15d34ff3a70487527f119a0e0e7f927b6456ef440fddc74a4ccd8063af5f6da1b3826f2c9d1a00c7593de32c3862562a63b3335a8ec532809e7434459c054bd9c675df3f240b64dce48ee6fc2703b22f87b26f654a8b00591936ce8dcd42ff068363792390e08044ec88abd2c2cc41a8d6679f2d2d4b4f2edeadd6147edf4b20c57b01d1e4cd8a04d9d00ca5db0a6a44f3f501fe694d41e4fb92745058d05b0c300fc77ad6be383c05bb5eaaa935db547d21a58c5a27aa56b37642267145578a58eacb4fc82cc621ea47675a04a8616bfd866cd742924f03917e93925c96029ff0acf18c5690d8cec08c20a06592b9ef79ed8c7b503639bfde91499940a2946a10c0042a0da05395091c4e62ab5a85740bd44fb12d52a8217a272861e64b9636a82c36a5d816c5215c04e3f919e566234b03d23500f0506303076838c0008d074e80c652636071bb428018fca2b9447dbd03978429e60741f42101b11cb280580c19215286d25fed3bcc6387868ef3a224489703824859b07796127cd28a4ee2520ba528c7bb0aaa58b7a68aee46f76f03d0c3a7ca8d41ed04df1e8e616f6d7dda92afb667d3213c85cceff1a540bdeddf717fddc84f057592104185d5a0ccc16b5682d8333bfc5f5c009b5e6bfede6ca3736ab277687be4f3c70370d5f6b2a8a7c8c893517760c6792ac52bac5ebe7ff6f4ece7ec81249585d0c86856b0ad7240192b0d425daf85d6d0f6a47689d7b6d1d71d062d00178acb021437250da88f8582201258525546c662596a1fb8de0ab92f251b66d51f801e2c8150fce3fc01a8d706a06a30e82a595b0a836cf1e994a016177492e953f2c9af9f1d15a2efbe15a67133cd45637f25e0e49c9ca7406969a83331e20d1850566f110cfcca4ee3338a38bbc290843d0c19203071f7c15c0971f9c0dc94c62c2b4c50d4a1da2d0115ab0651043a974629b3d409e6baa08c015f705810faeeab2bbb6a16f2afcd223ba1fba120b3345f7b7bf66a6ec7467e59b1951b9c08f2a58ee7095256e12bdb162c1085b9586b819f1ba9cf98002768be53cd458c3141bb131a433c7e523ec2d83843d3209b3be53bdb8fea632781143bb52a0cbd398bb18020489811a6e2d5495b5ed523acc69861d35630589943277d4466b729e0477e350ceac633d26eb1e1cdec138b19a84addddb5bc649b08dbefdffe33f818f143019080f25a898a406c5d32e99e6e9f90a71be9443a43acb4fe442fa9aaba68c089577e82fdfac75df2b9a9550e3c702da81d17426a5baa8f9c0c868223976f58cba360fad4f91ca112a0a6f4b7a0bdc183306086c9f122e7b7ddae4e2ddc5d9ef13ee149fa5bf16db12781f1073a0bf52d210d2ba3dd4241a1690da267ab615aa0af49158f4c2f5651d73eaea80bd0d09a494d3799fdb38aee8b4c6dd4694b250b4c9b0f1c002fb54070d8af243e24725994aacdfc6b5393957903b5a25e30506274d303d4328dec9856e98fe17cc122fa8b41ff5aab83cb300422b6d9416d6503b619762441216569998685a2a6db56dfb0482c849c1e0cff2a379a83771b807d340b6067b3ecd53ae9345b66fd0bc0937d07aa678a9652baaec54d20e88d272a47165098a11341230fee27355ed5a130b6ce4fe19375efb58e51b4caefaa6e1b7bd7d67ac79c757743538e2993eb21784e8f1aae94202fdadd01b195ea3810a0068eccbefd77a05bc8459006c0934f418b222201f50a939b015acc2a39dffea1bb78e0010cc0cc96fe21cb26d69208dc5d261150e66f40cf63663ffc345acd69d188b2f87d438da91e05943ecc52461a4305c28546c9fca24162061f32dca3dda62aab9e6f07da2508813ad491d7083e184f854368214f2d6f968408498944de58121ab8562f40282a6ab59e4780a830932aeea09b522309d47b1691e64bf9fb78205b6942d0984c8701c67fc9e83e0a4c63631706004284a5a719200141d970d40f2dd8883aff3c927f811cfb77d542fcd86324e2e3b7c25b006a30faa5148322d432376d7c74f592d8985231d31a7c994678628e8007695d69cda5dc299f2a1c6f067868d74ead6e43d0ba4b46eed8b995e742b1a15e5fafd971893ecfd227677661e9d18e47ca6486886214f66f41b47d7f1635ad3a77723c88187fcda7e5a5eecb7d304a95cc81fa114279a0ff888621c1307fd2b91338fe6638b1c1382465e8f7b765b6fbe4204c146c239acd9a27d24c0b5f035ef7a96333bf86c9533acb0c63ecf6665e39dda1d649b366f63126f777bbfe7993d035d02e98de47a5d150534d87f506c02d86747ff8893722011cc17610e3dc8b44bc181218a0dc1d41408d4636e1243205660cd1d218a4ca2cf9701230e799ebe794b872d124fd26621d28f7ec2ef626a80d86379046076b130a3734c8ae82b3ba3b8c86d55cd602cfb4f88002ca6390a42dc8dbe0eb6503a7bfd633d2244484dd10ee67f0169fecce4f9ccee423874a8a21155604f487384016f2c648c92d173c9e17f88a552304ef546003b10a12bdd0439f37ca4090384e4d0dd040cdb24797b1ca2313055092c137d30efcf7d243067259794450fa30639a53906a3edb0f0885349f1f70bc593d1f025b715dfec370a33c70cbeec4fbef8d9180c8f50b8c38dc7705fd81c00bb70c77f49426cc8dc2b4f9a269e6b63bf0f4b37ae56f5a5194c70c592c9bcaf0da681fc3a389fb367471ebbf6aa6069d77243c66c7b7e47690273e1e00a47c73087e19460f168b862f3bc88fe0c25627d127ea1273f9cb29d937f3bbc5a684b27465aebaa78c3407de98f4a6a235b9fc6407e0d6797f9002ced1df50284a797874290bfd8285e54c39ea1ee45bf7ea0e3941f86e5b3f6ecd9396710ff8266c7687d78cf82858c639033abd7ff1630f58000d7334af193adae6e8ed65dbbcf184c13b3e5feb84b8a0ea81f0e8db8237e9692f3b682b9bb8d5c8b1ac9c61e61d6d5b7eedc00a62e04b5bbba83c00fbb27db3bff4caecd58ba741e7e9f8c4f82c1b74713acd02077ea690cfcfc3d1988bcc195fd032cc0c793a1abf71dbecd82ce498ea8a0f59d8445d7062b536e742e9ace3cb63c8e33465441b75f882c5cac3ab8d33a127b343c7f67843f9f5286f0fc05f0a80aa5e5eecacfa6799fc3b9599ee35ba2c802d0ff9411119a7c44fd970a2dc3b36df032afbe67508436c6f86caaef641d25b6c6ea32a6ec250e36a60fff31d1d2fd89b01a4c799bd06a11d9a9d8ba4aeb177a83e1e40e717460b735d85b7c554c752af5b855e4386c2b1955f27813d8a84b830ad453948e994346fe63bd886c1be1b69d7af50ef7854062155e25f726c4345ae66f0fc65dcaff0a09687a08d4e8b3e9740f2487caccafcb0c53d6fdccb029a7535c37c286c94494756f7fc08036a250cbfffcbf30907b3bc7ddc2cb0241ecc502ed711ba7b7f0eb48acab3fa5ebe350e278c9a419ef175a34dc3470ab3605bd63b85bb3a5618cf725bbd77cce97cb6a5e57d5598c376cd1bea6870d941c0b2beb12b45c3d906194562a6fc77694c69bb0e2fd010bb6f065ff8d50cfcf9dcd71f293b20a8e7b303be4022fae9c27439d65714ad624d11a4b5917c92a0dfd7e7ea5524ff7aa86ed9db6546e9f1f7fc4bc43f9e38c4e087ffb07a001a04116210c3b2fbd36cd32eaeaaf0fcc224a9130ef38410ec861312502f85a0bdc19d7e53589463fe51052ad0a0dd5c9a395df2b1ea69d3f0eb26494e17e743b7b063e979448be503e3df81a8ae0ae08ef727c1592bd6a7bcc7c3bf4befceac5958491324f0a7ebd1202850f452a1f9b7fb240880fa20e1cb56ffcec9ea0acdb93664ef69bcb49dcc2b759a83b1a9578c9bdc21c90fbb5f83bf2cbce78f255ce4f2ce6f51ee3e3da43f0d1cbdf7c3fbcdbd9f62aa3932efc250bd2fed8ba418d61e1ef8a3bf6fb11ddce2d7984cea7e94b0d5d479aab6b1864dcc5cc0e3962f6a282c953ed9c3bb2874e1dee7d5e3bbfdeb52063b3b4e400ed7b0aeadb4dc90700da3a330e707978eb53309cba8c326e2f527b8e28297fe90ea9f34a84437eb330f90f0dccbc077972e8ba0ee5674328d4702bc169d3fd11e582ea0586231a8afcfd8c28bdc73206c86865eae998541151b53ae67ffb030061aabf919f377ce37379a28fd42a7bdf870782098a492b3f4e629c3706837c24f62aec21dbdb75644f5a661eb83a25226ef6c543d33c1a3d0d8480b354f569f4dfb5433776a32bb9b93f2dc592ba8332cb00c6d182bc5c0a00695788311c0e9edffeb2afac896fecb847586f4402d80720e4e978dc96bdd0f05dfcf7092cd8c1c7c379bd71f6f5e106b095386f50ad85d1100803c807a41e392b0fbe9de67d042815f7b88fa110678da3174726f28ea87af1e6edb0003569e6729e812e90845ab0f6f60b90925363f345f362dab0e30de574902915dde25fdc42dd65cf8a55360c62339dd8824b55046dfd0da75219d32a27690c27813812246f9d4b309542ba05687cd7930cc8f34c3410b3477c614df311f52ab4486954e788601d6f3785f7f7a9c19e0bc155a14c73fdac54c9b86291d4893dc7f9d9f33c7c8736f00783af8ca85937779d1c4d064044bcff3059ec3d58e6279beceb10e777b53490aee47d357be9295ff70dca766ba84c2ea8f59361050d7ac7c4ec0f9b0021eacac5a954470846d39c72b7f7791d28f574c619c3c0438f53eccb16f2c77aa7b310f9fad31272802939db3222204f47463a2ba2d88592d19a994254af629e3b3c173be93a355b49b219586824b07215b30d61a77a3233a699232339291bee5618865239a4e6b3b3224bc921950b372b1e561051664489c11f94a9777a3ea538974ef2b7b62982879d0ec5089fcfc5877816eede4920ea59fa968dbfdd0b736be67d8eeb8866a07a63a1297a85e5a68a1269c42804dcc1b0791e6bed355ea58cb7e4a16b35165353049c470c342843234d19ec5f8c50c211e3bc0164db7054d2bdd399d8b1bbbd6b1d894af2e9794c1f00753eb58cd753be90958a2112b311bad3ce423614b68ea0263e8f41a5eaca813f356ca7383e710fc30cc1d033aa5c63cf680ef06d81498f1ce9ee2c0fd2692fc5eef2738afaeb5f680f3c9aced0799643cbeb507a70db022bb8f112073c82f0079306d61de771b2dbb9f3cb6f3508d49f5bad62313bdb066849d0ffccd277f0b70f80f983f422f88e3ab93052f18231fc1fefb535a0b7908f10eedf2c0350a9d584497e8e442eb07e60694bb6adac2f03f0aa963753777d961456f7a461c95dd40b7b70cd75efe0932e53e63aab3f9e16f0cd9139cfec5b51f434d26952bd8b75f154bcf23dc85cc6c422bc5df6eb1174a021accf49b72f81584e707b464209aad63d54988662be024f537165149dc90d0ab848e97cc4ab748f7b282c2b4cc90c94c9c29667fd549d7f2a0ac33bf8b88ae418bd75086bfda5c64dd2ca213fa6d3bac9ab90903e8be0ae74eb4a26180349513d3d0710299414ae391c899643bd8f7d8ddb69a84ed73873c28c5af4f7e9a5c1d43fd699dd49c24cf2844d7de803eba26b6f03129eab1add8102a75acd8a9043796def1a0c76170cfe02b4247094a6833c94b0492a4ff2736f395b85521b2f3561f8e8bd87e7ef65dde94a6d5dd118ee8a97a3e134465623347f0330f8fd64f163410cf7d67ca30ff31079a18d1a08e7c1e63f41da4ddc6dbe1c752fa523a656f2964c2f44a40e05ec9c433cab8977bf95c620a76ef3b1351ae4d90010b16ccf0136c5089a9e36540b9e8b098d60ac22f47c55ceea8986bbe424bcbc662e897ce9004e5645c09ba48187b9e9a269e60ed013f46bb7218de6d443f7e03f3fd6e96536763536777bb41d2becb3afbdad72b208bbbe0885f1f333bbe0c4996b33072d7e3ec0d6840ee4586c225573ea0e54fb424cf69a6bca3e6daa9cb339789d02c39ea40916831dc17f6e210fed7428b61f1876d3b54bfbb36133228162fe54470ceee6efae0660831c68fa69e378a38fcacf66efa162333fe8908fcc40d5d3595d291cd3e0ef4b11f1b270a1d1958eee069752eebda237d3fa1c6ab5bb406bad81deffd126e94c9316427e68e7d9f8634cef75e294d7f91a1de5dd08cff1289331a8be7d8f0c7d2e5cae67a9a15aca19fc807bfef99e87321f82448c7cfba651bfa9ea1f796613b7b095e513dce29e4e76ad0c2fcffdb7aeb207bfaadc5bfb01800dffaa2dfef8576b266bd9f40f2ecc287b29be57834fbd2a39a2b9800dfccfebf1de9272f524f9e9e46160ca3d5f5ff4a65fe5b40441ad5fe21c70251f3be35d8c86b460bc2eb2155c0327e055b91af8ed4128bd93bc04a7e3ba693580d6f400bc2eb2155c0327e05598bfcd39b69e409fd73c32262f81c63b40c874f4a93c5f19a6467ba3f51cd6c8777b405f3fe456d633bbd50ac0c974f4a93c5f19a6467ba3f51cd6c8777b405f3fe456d633bbd50ac0c974f4a93c5f19a6467ba3f51cd6c8777b4054b474a97092dbdc12d619b8fb5e5cae631b654d7bcb796a99a8fa995ff46143ff2492c37f6607d7e046cc76de907c749c1e02da3238fcf6b466242f7af90de740f978135389fff71db711a3aa071a5f079cba84860f399919fd7fd23a030db8b6b7c0dcee547d86e9cbe7e681c19301150ba1aed2574f2d98773a6d93373a265f361a33eadf2a7115add60412b9728c2b784f5dcbebd3697bd648a7c576a469267d6efafd384e41681ae8d89a8f1beaed1235df70bf8cb883c6de4b20d14463e66b9d10d5c86e1d0cb5dea1533706b05bbc18665270c134c3fbf11438a885513e3c376dcdfe54b48cacbe1d9da8a39bc27c366fa0795424fbc84c35555436d0ee68b76ba347596425fe5f1ef86f518e0951a00a2a0ee7f8ae6e0a87e51e5d65ccb9d117e7d228578585e8721c0e4d3b44ddf7ae4808d954d7478cb196fd2c7daefd884f7cca906dd403df240410a9d7ddf430b7744af340871c76be5bf2f2d35c3fa2b03c2ec433a502a48bd27da70db081a25d857a5c22447492fa26483b25bafc5a78cd400e0f5955c6ca54bbff5a1f30fa5c7bcc74ace93b959451baf420d967c8ff20260d2a0532d4d09fae3d99e54e811d41293d1d08f2382755d10773405613c407a572d9b2976b9caf907c840b2ba061662047426cefdfc8b991539d30ad44eeff2f8a733bb5dbf978f88b8eecda197560ca0ab914ee6efc07dc657707129a0ede8b27dfd73ecd295af8483de39b3aaa1a01489998fa7d05b16b7321e24b654fca8e3aff832a7b11b6cf6451b758c0367e8df767fcd810b733f8cf2761037e11df8978a0db311bd26b2e948179d3e1ebed69b4cf6e0044d7d5422c24c50c1a1efa4ba1445b27a88a71a64afade3dc19a6138b7ba4c5799cd477634732945fa1daae70060089c8c42b06ab2aad81e9d97b477b581e8ad4330244a3e19fdc8e3101d07974ad0af7c82460aa28d56def2a13a6ea98720a7dcb4afe7127cca4dedba9b6dafa6575db1562e73840c1f54723f25d5856f31daedd1dae2e1a88d823ffe15dc46d61844f27cd61cdb330568236cb828062f049cef86e381b1036d5927e35703406c5b5c24673ec7df8eda0bd583a4b6806432845b794a5975798d3c1680d82aadcdd143672e36a5ddf40219f22bf1b0da978e54c322cd95461ef80eadf349758f71108622b9b77df16e16585ccbf1fd10614a952be44acbd1cd2cf8e2a3974ff264a0800ad9e44703aa0a02684b2dadce19bc8eb1e45895647530785b010eb59e362c278ea5a04ad6b9f52a7880783751cb83658bf5a644a73ae3149e8c4b8fcc550d3e7189b5511b50f837d37637b990e9b2b08611ced687b940b52b903a109bf5b397b87ed3ae7a15c27aad144be162818cf48b7f96cd85e88cf78f5577e39544c07a49d81a9dcc0e10b5ea437a894d8ce19348441d2836fd0d1efc85f190dc00ae3fd43fb9c827678a616feee4fac0bf77f5415858e13f55be29df0231ea6b0563a9f79048751e4f29612a40bb0d470741628b3bd7f87f8e3dc0e859fedc222559099382dcc958912080c32ceb2055c8b52cfc16e8ce32a29e5aa591845b0ba727565f69e06dd225975bfe9c44f12b903bb73c9feb38c4eafb8b80587de5a9627cafa6c0b3d7f1ada1c99de151d4c4136025b871d588415a0bda204ad1524ebcd8641648f42c1014bd654c5630c3dc1fd8ad1fbebadd88d316d2564ff6ca5b62610b41a1ac241c1fe7e0285d25136152734f4165212be3ba69aa93acec6507653ec416fd9eaca4c36c228ee7b4819594a885e234eef5bfec41c85dbdbbc117cad704f6203e3af03d93919975b63277396f8bf5f19197216116dd644cf3900495fcf831c70b7c0ce83f3e8e78b8a3f299f6d2139ff517dec292c962dc4fbcf44c433a8ae338c243b4b4c8e6ec0e4d9bd854d1f8989fc4f8be4aa8563e15d47c0b81fa6a9edfa6fe88149d25de6988b2bf2e72854d20be5da58bb7f64351d3a893e6238effa9d4f26d19d9673857613b158a331b492bdc4d38dcb2cfcb6e045b83a41a79aa8a93eb89f518de329a0bcdfebd0fb7cf184a95599a2977b2c5e917bd58cec135cb0551d3f487f971b6db3c170d6ccb36f02e13f4877a0778d6ed3359564f18b83567931cf18a0d3dc5573f9c2c498fcaacebe869de077d0dd782863830c5c2cd40e5a3910dc2e159dd3711b16c08e9dc3223f08612bbb84111d6233aa9ddc0eeb0083df6c560699c151bca4fec73c967288e6c516bf985657bd2d5ef3e36ca94eb6d42c2881d3ce1151f4fe3def1ea967cc7f433f66e12a6dac1e1cfacdd9bc779e7d3cdb503caf9b660d3e2e2ee74824c2523786c280ddfba7d7a6a21374c918e20e3a4c103b2814e6c57e9969210fc9614672d2d8e3f1348169e45cf984fda7f3a77277c3bf1b4fcaa9d18fc7d104061a79c05cda510c38fc21cfd8f68499e4ae9d81ee27234442c0108653216558cb8f81ca6ecf3846ef85d5f90fc5fb9900087677de698712fc69f26b39c4ed28b97ff585c73c39cb4a86b85605261fa0640a33b0baeed4e2223f0ced9d83666a8382bf43421bb4fdbeb5246b8c207974efdf7f8d2fec94defed6ccc5ea2817c94bfb1d4a46220873937b91ec75d85c557abe52f8e0fc4a64c79ffc8b54e591e93a97a200230191ddaac18ef905fc0f9bc285c142289c7d8294b55dbea8ad15f2f0432effb7fb645559ac964c3327bd06a8f9c045487fdabf86cd12b5e34ad001290a5ccb1368eab8f2c1d2f33d45febb01735c1d5ae15e6a9c3d0d3b0b51281df8bd695702196246a07f2903df4b9db9e6807dae1c0cfa79fcb83e0de8f4931cbf8cb85a65c8861b3b25edf04f295c2a7a25694beeef896e7a680f99130a8b376e3437aa6bcdfd429bbb65010e65bd47076ff9c50d955a60c3979f2f9dd69175760fc172b6fd9cb464d9eecd598ccb6b9e5a1c4c9b780dc5ce47b8f2dcb9dfce4f7cbba97dbe642d4f8088edde9553f0df0c5cdf80da6fc25be3025a4e5aaf9df6e377895043cbe0373e787977f73b9033543a3290076068ff86f68cb78c79bcb1ba0bb03454f800622b83bbc8f0ee3a9a1d62f65a19bfcc615457f6a4b6eb6fc502dedec439df46b3c5076b8c839cf642fdbe1132fa23553cd845423a84d1711d58cf951b5d2946dcdd1ff075de4de27e3c214603b50075b163044ce9556c27f57067e748695cc9ac842e53dfe46ad0ca68484ed7fd8763224b0cfb799a6e823d1476fededa66e666fd1a81f66945376c60d1473809f98f5a775e5f2843b8dc861c762a6ea4064d677f808528db338b173729a775775e7c6853e0293a15f5951479a37a75e098644515d3bf7249ca4b57e372bd5f553a95697038de3146c7ee34ed1e738e0eefce67ca434c84beb26b83b14e6f9deeccdb5ba104dc99e9aa46e2a893202eacedaa789d863de835470b973949f5d81732236f91dfdf944756477eed28d138831c3ea23dc1db3f70d92e43dab245177e69bc84fc1935cd5813fe84496cc86aafb225325a5bd45b3c1ababdac80d5e86cdadec1becbff3b5b8314ef3d6c9d3b7c0b317a8fc0560444fd6587af82b83b5c97b28f37eaaa98d1f3d460b73942aa9ba28f25eca02c7dde408db1c97976b3804afdbf69126ebf3ace95e596db028c86452836f0bd9e1303eecfb3a24b27e9a4c6d254b8dccea78267be378fc50992f30c77823984b1c68cecb7259ae0e9da5aa392680241135ae10c0f92d0d7c9d436e377ce1d6fd8b6ad160c9f07ad9e3e82fd562c0325c9c61f8d07c60ca0fce42ec3f073bd334edf03fc397bc25703229ae80c2e4dc819f095e29c64a5ae9db16a04686d80b8ad66614abb605c0693a7a75280cd74664026dc4a6f5d880cf6a84d455b3d4c2149acf6e133434676e3c497373d76adbbbc00aa0019753aba70761d1783da4b53f434f15fc7ae3b2a07f1bc2eefb4e31911f5663f42b41cdca81e453ada9201c503e1331fc8c358ae137114108aab2a1ffd9c40b0bbfdb19e24dc03d6573359c6d435f506339077d83c3dc283a6517bf1340e885bcf5ed1e6c3324886f5014b4e69f23d23a5777b2917ab25271dd214c34f876f00a51236131ddd09e66e4f957b6087029cf62b4079d2e41e360a4c24cec4c721e494ed5f3b29d7ff49d4b291fe749bd626c8ed9ca1083e7a1b5ea703ebc3cae629c7f379839a6484fd36efa0d27b000ea10de0242595f143233068821d4f62d274681935e1d3cba477acae75dc7591836487c76e8fff2ab81bce2e7dbaf58fb7e9914a3a34136d01f25e9fc252063958b299fe937e5ebfdf070777c71f5c444e98afce9157559d6c98488112bd5e52ecec74143559c8b1c1ada44a02baa1a9b3571eeb297466ee3a19041c3cb0519551da78d9d548bf7f871446119ac9004688065bfd4abf4a556250af0c94131841e97fcac453549c5348a928327910c8150b0cd389683d99706267174e70b0f571ca84b52ef6add159ad448576dbd9bca8a3b0f14acd12895077a972eb22fbf3489731bcf54632afebab5275430c17c04c6942d6aa31a25ce6885ef0fd312b7777c77e331da6c1c8bb445c447a06d99eb26fb603932fd421ce2a2d18d11b191b4554348bac6392fbb6bfc8fd6d08e6586e7435fad99a335d69dfc730709e6a3c3e5127edb10bbaadc95db2f84e1a42e40cb75a9581cfa9c601cffbc7ea802b58bb0dfe5fd62ef5f8ce70d2e1a31e1302d38bca8fab351f3fca61270eb3c05de752b6e4983a5f97e9497dd1f3f96d51edea57bdd45a1bce555bdc15b29f186c20cf149c399476935da374bb874cb66a5b921cce295906ab0777b0325b9a32f423a7bc3ebbadbe90d441bb6193873d91b0be85a4596685bd3aff4c8dd9bd97f80f1113956349c47e3e7db77e90073b9e0c3920a380d0379b826a3e3bf265c724cf738347a6af6ca93faa30410cad8c0584ba2aff31eaa3198132b30fcb4ffd5e3619a07e9a9745be82fadabbc2a75377ff4b704f494ce56a0ccc01a312075efbc5d98cb3199f3f7e0648b1cfe7d797fb88feb770aa07f722d36f9bf5ceeaa6ea352164cfa439afb8dd78db2939c7ca90cfed937b2255845c870201789e9478a0987d4340d5966a455f39f486b5a491a593c0160188a4b0492331a45178cf76521e0bdfe02cb6a7c755a0bd391c34e6cbaee909a36dce531c8fc11003e82e0b7ed5b948c1007f5d8ca22a39297f9a479eaab66bd7ae368aacf814d02faf66a042b9a189a3ed2bce584e5c361f8e2cc4ad2ad9c731ff4f152b8c861a6686e5c117724b3fbd4abff82108f92f49aaad76534d1cd1ebada27940707064d46ec2fa38805267144f8ee1cb2d648e669d6c8b601bb324773a2bed1caea6d68a3ccacc9c0076fc04db2864d7916d9c7011f114037f3973fed5156ab8a05397a33a063324c31c8a905cd658f4d5f9dbbf7c04b403557d3415a6ae8a5deffb90d6e6ed98be9a47b6f2a7a40d1377b25825dd6d1d4a6b525a646a000313fba5b1afc947e28dadb63663f7213ed16a5f6b5cd7e0312baa83ba1f5c5f23fa88bf0f098aa6640bbcf639aed67f83ed6da0b6b31f20c24a0833a367ad36e2fc5a3eebae6f200e77cb18b0acd451631d1f8e72c28059a3b2fc27c533cb27f1a9dd30a5acf213607f90314b9d72ba30ba036c0b223a2749718dd4b869e9e4b1c6d387b2c9012621f828aa5f8210ac97e0dcbc29726e65ac8a3a6a490bdb8ee427c619852306c3ce7c72fa58333d75918069b56b9be6fac612436eadb15173dcb1f9bd43d41f70a51d27aec41d8b6862de44672753a70686e57b17957fcb6a4a334e5f94a3ae95c77c78789a539fb9adc24dfb1ec71bfe6a84542fdb0a9ff3534dbe6ba68f47809f33071b2ee608468acafd2b1f3a7fdd07f9affefee5403593eeb90bb79dd02135e9ebe5b24397146bc4cd1040d70e5ead0728014d026e162a794286d5135f3e69b021e4eca00d2ab04b0fd2df409b747924779eec44a6fea3f9b0e49651ae253d1ab629e6fe7edb2f89c6aaab9b4056d05a0e2d460dd0068499910b45cda4e6459251adbb62bf7e89a95f1cdeb40217d430e9b0d213fbfe44e924be1940442e9a9361b9e622df1aeaf40116e8d0587084b0b679636d9fddd2c9b1fcf807eeeb0d22921c5f111efe5e42c7363edb8b39e940fb24708dc9c32a67a91231e0ad9cc1177e35833f3fe7f547ce0648ead9cca98561a0301cad7d11eb46d1049c20ca5693a29fc80e68e0324d6b34c366c27706608801e1bb50373c56d325e5ee899b4291a39c20a74f963ca9b609a333540d9484a57e26bbcbecb04c5a04d914caf75bd9b1cc18aa1f18ea79678419bcee7d2fdc8bc1a3c8e24c25cbe527c58c10a67187fce8b13c35faa2acbd402d85e8213c9fdca4189c1a9dad28a1bbcfb2cb33546fbe935082b8a50e4ad87cb81368be7829465b3b0c56e31338acca17f3751e2a8d012ddb63b3fdc971272c6b5b594d726fb1eae7cd557ff7cead9497bf8ffcd40c9c386a067842dfad36b98f2bccb96da13714ee754461328b6cf5ea9b83cb6c94d6fb5e61015b346f28a7c9418781a5504ae00826184fa056821111d02d5846e9b78edaf56fec6932d6d2c21d8f7a071686f0cbbeaeb3117b9576c78c54e00da0ab5f511ab10919e353635c0439c6f5b71513d05e04d237dcb55b2bb88773e3ad5db6cf42beabea2f1f8d745bf58b8230bb97127efa7f3f28403d8443387bbdd7c391c606e9abedbe690e5e4b2e3de47bb7684b1188608ed3accaee66a27d05be7cdd20b554daade65135cdf68ea0876bbc9a5eacdeff5d542816a484b6a65a2338da8f173e6b5a434fb02faa141d3d9577347ed9dd1c6931eebcea322524a6fa140800dcfacf0eaafb07e59cc2ddabc78650e72d1c894e2c9cebd9a0f08d7115efce4b6f9e2f61b85b3bd613362eec0d2a066509ed10c863f97422f49c3a80642ec16ed4d2d6b386f856bf7574c2ae7f705a5640be2fa2d48236d0179d8b5ba7d63150a2121f37804e349af3076a85605feda47b11b96ee153c994dbebe664173dd996f6d049876a7936c309f33bf32ee8be266f16ab1bab3f2260f78a4b894e26841dd0f43b3bca06bf31cbb4f81b38e408f2cd9e44ee8c82e1adc067bdb441cd82d957262d9aead55ac844f7d6f9b60488520d5d5dca02da59233df8ae0ff779a94ffce377d87b30200646b29ca385b23d3bec850de659f18c07c65a52c850af41318d40a4856ba88aa468415672cb2f3bfa3079fcbd942ca7a3b8d1d4bd7173a0f4bac1a37a22e25dfeccce29e82800cbcb25f9fa4094456c7131618b5a7f00d83fc66d06a6940fbfec01b0b9587159f821fb3b36b48da94cca53e767e9e1b94ce4dfd7cb3fa07cd9ccbd122e1e2c6b0da46563024a6da0a706d21f98598b7cad58006893650e74b57556cbdeedb51a4f7b27be54c7c2d9a68e65824970de3bb1b3b8d3d3346c2df136c6f1f952b7a41c99b36fa978d2faa1904b3dd689e2de88d780ea118856c3aa0fd13bb865f35f86569ad386278db07d9174d71da5769447f816740314e1ae89df6bc1ace8c31ac75efb0226c598d032f209a3e9912e66bc9addf58b5bc6befc2eb68f7ebd45e5614a7ab5d9ed21bebb67c20a193d842b29c38a1fab2e58833ebc7ab430a1c43b4bb010c9b11c547012e76ae12b62b11ecfc1e0354adae7834f769f6ae2a85c642cf759acf26b5a086a6aa4937abba9b6dc0db97f2a9a71a9e56bd8c73c39a99bb4d541cc0810f3b5a7b6a1d7b53abefd03884a0d689ac9a5dfe758372e66701e7a6fa38f051729e856003dcea9b16c616a0a46beb497196ac5e21cca220de1e34d570310c207e8c817c441b7c3985f519547ca55fe130bfd159ac78acda5fd89c775eee20f81b7b28072bd7be2d69b66706aa06719485bb9ae83173f71f368ddbb11b0d6788eb3217f959ca5ba4b73a64e68cb76fdd100d8be66f0f82bcf21c23c16382f48879a144ccdbcd5c5cb9cac5f78666cba514dfd0f442e7f7ba64b3defc2033a541a4ac55deaa4f9c4271520aae058f29542ba7ea6e4777f16f8f714d928726c8b8f0bfe7778dbc45a13d8f4a049c75c14498acb71675f222c5ebbe310c8518885215c0c30e4c1dd7c4341dca7b5115716f7d643d6b402ce683c4baea2f119405c43d0489a1eb1a39c5b60fb3fed4c2f3e391adb3b21a4e0acb003c9afee8a207f109b227b8f8d1027d47966a45b8306a722b188f4a9c3ea8eeabac1edf0179ff632aa0b9d7da1c15af98c070828f3045e55cc70655e855f38b1b9658641705118b1bb827822ec39be7cdddda8f000ebda0cb7229eac79ac3d3b3e4e2436a8974c015f147e6437d39edd2add2ce0f8ed6922c76ee86f22e9df24ce289b54fd8b1ec7de2d085b93bcb66df30eb581ab849fe71a8f8248c9d133f3349fd070cb1bbbd5099738a465f3dbe1e666f2cf5bb815af6d57435ebca6a197aefa96b887ae1b336efd16d0f60d74adc801b12b900339949d17ffb484b99f815b76c597e941bc188d8c73dce8b4e09019630b84bb7c1eed71dd7ffcdf96338740fa0e38c3a5ce087d05320a572450bc60f9be1b956be7bfd82b0656b3666ef33e4e5f463ed5884c89737561e076a93166f0474d9d0e778abfe62320be5a3dbec9a15dae59e6b954ee2bfda7b7ac27f7f5b8ed612871bf46cc60813e09afccfa85973142b9df22331173fbcd7b961164dc2b60c473f264ebcffc0fd47d6a561f2c1861af2b22c536e48e9433c6247bf9b9710c8ec630eee68a2c2426c6f62d762a16f9ccf78a3cb19ee1ecaf4fb94fa2881227e0a10d32738aac374c98c2b616b215770d1b3520699aff0b94a6fb413987771a3a8f4640ba34aef1f580f7d4bcb046ce3d590d8ca809935019605e3c5c1cd697df70cfcfa993117b551cabd74a4501c30513377d0033790b7f19288ff6c6e1e3509d875c2e74a664de0dc5f9760ca5cf07b91fac089c0952b2a385193550a22dab1f07717b971b9350e7a3c3dab216044fdc63a1ffe3827464c57de949966122e93f750ede5d6c5cb232ef4bcb2d5257d288aeca2938374ba85345970ec8de5486c01960a81c1bbf99e16c6b0159a320ce364524b1ceda394dd99ec57db30b565feeb12d8a59e05b20d27fb6d6d72e99994ef9917ba17463c3bbaf8aac6362ca5d8a9b532d1297130877534466db5076f0216ffc99640f7fd133cd57889c18a0dc96eebd7d83666a49903e79dc263e1f01ef87b098bf7d62166cfe5da411c4108eee4ba4d4592d738d255aa0d239f3a19b336d08472eb35cb077a4791607da72ea6fa4444054278f97305c31501d6d3ec62572d26cbc9108fd29871617532893e4ebb36b70e043b81435320f34fd0604924b885dc9e3d91df478d99873f34f4b5c87f801df7af9076e3649c46054929549f5d3178f73eb94d99aa930e0bd39344da86425c17316219892f40de9fcc111a4e53ad3df04ff93b556f8df939dcecf0796f117242bd17207fa6c6d263119ccbcc61facbceb726935581c418a8ee3b2467f2cacdbdb86d1b6c5d3510dcdbb40fa578e40f8f868401cafb510af478bc03ba0b3d83bea60c3a2dfb058e94c45428d8ca400f99849cc4622d0c661ca0c5f05a888f798ffb2ce16ff587193e9dc85e21f58e0dc4e65b1c5ccf642ea02d464d7010f763903b224cb5b7f6b8b3f1724cf40187e1f148e6bdd0ca43b89f9b36f0c35b075b72fbdf8bcc676d9f70e66bc3f8fd69c90b7cc445e0ac72f0e521e40ab1e3300a17656fb284b0e7e020c4dd8c5cf4d77178056917c27b5fb33243c273700a4fda71e6ff2b548e5c0cfbb336a970b28fff2e710632c795a450921608fc42108bfeed10b79e853ae21be00f59d2e1c36f0e780d5b361b3a5b9a61b6acacecc6b32e5bc1334d97ee51de83d44cda70e4eec0d8553b840df612208c59e77517c556b63072c0504964cec4d884ab1d44135da69b826fa7d4e6bc933786e75d8b8194e5bc3a995737c1d3ca7933658caf9eb87a11a81fd94d6f53ce9cb8fba9194104c78a4291902cc185a6f540fba631d970c0f12eabc48c3c73f8a9e0171a3cdb18ca514bb590ba8794e3a7af35ca16a1998b3e7a339c469c70d42984e04a8a6a340f15160a279d939265e9b29effff76d519900e866358af705203ddf9925d507863992fe3699e7403798ca88ebefb3e7a2be8510b4e057fcf177f224eda69cf8c5b9b7294938b066199edd569c368a4ce7984b6a2c4843a3b46b4b60c0673cd65b17798445a0b1b218d0e769c4f630b9097571c3e520fcd300675fc5da73c7647f3dbc9afaa9e3ee55de84c74099cd2e75811fa922df7cb84c862bc09106fb4fee4d20e9b2a858ab3137c921b788d56ea85cb1944f0a15fc0fa5ef62d607d8ae9312bfcbc9256259532cc8a0de5572258182b2fce5c505a7d33f0ea124cc2b8cccd2a81f0ce98b275426c224ee5bc9668e139d4931930897bdb09221e702662e91a5790147ec682667553653952badf1a487546bc501319ed10b583f6d8b50c7894e9f09c1c7f1f3e3d74d39657b301880b985361692c327f0d2e41d74bbc9eecc68cf470b4555ec84d1b95891950e16d30fe8691edcbb485cdfdebefc0f0135982ffa290cb27454040634c4bc9667f25bcee0308edac2ba9fdf328244cc0e44a3a3a0f254d823c46018dd40223db0481043471250ed4de1e14f40a2185c7581cd4e4fe7d7b0dc0b34497e755d32c870c22c70065603e33e81a5b611db3eef2e07d28197ccfbf77a148f2099d5b1b60b72b5ca4c59328799640d0c5ce64be2d37555043eac57b922d1d8dec3f04cc6e7f2a251d4f6f803202df30662b6a907da6220cb4065a59751eca9344a8740b54b851e710762fcd4ed6e507833cc4c91368e014025b23a1488093e26587603b7cc483a02ce5ba7514eeb2bb873a9251343d8cc35342188eea69bbaadd4646fa137269ede0998ecdc19ff20b0a5d3c1d8b98406f4dbd03fbe606f60b6372c1353ce40ae6f1c87a26306d9f352fb287e8706aaf9852119080b26ee6ce168e3766c2acc076dd06dcd18c783d2007250b4c9cf6bb9a430ef014934acde48b64bfdbc7378ce81b3a9334519972d95bad65373f9eeda37f1e008a292e8a518cded91a04b082346093078880294843734f466a6db7b3a71dd4d0dec391679372a29f2b8f4ac3083fe7a97395f2112b73bb9c2506e37b8ec724dd53f69eb50341267dec89d31274260745911776ac1d93dc7efd198f55f9bec503762fff93b352bea1b00a3285bbd90c17bf3b48ded0576c3446d4c7eb3d3131990126100f041e07c33e9be5cbe3a064dd11f0548f03f0b84fbf856e5c0f9838d5e3262d7daa31ac70e5d63149cd7e97933498e70648466e166d4c3471831b046c0130e9cb21dbd799062f30880b9ce0df100b8e6b21f9109e342ec0164160eabd9f723d5713bad1a2ef793459627bb0b7c56a21ded0a6026b1118d41a5a8ad14863b704c9440ba3c5fdd9e580ee8f17ba665e2a130f79363749f829dcf6d9a13095e3e618e193e4585ca67fce1ee9a690d7b15ec0d7f6d040027373db908f2a3498d872d34fab8128f8d563074ba0630e5688935a50753a2c378bddd927609b9aef24efdf5e5025f9970b4a49e293af2137a20dcba94f08f419f126b763eb5d8c67886af3a3f3787fd1b50d9a2623f66ffd2f23e1a9ccde5f203ede6bb1becf4a1a89071b5bb3d65613054872c09aaf6e73ece29bffe5b7ed48ae454b656ebdf3d88f23f6fb5d6caac04d1882bdddc790611e6ed17a0cf7753f20bb2214772bd65cf97e7793bbc30705947fb9abcacb1f81754d6a967cb6faa9ef5b1f25a0df01df68dc6c532ef56cd596b38d937035772eb97a34c41fec71cfa394815984d652864fa90681ee51b81b098a11434d90f9bdfb48c21b65b9966f5564208cbc2968fdaa904767f8d854b60a20d80141595b10a088723ee153eecc28bd345aff03a1258b8e9557860150093c8a5cfd839a42ce204f8cd2fd829b854704ee97d862f7dc62dcb2d61937072f9870236d2db75f3e0b13d3ca2747a27b83485037fd543eb189f6e986b74aebd379477e090ba7fe23893e72a583f7179cc6c89c18978f286692bcfe6df0eba8c2487fbc801d9c9bc03ab7c0031d972c217a798c97f83e6deebadd4fd709ebc12586bae2a9c47829c1ea1c9bb578886b5cd0e0fdbad7538f05341fc9f23320464e4ea1c36d5ef0cf7cf1632b3f43cd612f9639e4e9e40b85d076431a1f34ed9b2cdc47aa3008a050af58c14a955bf5e42cff7e3e311244d1290b49bb6107871f672bca64c47f120b438b54ec23464dc2f8c327dbbb45434ba3b382650bb1d2ed02bdec188b0b7b8656b93db52c9eecb42ebfdd995335a6fd3bd0cd7c55c46b01f0f0a7740e93e8b9bc6bcde581d874a0c481bf00072c0a022c97d98b58c84886989980f45b4cbb0fc133d51a940fcb657539171957a4b373c96ab0b0145202828f3977bef7c8ff5434d56f152133c5e1d223983b7494758afacefed4544e388b7657706731ea2bbac0f816540ea5e52e5abddd5d3832068dd396bb7dceb9ebfe97d87f0e83e9a0994cde615eced1b1946d67eda628cd252ea0985a5a89843b68c5424e542fd232518b9209a0bba1710890535572272ebcdaa748145d9e4608e41dc39737b166c39862b37ad0126d0c09e24f43490c95a6b6108b486111643ecbc1d85c1d4513e6b64df501cf0c7258fe12bd5684686df9e20604647b8a210481df81c0c0bb794571617f6d9cbbf5bb40b6a795f46c194b0b6ec3e9bd890fb3767044461ce1eba5edcf25040a4dd0cd3bd6de43722ef2932fa4ffc942d2e1f27ac982918c3c9c60374830028c31b4f03febf0aa6a0b0f755c60c487feb6117b12c84b78c0c1e368ef1cef5d07e4151b96627a4595a81038fa7e6faaf552a294eb885a442f99b1cd010bba4d88983a1e97414117e6efc1c076ade9fdb7ed5857c8e16cd2893ce846914a5ef87140da4584f56ce6f9a794f948f37de0372c24f1284ba0d4f7cbff456e68a4ad281f7877d79b2b769ea37371dfc3fdd88b76e8a94f8951795aa7c659fdd393b90608a9fc20a006ab935791f73d51b6fc5023f959f6ffc19e01f589e88069c0a2a3f0d3f073fd776109b162fa042d92cdce04bb1e913ebf117f073b5ff0802c85321bd16ce6ef4e0a1d65dfaa41ef43a9988427b98ad536e7ef990f45d5f68e7e244dbe68de06cadfca721f40f351e22407a103c4d88232b314fd88f4cf74be8861edf8227e95695cb5958ff30de78921f67bb5ebb5a677bf5dcdbffddc31e11e1d24b3b5c1b57f5b9e1e28faf3d718c476dc10744711cb88a6f8f3529a0e4ab81190c82fc251bdd3a63a878d8eecfee3177db7a0e938b5b6d6afb7da1331a361f3b0f70e0f5f917d0ee90c5f53964d9d9b272af4cfacc123783867c53b688555eb268b20b5c84a966d9950d333ef8d619466b9a33dd66cc29c7eae736e3e635ae55fe0e721a4ead3a6f2049de47c267185fc720d46dacbfaf8d1ddb410152734add9e6dbdde993ed3a3692af6f978adcd2a7f1c11f1ef54442ad17a5027f76fdf2719cdf57882403cda5acfcc45247b9ddbb6fb3ebac6b8d689392d8ed211ab1f3b6316192bd3bc5374a317f43d1abfa22f9ab3629f6ed849ace5fbe76b826a647ad7b2b6d186058e681aa46f0c65fe77f8aa412ab85443298d8754e8a54b7b7b3e8a0bd15986bcb5352bfd3de2c046eff1952759a5373d43f19b3d8f2ba6d25462f5834a9b975375fe24d8596dafa0346e4c0890f66de522f4559a925ea5fc3dfe7b54ac6d97eabf1c20a41b893aa9ede58e80134e3fcd90b465d590b57ef19e2df169fe657915853505b405317e199b7f00dd9486b39f3d98a745d399fbc6abcfc90d36d2fa7bce9cbfdb1aac2b6c55f4d9ad7b958530293874cfb008de89b456cf598f0d73b20c9d1a7228a773366a94df83d1b2a5d9bbb8cadc44e47587bf73dedd6de42a0570ffd4583133ea161457f3cc009d266c44e671647f8b7e9b629b64f26893cb910b7278e817af547c87486481529cdbb7cc6efb79352919cf87d9d348798ee7664a576161fde49a651a8730b83a19c504f1d61177642a32f01a4da386f8476aa6f904df80d9af1cfa382fabc75eed61b72cb928dd4c2a0250da55b38dd4505dfdf2fc583852787c081f302d1794b3eb212b59635ce0bead5e4c1b20d88ddf6b969b0facced21dd09df4d14df4cedd08493c858e334b14d84bc7763209efbaa34dfb1f35a04412bd0c71f93a9ebbf12d9702c66e631cec35d4cf51699ffdd2742df0ad9e86dca6e0efc10078ff0b72a6ee6566529801e3a1f91c0fad0040d0347bd3dcae827b6140cbe11f7e7ad87a3c06f6c222aecac2fd6a07d88f5aae217fa259a72c4ca7f29d3411a98d6dbd92e203f3ebdc32d226945cecaed8ef59b9be19f6f42457e146c2f0c83923bc163e46ad2dbd3259fd7d0e434a60d85e6e6f53f3f2907f761a1d178d170ddd0cbf3a38d0d6cd5e780c193a0be57a5fa083d5c20023cab6aff94c7437e44f1e6405a2dddfba4479750e07a12536998c4019e512109ddc9ef505ecfa72dfa4ad4b13bda76a97dc4d02dc5dfddbe5de3dae8d49c0842b1f31b900ecad06b29b452d6d5eb176207f6e8907e97b6509cb4e3ae21cb03123fbbccd3247b94d9be9aa7d96e09be049265a3feb46b0af2a616d6c9c8fe7a828217dbf292dc8721e6ff00fffb9663058555a9ea14fa2bc5c3b2889ccc05f2e7cd8ce227667b91f3c45b2264feb0c9886e32f8dfe843a771ede012b69fd019803024083e2151d48dfb4763bc489b81fd1690d43e411de9fab1127ed89678fb2c3b7fd2e9b31f5ae86b5c40ca9128f07b2947b683f70b004d60ef782832bb71ac22761db267df9e68499e6572e0e8ae79f8b6eddfbe2a202a161e33edaa816242d6ac3f1ee0ab1bd05b59c5465648679b4738a308c86e085034c098d3ef7172f757c751c9fc72879f1fdc04095cca4fd39592789271603812fa2d5b57d14eb1a6fa0fa7308571a39fa3f05ec80acf819c873ad525df9a03d1f867d8f74a592d6e1ff5272157efbccd498b72dda4154d6de12eb1c325fe16754dce62610ae19edd8cb4dafdb38cfc65edbcb8b696c4f95072e4193eaa2226b834ae31ef4d0c0b1850b80a58e3844958c6ef4b38279791606515f55fe20f6bd803de2698f6d6feae19aae4d93f0c2a02d210059543afdf32a0370d6a71a6196eedf80c9808b955c30f88ccefd404e4ff6f1036a5be3d5bf171c6842c3b5929b20b0ec9859abfbfa69bfa284dd978079c4547dff3d3ef9ff8441f8ca1ced84627295fb8864f8201cc5866bd00f5a903d01c20f70a6e906f64c03ddb8daadc89cb159b3b3646bc451e5208c4ce2c2ab08aa19955eac7c11094b61aec410afcec7bb2ae20be88e24a50456aad87f8a42ffe399dd7e197210f2f97fb1ac358a2e753207abbf49a1ef5ccf4e0fd0fc0f3c94a7f7edca36bab75ed6e752cd4a72e5221f2a7f8c28f21f1dad862ebd4e7c0478ee1f7a087a709476121ee678fe3009a9f29d0ff7a067caf07c2fd0be41dde9b2e2c52353325b4db798bd914700f918d6c32c1278db0034e6175dce3f402993324537b2e03be6c59c56a926a0c343e0cc2c433dd6ed1232816555afd8d9626bde84220d94e02c9a5251a8c995eb904234cf7a7f8583c5a31012e8791d03ef388d3761c82fb0b7a58b900b4c562b4a71eb375145b3ca64a5bd3cf962c8b975615932a47e28c0e1e8cba2c39a56d976f35e8036afa5da2fce99e6258b1536c083c90e0c13e826708830f74106171e6993fdb6ba33f2c4236687d06f934fc3a327a367e95aa6f0f8e65e6cb5ecbc7d5b9490be1ccf6296ce1d737b475495bc46c6c5f8dd9b9cd9b1d7f50fd28c284036a983ef848954b3472a775d91fdac923451878fe91d3c12076f318e23c6ae495d259d3170409ef6b2253de305ac234c6e880ccfd204b481412e376455e78e0fe15ed0a900f64fe55b72901588efac596c82d2ca3c2aca517e500e1b23aa9cea8b3af12125845ad9a71718e8acd53f587b354c987030de590323b542732494f1eea11c4bf09bc59cfa49af15eab6696c70c90df66f7ec488c02f43d183fbb60d6c42369a51f07b65f52304ccf0b4d80a766ba8db3d53d24d1707179d4382de1bd727b038e2d54e583eb0568984a8193a19bc0a58af3ebddadbfacad2f812853ec0c063c3b8fafd96d16714b45bb7ec162ad182811e1f2a64fe826830a9d686cf7453e56923530060e62420a343f1d75dcd1dd0359a967bb8a4b50ca212b70f7ce93743ba014ccd7d99fba0dee6606a1fc2a21c100fd2db3fd275486a52a014a1f0cf74bd7a1fe32e1bcc9e2690cf3adb3fc9d9277a64fc38384fa00d9eee72eba8323a5b1ed8705eafee985973ecf60fe51202634b41cac26493e2bab462000a76785f38368b2e107da77eac5e46a5bb4699f7d4ded25005f48cb7e7bb9c9890a2d2d367e2b484c5fc65aa3b9c96badcc42e1fc2bda51526c7a710cf77115494b468a200d67a40cefcf8acb0e7d7a9a664e194b640c256b0c9bc8837fe2e96199e49aa002fec3da848ef00f49ac00b5d60f9e841be391ac1772ba36fa2810459c40eff8a4e30a4bbe563ca81af27820d8b1f706a55a3064820688a47033db08cd4f4dbb3618defae88e5795a3f3dd065ef7d63eae566f1b9ed7a0f70793d639de9214793d7846c53e1e7d771a7b00ac726d8ea47edad1ea00e496a02fefda58752593a7858a5c053f54790c3e8c9bc12127b0900eb18687ef03a1c988b8d4a17b4ef835219e75375897365d96b2cab52a3205ee9c8a2fab98cee803210c96ec0ba5eb75bdc7230e0eb9f839e050d5e1749684edec85c44387bdaa9c2c7781f0af89a76fae3d77e06540e80778f28970e001605074048098945f491c17b9f214a8759891e59086463cdc3520936bac043cd0f84e81efff1a7027b5674b8c561983f38a0475af65e3786b6eaa82661bc1f1db7f85350ca38eb2560cfa195f56aee6cf3e0b9806e81fb88f6e3dd5a62338e98271aa1cdab4dc32b567df90486091b47bba4043428ca314c795e2dce9507efae44c11f6a663fec4350fe55085adae0ad3c26f2519ffa102663984709d9a8b65606711fa012b47717afc664e6e51988ebbd98837e60c0a8adc7af4484527a6f44f8cd82db2352e705386003e2459b808a98500ae4beadbfc4a505192380e1004abc8019a9883a0eada09f7fcdb349b2cddad2560433d032d1675aebb20216831cffb29ea9021b4dcc40968b5df1281614f06d0c7fc28b50049a34d239b3e4430a4fa970000af8aac925734572409d87d15d633ce5ace38038cc6cb345bdad87816aa669f6b5c13b0c37da3fdd76c19ef09f5e4be4ac2e4aaa8bd028261de630a3076f8775ab1ff7a947cca659f7c6b84d08e050b8059db1850e3265e4f3f914f8bfdb14c1eda874dcdcc1d22532bb57d4fa3079db678f572a9dfbebca979f0e4dd36b3a5145d3ba5da082caa401a8636950fda65c6c35e5265e6c5e3e2b011a735c0240895eca28d81e0988e4948738c0f013d5ee5752392e6816def22350495b936c84b653febc7507684d93a3b80fbba53cbd283b9ccd1491dbc41b6d2b57f28d97a176fde8fb3069aeca915661d0a0652e8002c073112f93732d07401af4e05943dce3b079e7ca48a4c140088ed1933d059c7528f8af7385f001eb24cd0a1319d6ef740379156b83966ab73338e9ea5eeb05298864d4c0b1679fdfaca17e94b44b8f63d3d20999e3bb8a43e27c7fb17d62a08fdf440f5f748b0cb027f6d9918c0c626faa0638c15551b10f5bcda98f1ceec1bdc7fe66d07caa8f75ebbf310b7d6f6328e6987c0f11ebb5fa8fc9ccf16dceae90bee4cf735f1bd488d16fb0080c6ad786396e09f6411df2dba88ed890a9be9cb08aac6a9cc31fef31391b7a8b4289780193749664e40462160f70441fec5c6d89c54840c499e14acee9e09b39188c861d478492d0f0521bd0dd236ee8b5a40c90b4f9bbf4a372130ecda37a42c5b06aee2e7ace4408ef15f107027841ee4119836ea79a6fa7aee9115b93952ff43119a311bfa8cebd56b363e0626742e2cccb85e9ecf9a7f7f9ed6fdd9c01f7eeb0f94edc38b697702b7f86a4ca44b5a5117844a5db2e3c40ac7351eed9f38381e22277607f50d5b4ed68e0bf298cf29dceac9813a7e46d4cffa734556ff460eb67d58edf27e554c0a88925eb93a8a405f6cb08bd71c4ca242f86627614917a45e4f7d050d2bcd8564fd9fb21b51055126d2ebd7cbce30bbb3e94d56c07386e290d3fe11e6e355e981f1c7ac088f303b89ebe17ea62e7d3c89bc6f2e89b67c8d4ff429e41b80b4a6922e1f3fa022306afe3990747e1ac8d30b84e5b78eb58c2fd332c7bf3c715fe1fe16eac3d3fe7bf4ee6178be9c9d12afb7e2622315a4aecc6e758094ce0ccf30d317290cf43acc3439d7307d65ad942787925b687ab6a8e64e90c335412c5ef0aa212d0ef3987fda7e08be228d8460d1b2589eaa53b0569a3d811502b15b5421b0d75ccaf57e45ffcf8e302da623d84f5cf71a9f5580b12823abdba68420a5b901301200e03e15fb8af1e0a7c3dff1df0435b7f996da225571a6e6e28da00e6174c735f244219101514c88a6041168a0d552fb0112a608e5afe4a4d100b724ded811a9a886ff67f588ddd78bf38958322e9567ac18164d11139ff80e58341beff18e23faecef1d77c636ef2c4b53b4b135c0785cfbf8f90f606256dc9eabcac8f944aa868fc741e3377dee41ae12bc14cbef0307140e0f17a3ea5b1137c10f1b0876dfffdb0f32aff150dc9d39282d9c4d467e0ca14a1d8c3af99817408dc971eb0e3dd079cf4bf563ce1733f9923594ebcdc5eff9b209675429750f123f5a54b8c0dd2a7a7be9f12e9b92704b69927bf4fd71ec42ef48ad165cd9912d5eecc10be0303b9dc55d5eeb8279c96d938e49f5675dd6d8905683bf8f883503e8f575af5f3b85e1921d34525421b33208d878956e11bebc5a25de8e17d5f94621c8b7a20c7c7796ce658260c15911f85c73de4f6cf6da7e8cc89354c8d9a839bcf1936f5cf8a6654134e726d6876c2a621d4f8ed729042f2dc637184e811471f4ee09331c5fad1b3688c43904c4bdbbcc38079674d2fcecde9a6fd1aeb4e8ce2867315ac6281c03b4097e88ac3a12b9a5e127ea321ae94ed232ba90dbce7d26b0d7852b80716d2800e34a373d9306c9eca0bf3ecb1b7af44aa45a85803a182af2e321f09457bb55cbad0d375b0b17ec20f98b65eaf40bfcdbbe2b8031811b689d17d719390bf973f56a7d8ea77716c74248ee2abbb3db47581193b2c06651d4e121f4cd25a829056c4439afadfd1753f81c186066273938cd42dbb038ceb4f44dabfeb6b47d84c848c1a945f3932335703b87bda8ec135c5f85ab0b7bf571380835f12c34bef5bfad0c91de1bd57634bf4910f089862d9b724e8d25b5a5469336d25cfefb99429f186b4c184263bf1f48799c6a94e0e889babc475e7069760827e661dcb212ea3c011209308e5036f55f69ee799391c0694f362f3dcf8a3c5a7d99500788c013938119c7a1f445f0891c3f4dd474ce173432b78db066e7c2efc5d0d246bf530c312883eb99df7297e7ca28b4486ee08e5ef30b279208498704748d0e38e10687141f0d1f9081253c6cecf1fdfa0b2fdee1274cfe334275cde3a41011b34ba80acdc1a0d4b9a4090d5c2cfd2bd1eb97e324a20d644f08ae942883b2ec607fd0b3c99be57f33f107b3fad4bf708f9b7f47b74d87e4312652c29037586b4b8cf224d695257c767ca2d7b1d00ae36a0585d9e0a50ec7176866ab42bb41ad73522f2e39804f94d8194564eab123ccfb8a6a9899fa660a791989d8fced2f1fc0388cba6fe1370abb42d635bfd5930bfba52979be01f9e1606eeb088c77eece7657096410af87440b80ea823fc630a5f335fa677f5225159905688f0272c66e00a1bfcc553de04e5015fb4c4e63563ba3026bc056f36d100f551324b3879c32179e1fccb0e75471377775c19d0c9c2ea2235b9eb61de4192ea34a4e84ec94cb58c1b2df67584701deb55ab20169b8660fb0aea96750e492fda93462b787c686014867e2d11a08c04c85d4bd9cd5c2b1b50be0be398fa0b423a7aa1024f37194bf7e7f68c00a446fa749a48e5f0108294dfc6247ef94c8070803b89c2eb8c7da2838f6428a3fdf8da2b85c3e32aacdd98b7db4340ccb1978fde0de95ac2bacc7ee5ff32d82c12b69b0f3e07227c82551a6aa96bf19a48fed1ea461f4d44ff27c04f846c3b5a3e81beae7c980e695a1a52baecb4d70dee370a1eb287c8cefb8807b2caf523c95d97a4bcd42dc828e41bbc9273d0b3153bab91b2b195d82b4cbf7bc26d3c4929f7a2116d275c23a4db332d96918b8c4c196087f49feaba1f4bf7682b27a8b5290b66955a560730dff498f8ae17ac102c63645323e713f3da9b947329f50ffbf74f4df5b19f0fd18177e9bc7cb643fb12681ccfce90bb5d49be2b99532c7a4d3a0c891748b3ab9cfcdff41b6cdfffe53912b56468d27e2c9ce2fe08ed085b6c9bff11a90f5ebcfb1753e5ff0903f19761364422d4745f93399895579a9574642d0be5503c79e39ac525db8a43aa326b6812f8569188ce2887a36a8ede141f33488359d14eab7ae8fc7b5d3d5e036e8b77c17d0c616d2f573959b025bfe4c3a63281f259f1b68d66eefaa5b2e22bbef23c493a8f382faaabfc23c1ef4dcb3522b401f1f33d78233c9feb0c289a82b3c12652eb9a8cc55512d2546200fe3473a84ccfeb252bd8be2ce819e2d6d84c96bcd4c38fe1ecbe22ed72cf9233dc6e3790fa64ca36192b419af4284f38f8b84e26ae0bc7a3dac30bae2e46f83f108d8ebe480d3d5b9c2fb721ff8080f647aa1f2d66d8c5b5a6c2b4b6e2efcd67fe9031efdf4e3abe065296b3d3c0085bb637117be75dd607a59b90e37927a28f6f588c8390508abfc0dd651fb372b452f3205b760b04746162e24a63c0f923871ca84972840a26dad692f28c555d2cc7e2bd6757222532c564d2abbad134f9ad74b13f766a16a6d519f891f1327ca5c936b86a212cd8c486d8e021f323764f8f12ffb3a636d8f6b18dfd8afab6fb9e92f3e6366a330123cfeeebf8fe49a4cdeb61e240ff13a0f22606b8fbc4f0aa71c4e67f8c7f433da937eabebb81bb3b8bca4ca4c7db511bee48f7b2fd65eda386093b6e9773f31bbb5d72ef0381de285f44f170cc3da0b35731dbb5713f4704e30d5c2171f697afb1ae284b4ece5c7a87ef71cf8e1115ab6c177655e9a09a7c02574783dcc54eab5c3750b2605c19cb8e23adc7562c7a50dd8ec1e2d9af79996a63774dc405705da9d81306e425da68f4f8ee66a12e7f5222fe791d37ee00c6c95ffc314879148cbaa3e8e320c463bbfa5704ed648965f6995c3acc5f42e7ff53f2d453f3f69f192b3079f818795206b3b11df58ee3d73af915a49a5d2bc218b0821cfa0a37a97c1377a51f6fdccb01a5a38bd2299e7ef44b309ca463c102090daeb76f1655236fd138a76eb3d056491acff99078893a42aa0db3a50ed402411d46323e80c0b5e7390997038f1ef3579b373e4a215c8584be5ecb34c9ac435e65ccc71d2923f219438aff32180335efba48b4b9a11a09eefe1fa2c0cf0f644d6e5b5efa912f42661904a157b4d82a616171b188d0f95a6f29ae6a75ca9464683a7ee55ba28e10a755f68a0774def914bce2f9ac7078173cf2b239c219e0f65e71149499023ebcc44c0c3c60ae26e900c3300cc3300cc3300cc33074c4a0f97ffb0aaa0999929cdc43468ed091755d5e534a52269992e0ccc4979ece4c7c3a33f139ffffff91ddea0b7c0c8c0c076179e94b45445270f5aead0e7bde9a4324ccc65d868e314482d04ddbddd01739964224f758ba98bd62e972234492c5b0954b1b6db55225c8918048c4bf04393a12c904800b600c2249c78f2a9ff9f2553709f8b0f181800f0960e1050c4124476df34b42cadc7c1cc28319f061e3238b0f2db0f888442211c445a40cc40ee222b1002310c9d933764e13516f970b49cb9170ec87165744223c6ee8e8828b2e6000228b1ddb6365b977ac70b3aed0a4322dde9821f921010a7c7c48008b48a48c201221418e1b0bb891231221418e1b0964a900e30f49b536f29352f261730b49fbd0e28a8f08053e6c7c340087172115405c1c00d400861f92b47c3484a98ea7fed487c4d26ad19cd4759af990944598d97a68bf94827b48d43cf25cffc3c9b49e1e12fdaac23f3f95c5479793596c01b203461e924e88ee533206f129966e01030f497a2f6679cea8b8e778ee90149336d1d9fba1e3ba2b76482e7539c237bfa4e61e92c7bc805187247d516b29c65ac89047229148064c165b8080c0a043526511954dff7c45ffcc21d933cd3d07e149ef5a42d2ce0160c82131bec6db86be0fd965485ab1e45c01230e49b9dfacf23cd4dddb2f7a7b78a10347030c0260c021b1359338351f9f22436f48aabfea17cda3b7977543a26b0a72c388bbeaaa6d48aada1c83d4bdbf90230c362459baa7931522173dcb8103640d495a64deef79ce20ba1a1264e68eab5bdae3c26948eeca146f62a3a4bd684872f98c39f62b6fd73324ef27711daf6be163cc90182ee85ca63497c658860495348af6d6b30c3a32246b6652d2c365ceddc6906c5632643f5c6c4c25312408f5789f37ac66f33024a5f193bab94bd4074352f8ffdf5ce5bf687f2141c664a9ac3e95ccf65e4874cd1a7e83b6d454ea42e25ed89293e184facf85041f0db275664c4fb885e411a57b745ce7ff722d2496b69caad1475948f64af576116a2c24fdbe76eeb46f41db7d85045dbe95f543580e765b2131e5e4a26dd55263b8ab90f81ee61ac4aee96b9b0a895521e28212e9a6624f2141e4cfef2c97e50c5b0a495e4acc4c27d32caa8e427238db8caab9629590a190b82174c69db77958f8094959a2972a67c37c6a9d902c9ff9ae479caaabb609c9611e4586093121c1cd844ee9d799b95d4272386fd3f334632aa34a48ce6cb59552df87bf68121236bba66db9efa620242485d2b70c6e9d59c7232486d1cdd6d93c9fbed20849bb1994a8e7f591a92c4252e5187b3ceb8708c9fb394675a896ca9633842495829eb28b1d2124fde914eb4d3ae85f320809b3d12dc85e35d1d60021613d3da894e436c8d5fc20f947e5ba11a74d69d5f820b12e6ae80d16e376d2f42029bec88ed174429fc6f02071a4a57c9774c62463cc0e122daa2825ac4c3a48cc8bd62d9682b434e520e1e45874139b948a493848d2af34ddf4fcea166f909c7afb662a9dccddd006891b355b949329c5e0d720612f77bbeffabfb53448ce59ccc4e8b5cc20c94505d5a192bba74c914162899f8db5a71824fdb6a739b94e1e8241f2a9cc9c936c66aaf40b92cf7f4b9d34eb4dbb20c1536bfe4d328c16246fec73919e1a359d30589020f62abc8f1891f5dd2a12e37f4c27478b9865a78a6411fdfe759e56749e8aa4ec182ecca7d2a7332a9277376c57a74e95d74e91e81ebe2ee77535ad99291274dd69287929ee95aa1449a74f28194f64a8ca9222592ddf59e8b5ec54b25124073df55d59af427644911c847f586b2514c93997caf795773c0914c9315784febbbbcbe3f81b20e847b086de73200302a296c516200bb0e21389a9c33cad099952c61b7c010484159e48f6af5c42a7953a91989741a7b2e4a2f33b2712e5f754da58de269234ae99a69841ee6f0a0708ca911fc0c1c5170a38a782b04213c9651927ac742c13c9e97b2a54a89c4c4dbfa30788d9ebf8420b341e00088415984814297f6b5953fda9a04b246f9d8cf6b96d46b36889049d4a87160b2d246d0421d073082b2a91a4b5e683584ed1635e4a24e5afc6defe7ecf519944629996521ee6d5ff11840024f1df0041bbc003cc05200f564822293db626993bc6fc4e8a4452be117a93fa1883e710249282101bcc36d4cdeb472479c79ae76b7665b71d91246ff93a69ad0b3e6e2392b2bcfac49f8c419e8c48ec30da32ece2c53db9880421734a2fe61bf25adb1b8c63470434ed004014562822f9448474932aba54502292d4d7e575fe1caf5a4424a58f9f29a78d29ad7842d24072b876c08a4324e6cdf2a343e88a9e6388242b338be9d229a1635c88c43b99b19da5a774ac42d2fe03fe1fd8f15d98cb61052112b4ace6c78659101e3488041d634a5aa184acfd2c8804cf0f1f4447bb701986a49d644520123fc35bea6ced523b024492d04aaa6379fc87e498f1a1fa3c5ec6510949bbc1df830748086e78d1c63eb4b8420b2c3ef6adf04362c5a8ac393d6f2a4e7d480a0fbd2c51bd29899c0f494a9452225d6f84ca7c0f499553cb5d53ebce8ef49018cb64d5c4f56427390f09c26d3c8ae5b1a0f38a87e4ccca1e192bc8ad94de21315f662625eab143e207e1c13f954a76725387c4d0d3dc1525f767a143c268395963c252c5abcc2131a7d9f9d2dba5d3c942d23e8003c4fe039ef06361e3e3021f363e1ef061e3a38717108844767c08767017e929f09e238b48241289945d009060851c92347bbc7842655c37c521c994878aa8656a2ac121e1732dc3e352eafddf90e449dc754c64b57a3724d606193ffd9ed08fb72171647d792599c46294d89014d6154ac6590b954e6b480ca2bf59eb3e5ebd490dc9174f2f3dba892837a521417a6c6aa9fb28a32634247f564fb10d17849de90c499d475787c6d11c663243c28bfb97ead69b90496548502564485319eb3698c8909c4f552dc831ada692c690581de2229aa1b27b490cc91a36bc7fc758a972290c09fac44fca49df3b2d8121b192deca78326e28ff0b4967dd1d2b8df04abe179254d0a42d8fce73b1ef42b2a512a1bc3c2e899c0b09a7cd74b79c8a6ee8b79024df3c56fed8eb68bf16124505bf3f6d1bd5f5672139a45f8aa9b01a133f16923e297da5f19d9398ff0ac939368a6d0cbf75f7ad90f419736177d9c9b35f85249d3dc71362939fd0792a2458cef4ff73298feafc14123d2e9d4cb12cf96c5e0a4996151fb3a92d8ef0a390fc21c34566de67d21e0a09aaf36ce7c7dec8ea9f903c9b496bdefec94a724272cca72083de3bf352131253253b4d0d13d79f0949f739a8ace761a4f94b480edeb9829a3ba9bb2b2159764f29fd36d1b52721299d650d563a4b9c8e84e48fa6f2d6cdc354fc0889a36288ca237473b48d90201afd3efb62e9921621e1eb53547bada94f9d0889957544ca660809d6ebb9ef62cace092139a797d166397f6a198484f7ce9d25bcec72070849af1e6331d67cd29b1f24f57abcd471991af641d2cec86dd1fa2617f62059bb65fb335d675778909c5e3bf67b58a8f576909837738d7af5105d078931cedf8e3ef5fae62039c72e26d933f94f390e923aa7e0ed7baa7b946e9034a242c9147e64850d924ee36becafb0d942c88a1a24fae6ed4a0d16df6d64050d124c8a69a79c97a66164c50c12456c380bfd8c5d17592183c456150d2ae7b31c2ab2220609e7a57dd3d4659a0fb20206899f82761f95730a4283ac7841524a32cfec59a62c1a64850b1284f6b724aa458aa5202b5a90f862bf3ba2c4c7c790152c48d2b93655f896af584800abd8539e53fd0aa922b18434e9295a44ac291589416bac0deff2573f2a92b4f79eaed1eb1dfb291253fbf53573532475c7b9eb5a121eef522477abbaa82d1d744e9322e1d3dae2977e2d937b14492e22daaf671bb46d5124a9d5a7d0b90e45e2e9b0bb939fd5a4daa04812729643965042d9d99f48d29bb152bf527930db1389419af8f9674e297aba138971af9f266447119ee644d28758da7ce7f17cd39b484a29eda75c715398d89a484aa74389cfd3cb6be94c2485b3fce8154aff7b8d89e4f5fa710dbbb494f52592e2df2e74cef2ad6a4b24dca8b1509b32fbe92b91acdd49684f7147ba881249667b722ea9791249e253b2bde441c3bc2c89a471dbce20e66299cb9148d2aa55fe29fdbcad0c89c454626389acabb4243f22f17494eeca525a4f871d91a0bdf9392baec9fd702312d544fc3f656cda0f332259335ca94e21534e0f2f22b92aa875f5ee06b9614524ac59fb75a9a6998613913473428d27d3385a64442476544da6e25a8e06b903e6973fb4c0e2e3a020230e496aebf1956a429bb864c021e9d462b45119bd224a6f489ccbddd9563659ea7024f204196e48ca271f1e3bf5065db90d4979376e3655e9745d2c39d30ac86043b295bc921fa1b2785d64ac21b95f64f251756e966342d24aa4011f366e0a32d4905ca1622ac275b7e6bac16307028e211c5ff04003c84843c2a5b84e0b4a4d6b500a490309e1e1858eb2bd42061a12b46438af0b99d3ef7c86a47e2bad1e5aa7d469a320c30c09e2fd2976082dfb6ecb90d8517436fbbc66397b6448d84e19214f0651f56a9d20630c096e17639596e7b9cd90b4341b1f957c48008b8f2cb60039810c312468dbb09ef42915a39632c290a05ad40661a64bec8238824864419020030c5f4898cf6b9d2f256155b18323b802c8f042829acc35ffcb2cb153489a0e414617d299477db23124ed4e0632b8b0fecbcccdf5ea02195b482cfdc9b4634a57aec19034906f820c2d948c2c94b2f5abe8b45752fed42cb60001400e646021312c63e7ee988485e884a495c49320e30a6b8e1b64778a69f385a4fd0e1d2039dc58dd0a645821f14c45533243fd05654722914824725676699051853d77ca5ab13aaaa5ee8ac14e5467d827adac391b1f36f4f8400615926dc745b55f8a135b4f21c9f268f9ab2ccbe9974252af78086da23a834a461492f3e9f4f9423dc8cb18a4c77fa0c75f1189ec0e644021d1a27c75f6d8d02fda2724c94a5add6d4d7735c60949992ad6a9b4fead7c13122cb5a99171cd91291392475f3e2194c5969074b3264f4366b4af78a184c4f2115a47a9d5dab64948f8dee0b1cb93ea6e90909c35749df55950a2324748109e529fb9dd9cf4abcc40861112630a96299d8cbb97531112d6dcdfb26555ac58224292989c98daec595ffb1012f37beed2a24db33c4808c9e71e573c75f0f5980e42a28a2995cf74b659110321d172446d998a7f902093e638f517c592cefa2059364707ffb3b87b393d486c3ffd9744e44d8a4880f63abed06207060c063278907c7a749215eb1099e91d248ecd5ec5128d7d2624430749e549ee997fcaa70d472291c8ee909183049577a7d72d28517fc241c2f7789f18dd603e9f1b248f0e9e4b68bbd820d9a478bd5f8c18ab5c0d12b6b26c978ca3ad7e1e2091c8bbc92cb60021810c1a2485c71a7d9d2a7b076d165b807840c60c12748efe33a7e232481895f6efc35d4b331b83e48e959577ef62e729810c182428b1cf95f77e224e7f41920ed7d571597537d31d90e182c4b46fb37cea4407437a7041026b192d48ea8ba3945063e19b4e32589098e2ee8c86c78bcbd12a12536f5e5b3d61579b7d05b430554582b8ca5815d6c2adc3a94812d2c3299d5355396ba8484e2944cfed75dcee4f919441a7cfa8be0f533aa648b61f9556bce276435b8a84df2d0f9afd4bc7a563902231ed6ad0aa72f7b1330488e02bb01a63148962a3d492967b98fc185124d6c90e9522963eef1d928627462812743c26d54b9b0b1950248dfcb74bd32986d014e40338627ca214254e43e5361187a41d4f74820431389198f459523a99eb6efb9b48506d153a6ef6b64db22692dd3f7f529edc4c24c5f6c75341638b102a26923bce7c8a33ddd9ba5c22c92dba558eb92bb9e92c91b0c1c3c47fbab2cb2c24ed8b1d3dcc74c7f7e002635422592c3eb57a558a6717f522062592b6b2b54ce78ff3f2e8f13c78200073120715d76bf552caa737043124c1d6e7f5a0524c35670deee8a12346248c69ef635d26b9c1c41e03129a250fde9eaa317d623c22c1bb4a084fca2e67d82c80021f6780188e48dc191d3b2fc598d37b2169e3e38a372012897c688185d90f6234629dd19bb289d97c311b831109a3dc66bdbf37b8e6622c22413fe9acc93c6c87ff2611431189f6322aefcdd68e25212462242231e5f9aebc5c47cb551131109198efde82fa7499bb8f0122c62112334468919df4bf5529242d3fb4b8e2e36f78037044202f8b2d40024086188648b2978b1f65d6e13b7f861885483679e2834cf94975a643d22a1089ec781e63884188a42463e944530e3a056119880d225174ffdc47fba4188248b08a8f29e8c5921733c73a10231089a552acb867a9410c40682f1e33c58bbf43d248c03b1e99187f48d00e55ae56e9346d3e24adec438b2bcec920861f9246b606cdf1ff3db512f0a105161fdc831570b810a30f8949698977795ed1a9a285187c48b24ec1f28e9e52bd5524620662e5b2d80204005788b187e420f2378ee769e91163e82139df7d2a61c1c59387b13422461e92621ccd66629f73e5080f09a253651b317ea6c3e80ec9e9314c94e98eebbbed90943f27edaef650cd751d923786ef52df613a24bcbc8f860afe9a7bce81b5d8e017345c057d2412899c81989a952cb60001802762c821a9e3eb43e7521c924b45644fedc614730687c494d35cfc5097aa93de90202a98568fd1c22f7ae8e822c111810f1b1f8e838b077cb1e3bd98c0878d8f0f1b1f23884478bc8e2f7a0c22861b123b5d760d4aa9515bd23624e85c931f57c9b2a6d4b221395f68964ae93fdac715440831d6901494de18cf31c520cb53a210430d09a7beab9e9ad7648d4240de045cf0484352eeaa323d661be2b45088818624db9c2ce7cedbdff93f43c296c8dc369fd333e966487ccdff4c1f6fe3622e030140136294214925691efcd294494178f4c0c167ec6c2006191294bfc9abd4b3a04b1d92b638628c2125539e16195378e3064722da238618123e495f3df91d192b179276628421e94aa71837c858db9e1c7923061892530e1bba69a74f5c3e24f13eb4b8c218cb620b1015c4f842d2ab75ca56665ebae237760831bc90d451f3530cbbd183287521498de8b1d5a0662efc5c48d4aff82ed9d51d8d6f214198577e8a95f9378bb49028aa424d74bcbbf9370b09f24fd46e9daa4aba6221e943897938bf5c9acb2b2475eb67b88d39c8868d159244878b23b4e4c449b10a492a67d7df6f490bb15021297d7c3abb14f3c8cd4d21314673306d2f3fb53b861492c6b6e32e962c0a49ea2986b3f1cc2017141236a9eb78daa257cd7fc21d35c9ded67cd4dbba88e184e4334fd2abba4aba5b423212e11189a09a1d3d747020461312cc37cbc6790f711b9990f8a9a40875299408bf428010630989ebd7aa96db0d2e42803e88a18424a163904968dcb01ed3e791848453167a39b65e558f8404a1b264af259583cce908495aae4bbb36e5cfa61192d3becd7da877b6d417213905956a614622689a74eb88a587282506620c21396f30b124eee4e82a8590347aad627f3008c99965f3d7f8a526ed0021c167cc3fc7d99357152f74fc20d1bf3533bf443e48eacb0d1da24ad55fb4074932dde4c6645d7af81f283d88c183a4b2bff29316eb3abf8384d323d7522ead3e99749068997450eaf2bea1fb1c246936b72842f9ad577090204a7f122136ad8daa6f90e8d7a6dfa6f267ceac0d92635a2e554d31b3b73548527a964ebf7a72bb940649624288f08a4957e7cf0c9247e869b4b49ddd622383641122f45c4c423b9db5a3475d1189442266478e1ebc45881183e494d48679ddc8c9a08741920c953e9310b9717e7f4192cdaa5ba5f8599b6717247f8eb18ffe7b29a9589d250362b420a9c3829219f31fa7372169761688c182e4a03193a76a7c6dda0bb50f2dae8844de23912eca66b10508006c00631549caf406958325594d5e48dad95d5145520c1b136dd1d62b038c5424c6baa096ffd6f531848ae42cd61a4c9dc8b849c7e37b7cd1cbc32c8b2d4022304e9160e9a468146162bd02b9718341f63eb4b8e283c78d1b088844788420478e10094422918899e2507b27638c9961643dc02845e2afe88e1e43683395d58901062912947bd2125a39073ba50f1b1f5a60f111310331a30518a348f64afa2ec69ed2edab2892e2e952af3d719be2ef0618a148165bbd64eaeea3390b49cbd10324123103b13a33c000457292dd167eb9825d7643d244f03c3e91f4b2a2f2c59cf2d48743d2747017208ee33381e18924ed9564f0b1533a2f0b49c391e3460e04d289fc2e7d4cacce02290117e90c274c9a84ffc7cea1623abee80112827f1d190263138951532839b9b178537f81834f04606822c174cea961e365de4d960bc0c8447248cb0edef29bb26993050c4c24acc6d6da4df227375f22b1e7ffb4969629952d1fc091e3864e0086259252cc245b6fff3b6a2724ad12c916e2bde1d13fd6867716804189c4a029cc59759cdd749a44d29c0c39dd34eac208e14908011892482eb9d9f2bcb44c99b40b2ed07b24922a4fa7eca931c39e1e9296723cc88e1c90f8f23d9aea60a990b4127cc102c62392c67256d9cf3199e388c22e6393a6ff2169660ab073008c4624e7fa8b72954773dc2824ad24e6fd0c0c4624659dbda815df3c9a5cf0e0620466c7f3d8c11220008c45248cecd20f597379d55544b266d0cb9694ccd39e4d44a25765255fba0c640c34b490389b9ea4acc9decd310b895e9f736e6ab30834b090705aa4964cf1275e63481a0fcd038d2b24db6e6727b5ec20220b493bf6a1c5153dfe8ab3c2a1ca4be9fd945b77b3071a55d8949e93e1f36b44e5692fa0418584f17c7d7ee132a5cad9f828097cd8f8a8087cd8f8a82c3e6c7c14043e6c7c14161f363eea011f12c0e283c614126c64760ca62f888c14122b79f89439979b6e2b23684421417fb018751b4a897a43d272470f1d5cd0804272ace66c257e17c4a54f484ab14eb3599af56817485a82861312e7a2e7e5703a98855e12349a907432e6946515db92a9e431582e12349890286a94ecbe0c253534a3b184e4de28a6bbccb2059f43d20a0d25246e093d5db2d5f3b7a311349290f06759630ca3a3c83c4242d25bba0a212f692ef1ef11681c2149f4c4d6d85d52abee1a818611925c64ee2cafa13399b80889a2e49b66a98e69849d55a04184642d753961fad356cf212475df8bbeffb8eed7508186109284fb966ecf3d08c9222dc77e110d1012b7dac36c7f4ce79a3a3f48eeb7f1ee9a51963c46c3078915f4e9ec1662214e1e5e380848177a4da307491a3afe77b6fb8efe19101a3c48928b31731e4bd963ee17a0b18384d3d9da2f97455f2aad1168e8202944edcbc9281089fc8dbe001081460e9233697adc98d945ade6c3868d0f6fc0878d8f48a49081060e12b793bccccf9d9e5396bb038d1b24478f93f55435259440ce7044c00211d0020b36d0b0813d7739e9fe8fada690b47210f8b081810f2db0f828e56c0d68d420f12ea664a926d34c551a2429d369fb84d87e40630609f22be328e5393d78ce073464909439658cafbc52a9550c92a3583aa1162e0a7cd8f8a8097c48008b8fbca1a30b2e763c0e1c5c1c25d08041c2e595cfb135b22a684da0f182e4ab7a75ddfb58614e172459505d4ab7eb767b121368b42051357a0c672a8dd506d16041b2e99a6fcf9a625a6815c95ba1944a327809575b1549272eef661c99f308995424e7e79b699d6c0bb584a4e50466a0224929754a7de35e34972430e314095a721bbf512c37f7a648b07c1bd3d539938afd952229cff6655fd59f976a1e308314497fea77ac72ce1002c9e13b8aa4e06a156436796d5d525124ac7b7fe84e8dd1608e1c3a407278862231650f36e2c3858b3a1bcc004592ce7f174deb668adb84a4290d667c22b9e4dabd06d96226a39034901c7e6430c3134955967539429fa628091ec7efe844520e0b1754eadd92bd85a47d6162308313496a32dedc5b4adbd82612f62ad9a59cf3e81b2487230c666822d14a93fa89d8ac56f290342f3291f8e1df9256d3d13326923c9f0a9b96e3bae71289f33aa67ea753fe7521692039fc5c30c312092a99184fa9520e3a3d9548bc50b3e17e955a5c0e49d30192c3ad05332891a4b6ac5296e9e59b3624ed6f341b0b664c22e16aa388c9399d636ccd304312096ef963e62df19d5f8c44221110d3199148ce675f42861191a23121696f8224c10c48248a5a8836f7d98c5686a49d11cc784452cc5a28f15bd5a9bf90b42a2798e188c4127a47e6ad8b4e1a0b49fb1bcc03c4404280b8e851b6e3439063c717331a91a473925d4d7953379d1149dd2273286171943ad12212b6ae343c28bb905e86a4993d6a80b1198a48cea235a6101d6ce7737ae0e0a28b4424567a865aec68b983638717bd17988188240b4bfee14d7d0ce286a4150f661c22e1cd825e8e3fb5a242e0cc3084193ef6b3e870d6c9425c1ae42b2c736bda94a285198448f678fa84b668f2da4637ba47032291482412b9620108c28c41a06e2fa58a921ae40f49f363382c509629982188e49c6df47d55da0fba0f4973636b811981483e37d37fd9964999199236821b39be40aa0510892194ee24426d2b7a5fece8a15fecd0c28a1466fc21d992e6a4b34187db759230c30fc9de371e97a63e2467d56b562aedfd69c487a4fce9b9fcff524de6ac1166ec21b984c99d13a69485e9f490982fb86dc6aa320fc9d1cb6eb35f140f49f76516933a2ff996df213969c9eb1237ca72ba94812c61861d92ce532c7ca63e211e05cca84382d09a9e848b1eab14ccc00c3a3442a886ea1263ff86a49d197348ca3146b6da9a4add3a0233e49018ae3246bfc3452e1b92a61f981187c49b51a9d2834e42680e480e3f26980187c4f2ca74357af45cf043d278600966bca1dc9060a3b51eaf3742e6e2468f1c38ee4630a30d49a2222e68d2bf502a6576f4d0d181196c48d00d72a5b4e51c3dbf630d89a636b7fea67c3766a82169332813d5f3def47c481a17652098918644d39d5410b539c59423c20c34249c8914117a154ea45198718604a5949f909b66d7926e86e450fdf1a37cb2f338cb90982bebbd97c7e89f62a5cc2043c2967f72f7f92474e72169261261c28c31247807ab7c42b73a72ec504024a223c70e6fc0073e8b48a40b2e22911962481a556e32ab2a7ede38e4438b2bfc06175ed88c3024a56813611ba488b6e8d9058e036680814ff71973fbb4f885a47d2131b45a37fd64cce6a09d20667821d9de34468fbd9829cc0cf8b0f171c5878d8f057cd8f8483e6c7c28e0c3866a1712df55b37d2ee175f1c485e40c63dfa3c22c4fe52d24074f97325632c718a50a66682195533e939eee2c24872719e3422c735bc54272cea083da50a269b7bc42d288673eb597be82d2592141254f3199ce28329f6c46152c6dcbcac12aa714538a29337abb5db80abb9bdd871657981dcca042e275d8b8fe297ad2610a49d30f2dae78cf61a3c757608b0733a6907023cde4854ababa5433a490a0424e35a6be13261714cc884282caf699f1a2af74b341980185c4dc0e6db1b17be38d16c44ece7842b2e612535a1ff27e2f663821d13bac64ba794dd567485a08c2c13b1a0407171ff83efbd0e28a1e3972ece8827f478f0a3c173bb488442299c516202298d18404fd14d53ef8dac50c26247a5e66f7d0bfcc29c7c58c25247710d272c47f97927266b105089aa184a48b8d717ab3b369f9242468bdbcaf9637c9c51a0949d94b7e974cfff1527c84c4bc0a1115ec354282289967eac13795a908091f1efe59de7acf2742c207a5d288fcf3b9740889db5f32db161442921abd993cc53008c9d984b2acefcc2c2a0442b29ad4bad8a23bf45e7e90947d74ce6ce7830411f61b36ae5d4dd983a468af266ee37fd618e341621a9d95ffa41d245d0757b3b00e12f36ac7da17d5d9aa34302307092ebb9d9be637741a0749aa42abbe798ebf79832475a35ab529c472f536488ccd25a754cca43a5a8324cbd96629e5d329e89c0649f23c9857b438911dcd20c1d2a767c5b93291b30c92dacef2c566f37ca118248ada1cfebeb3754e2e0c92d2cdb68592ea8c1724ff5d0e4aea65190fca192e48b0be98e4e34f7b8e39335a9024449f9299cbbcff9a192c48929e4dcfaee550e16356919851835ab098d12d8eaa482c0fb23394be97853115c9a54c73ab2ee7e0a2828ae44e753bcb683945f2eda6ef4ebd1a231653247ad850ba44673be54a2992c4fe85feaae829f72345528a51bc2ca98bf182378a24bddedc175d1489aeae5d9a39e6dcb68522290919458d322b191b1449a133a90b1b663f69ea13892e4a6492a9844c0d9d271233c98a5529c46d0c071720df83cd3ae18e8c5bbbbf6d23f300199c484c6225f32bfe4d24fc893f8ddfd5ca18d544926a6829b9f031648c3391b4de1aef73867e3e0f2612b3f87525e9e125123c8c341d4b755f9880b130698924fd9a2afae6dc257141ea3eb4b822f163614a0f199548dabb78a1740ec2372d831249325cfd7ab4289d278724c88e1e3acafec89884513b6ae524aeaeea0265e0ce17322491249355eba5cc610664442231b9464d33ea9a269442229148a4b4900189c4baad6fbf8b3d22d9b5938bfbbfa698b32312bbf38d1c6fddcc1c6b44f29dc69eb55bcaaa970c46249575adddc808f73c1791d44977c43fba7790110d3214919cdbaa3e45116b639f0f2db0f88844400c2f11096a46d59a9bdc30eb87a4b13f20758848cca2d4c7ced70de1fd19641c2241460979d1b796b4980c91fc22facc76f363aa6cae1009af2983c5c8fc241a2112bcfd457e7aa5eeb866f161e3069194feaf2bc7286b59418620922e43fe76f4fbc2d74024f66c12b929850191d4374249b1ddb4c1ae48e48c20123923b8fd4352b81513d9799f5310fd9058fae64c8a8f506d497d484ae253e8cf4c69367632f890ecd1aceb3d7decda7e0f8643861e923cb7df8285f2542ac6a3040c810f1b5ffc03743004b2d0c15de0301979483669aae7c3b7621e914824823c7070c15f788e04a408f0684024d2052a810c3c2466cd2932edad9bb22c023bbe871711f8d0028b0f2c1490228064907187e4fa77ebdcf39ea4694d1764d82179bff336af4ce73ca3312dc8a843e227b3f27e95d3ef7ee1820c3a24c5e4f7415fcddb624c1664cc213176ff2b898ed5fe17392499b4f95471330670180017fecb5aa954ea86016c21194c56308da9db42e55a70e35b43c6187e1747223abee861d830802c245594ad9cf1792c24970c2663da89e7ebfc0a49514673bf7b66be85ac90709a7f76b2765afea942825bc88fc98390ddd95321e134d8989c174d21b14bb3697a897ebda414924d88aad51f1b39134621b1e3668f8aa9ce190ac9b9726955b8acdefe13124c8cba53db4d7dba1312e54c7c3d868a418fd784c44e7284d2cb1bf59b094952d4fcd5aca84a295b42528c8b8f97f22b21795b523ca82b19932167470f1d2618401212538db2f1ca9befb208098929ff097d1d439bab7b84e4719bb93fb9243c3542b269cd9d64ee8d29a61621795c4e567f5eb6ae9308097e9727674b865bbd0c21d18412b1fde661ac3a21a4d2ceef6d3b6cad20247d30193b664148130261004048562b21635e0f9d9bcd01fc20f1bd3d7dcee3bba8a70703f04172a6e6f75d3839ed2f9930801e24be7a4ada1ae36691a990b4828401f020d94bcda57f9eea5cff0e0e0d257536eb89c83330001d249a3a1d742fc8dbdbe8e02eca007250b08cafa61f2a963ae1201db467f9a47446e9fc0dd813793a98fadab80deadf34631a5ed942a8067b30153fdc69afdc300d0e739d3aba8232f9f10c8a1f453bc9780d23b4039041418bf9f8dd55d93b8018a433851f958581495beeea144f78d2ed0b0c66a56329753a6c5517186ede42866d533a2d48b8a8111fc4cac33a0016f8f1f7d28cd00bb999551c36585c853cfd5115e69a13fafea5c25c2a79a891a1a228a7d2a8fc3cbdb93a056b2a67130f0b993445828a31d7bcaf45c5684bd1767c85eb3fab8c14099b5bcba2b58c9e7fa370e6eb3eb62c840cd71045b2dcdf6ccef1b576ad1ddf830bb3bfd12b861aa148f4cd5dd61fee2c37098ac4acd92d2732e6ef793e91242ef365ce92a1349e48b6107ab3d426b1fd7d27923dcb59a9a034e61c744e24d7754a498c369942bd89c43442e8d724b65392a92692cedbdab4726bff66870a353291207ef76222a763ce87807b5c710ff8b0f1612b851a9840869b9da97cd4d225924525f978ed32b7fd5b02954f5e866bcb551c5522c92e3b3fe78c7ad4a004236e3bca6b335fca933865b95b57cab0efa2243ef1b349c5d8a1ae48a05b5314a1c3a75421519041e9cebeabe5a87a3ab88bb21cd4784452f08a5db1f98bb95c1d0c81bfd15ee450c0b182450d4724e7d49df2595cd228eec80162b7811a8d484e95b3b8a9f775ac54a00623f8fc0df1a431af6e42d2bef81080e860bb321ddc4529418d4530fab2d3c466cc40729cba1a8a48ce6059c572c9ead9bc711ccc800884f4e002039148952cd448445210e6a2b973ceb6dd35109130da32a551669e2975882fbbfa8aec3c327a84234716050c350c91b01ef3945026739a172db0f888448c50a310c9765254d8d0d469e552b0062112337d8c9752a325a11e3972ec1844a2478b16d325d1f84ac261763504919c59abbed762928f7319c142a146201284afd6767cbb54fabe2fd40044e2e7c80eba5f22734b5da8f1871a7e485041940aa77b653af49034335d408d3e24e83d5777fd9e0f49d22d3729d5b3d032f790d89db4f5938ea2126ae821b152bde6d17ba533e47948aaa4a62e7b41a8cfa80ea1061e12af46b35b903ad2e3e50e4917be2e34bed4886d764810b5b6fed5ef0e6ad421418356984b5d73214e74488e39c6bab4179499eb7348b40f179ede6c3f942a87a44d42838e5015ae1d8c43929ae94c5f55beaa3138a8018744379d6ff684eea04c266b50e30d0916cab4685c891ddf0dc99934c510bb516c64ad831a6d48ee1f351f3bb3fda5320a35d8909c74defdac9b2bbba5ac2131e5e866e8dc1999a61a9253e8dda421e1b3eb4a776dfe90d190a0ddbd95c1c488967e8604f9a1a2698b69ffe1364392ccad2ed3ea79c173ca9094fbaa3776eecaaa890c49619a6468a98fd39a1d4392d26159f53b848e2bc5909c254ce797ab4fe66718925774d0b1650386c41759ba2a9d1a13b3f9429236f1fa58ea72b4d2bc906073a5c305994b23b52e2408a1c39fac8f594468b890b827bb41a9cd1612fed2849a90d79e64d442828e77ea84fa11a15dc942b298284b11f116fe332c24655d9296332c4da5dc151264e54c3a088fc9574d2b24a5911e9f528b67279d2a2448739359d5727869900a095a66e6559be55e54a690b86fe15ca46e76084f0ac931549ba95259a14d1a85a475abd8b55da190f06e632a9bc7176db127247b5fc69648cdc154e38404f5e172b9fe0611a969c29ff1b64125128944eeece8a1a3a4a0061312845d99071935335bbb418d25248e90d164f8f12c4a4a484c6e4a4bbc4871bf38098917ef496b89aca6b320212993c71bfda6cbe4a747481acb7556ea9f726c23249ebde510a73bfbcf5b84649169f496a8933a1f2442721293a2e4f209cd5d1942e2ce8a68f470d9dd8d109254b5c9504275caa5ae2024c954ded6a3ee7e39034252de303556d23e8bcafd2029e6c609cfb9a563c93e48dc14b4a974f9dcf6f33d4850eee25ea65b6749850749e365e2ab37b383e4b31b8d166e1656733a48badc64d237c8ec24333948107e5ba542c53848dacdbef9983b374812b3b931e3558c5d521b24dfe5b9dc1c27d4a841b29be9756bbb29b59a060926f3930e9d9387fe76060963f964ae538baeeb9141b2988cf58d956947b431483061214b6c954a1e736ac020b13df6bb05539df5f11a2f48ca14d7d53c8852a73c355c905c42f594dcce76d1548d16249985a8d70b335722afc18204ef4cd3d06c3122e755248a7ccb4e9e1b4766a68a84cd74397f3afda8234c45929fce4cdd2963e6cb50911cff39db16a4b7c7d829923707f3504945a648debcfbbe501fd15f9622c984d86713234c05d14891b45935977149890f975124c64a51398f56b936a12892aac3e5cc6aa24cfee1e9c5c7eff082478e1be8a3d38b0f10bd5024ccad9db4d3cd3ebedd08ce093440911c224c788c53b31893280391c88d2012e922c78e057c81d03e913c1ac7dd93fdfcadec89c49c9a6396f84daa9972837144e0c34627923bc36bdc4e27f75424020d4e24fcabe998dd6c2229aa8fa6ebf7303e1f4d240759a9396a07e155aa0422112fd0c844e269dc4db5f1ab714b4c24696fc5b2fce125923283c668237ae4a6c512c99e9ed47aced34cb18240a312c99d5247a96ce788d8299194fc472695119a44c25d8ae99d4efffb4c92481c3791e67174ca958b9148501d841895dccf4aa501894c7d12aa4306dd69e52392e6cb55b3887c54113b22c136a71026ecff63ca368259f712e2c27821698506231236ffaa635c994eef952d2251b4ab82fd07d56a15452478f8a6ea6e109d3f9688e4709dc2e7d1d37262cd80062292fe672f99305d3266cc2192e2a8fb18757563474324c93f69afa7c16455104f2192fa53e46b6d7912dadf811f5a5cd1c30b1d17031a8448fa1bf9b392a53b5a1a445252b37ac94678b2d00b224925a59fe71d26c2cc4024e694c52fbccc7ac78a16587c44223d10ebe84206340051ce15ccdbac53271d59593dbfd79d1493a1f1874439cbc17cde2e080d85a46dd2e386173bca0f4939b6b69312fea24dbb39a0d187c45c5fa29fbd69ea530e0e68f0213986ce49eba51c99c68336a0b187a48c75bae59d620c4a9bf86f6c0a68e821495baac8a6161325d379481053b2b6fc653c2467fb9cdb43b977485032c7a4e99256161db443f2da58aa8889ea195d489a832c0d68d421d9ad3f9afe8709af28d221d95236a1694768cf1c92429aa65042be482412c9620b9012d0904352a611be66c2c13774b433c073d8884392858d7453aa3579ce095816d080c3779e52c5c60d7aa73222a0f186c4945ae3b59ed208d95d41c30d49b9849c7db598b73246a30d891973acd09484ee546d485a2954a0c186e4334b6acdc533783685a49999800b85028d35247dfc8e231777556e4c017c81861a927295fca714a39c3a73241c5c5c0281461a1244ad72ea8dbf8814e1c8a1aa041a68484c4294c937cbb80c3b248d07173c70e4283333335b3501ec80c61912bdbc746b18533a0a628a1912654327d53bddfda613920602f25e9432051a6548aace7e298c6fb6745f481a081992323e654c73356eae86a4ed13688c21793343c8de7443d2ee9040430cc95671b5b2c80fa22c672d0e34c2901c459978efedca5d1d0e34c090e8ada393afe9bcafbf90687a336ab820653fa5bd901864e62851955a1b68742131445ea47f0c4f59e242e2c7d12f9a5b3de818b485c4984264afff4c278c3da8242ee643d2501c0a85028130100c0a9aeb9604f3130000001016920763e17848d495791400045642324a2a261c1e1e141a8a04627120180a03c2a140180c0683c2604020180e86d2d21cd47e8711bfa02112f9f428e6cebbdba83bead515e25eec74668d33d28860f9b1e8258070f9198d5aae8f2f40e0e8acdd75b9f811a710c019e2985bbedeebd58043b035b8295183acc0874315f4e1ecc50fc7538003528fd297fc8c0e741bdc3480bae1487a863106ff9556bd3018e643c27dbf012a03870c1c5b7076820304870f7c80b011133216577a137ea717d0ed00821f8f1c35f53b53d2ba2f8fedde3ea3f317d7abadf461e8247511b6018c0ea620dc185c3038bfc126f4061669f53851576c75c498fbc78952622a982a1f4db891b8323b6d14db17dd0f4f7d130723351e453f50a31b0b608261507211fbe03e8f4faf99c5887d8b465a3fcb4d6fe00ae5393883fe26d21ea0cd7670962db41f5e2ea5d40a3533b1e3e62e42d6e9d2a51c9fbca65f0185baf2e87b178f047483d792dc9add7dce28025811fb52abb1a707cebbfb4884ce139d27608e6e56e245b4e5e6471bab6a486f4152da2f112132ed288ae8ca487863fbd6776a4ad2a9243edaaf0ce66fefb5b864e30078a93aee3146c84a00f0d284a93bd61d89b432f2da0989de26d90bcdf68881aa105f0ea306c9de565c4491cbeb9245844622a501c72ceec0616b38067e210f93319797137189dead2dfe882f61c958f37faaf5080d10a361c066a56e259d5b55273e3ab849102aee39c4f79d45ce9e54e7cd27943632472c303fb45406a70d26147a67b079b4c67892f91afd50fc0e8a7fade3a424818c07f086fe560fd2128c010b5c0e796a4248dc49fab0fdb7c65a306512b140926b99d2b4d421c920323996b029d40987c5c99724b149759c53b97af4278c788e27447592e8681302fc60ffcb042c2144a9edb21ed5a17cb2cc4ff9d522472c79c8aef196abcb22c251b91e34659a5d40b15e660ba2b8e07980ee51560ca5ef81b98e814757ce38c66b50a0e289205b8f59e8f31bd15eaf06200b0f78c11ee3080fb6f74c8922f25018f9fbc065919e4b658a8e25e9a6ed044c0be6b8390e1005d29d41283d9820ba9623669ff9c63a5f1b32b2aa4d39ec24160ad3ea9096204f9ab7e0307d6958277bb3203c736cf18eb9490046afcd8191a1918291c22a0aa3fd9786b52ded6304fb547b4410ab7d0c8b074aa84791d007f15b7cb966fb35057e8a570cc02340a77b913725631b359e5e4270b72a2c5f6ebbc9daf2b32047cd61e915fa4ddb12782e3f8edac192a8196b5574d8351b95cb1856ebc6c48bc0996c86ce680cdf33f436f0c69fd1e0071a25b953d4b7b4632094785bdd5627e496a5ea47561c418ec7e0b136c6921d7e1aaed30547dee2e764369801df9de57dc7abf88376cb15fe53b4636e5fea08d300a58dd54cc514ba4e123e1004dcd3dca5259fe6fa4e630b64b26d923581044497136a4f7b153054f7e5c8107bd2b1c9133af84505b4554cefa5e2935f2503325d41a8bc03eb2821c19279435ec789d797dea125b521cd6ed9ef1ce7a7a346f9da0b162dafe39bbc366b7b8d55a46db3573288e47f6df3ba4e5e31333498492f025ea9bc4244af37d4be7d7ba35e6f5ee8bd9a7b35f06ae4d5ecd5d0ab815713af30fcf5442b37d724f6dae885969745bb5d0437b6e0c4bf6469947fa0a5c7f3d07fe446486a7e24934c5f37060662f9ffccab3f3aa27ba4043bc96da8bb8c4df25fd6abb017895fc5c0d27b25f16ae995e6d5d4abb15703af665e0d5e79bcaf279ae3ae25b9d7b617dae375241de972a1abd72202b06bee5ea6f5d54724a743ce33c27c30e2784df7bae775e5b5bbeb7ed7a6ae4d5d1bbb36bc36786df7dae6f54d5fd723813e1b929769af035eebbc4ec8eb384ba3f2181836e0f94ee5126df9c36591af40578dc46f4418c2805c9a9ccad20ed388da89dfb1c2d80fa22bf394ddb463a9ee6b85ae1aca6a419a1bef25250515dad078747f013d52888b20897a4151744bdba41f5341e0a875f690657e2410f9179426b8cd4b4366f72dfad28f3262617819e583987436c0933672a9dc64f3b10b54efada4c08a48c6a6887521c78074e5ccfe1895d15ff3d239782d7f85d009a57c8f1025230896dbbe2aab14634e6d5b03cd7d835053f73ecd2e04562170847c080c017970330f3a431f141751f7187764b5b2dd0a3e0c18424b2f17d9d9034d531413953c2f8f2965908c8d3b8c5f38eff21fad1b2bca6a8f31874567d77b901f3adedf2739a7f9e48745adc7d34e7c3cee08f1dffbd65d5577d37dc3011cb62fd0d80b87e70b4cc7b3c012ab7680b4d96eb08e3a359ee99b0216d8286be809449e55b66f0042824961a70a331c757df6b82d6852141af579f997e7e929a6a2d96bca5cd5bdaa4db57127d87d39c596cbe223352e7f67af42fb8025fd03f5bc3528e9ca0f5388f5fa83426e469ef0d5616a7db5d8a123c9b465ce44644473a1fc2712ee990be40cdaf4f35b46a5d9872125d601caa1af885f73ff8c654ffed36fae06142fc08eaa687afd88344248409d872310061a45c1a6be35213ed5e9d30ce677d42e66f24f2f62ec4b0cf71176d6c75473b81b045b1d2fe87adedc474fc31d963487bac2b91515c2eec39e1abe697c7596a1b86a8d8a30d26725671018b0d74582b11c1194828329b58d98186815693112a5aa26cc4481991aa2685933f3912e2bd11858eeb30aa1cdbfb5eccc10163d37e94295e04d97c9e68e2a295838946f8da3dc0524343890e17b734cec52b70c6b9b6f31f492c65c1d3989831bf42e2f81745bb314ce56fc557a0c75484d3a379ddc303e8656e4340909f4561c7dd5185a14dcb82daddfc8f56975b80e2d1fbaa1545e7e14d1ea59ef98efca731d15662ecbeebf401e03b06f0b7151a99f943eedb7c41a1273412797451317e32da398961b1d313e40264ead1df5c8f2e024a9a936526252a40e98906a8d41aa587dd4741e251751277a03b39849e18c9431c2e4205b86593a3bfbb122c8559de532a23811d30bb1ebf30c321fab5e1e6c3eedb4d0a92e5410691193e12db0c0b62f558c780f1e731e703094fc9fb7cef03a3ada5bbeed29c9f6440d0b15c31363063b1e3234a3daf839802fda6589901ad58a9d218980462c9fe95e3fe054ea9913eb2dc29032a693a094fa60a721ba03f1e2739806144e9048e6f08d90f8450d97479ddab9fb22df6e0514d77742621853994328634c35c4fda6843bfcba4fe751680ea214b38582e49254657c194f58a89c7e742d82f4ad643398773d0ff275a7c9edc9278bc2272a5392d59c74882549895bdf5936eb98eaa511596d12065fa876c6b122f923a6e29cbb1257ccce7ee51344225d6a8ac5d6d60cabc3a3dc891fe440c3ef739a59d48f2222d75464deec75a7b9915d6163a01b8f79027d4a538a953a4b103116f1744e7007431ccc6a013d237f04222de23952799f40fdc12e3e4a8021f032510114359e346f835e157f028fdf91eeca388de4558c1799ad8e682fb67bdbda08cca953a224bbbd9c8d5db7380a006855dd291b7561dc3819d5898e467d50f3955dc6d9f482363d48cab463d0a5a1a0fc33159a9e92d71b59fc784db73eec55270b79e80719384650b4e46fcbfd5cb0e5e763d107ef5dea5175d4d82a79430dd407a811314118962ff8c9d2ba88f1a140b5d359bb828a1411b4bdfeafd67828fdb37dc5e338cdb37513684e45629f5c975bef42b2ce62a26f572018b0205cbb8019fd7aa7773cf28369fe9f3fbe2d5e71eaeeee13e07ae1ecc72ad98f4b87c20af19cc5e1a3b07411eb6a88fc9e3103fde5091f2b1a4d7d8c9cbba5481a4cc6cc13626f57fdbb569d0b3b6ca620a5ed663dd43b081fb6cad749bf12df880a03ba0e78f4b374e20370f5dbd4f900d62f650624fa0f22fbb51ee32d3d68c2503b7d1b9d66cbfd5e7f7309b4addd4ecd9beb6b7bc0299e3ff3d6d5d269744c7e150c0f9d4f859a405e304d45aab362a191e737fd7f45f8d763555270ef466681999df24b910a503ba41f47f5c68005460f338cc11c31437ea1ffa204825c293c0376e2690711619e62acfe9a9aaea3cf45738f76e5f49546f2f12555fb649c99b24a148c969e9f22d1dd8c3e695adc087de1fd1bfbf67fbab5728a49e94414fb9a8d2c685cb1ef0ba2092fd7c7d422d88b4ca6d4057094a4d05670623843f769b2234168ff9eef4a50fa907932c0e4c0d27761ee398094251b77c18d2ea3c53dbf8e18711d1ca034c23282ebfd199c7c2e2b6e891db9d20c15d562b606093e8a4833589b37ce5fd6a69788682de3b6527a113ae44cab750fe9ad3748df6c277bc0042b8013096b877f17d30748a99b205e40b2b889ebe81bb155aa11805c550f2d26e24ad16b31e587104ac5a83b9c1d61420e3aeddb34bd520280fd00a1a013496f14d0dc5888eab677ba57cab7a853966bd835edd965b9220aa23ff0452b6435a2f397f98d313ef4de5dfb1925826d51c44f318e5fcab4fd04073ec991cae975d9ca021fa5c72b9977ead24f5065e46a0755124d401f859cfd1183920840319504076f252f098350ea5d77dd23f0f9fb895910fc8fc0d769c98120d520f618c048951e913d3eef388614643ffa247fcc2622f2c862755ffd22a01641aa0cda634fa755a6e142646fcef14d73d2b5e5db1b99660cf1040200ffe942f478235fc6908d6ea56300e136ac3989f9cf63c1114a383252097ffaaf5aadc6e5666db56c4cddd4a788f31f472c8f02957f64d638eaf2ac1e7a9342822738c22fb2ab14ba9cf82328b1fc12b8c1c6df798febbeff7dab6b2c6b9b04ce3698e458f7681bf0320dd77c76245ab1b6383d6993ca07701c515ca23601052961711f76d69a9c646b4260383750e4a485fe3f1082d6e1ca74e4284b36fa405e4248c289b37cdcf11b2aef5abc1143161687adc9582855e12341c0ad376fa55b4c6e36c2d61d8d71673779b411f37dd246a3cd7d430052ad5ec10297d330d90667df14ce7c3198b38fbc6251165b93b3406305e24637cab9b4572934e4023a06a22d07c661a2b53485375dc07485560ec062da0e7c35686ece1e0677d3d99094adc45cdb4e9e40a8b4cf4d235ec795cd811c7195c00e702edaf3a33153d8392a711b89900dddcf4eceeffa1fbe1b9141bab124107905904f1608730acc47a738297c165451aeef620a7162f478f8202fbad29ff814c5ce6fa674d739c96c2f109686194938d03b8129f7d5bba5a2524fae0b875695f3811405aaaa4c51245a5bbb193d6ed98e312784f606beb7cce6a4412ed862c19450a9ea4e4464b2cba95a3095ceaf1bd6ad7be3be5c641ce0068388cf20c7729102e148b73334cc3faf4e6cc40857360df46326f580c761bf694fb75396119fd5ddcf03dba0bf3df6807152ab7b8c9da92a6ed921137f59fca4fb2bcf8528a7d507db10b7329ebdb2ca2ba547a56460af4478d6151d6aa90e794fcc3a8280f03963e10799daf9f6e8320026be84e50f9eef877f7432a5b308164452b85da159241255983209601d36b8dc7b686b1f4a5432a9430d74d881a2f50b13cab720a471a98e4c6a9daeefbbf48c0e06446a2e2014aee9ea4a934daf17537295bf90095e33774968cb2e62106be15420323ef671d355f5447213e2c0e1b30e202f5be206befda42558dd6fc7ca8faaa6fdfb4416a5efcf58e5551e82ccb507d8cb2dd8174f14d0fe6b62add66b4cbd7863bb9ebbeb82e839028147c381ba0217c1be6a09ae0beb38ebf730b730299590c0d232a21abf315e5d069340a1e0bbeeefb1eee09d8454f6fa69319cd16562b33b23449b63449d8f55a853f27d8e851a8738e1aa8490dac607c60d33f6993401a0a93eeca3af6b21e9638c241769e919b554a99a2e29f75a94e7a8cb7bfee8663a477fa9d21a0df0ce3662ec1b8967353c685315ea5f599258f3c648ceb8301528e2c0528196899ca2a4a3a8d9b6b3867ee437f7c1ed11ede35a1197bfa906a86a0ab89c555428664f8710d3bda35adaea98f70c36be3f297ad09a5ad31986bd89ba6c5baaf8b5f4f34d017defa327c030bd5f6dc9423d0907ce049b9be9a5b90192d1d8c40026dc17795fa2b2389a530a49b9cfb66e44e173b7e4924a9d3fb3e869b354cb9248042abba8ddc4af9b7b2f7d65bfaf9ec645c4e33efc38edd1428afd5d8088e93bc72de8d205de454f5d8e3de77113ea7af725068e308bebf82136b193f1e46720407a2bf7f31e072ca52a72eb18a540115f1db0a0b024731f8d05d23c3b5898b24d5cd421a598828472d4f3b7cd61d20d0848d49cc2e215dc13214629e3f3a50a4c4a0241c1bfaacd3c0cea11d2d84d98c6ed16c9b2e9094050fbe1b854d9a461840f782ca505043f817d5c2250e703198212bff0d081cc4e81070f30e7765cd5ea04588ed02d2baaba9b4d335352ffb8f73e6a148216e4584ad03180bf96cde48168a34c9397445dd9566bad4d5e6ee5fbd5769ba420caddff14427fdf71dce8a46edbace525b6c91b6dc4db8ce9280d93747883acb365062f51e6ed87e0a9313d0dadc6bda4be55c753c700136dacf8d04b2a4551d968f3bdd4eca1c76a68a39d74fa06684bc6e98e48508b4f395f1f878c1e0583d8f2f1ce721bdf12ccf96466b0806989acca2a56080f01f63690267f07f56235a3d62a3303e6fd54d26fa6999f25c12a476130b8b3e1b29813e0d4d24f5c399718854c1aaceef4c307d0651a05a6c272d2ac9ad14b4b185f650df4ef114c0ce8604f910f7e527d9cb7e3f1845293e4342295f410c1e35e049b09690865d76bb40f6591a901c813037a55b45742f8d9c9a5f90666b909be043c0c91575460f8853e68b47e63f51cd9081ecda79c25d0b84d0ed1a9175431693626fe8d06fa7572b0ecc9edd47222b27e157e6309d1c7897928f69833cfe8b7c4821db5766cad5c188ceeb80e532f6d1939b450ceec08ec041280b861346966ff13ea568847e688fc455e2454a0f6e02eb23a6b95ac04636f80bc86e9de1996da700fd3808c59eb02236bbc34dc6e51a3727b45060f79530d3b76afd60c6bbc2526a8d8d2aa836c8225b407e40f95868b56a9fa13d38a1b341f22e58abb5511528059e9761c5c6ab9fe63cd3055bf981cd25bd6940e125a6efe9abe34a552d7e58f8f406b948f963b1cb612b8c21e9d8097063fd53ea36ac9777360b347050c24d75cdef5ae69c995737e4e0542f546d399c838f8cc287d3ee164a67cb717821696d2308a0ce62c320dc8828a0397f7d3754998c8410ea37b9a0a6f82952c029b767736307262dff20cc6909f09259451f355227bf96924518d3cdb4c89147363dfc7abc74c28f6a50c15090f26b27d4a6ee60b759910a8cc82c272aa3c959ccd1c95e9a543912e8aa4c4dd469139402ef31c583a3179baaeae44978dfbcfeca37ae3568260d6242ded79f00bf50e3fcb11381a7ea61fcd34cfc7148c31f1902d23bee6c8092a61c92415cde24d1a330f1c13b491500271a6aa8b79ec6b4e443f20203c4d175affecc1bf29c92ccc06aed21557a37bdf785c25d7fc03f6eee454987561f02d71bb98a7981f868136c73bca60b6376e8789b9c1065e481e3652b51805fd8b4dd6e2ecc99d50d508f9af32d4a55531f2706c8becf3567126fdb83db7fc28ee9cbdb790f0d87929ea689f1c7a32c622ba78aefeb446e005971640d248d4ea418c27c14c3ff78db05f5053e85658d2bd24c9e3ab5a1816c508244da3701bcc139fd4fb8be13b50964a4666cf5a22b98e05c2bcab00f7c68e9debdd638db466bf7a9349472a2e91ba2c047a3e84540968bce209afa11c79a69814bf47b798ec8c7d64a95909ebb2bc69e1763a3ba7effe74fdd9a572bdcd127b41eaa2a9bc4a7127c767ce699d30a62324d370a9c15a2d6e4e4c7c0533f020adb3aed659c77dd28c528fa51f810ea0af89ddbafd7c0d4a96d00f18a306e2e92161ccb9cc5de6707355f3b9796e8af53e8d85f9be891de7827c024424680cf234220d52604eab982396854e9eea57100ab470268ac803cdc96f9a74c293a85ce01fd7bad9959d4f2fad381d309b537dbaa062ee7a9aa2f49951cac2ee20d35927fbb190945ed484a8d4f361270f3233a60ea2c993ec150010d76da1c180af03dbc4ad7bf6de02c6008ad1181a634b647cf78dcae98c1a8a5933c9c983531cfab4f85965e57a7d89bb278b4db1c2edec071c595c6098d8515248ce34337f9be637cc5ce075ebf1828060b49821deef52c33500dfe88948f16b1525219093f42bad306f4c3d2659b47dffee94e9501dfd0a1d821f2b7f98870d98633b1039ffabbacbca0fe657c51b03e58806031c2c558898f392f92597fd611bbb931f3f563c0ba808d4770baf1c8a23cb23265a3c4bb25b46a703a78e8c8ec4e6ac87d0d7799924b7fb1bf95f69e4aea5425e4365ce0dc647bdfbc53161165e34edd28fd7f4e561381c5a7ac0c4963d9895c1dccab5467c5cc34c8b0ce5ef1f44bc869fbc83bc4207540548261ce628a11752850e9c81abbfb2c862ed90aa02c5be292dbd53d7c4941db7d419ae87006ddadbd809669531e2b7a236bd53836d3d6cd3652e97389651772e50dfbf7e02f14843c29c40be501aa6cb80abd3a5f68c24f86b01054a4ed83c03388ce66f13992016ad6e4110d2105e8285df323652da9132c549b4c395e686c4d4e7a187ee2bc48511b57b9736df805fce2e846fef32eb41145a650fa0641ff91eb6f6257d7b5fb670a419ad23026aa1e0913ed655d41069000902aeaf96eb1009b30ec595b58f3e0203ad0e3c4636a290743bc05697d185e4510f27f1cd840fca61bbb1d7c5d8e35e1ff1a2763eacef9af3684c1dc0f651ab0ca675a5ca730cd5b4ba8bcfdebe60e9fd5e3b2d3483e1748ae4619a327a99ee470ddf619f72ae0c78a63b2cdf70e2e85300940a22df9c68cd86b94c1c373cd96a09ace0529fb664db6a18429666c00cff7d93397a81be3a7f6b174de297291554296f54647b0a3f5eb3f73b2350f58f23560c3c5c1594f417a53b997d2c2147b05dd967424dbba657544ddea3cdc6a028d6becef57d557c4363b01566947f397669d52bebdba860dfa090c405d74793126fb70706eb483bf1a11aa34f9a7048da48ad4096098885b9ee175d6f7780322ac91cf0c811b3da6e05061499f6edf0c89cdb69dc0439c3ac46df6b1ba0193c8ed1d837891875b31f9743712bbba5ded65acef52f23ee86a4724046f18c0218053363eed13aa00064ac0ca362a07aecfa2587999e9a8dad738f56539c92ca14aa2b9bdbc97d2c8c1913052eaf2253655a51700c0e06342668e7786263c6387a4da85e0ffc96baddb4687e09eaa10baaece191a0ac95346b7bfbf52f1527eb8184c6c963534db115ee538ce2668501353b507a3a8368109e6171b4c2a0ff1597ef281bd623d9ac4e8cbbdd601d3ac6361e528932461d7143988fc2183ac30b00e9552594e0235879037312ff7658712c71eae96e8f63194e18040520285b5985dd13f0cfdf652123febe22745677b9c58a5e200704c7939bde60e37cb538f2a846c8e64dff2062cb8869ff244abd04218706b8215204cfa7d0d48647429417d5e76cd3ddb50022a4f2e85bb6f161e9c7096b2b43ddb98934013dc842c0d5c1d4cb94e8516af8d0457b2d04d8f525697227ea07ae9d8d8b75b1b9bb06fd06020d441808313069606460d6c0b081280c362f33287f2967dbc1e2778125071b3ad591f4f486650335de73e967b10d9b89cdd65165e2368edeaccf274e06412abe282965b91629ed95aa51535eb7a28b85f060433f7e86cc5fc1bd9ca504cb4bf78fb9cf1cd3da9d80fd032c05dc8d008ce4000ed13720ef54ed2f3eedbd70dc87c10001842dc1ca8424e00093296d182941ddd23a91cd1000f71280694122cffb36495085885c44ad446588fc44d44a6486c80e91160810296993a89b584f168de2d237a701910a3263a1a6a41b8c8280850b1a970798ad280337210760f42c033b42bee1f4dbda81af8e8e64322745eb6903376cee30fd3031d881883273f5303581d43c6b7f7a28e0c64e4f92b31373f985f8b26102c648bde3fe7c3c1d9ad45b556676026e69f18f8fb9002274eb1516b18b27b6e442feaa694b4f3ff52775d81c18713a59751a3728d3cf3aec15c80840e993b74f25521427b683f08cf1a2a8e30cedb38fa4edf14728c480baee8cad3b57bfc120999f0c4578a35e7e38a8f98466f98625d04958d6d3b68b07bd652ea75a84bfda7d0d31021ac196fe0af988c809d4e64d5b500a5a87282501965c9827b57b8005eb28b7c96a92783ea3d3971f581b37322d69910a8a582a8d50cad0b922ac4932e07ea82a16352bc7e4458168fdd17c22152dc5b07cf423c7b729bdb5bce47faeed0e5ec70833c7be19de42457db7a1358c8693be362a6d8e87016a4d828b4d455ec2cddccde2dc8739e892d3d5bdb16a420c6ac83b8274ab4f6499b31b4f89f18f891c3aed015c2786515af29a8d86fa5623686ebdd159ca92cf5c86f6734af45439a5857482b1227164c18f64f532b1e70065ec00f4cfb82d7469ff93b1862004a313e61285471347e1ec2b9cda3def4208cf905ac66b58fe9ac8c479f6965eb772ecbcda2f9e4089183fd74e11a04206e883b21017f972db7d82247a66b6d4ba5ba545f152d44fbcf98e95b999aad592438aa91213c617608aa20a157027c640316a5ebe7b4d3e5688a499fe3932232acd421f6a326d302944ff9ecdb924abe3ce910e5534e0817cb2ba78e5eacaace45e2e2a354db2c2afb9b39db80c4e64b7c3f512ec547a43bf602fa4aba25879b67d07a87e2a3d4d4f3b1ff75554c339ac8ad32ea5f75f0614f9008e99359315519631cf075435de564651fd2e9c31763280da110129257491cca783bb7e8515678099345d80d8d569985b60e31a790218909f180a38ca017042bf1912165b1f4c4f67847284c3077e936b50f51243eaf241ebb12bdfb93618137930be353e125295940c601948e3385d9ba116e7d4a62a8d8cc4622ca32308eb0b84cb58b95252915a8556bdc2dfbba81cde3c703ee77b4117049cba053bd66e63f3888437eefe471b12c304e6ad8c1bdc4d5f8b8d39ad998394123fbef4da3e36b42df736dcc6b69ae63f0bd5f2ba511bc96a6f8e5b58438a64bcddcd096be2db838dbb2164c229a885425134aa40379440dbe81f35834bac9409fa8af5a16058da6cb04db5128667563c65342e1891492e31ff1889dfe8880c5801f363312c85610e284077ed54cfb2c435aa4ae86ada7df5a5569ea274cb1dbd9727e3dfdf4e2a8a7e4da5b719790152611819530ab59342ac6855858e2851da50bf52f26ce5b5e69aea74bd33b3588325b3598af4e39ae4a5b3dd89b30c769ee9ebe904f6ec143bd8d203216772baf812cc5bad767ea23d45d7538ababa4b27d444aaa80bc706aa666674a875f8cfe476b33a43dcf11a20673ece18dd9ea8dc1031faa0ef7fc21c9209cd8793c88d43c042b01c64c8fd5e511aa5c3f1ef185522ce660240c8322f5d9a9444cf95c4ce329735a643f3c7710d80bff1f4af7fdfab47eac3d6e1d1dee0a142e90aac1613913c12487c6c531133bd881677349f6cc122b7284368b996b9aa728e966b99c3aadcb7314b1115612f8955b58bbf4768e90480059a2772323c1f4488bd1d048f3666208a28501945cd23976de567e1cea134abeb1aa92b46be0db20fa783530a1714a44fac8d5f2815d7c9504967ad9f4eb9bd78563cd1d212fc02d34136068d06503a213ba40d49b0366441fa2cd493057b5bb0470bf660c1f5b20b837c9f5c1199056e7ae11b31fc4db83022b747091a0252760e014057fd001c13d21a6ada3f71c5e3547af5008cdc1bafa8f5a6bbb0ca648b4cf1b1b8959e0675e2c5637ace9d454fcf0c92097221276449fac838992227724816a4838c2b539f8373fa599a5e324026c8899cc922e9202364925ce4942c930e65ac33e39c9db3cfc2d3ed8c7d269eb37366525f7926a30a5b66649193ddbdef473b2d8f7d0bef35bb37fec093eb073c85b59bb1de23704026c5b44fb4a935bd537a8a4ccab49bec85ee12aae2f14c3b8dedcc50675ef8eb06bdf0a68a640e2a4f24b6d4209af44327e838add12bbaa5df74868ed0da7aed7e6f675d5c3efc86e44cd0291305a29094420d149dea512f2aa5c2ac61529aece6024ebb44460c3650b4960efcffffffffffffff8fd2887c6ff27f2b999294d58fcab9ce94924c29a5c87abb0580000000000000d04d4484b42d80080001360c380c950c32be6008595bbed76e5cb23bbc604e3975b2d27e51818c2e183cd488385d97dd846c0cfc21830bc690d5415e4eab2c22af438b87990f195b308fd7285111249d3a6f0632b440b260f89cd7ed3d96b8fe32b0608a20d4e79a1094a896878c2b982cae44f2d8a7ab94ead01e3f72b8775ac1e82b562ea7f3a7f7fca71c2690510593ef7e8a4b530c32a860ba0ed3edd8bdea49fd2106be0978f48541c614ccb93f07b17de1397e1e8c1dfd053230c8908271cc5e45ef9e8c387a13f0d8b165901105539989a4bbfa74aa5aa0b02290f1045390175fe36d363b270a64384146134c5931a922a5a4f5ff924306130c7b5a3dabd7e5d07d410bc858820c2520c962928c65d58ae21626e7eac8f7152cdd29305ff48e1f6180816424c1a45dfcd7a1c5a3023870f0e88104e375c4cf6939c7945a8c307af87030100bca0b328e60102968c4ce53659915e204194630e4a477b671f2928629a308265192f26d574e87160c6410c1a493f289193ad2a1555e206308063bfb522ab25ae94a76ac005b204308b6984e6b59e2a2436b05cfe3eb9220230886f19222724ed64ad708328060ce733a692dc98e7621828c1f986329a5e517238aee8b0e2d1f984e9d854d51917f97d2a1c582771e3b7a603e4b27224fd27aa1ffc1a34d904390c103636524b57f7d0786f1bc9274d0ae25c602820c1d18cbf4689113ea3284ff62e4c0604a4cc850fa617a2f311fc8c081215b12722ed3e31ec8b88149743e7e07ad7568d9c09421f53fad5c1621bf1a982688f4707d8f9997f040060d5e1391b28dacdcf2608b5998f3c4a986b4a85a57ebd09285c15eb5b7526e9b66c8a3e8608b5898622fe5c9493c5a8a970e5818a496e7f190b34e8e1d71b0c52bcca9cb4336579f54278be10af349af9b70a163b32e1d5aa8bf08a315e6170f22e56bb7b2a7fc8f1d3a5690e3c79b8015e652a2848cbd0a5ad1bc1b6cb10ab3843b397d395bca35abc2f49f42e860fb2162e55361ea97d5920927edc46936d8021526b12c1122c9ddd6f33ab4c816a7307cca99543d97bdf42800821c15d8c214e6f9b99bb0676d396ca53059cfacfcbc84fd3e91c238497930d5151a8541eb25191f2c6ce6e4a23067d97e086abbd65c120aa365e59ebd3c16d6c4a030c77d6b6fa79f982d7ec258174d84890ae2ba2e9e30db998f70cb35298bd60953dbe92a31312d54789c309e6e7a8a272e5c3db50953f786d7898e2da63b4d984d727dc82e52ae2d970993654c1a1326d74aa329a6730953522b3167ba92e59825cca13b9fe167a9ffe54a18fc92d249e1514c871825cc62db9d4a2cce8a8b26613075b9b5151d7f594918f5e285a4a265899d239130ff8e8be452da729a14240c9e5c256ea5f434e9cf91b6c5230c27afa146c8890e25f5c3470f31f0b6708479dd46ff8292fa398503c7168d3079578e9714bef46584b153b810364a7aa560151c3836b0630337bc78001eb6588451f742122161357b2b3ab47280d1c347ca91e3c70e30767c9156ea070bfe40b085224ca63eaa8d2a199de3096c9108f3a7ce218e85b5dc35025b20c278fbb12e4eba849c637708938ab519b3f5d1a1f562545d952d0c6108ea42e70579218c372a7b50f1720e3b13c2a07a92693b1321727610467d2d1522ab4910262dc95cd28de7b69502611011abcd523e01c2e4e9efb3e45c349dff1fcc714d474e426ab609bd1f4c232aee7605f5c1a4cdce93aaa550d17e3e18430825673fc410fefd1e8ceb414c6d248788caf560d2ac0ad92d6769d9511e4c26e952505126553e840753b635b5aaced9b27eee60eae83fdb913c97d01d3b18742f8cac1362ef731d0ca77f3b588ef85eb8e9602eb92d2741db5850f61c0c7af44fa8d0feefbc1c4cdf61fe34662f54380ea6142684f59451eb398683c92ee5c5ce65926bc26f30a42417e487707254dc0de6f4a01e414fe47c396d308712af949c1637b46c30e5f26cabde497554d7602ef99175749ad09dae1a8c15f2ede4aa4d83c1554d3b744e75bf2a1a4cb6276b6694d2190ce1fdb3da6454d2999ac16c273bb1d3da2799963218b6548c45eeac5a9742067308f7d913299733cd3118f48e6a68eda9d1498ac11ca3a5564444f52485c1b8bf3a218c12ffca83c1ec2a33c9d7835f3087d1989c9277f6f5d00ba67496ddf537ec82b943a56471bf37fa73c110e43a8bae2569aab30593aa5c6acbb916b43e2d9856de4ac50b1fba542e0b66493bdaa2164f8fecb060d2dd117ee296a13dbb82f9fd7d4dc65356305c081682f68668b55505832c95b774b0d4eb6a51c1289fdb838e9e29987405f54e5a42f8a9a5601c0b97d2f327319e8d8221ec98eec50be2270a0583fc1693b150d7957b8261262895b3a2bb677382b15286d787c97d3921c0164de0524a31dc24048fc96d593917534772ca703131c1f01f7cd7ff4b8c8ca00e2d1f3d72fc781360ed12cce129b5f78770d7955282794f3c8c1aab2c1ecaf15e77852d9260128b9ec3cb2a2de5500b4e0e317ec78f1d39c21043013f586070e0781e3b74a0068330610b24184290b1133674eeac901c373420811b473055face33d17b4fe81a070e1c595b18c1702da23f8914fe923415c11892d36be4082148fe8960d2185ffb4a6dfaa11d8239899e2e2513e286da72f04839c010a3579023478f1f770ad84208a6097ae6c42e547c82d01641505494afc69b50dac514fc02d073a0ecc748c17b0ef42ae01d5b00c11cd73b6c5f6559b7fd03d3ad09f16aaa4cbb5b1f9843bc8a3d3b49ea57d9a207f59d505555a905c2163cf8e2c85d512a4359c4d86207a6ca695fce3fae0363e71429ac7e69470ae5c01c4452eba52a7b75757060fa306a49dedb83c8e506e6318fa192d67bb6326d60104b699dc74499a9af06c65bd950cbda163430879295d729b7591873d3237fb04a0b59982df6c8cff1c3788612fb418b589842a827d1f5d3cf237b8316b030ec8e97522d95da93a3052ee82f8a85408b5718ae4a7890366695aae40a73fc6c4a72d23ffa766e85f1830822bb649315a6dc921b2e21e4ce3731ab16bc09418b5598527ef1d423fa4244548571c6cbcc63775cdb3faba0452acc9f44326dfd11265a04155699502dff259fc230a34cc88f2915d6f6358521cfe75628fdabb3b018b42885e1b2f7fe45f49a14a60e134cdfa828b1bb1c85395c5acf339eeac2afa2308eeabc48b9d3f45c96408b5098cbf7b44539edd65c3ba005284c6ef26974c3b49b7f72f470b51f68f109834ae9f4c7ab3bdd73da400b4f1854884aaa840a75e408038c318e560db4e88471945fb2244509a1d3ad43eb6c075a70c2a0539e74d5c5408b4d18f34c6507a1224fae980e2df5e2878f57c18f1d1eb8e1c58d09dcf02203ff0cf027560a2d3461485a232f5aeb3cef291346ff4ff2d292e80afd63c2d8e13c4493f1b86df94b98228994093bb2342b6f09e35616190d0f6779f74a9823e57a4fc152840739250c22e798a0746cd2567c12068b2fe5a2b327fd159284c93e0459f3ac643ae648987278ccbfdc25344b0b0963abb88b2ad13ec224223c789824bd76af23cc9293e571d1e3e6d1d2084352298e899810234cb225b65ef8ff7cf5220cc1de3d6878fc34a529c2d41d41df52b8c48f13618edf9cf3e01e57928830756d45cecb8d649b8fd721463b40145a1c82331591218c75d9794cbd2d43d742984f4e7b24091129e8130e1ca702e3342d0861c86be1ed3e9aa987e8200c9eda4f5f5032e2cd220883d67de9b3e471443c03610ae6e9df2cdc9ef65a00c2dce15762ebe133299482167f300735c1652e47889cd65a410b3f18ab2a64cbf1d64e418b3e18c55475b6b353d2adbe2868c10743f6d5135aaf5647655aecc1a464d632540c1145490a62c17e410b3d98735bcd2f2c678d11c181038c1cffc9c73f036e7871430c15ece80ef87813348f9ec03f0370e030841679305dd073aa53be893e3fb5c083219a051341854887568e1e583734d0801c28e8d1c3012df8b103f5f8e23980821e3d74941677305630154b295d314f5b1a9000056e7801868f1e490b3b1844ba9eb7904f7950578726d2a20e66f393d153a254c4d3820e26152bcd89acad2d212924d0620ec651423fc511f25da43f5e0c315a0b391894dc91266cdb93fe6c1c8c93bdd2e73c3e726d32410b3898c22ff57a7c9af0277f83f9f3072574bc3531be26410b3798472895eab3662bbc7c072dda60c8273227a94fdc15291b8c19f7a373b0aebd11d7609611f94295a67e75eed460f408c254fa9a4e923b70d0220d46afed30f6975375d7dc062dd0603e35ad382af94688941b5e9ca9418b3398f3fce5152dc2a4e792a1410b33183e524fde3199ddb6dff0a2c6a0451978ebedb2f2fca2f722d6879324a61406c3a7df8df5090c061dad4252b944ac17a52f18bf928e233a0891523679c11c93c4988bf6d1c9a62e1882c867852f53b2b4c40563e918931afbf3c1b40593d0f13e4a4584da5c0be6f68fa3a498c58aa32c9853d788d2794f941661c158ede37eef5e2a055dc1146e3c7ddd862419b28279fe4bcee8fbab6090e62616744c8da07e2a18c6624c2edca510d69f8249e95dfbe0f7e1ad7c29182e8cd26b23cf46463e0a269dc3c272fe50302825ce2b45f34bf67982414fc57b0f2a77dccf0906ad274fe85375555a134c3a8708593a449e5039130ca67f365b72eebefc124cd992ec7f8d9460f2fb5825314549307ad67a4a592349bc2024984ebd8268af9d8c0b3a827945a276cf858c609025eada84451e9b8b607899d4bee7fe612b870826bda2fd272c4dfed2108cade9ae2573fd742e0453ce2794d899dc9377108cb91fbcf64a290f910682d13d4552232d5e9fff03b345d5105bb99377da078664559354277c52ea8121db0753ab5f7d7df2c020bf4c84a8d7eff9db41e168020d1d9893105162890fd1b9710e4c49d32575c8180786a0bef44bd27e55a51b98c5f75b6e926c609291c44a50313fde5f03f3e59cc2e2072d0d1a9892febdd42a1b4feecec258b23c4cc55b656150fa21251593a4fea8b1304dcaa3c4228ba70b515898267accadcf6c0f7b7985b9f5f23ce8595d798a2b8c1d5b56afdee1e45b5a81865e532774921586144ab4d8d8f6e55856618e89be267a91fbb4a20af3e851a1c3ab877b2815860b8b93f20915d209156635792ab77592489f5318b28bb689acd3144679718fb91475bfcd52148e19a4308a57aa5b4a99fda65198440c69a1f2c6960e89c23041b25ef6271426cbb1333ec2a030669c5afbd04974c99f30fa6ac88868f93e56d0139d309abc4bbb3e274343e484410961a3da356ff2869b306875abfcbd5013e690f357055342849cbf4c60c268d13326a99cf025b74b9874a6c911fd99b6bb59c29c3c884d0d9d44866e953068cf9de81991db4246893c5e658859cbe973d608332661d69850df7d41a77b86244c29528f4d8e15260445c210f4225f277123f503095309b9b1a011b7acb247983d674f743d0f92e208f3a6c4d4fa485e426f84419bd7d68ff43f1f19610a2a75e53849c482482dc21c16f4eaaa9a84982bc2b45d1e5f553ba2a60dc68c44983be864e796e5647f1061ccf1ae60123dc40c4398a4e50e2b9ef6ed82448756a92f9a478f1d5785306fa530aa3bbb88b7b00eb531f80433086188a35ea4c596a7e8fa8c4118d5238f05bd386f396c8230c6cf5a85b6331046ddb018eaf3497f889e236df978318e0033006130d78bdc414e8964f78c3f184b4f765dd6f51f7df4d0f1638caebaa10109e01066f8a1cf4962e75e32ebeeae0f26ff537aa7b9a227e5834969f3ab1cc242f86e0f065552825f0c911ecca2cb528544d339964e1e8ca33e495dfef849780e1ef89a64415a4a4ab98b7807f36ee4135ac4b2f34d3b9cb25809e9fed5a190b6e4fd4513f25266c20c3a18c3b2c7cef924fe7c7330c90979b6b4b7f8596c861c8cfd97221d5ad21c8003c70d0d4860461ccce51546ce2819a2b28203b1cccd2a588879a787a524ad9c9b5e1f9b958f1f61a861c61bcc2985c91c15f2575ca243cbbfe8f1801ecc70c38c196d306a4989db7d2ada154d9bc106d35cccfb1625f2dfd83ab44831054090430033d6604e9e7447f850b711e42c84196a304ffe1cb23f3c92e7c98c3418ac74b22e11ef4907090e1c3870e0c0d13ec6e81968b825857dc81354b2a843abc78f349f7106f28e9bd05f1dcab34d3136c5c8007f608619cc55e925f731544a1a6ee086052430a30c85635730830c61cc188329d9c87e49d2728820d7a16580196230e4122a7867ee684e4a0312b8810307f9c18c3018dc3e3eafce25ffffc1601a197eeab79d2f18d5cab3d28cbf5759bc604caf53714dec9c2565170c22db079d2a642569c805b39fc6dd64b336ff666cc1f849747a74cf2942cecdd08249665859fe7e551b9314db8c2c98a45e557f927ce1546233b0608a10473cd89c55a490fb30e30ae6d0bb6a9f99f45d991d6658c114a6b3e73af9ecab38d36146154c492fe5d8ab6fa9a602e00c33a8608c518bfea5840ef2f41b5ef461c6149890b44e4c8f4f1b6648c19cfb2147496f414d4e6b46144c41656fa9b0154a07bd176640c1f81d7412499ea494ffc486194f30c49617d5dafbffa934cc7082714d09cf15d76b82a9b2e699fab0a4df2530cc6082f14e8c89bea518c2f59fb1044338d13a22ac2d82194a30e49cc6248884a01742c418a3c3c821c60e6e818f1fe30238706ca9624612cc1d63fb268b30155aa4438bc78b5139988104534ff28bb0358f1ea52aa0a5987104d35bffa7ab4776f1920e2d6bc40c23983f6ba86d9365b6629addd040038c0f338a505cbad89e2b29443045ba2472382192a537cd1882d92c9fdbe4dc0d2f1e8f304308269b3def5c5d62b456403023082691a2f6243523449c3e030826554b428a89084984cdc630e307e69e113ad9dd7c6c4fe1c0e163475b400c31ca15337c60f252b1fc3ea558e961a1193d307bae9945ce7b29f97c43030df8b1438c1d1cf02f7e070372e4c08103078e1cc452318307c61256722a5f2f57590670e0d0e2cac38c1d98b30891f4f3bb622dae03935cbe4b672aa8bab6941939305b75bf07ada2c2b636030706a132421223bfb43a35e306667349d739445fec6e0d98610393ce7b9769840ffd7a0d8cdafa63914eab9bf6cca081b176db364e2779aee82ccc4946ceed8dff08a693210be3c559172177413bc5636194f38e2b278260613cd7ce31d2e39da6fc0a94aef8fb9083ee09325c61ec7cf23a3ce4e6faf60919ad30658f9c96142537bcc0218315a6999073e4ea910e2dac406291b10a83acb7549adadb2e4a2f9cc7175ff4c0814355610e42c7f149e6e9d022960ae3d9e892a3639f305161167db7186b61daa7c5ba828c53a83e76aa4445047bf4d091e30bdf61860719a630480ecbb94eaf2c4e2cc8288539629c6e8f16d7a1556490c22017a9b3e4725bb3d50b1d3f7674408c2fbe48c00d2f6edcf0e286173732a0821d482a4761b4b2a0c4e7876c42045114a694dd43540f391446c99e647fdc49ffa2224106284c21e662c4c5f809835ac8ba30df19d5db138631b7ce412e44cd8e77c214ea1be1229987105e4e98f3660469bb262f4b043761883ef239a424e652fe6568c2142ff2b9cda92492ac3361082a4ac7896b1f3552ca06199830697eafa59438bb9294a606199730a91472393fec32ce34c8b044f1e1b533934483828c4a18238454562a4d2a7d6f0b3228619654df9fb3f6c4c93f13644cc2f8a3a299ac1b99f2519c820c491874685132e6237f098b181d0973ce9582ba7e114ae78a9546410624cc397b4fd01e27be82e8112699a49fadf493490871842927c7aa30c16b84c14d9db814132e7d106530c294535055f14347c78f1d86b508638cfe6aa8091b1f725610321461ce0f95cc278be534aa1f850f321261fe380badf7269a21727490810843184f1b2925ed8dd172d4231e3d78941b641cc268b5a293fe9b0b13711c38725496187a906108d38eb85162e96154f40b6152295b596f48ca1631214cb9ae944ad4532bba0ec2587b29b2abc3e5944710864b89912bab2d4c326504c2f4a22599c908353f512b62c8008429b279e9cf130bad5518eda3037f307fbcc4f8bbec74effd603aad350b31e42751ea53c1a9c0fa60ca29fbba878f947416e6833182f7972a9d2e9550edc16821bbca7e9c6fab8f1e4c25f78456ee4aa3cc9307e3bac82d51425b3e7bf160f4bcdd799797aa454887965a828c3b140e956107930862593b5adbd529ad83412e3dbca9cedc7a4a87961264d0c174f165a636deee1fcfc1b4e1bed6d1dcc2a5580e46577d8bd955da3ed70641461ccce715a247e4a685d02e1c4c55791b3176bf2ac7379852f2527d13dbb4c99d4508196e309d5e9494c3855cefa71b1a90c08dbd3bc8688329447789134a847ab4d860086e369643aabf20630d06d3ab164fc505196a3099c8113b2ed7686d4f122bc84883410909e95208299ee98c06438af4a9e4d9a4d39f9d808c339894ead8ef3956e7b0350f1e0fd811460f0dfc1829d8c163033a7eece8000e1c26e0b1e3c7183d7ce0c0e1e3cd60d2a3eb391e2b88e43c92510693a84fead6b1db316e9c1ce3c60d2f6edcb00006bcb8e10fc081c30212b8e1c50d1c3878f4d8f1c3021240934106938f29edb916513c3e7c7c8e301a0c6519633045fefc7471afa4fd9f500632c460b4cb712409157eb5727561307b2ed91a592343c74d9001066307ffb4506da3723e468f93429bb04cc1e05993432f220593fe892ef1588a8249f642d5758a9ccf74a5810d2818a2de256dc154a594631b4f3005a57b2c7b6ddca897c70e1b4e3098fc29ab0fbb8d26186dfc4ae297a7581d31c138c1db5358a99760fcce5e5bb335a244af049338bddfd5585127e6eff0a101fc612309a638a722e85cd9ab944782c1f34f5a374f5727130a8020070f1b4730a7cab6b09775c17392114cef1527b6adbc2b45304a94c97fcadf3ab8fb3688602abdb1e2794255bd3504f3e587cf0895297a9484404e9e93b9a52de8e1e38718ef6a413067567ff6a9708fbdb16047e206d80082c14c9427b359316dfd07e6d841c7eb493aa77d30bdb0e103b2840bbabeee8139b57c643fa52b6b877860ccddfdb1dc9dd424ed173d72bc0f2d0bd8d84127529410baad723d2e810d1d184bdf4bcafde1937e6e47056ce4408b91f76534ecb64f3858dbf7c4247bfa8de8d0b27103636c97c43711d361c30668966f7687168997ad816b7fb927a6c2290bd9a081297c7cb88aafcec254c12dd8cee994e654b230aca82c51ecd4669f3c16a60d153a9fcaa8e4e8ead022b030eb6eea878c32a52ee815a6d0f31c952fe474dc1506e595e553fcd22263b6c254617977d262d7299d1536a0062b4cebc95a553e45e598afc2a44ace6304f56872d6508539f7be5498e3cef87d4950117c820a7399d5968aa4e4f97fa7305c482747e5689bc254a1bc8436292985294d8638b7ecadaa954981d611a7fb4dfd3e7ae4781e3bbee0b1036b8cc260f27241e59cebe324573fc600831950431426a554cbdbda6d49d2c9e1a3478e15b48fac5098449b2559417e50183b55de587f3491c4fd845172f04962d259a41250c31326d931a25cbb69c4c0b8ea8441cc8b2c112972501d7528278c3f27a95626a55d52f5f8811da8b1098330f93a3bbaefc953ec050a50ffc8808f0514d384495f859c773f972ad5eff0f183003532611cd7ea1ca93e4eaec7043530611222561a3d218a0ee9f4eef145a97109e3bce87a90fb31a1a52d4b1872cab57e1debd2fe54e2501734e4828a52c2202254949b8ee63ba3496422ea537c477bbcf0a22c06c00a3524916d5aebe54b8e732a913067e6ff08d9134aa4051f011d62b403bc68818f1e60fc04b4f8a106240cca6544b8bc9fee0f070e1c38321f61489dd536d4e8c7d1d611a58fa79c92295d75a0f6a21185a30623cc1e3d7cc5c9c832a754eab250631124255f215b96861a8a30d525b3b150154a525e65093512619c9c3b251135ddc583a48a500311467def2c2acd64fbaa09077e8cd1a3052d0122d43884e15d2df4ed1a400d4318a28ef2583a7cc84a6f214c979753d985d850ca25844195d0124b2db509f90dc27026d2fda739a5c65382307e8e1df2fde7304ae8cf63053d72f4f841017cefc103b74620cce31b26522701c22cf6f15a2caf1c618c9103053d7a7ca176811b5e707d515450e30f66dd3adb4a7e5af22460ecd021068effe2f40f151004410d3fe81d3f89f5b20f47b90f1f175d7664e4033162ce45313ffdbfa0c61e4c2f1f2f4d5d7655317f50430f4813f51a9d9da72b561298c016dba0461e8c966a67cd2f88ded58d900703ac6ae0c1ec17c9b2ea5ef6e756f650e30ee6de8a92fa849957bedb50c30ea68ed6692d8cb6e4bdcdb8461d4cf2fd3cf578e5a778c3c8f1a3ad6bd0c158135b4e4c3a8d144e1d5a24a83107c3aae5a0b4940e22a6c5e460f612e27954362f754b183b5020461c0c3bb6292a4cb669da3ab448a971a0061c8ce731474f68fe88f9cb1b0c226f259554861ca99230d47083210825c67334f39c7bc951040b35da60f6dc972da4654922a86f6840023770e0b8420d3698fe947fb8e5939aa51346bf036e7871e35db0c3046d811a6b307b2959331d961a6a2852bc53322aee23a635d260ecfc9a10b4b607a88186f5b4ee44cf609693263e27a3066a98c13462165e91b70bd42883b1b3c8f458a16f3984a506194c39e364e9143d8c4e2a5553630c069d464e87b42a492aa544a08618cc22b2562276c4132daa11863c755885cfb2256ea006180c723e399af652ef59d7a1c563051d8618955f30bae7647617494504690d2f184ee879b40ff69d1ee9f183c70e52d70573c9897cd6cb95c4a23a34470d2e98f284247b47f6c47d7e0c3072fc185fb40ad05250630b85cf95bce59a5c122b6b68c1f8396f94d0398f1dedc38b478d2c982e549ed9f54bea3f8885add37cae31bffdd2bfd8a1c30b1c382c20811bc400a0831a5738a5895421924e1303a386154cf9e2b7da8b5fd4a88227bf4274f79c1692a840907fe1fe6905a1c6140cb2f44d92a87f22844f0a06553a9f08a92395582b0ac6ff9ccfc9be46574728a8018582bbc5d6a83c411b396216d2ac091daae104a3f5a589a182e59ca46f8231d26d8b2993ef9dfa13d4608241fefe856ab88b1a4feab2a3c6128c926e945e9db80e2d1fff83c72bc19052249720440c912c9b6a24c110fef6e4a988842bf3336bc289cd521d0c6a1cc12445251d2392fa358cd099b04bba222d656419d42842fa5c5e539474bd356b10c160523664a81c77d6f7342daf310443163b7d3a89137e419aa330a186104c1e26e88533fd7fff8aa046100c3a98ca76aeb14f5a0404237af6783a45ba3ca2c60f5049693e7aa41c39c478efc1c37e8c510107e0c0518a1a3e30e58aed263f6ef5942c871a3d3088912d572a44b20d3578e027f17493dfabb103735ced77a8990a57971a3a3087943f5458c9a73ad960e4c033d4c881d922fda928fd19e1e339c46852622440af060e0c179e3f9b87d00b356e600c0b4a4793f74f178cd72ed4b0812949df1d6d6abd638735307d8f4af9ae4e09c9162ed4a081b947c50e2a09a15e4e3486037488d10ed02146ebf8a27d3c18af230c830347de2c8c212c52775bd29fe6781e3dca6461f6bfdc2a7b3ba1b5d6520004390a402316e634e194a7240b18edc3470212e03c3e011cf8e28b0623035f7cd160dc6981062c9c9c73ae5675a0463edec7991368bc829c3346992e9bff920e2d41d07085e94fa7cb2e73db772740a31526954ed5a893af0e2d14fc8b81ac30975c18d7ac6c17dbe34a0110e470008d551872cbf9dd4fc8e621c80c345461521f4f24d1e5a9fb16038d54e4a73921c9ca5ec1da916305ed637d40031566af12a7d3acfb76ad5314219f09917c6cae44caf0950a020d53986754b9e874fb90d26c5da0510a1bd02085d1c3a5df13ad9fafd71f6f82bda18106fc0e1f1a50c002c0a0310a73c8dcd2a33c2d99ceac1c804301bfc3870670e05851983aa66d7fa5a450183365c2c5abda9af280c2f471d7bf72752539190e1c9f30296d4a694790ed1cce22030d4f18d47cc5778e36a94d3c061a9dc03d4dcb2ab897881c6d25f6f5d161bc8f30d48b0caca031b0464c063438613c51266e4d45a408343661f059f5a04bbec4451b8940431366fdca7dcf7163d2c45a9076fc48cb8471cf52d4fa6c75685565810626cc394bde3e1124df098b0b342e61ca2effeda87ba2758e1e89c7abe07d9c95818625cc2112c4e8add7d27d791f581a584163a06c05ed4302342a61ac5ac92a172f57e93f0337bcd021463b602d8c06e3980220c801011a943097cb9588a6ddb144476312e6cf27c9ecbd52aa3449c258d9fcadae258ae552240c97826765dfaf58c9878479cfe244ae6f8d6efd11260bb3fc68e97e270539c2a0c2c9bbde11a722db8d30a8a042f3fd466ec66684499a276d62b45e84e152d85af913492d164518ab5256a7f510c2f3980853a5892343a99e5069448439dae8ee0f3d514be50e619e496272a2ae6e9e9a28a061086388fbcb56915408d515c2e8b3d55797231f4a8430e90a7d4a6245cf6ab11c5961f4040c01340661fadcfe97453541d457f24f4ad8888f1e583f7818b3301a8c3b340291eee4654ad51bd00084d1f8c37d4a45be7ce7eb29411a7eb0e3c8a4cbec35097a0660e086d51a68f4c1543ae5d3c9084a528ef1d841830f26c9a52dafa6dede227c008d3d98e2c76c46ea91e2f1530ca0a107739e144c04a1b742d7d963051a7814f4170a1003078e1e87041a793049c8f1b3766944091d1d8a85a583061ecc3979b476ed088d3b9852d4515d794b72cbf3020d3b98279e14714d6fc9b9a4071a7530b9a5ad7f38f921beb581061d8c2a2a74a9eed892b3c6061a73305c5e5910e97477d2b71c4c171a274aac2ecfaf71308c0afe156a42e868270d389874aadd129d722a914f1a6f30dadedaa7ce6621f97783f944333d7679d2f15687968e80461b0c13b52eeeb7a738f5d16083492d788ed12372f2d3d660caa1dad4472d1a6a308e8ef20e1d9d278eca6909288d34182b9dcbe98d243ddd8206e3298b35e22e2bb682ce60ee971ce6eb7ed5e5651c689801d1b32e4abd153c8f2a1c380a216894c12cd1265c96d16c097fdff0e28617371270430312d8000e1c8767a0410693b8ec89f82989bff60109783076fc00038d3118f4497df3eca81da72406932475e26830f6769a9c7412f14e5ece60b42f29625732e24ece0ca690b29f71225e7dca3298538de796bc351a9223836947663cce047dcbec6e0c66f118ad58b1c6d08518cc7e215b5b1669921a06431a4b1f8408263018d62c249e2a1171dd3318baf8824956f4641db7a0dcf35e305f8a914709e5915474bbd005170c237a3b692451af276aa18b2d987e4f462959d182297479da6e87859c9845e8220b8b09392aa6a89073ce16bac082f1d4af0879c1fc2cd2573055f80ab25348ce1a522274618552b8d8ae4a51726433b79817a5e73d5cf9f758e8a20a260bd62772b96fb1bc2074410553f9dcde958974895ee2144ceb63d944d8fea04d772705a3c987dbeff93dd7d754605130889435bb6bcbda4edf0514cce27aeaf489a4271845899c62891482e53b39c1a89e7a4177a834e23522852e9a6048df1a263c8fd08f6d0a5d30c160113d89b68c4d7fd112cc23ef849a70093a59100a5d28c1f8923ccce8709554971908ba48823164084b62941a9b5ce1c08103075617ba4082d14aa43eaf12d94545f108c60c791d215e756104d3cb7b5aaee9b5ac1626745104a3e7526aff3c448fe5218239d889a4df7a1e82c9652497484229953a672ac8612ac8c15d08c1a85a21e1430a6f0bba0882c13da478c976ba501110cc622162440941a5f6f507864faddef20e2654ba74e103a38eceb994be3b11d6d403739bead57c51fe154d3c30e9f718bb8dd4c9837660d26ef7163e483b9f5f0786f9911797eae7c0d8ea4959367d5b36e3c094ad73775ec46f609e28b271fab781d1940a69e369c452e7d4c09825dc93c7bfceb4ba0b1a98f4c94792772be22fb3309d1615d5aaf2e91861599824e989d99525457f636196cbf20c4b49bd220b0b739c5dd3d77b798571267bcc15062194c9b8aea6c50bb6c21cefd2c87cfc5861fa709395f3534eddd92a4c32940911e53a92bda50a934ae192d8a79718499b032e5261f4d06149e9adfab81415c619cd0eff5449a5e49dc2ac7a1ed29ac8712757cc8529cc21f69d3aad3ad1e7be808b5298d2bec73f5f8c49f196643515df744b0110e4500117a330b748f068c96747b72c463117a2308499b9cbe9e4a1302479399e5bec10e3d4a030f929799f438ff64ee94f984fe6a9b394145722f48439554ab1546676c2103c54f0d4f1d3a4cb09a35790b359d242ca966dc210a48548d9b3ab54b65613c6fd8ac9219b7afd138d910963c88b31c9fd8409f38920b27b07a13ae87e09431ed7b81153f13a792c61ae9336412cecc70f57c2a85bee4946357e46a684792dcca8d4900f6fdf240c2e1639b6ed250953ca3946a56ce1f3ad2412e6544a7c72d45232250b09c38e8f78d1ad5dfbeb234caa2bfd848d312174ea087388ada43b5a8de494d208a3eea8e7aa161961bc58790f134afc9db508639f9d56c826449e9ae8e14211c6f288b5716e39592425c264712ed6b79c4e297b106174f708fba52fcb5cf210668d1c52ce25cf10a653b1df26e4b417c285306788701b7ad2955eb92084397afed5cf16e71f498330eea5d39bd7e9f17358102639efc17d74ee4f6803619212948a15f92cc4a880305b74499252292df7297f30484af36b9bd30fc60ee27127680fbd2df6c1182284042149e3734fb8e083714e9c1cbfb0ead0dc432f2adcdb2c25055ce8c170156fd4a98c502ae7c1d4c94b5faf96af248bc78efef13e481d800b3c9827f887ca8cd0154ca8035cdcc1d8d559bb2a516bcdb68351a469aa44d3c147c975684d7bd221f62d74307d4afa82789c6429b23918d7dfbb3c3f85f66cc9c1fc6a2e323c290e868b6b11c994ae3093c0c174226d85dcd8d688578716c7808b376c23513bf54d0660e0866d10b8704351f5730ca582d68b29b6e1d8503812176bc84f3b07997b22cf05065ca8c19c15c53b981ef352b948c371818633983decb53cffe80dadf2e0c20c65e0820ce68d98135cac432ef975687106b818031762281c18e0220c25792247b780551bb800037a629f4ab22faefb8239bf54e948d0293eacce85170c07175d30baa756a8ffd38ef51817cc17e14ff6bfc52e9d70b105a38794bb9e4ba405439e90440eb29e2c982de65dbcfe0b93ca830573fd88f80aa6129d645f1172288dad60ee54c2f3daaaa8986e158cafe29e477dbc934ea9600c8b1a663a2a533057fc701fa6c4cc868a140ce2d2d2ccfc1905a3e59517b97c49de07a16052e1f465316d7982719405afceb52ab19b130c9e53d5bfee4fcaba0986a433d573ae3b7ab4b86082b94ca99f90de5f8249bfb25ea7da9e7b4809c6fa3ced2784f810469d0473a4f86f3a799f4a949160fa2064e7a0bd83be6f4730ede6967ace13d721c58511cc77a72bc764cc45118c0b2218bc6b573dfcfd2c7b968b2198c35eec8a33cfe9b2bc75e04208e67893f3ce635ce93c291ab80882d92b299d929a4b3f1ed601174030598821a394ce5ebef20f0c93948af390fcedef5e0eb8f08129eb26754851990978ecb8e1c50df4a32770c38b1b3888e1808b1e1824c44f4fba2d073dd31909b8e08129e9285ff2ed4e52f8eac0c50e0c672a764e49fd3a30bddbfc05a5e7c090534e77eaf6ff727e70602ae927c54267d50a3937304ad239b6599738eddb06061541c83e59f9ffb9b9a88149ae7bbed694a0b4ca5cd0c0f4e3ff9f575eab559d8541e6df95672a0b8327557af26b5c8dcac5c2705176ee2e8385e9fe4f6419ed10f373b8020ab0f10a539dec59e7fac58edb1526b5ec7a5e210551e96d85d1934cd35d174195b4b0c29ce3e933da3c26a5e02a4c71db9252e496111d55984e2bb9ba488bf7a5c220397409e95a4187104385f1f25772d01f611faf531852a98d105b21bba6c914c69ba472309dbac472bc14c68a687be31f77ec6a5218fff4c66c844effd78dc21425988cdf505a73335118accd2c34dd0a8549750e1a4a85adcff10185d1447d1c4fd9d1fec4363e61b4937da7bb69199e270c3a7bfad4e2419212f94e9863a8ce06274ca7674936376468d7c6264c2145b2d86225b7c3c786264cfa797cf7bfbb53884fb09109574434ab1cb53ddbc08459edb292240faa335b1f3d6e780106f2800570e0402c281b9730493a9597b98f258c22ff734a1b63f2835a09b36f29214feee83115a2432b058f9e035afe60831226f1523282aa1c361e96828d4998d3e8f8a444885f22846c48c23cb9245d58b687534148b01109c3d59c641b0f3944cc06248cf6a5effa3b7ca6866c3cc2d49e2fd684485dc086234c4a9f14217374e5d0fe4d7029b0d10893d0aa8bfb693b87d57a78f5b0c10883b0c8de651fb63e692810a327c017051b8b30fa25df09494b844abb0d4518bb4cbf77457c885c6d24c2181e3cfc9dd4309f30220c9e93f0121a56af351ec214a49a16a5661f0c3084e14347a4aacfc536dd033210c618fe0bf00f630c7fe7828d4298a44dca4e77499d5cab43ab7afce0f1000da00f2303387078516c10c22ca3e457bed69860631086f8492b7f88916b5b2208c3df25f716217ecd4f360261d4ca6142994f1821260ad8008451764d48bea0cfc6471b7f3065fadb6e79aa84c1861f8e204f46e54c57d1c7f3e0b1237f60a30fe6af93277252a95492bc8e60830fe69195543a112dee771bf8d15f3000070e1effe3477f918a60630f0679baf37934c5d2c46ce8c158ea259aadfd44af78d9c8832917dc2359aa4a7a4ad99d69db2fdb47d9c08349e5d592488bef6034b5b5bc30aa938ed20ec64f39443a15456997570773ac65ff7277f3942345041b74305ccb5958fa768e31cdc1282a96eed6658ba54a7230ffe6e7cb895e39f58f83b9826ffae532eb4b3f1c4c724aa9da9b90635efe0de67c237de28f2e7929ef06e3bfc90fafdbb5c1f4a5b26548f2cf2284d8608a286a4ec70b21cee5acc19cbd7f42e85822df78d4609e09e7c9f39bf4de4e1a0c263b5cccea4457d3a2c1a0ecc7b44cd4c7dc3d83293c8fe4b524c7fa5c3398fdc476bcd1b50c267579bc275e8e98aa643068a5d293214b8aa59431984fc9180b693907991531983c5bc7cf8c4db41cc3600cadaee31b1ff252080643c82942bce4ef0ba6ce9e161f23e8657c5e30f99ec452ffaba6dd75c1704ac5da7d23a67cb86092cb3aa3feb52d98cdbf3c5592acee6b5a3057c8dea698d887ccb260ce93375b693145898d5e0585061b5830e828e163e59b5dd05ec114b4355594a79d39cb0a26212b4fd9b5dfa57c150cbe3d2a053d51ca83a8601a917d7af653018f54a894d025335924100743c15010c4403cbc6d13130000100c1a92c662c17848268ccb0f148003543e2a523e2a1e262018890503e140180a8501e180180c06034261602806c349a28751d20310f8b499e19b9d6bac49a2423657152f5569d5e3c380512ce05266d1bddd8312c362bec94777db72661ea541b2ac36b3d306f1af80a70ef03dba974a6be65752e034a571120bae82e15cbf6eb5e1d18b8b7d6154f19942a700305298cf2e3415a7267fb2961ce7e5e56f2d1d53f4edabb0d3e32e066c7a12232aab4beb137361bbf130dcf1390fe5319d83bdd9537b6025b91e92be782e07ec432bf114e140259fd046b6fab2a22f3a7e06f1d24f435a69f112f44f9e7f906520d8e9a5a2dc07813d937072cc0fd3199897d87328dfce1f6e1f6a861254fc2ed413e7c7a5e1c5229016c2f828b1a9a733b70de650a90d572f6c73a196b17fb05c8db0e6402a0bd6f05b872ca89b00dbddffd5b68524d40cb97695066edb939aa4f00a09e6f1c10a9c856e64312afc5e1adb219956da22a50ac3a67a477f99a43a9ef7178bd5d75a361e08a77379d190bd810b622ff7c671dc052494eeca73c9adc552ebbec6368d3918eca3e642911cc289dfd627fece88620e53aa2f87fad6bf6fc919121d98234ff8b1515ef24a33fae3c07196c2ff76baac70d578fe92040146a16e358123ef8df6c684c0b16e420346674d8dcb9ac45af489a6189a4832f5a8bc3bb76ce929b07e326f372bf3f21f455e5b6b0290e1eec65e6cc5fe8d645439538fa8c1465ad14a6bf2c1620a41ae8c6a00553950493d2386564935d5e9a8f2cd06d5b1965aa59a6729631f7807769268858738a4c4a6dda019a84a0ef5e459815517ed0d05ac5346a7cd294869dee33e01d11e8d836296db82495eddec12b10e683e3deb459a05b37ba42c79b44f1da27cbaeabbc54e4706099767991557a93dee0a07a70d058ff86ec48bb1acb54a39af575cfe598f2d6d61e9cdc773081d13b51c68340462a8c5bcfc611f15eb58c8c7ad925e962e938f58e5a376f9231bdf712310c02cb86e384438b5385bc9284f3d7db9d73445c3b40898941cf78d6ce1ffa37fb214c5de568c3dfca68a7db66adf664c7e84dbfeb905cd1ce96a5264ca05191612a54651311f061b891055b591c0fb2200155011b0ce43134029fb3f005028019445046f5705712b21be2accf6e52206e0ef8e38d9fc78937c467586bbe0497c57751f58f907c76d3a61d3349ba66dce9ccdd8df06e383cf6dc2c566c6aeab5ea9c7aca650ead4c37cb60b1a56dbd09bae6198241209692381d0b761954cd2fc2b6a478d8483db0edddddf3f0b8d5279a71f7b3a4c1a3f3a0d52d0029b5bff1a4a6fbbcbc2a5b3d15cf7261daa45536d6427c256a4b7b4f2eb147e3e71b59535edfae4bf4b5256c21d7a79e966e933983921f1be0ec1e111ea3cae8132e18f5b8181c0b5687972090bd9c5d9722346b2be794fc7c3879008da71cd91f6564c9258db5f40b58bc9d26bab985f46598d0cd6854fdb0ee72bb560595aedb7cf488a53d5bbef2a852d0673b671f076a6c4af980a645b4e8c863a0e96640a64c78e2232e174434370784c61e35f96174dcb54f7a823385adcc81a612f4636a9143b54cf050cbb38a062ba61c1648392636b97c5e2972ee0fe25c01c0f4e2c871d25bc73538d344e653042bf476ed8d971368b34e5739ad260e9988434bd9beec966fa7b9b0c62ec605e991c665ebc3901172e8e862f602ac89cad4f46647d5be043e51074a76d8b08fbb52c80d6af0c78cfa4e3b1a4db49896b0afb556af762711aceeb0a45e94a8bbce25085ca965cf59432af3a11bd7823d4965a751b7b915db0c63c52c9dd869b642d9f5051b4468b1ba404c19c80e2d28b0df68d3b440ed19d21d3239d64c90fa8832d2566e7d55f9715a9346e58b23f6727f5a6b5e0ff2e6789c3bb9a60037b1526127773261668a3aae671275fcb71fa47779967121f1a97b2cae77456676ebc1b4639a50153a22b0c8cd0b27072ea0a64a430036c5b451c4766100855e6269830bc00c351cc090e892760078d2905276bb91950c0065c91ce663266ddd5931585a07a827432558fb4464a4f3a4181466333a5b0b810d0993edf6e0a9a2a40020e3184b2cf5184f54e37f76ad388e3b72bbcd47461b339d8a51a92d097d5ae450fa4e32c8d36a703c96e61a3298c4c61047d23298b4e5b44b48fe64ad9b34c2023813d8e76f522c30c3752d77ddefc93a7ddc199c30fddc4a2a7bd1038e4e05ac166817c02aae06052aa4294396ab6965b5736b5590281e384a690516894f2028399cd7d0bbea4106db01981bd891e648a7a2aea9ad87e40d7bea36fdccf3217bc0e994ff290e0c0cb60c941029a8e06e238a0e9665d101bdadd546d0baa4a293528038af25c73199f45655bf1d8734a5e060cb55aac4f0d1b93ca924d2cd78230eefcf001b51970671fdc72535e08cfc99c72a66bd357a1745a4c7552e883c3c0abc67b343e457b3a22c29a61ee78c3a7efbf8fd3fdb37618088746246e03d1ec6607188179121cd9d28156b122a69c0952d52f7eda3c751c75b331d6f3b82953b7dfc41f57278c09e3bb74994b5cf36dd8189a35ca092b8893e22a3919e666ef430afe86b59c35b85e085fc03f85650062130cfd45e46cb653278e54f94e2ed4aa4f05897762437f48032d1f1266e014e5c341a77368f51855ad204e99c684388f7db0b9594800e090c6d145d8ef70a71c1bf8db19601e19819dd4b11f28fc2222da55eb04cd7489e900d649c0ed7e1178e75d505f6fe2f69afd762ae9577914d638f593f6cfac05dc0c71d36d4e0c156175f171a57c5272f426bdf93b6d5ae6b630bc42e51307f6ba7d72a704a90367b59fe738f3630d699e56d84d02da54b304f8498bb5334aae74845f6110cd0481c198e712298b37298657995ca0d4353af8f4926d114a3865065b4f7dc57afc1b4842bbab1c21dee2807495908c6fa3f6323fa7047fc0fcb0063399ea6d72277a0790dea6bd710c09e468ee9f3606679f76314f13bcd7ed0f2f714ece14dd65e85475e7a3d63b9d9af7194cf8f543d8300f202c8d68dd9aa20837c14b2bfb3c2904752d403a5387efe5252d7af1ccd30142e6008bf107ef3f65e697ee696e7c75f860cebff4b865a2ede1fd93a222f42c6720729d7ad59bdce495ee5d9ac7b0279b77aae28d70c11162ef21cbfba007a3679d772f8f8ba770fe3626ef665d2079aaf5f0f47cf3c2f25242bd09114008e5dfd3cbf3c52fb0091f1b315214a07b5479cec37b7a47802c5c01e668960647181d85101c078c47b833a25347e5e55895076977d9a081fb483a54a6f0c6051e965182688cdf9f89a98aa2bcf117908fef69de2acfa7bb66025efc100c2d46c03055452898b990ec20698ec4250e06126e23ddc76a7720822ac22ce6d1a6b915c2ebf4555fc69d4743dc39f9040664a7247476c848dc11dbec2386721713445d2b1f611a1dd78216409cc6e2d3da6df6a8aff2d1e4c3e59a1a2f7d143c2b35ebdfecaa10d690eebdf4c7c6a03218d74d0e53f6e227d72c070dd329421c9070f100083d2fed8df7a627a46a741a1b06d106be25b990de10ad8713de0c783a66b3fc6a20e90234318ae816cf0f02cccf8b5e6fde327459d8cabc8117f5c640ce521091494731dff2ae38892a89c34b9c21dbab4d999fb699b077f2562435f17d42a209a93cc046ede4c80cf046f6166945cab259d56a0a477a78a3e0b009fd23e219bb513fd462b9db0bcb2aae456ddc06dbd38ca260a65ac13b50fc71e6a08f16e6b81bcf426a3334d41c7f5524526bdb3c8430bd9c50ac2eebc7fc0b61aab2cc5e9c16ac485417bde40617814c905bc7bad1b9f93b30f705e8cdbcef093c25c19fad8d1885694a4df2615a5bd0544c481c611ca3d6dc08f0b1980fb1178412706435437b95314ff7ae0225e4f7f9a893d98c95460acfa0dedb129b3edcbdeb64e298d294fe9b9723734538d1a49a26543759017503da47c2f2e402c78d9ac5c721691f292ba2433df915acc2a5a652d435ff226f89ad82d4a878246f4ccc279c4be5ad07949204799bf328845ea2ad218cd4da172d75168e4ab2be4adf32f50a5fd6b15027a5db36b343c4db31edfcc996c89ea87c29689c58b48cf46b72312f416d11954b3626d98005af89cc2bc2ca34d7ec882407214ba12a8773f95dbc1c0ca646295a83f76c6c3019e03854150e5ba115607a56b05ea97711bdc3d805482284d5e74ff2abe116eab0e4a943b9351d39e41c3f29f6456b105507681b5d6a5f780919b977483365040d368855885f2ab46e5ac8f29e11e7f324bc82a1f64ed01ec4f7f3888c665b34eb275bf068f9d3fa06b1e77dfe69222412dd15bdeb2b08739aefb9d10e5017405806fe1a3a6484b20b6776ac3db078a2fb7fae0be339fa5c6cd936e2ec390fa42de5cc339d5450dec9f586acc1206e6ff97819e2a30ca29a71be3afc18e036b83975a802f0ef03a90db6fca0b9864a36251679b5eed17f5f37fe0c8726cf9df2313c6a54460a39cd6467e4fcfc0296a78c692a0c47b825165097ffbb2a53de36693a049e6adc7523eca6737748601e4c35cc8033909ee502852ed838886048b2664f4744bd9d5809a486ba4def9cb6be5021e71775e544a7e060e8dcab300ff427501a1e39f0cb0b823e73dcc07eb714820a686ec76795ad0dea05105c66fba636caccede7c3a0863dd0688dbcf92de66f7b2c33d6f23dea12042173887d0b43dd1676850d0100dedd02b3139eca4105b64c168f2005514910058144e34780d62701c2c925bc30cd85fda2e93fe37b797630b91fbafab1181630e70e45ce4b7efdfec087fe31e5134387e865fc4e47773629c01e90f477414134466d0a98ad5a0ed8fc41e8c81eb162e068c4165027681f08d9a9e0e78e3f25000b2b0cc546cecca2da9eb81bea0d4dcacc814f073d9e8efad6e26dbbd7343421caea293fb2aabb615866d670049283ded9b6397c5df0c339c84a72e2e29ffbf6148522f74febf91f269490a1ce31902810967cb0c6508b81b068ec4b280bdd009301807fbddd0f84ce622a80f094dbd5868dcd214d55414f685bb6976eca808cd6c42e16d80ec3916596da24c31a731cbdc80aa51caf6d1114aab44604657cfb633ee1ba910b4d314304acf879c3498924d1dc7c48bd986307866a9c9e3991014dd752883c08c932831ac49eef518c87998a08240c44a27c596959d9b090c6056d8744f4c605e49f31c38fda7a3c62411750d95fe157748ce7c868c66cb1025121e0645dba5cd1a8b6a08c5b8cb5e3939d0adc4f15022c4c318065463dabafb62b9a8f0f20a7cbd44c86c0180b187ab22f98a7d35b4521367ac03732761288bdc36912a2bfb8d0c44b9d99d93406276b558cdee0d69990c94f0cbd866d6dae13d2e6ece317134f00e66fd08d0dfca7cb3d1ddeba20b62627799ce4547e1c99a62c6f1ea680f34adcf213c55cb5d5aab3497d90ac89d7fe461ff59fd3aa7994240d9860e9b4dcf59a8fed33825f8e4556d95135b69f7c046030c5b4c342ac20a11a5da9d601a45f1db42e503327c86ff24d5b0f97ce45d6545892926ceec0f441b11711f2d098024833dab0f26c43fd535aa41310754df2b0137f55ace97e0a2b113b52ceb98a6faf6a6835c2e0091ee48b0aac5f046a188e9447e8bcbc476914c73a9712d4e41b155cf2e1d82315efd519328c0a5528671198d360fb249c04db4c0f328a583a0528394b019ab63a8c017ff0864cdd3cf53b3ab76d5443dd1750cf806d81f3706580d1f107b29e0f37347909aa5e26ae36c1707c8cc1167feaa1834c25ffae7ab1411a07607604c2b5d978cdf51d03056e41e0ac6e3700ebff0fa2fd008f6497133f3edd116539f66d296f6cd25aa5a284d1e3b643541bb18812092ce7cadbdaca3189ab97a601317a12b3a3f29e47f338c950accd3e1079629d5dfcc40b06c87d014747413c83f02a41c59bae590fa251982e974e0a11451b1219c7a3c605dc7287253e29ec039d5127be398228ebb4c2297907c0587f366a7d3406589ed8b3ecce89df6803155098f5bd3e40692a99f0a0c4ea0ebb12a66175b8b488f1436761ba9336a2b80974cc89af07fe9cb0b53c976c588c12b69ce5bfbabd172994d4086b48f80ad80523d82f70a73028ef8dd542164bcd118a2685d650585cc11a8e57cd63926981851f3b0d49559d7234d3e61ff8f3859979309be98a9cddb78d2b571c5c622b12b2b151c6bea4adf23a42ff101393101ac4052628486987c0ec47df25532e40e9f931965e3b135a1c3f543752febad0d5bf38e6eaf8bd584a9d5a348bac32b5d5939ea50a29a97ddb46a2b52bcec65423495533e15c0c75f35593aab8ab1259031bb07671c8ace71996be3668de2c1a15305bbce4db594fd410d27c9cb89ec304139d9d168e2ade362a8107e8f9f3cbb63decdf4a23f875d88e9625839de55465783bc6d9f7c721e4dc844b60e3a09723da6e3c0a76a2476027ccc3b3ef13b8fe6448e15141e3320369b440fa52e344844a03218067a5a0f435026870307a8458508fb9e15dda2bd52d9dd6dcd2312606bb544680847e57d571d8e71ffcec94ae7dd6097a2cb3716a4fd90bf935960d9a44b175a60d794ad78b757836dc7e865baf5e4f531de949e70a1917932503588819d246b17e5b798d75078569fff3a30cc8c9c52f265bca384b3eb8aa02fbd3e85e110c92010321d72040ba517f729be6cc8fb743e4d429855278b501c285a453497fa9fdd91425f4ae34f18dcc0903842b425cbf862511985892c0464bf1bb2d5cba68f5972992f0992d9e50b04cf10dd7904942214bc8ac2a727dcb8740d15e0f3f14f24b5c88684c2413e847c330d2cb6948a060bc7894da9ec75dfc80ef3105a05d7e8020f30096af6297179d876c20aed32ddb4706c4181929e9118fd7411d03afed58e614760625bca38e3f60eb0cdc129e6c134c541d6934b4b52487d7d570b023d257901b82a8328338ecfeb2097148fdb0863e38820dd0a3f5b60b0af72e2b301a1e3c030be54dc341ec81c232920ae897ab12e9d037967090a55c0f033d0a2a7ff9945260d61f7bc5f0f08148706a80643ab38abc4510424c024c48804680f7263a0fd3906446323e5a6500f3dc922a6a32dbc0712c2e478ebe597a430cc7a4f29051a2040b4c88210155970d549a4e0e891ad23cda8a26a5a1f0a4d4028a32f9c0cdec6ab8505f2aed1d01742f20098753a60c990e6118092870418961c58ab965b706f4d7d3e854407eed61b33149e9457b2aa8e2c451f5eb4781488dbddd5a7193934fd0c159740075b7ac5492f841473d86d18d4c1b4e3d6692e6d0841934e7836c80792d548edd89a8c72e5a61c81412195b586063ed5247926e772f5e29300fced024a689d8623752c4899345af69b5e819af4b6add870d90e8632d4c1f87bd25163e99b7bbe57acd0e352e6a58e652af0660fe91e25fa0104632df225ee104899b219d7df565c78e5bf8e7274153dab03d1436760185990dd1f249dbafcab550b959b4351c3c318c638e2f3b48a415a546d222249ebd1496c4ae90efab227bacf0050cb8f1b59f2b4cf8c21ac9c6884756dc49db1c7d63347a110b2dd7c99e41cc686373898a7e4bf39b319222f43b5d2d9a7bcd364949940269f98602980cd64bc63a259d0935407463267a9f392da6a7a6aa5702eeaaac624efe27d360d4158b086e24ee243c3bb91499fb3dc7bdbf2d43c22d42377305136f0eaf1f2120615999034c798744bc8073a4ea92ac45118dbdc0109b51570c7aa8c68f7248ed8248d92644e4cd19f80d5424b78144392b80bd0a6a2fa26647cf958da8230d6a49751677144f6b8e0291f8b0e90446794ac942d30d04a1c7c138b5975183c9501e9b072e9917f4c88fd9e8d2bedbbd26f1cf42a1c1cf6dddd65478a22ed63431fb1a4d9746ed8096a03da7af7519ba4da9ffdca676ed187d92dc9dbfcc10004c8daf7aa631ebd253df0d88b622126d13db3dbb57c50eb6265d5cf16fd9062cce13f275b87e5abad6c7363112484409f79b518e957bbd1b205b0f7c16165db760f03df9c44057a28de50c200052136e6a6ebf7b5a1e2e527959345e9f1cce5d92c4e6755df175fad643a462aaef562b3d013bda9896a47fa054a80ee8bb84237d6200ae9482d1ead57c369e5aee13c2eac391aa268d22fc0938336a1aef967827095c2db4dca77fba0205af57055f27c7c32b7886d72bd513961c7a274909a428d7ae788e72661d24a9a9ad47d42177112fd570ba2cc62907940a6d989ee44efd47c69ff38da1e400f76f3b991171de02459eef153ad5c8d574cdc59e46c0fbbe4a3473b1ba4e326fd71b538f07ee2ed20cf112551efcaea61bcc99f856f8888bab78afda2bea0ea28436dfd2705efd2d503c32d95527640d46b809c69ec016019e6f0f79e0335861592e6b90bc1be1600123150ccbb6267e5d71af0ca5eff72a282acb556280d979746324e182b71b1782e422b2b72c0fcb2c7690b8bc47b08843c1af11074c7238d3caa689e69743b9435e87904126710f3795b4ac6f25ce0a66486e86d7c81618832acb52cdcf162c34c336aab183cf12846f1b5e4fe956f250d0ec437e55874e21058955ec5f22e89b03b1530ab68f1c4245883277d53224f2dba9372d4456a3be07cf98cc32c414f9d70f18d2de61bfbc6270528776d9542c12e1edc37c9df0d565c818bca6ccaa8f5467e49498398ac4b6b1663aae2f182b2b61e4b51a235f880ec5193976956cacf33ff4862d521f6903838aa32e590419315736936f442f74091e9312d1df638195a0a191f2752327efa417d1ae2f7276569be2b4e28deb8b4dd45dc121f9ba3d142850a635dd5654ee704d0e3a295bf69a7ed65fe79077a7cf3b76b318acb024097520d505fe5aec52d5c08d490cf4d613749a5383110aec14c901761cb056fc74f3abee5d20208798181aa3e28d39e4f18870e9c6d1d6cfb4782d672cbb3f8ce2b36cceb7201b7175266ce1bab62761aaac623042a67c49a5a2c1289f1faeed37ec88d57cb158018ceb9eb4d15f64fbfb4d4d64791de7432c0a1220851797cb4a632813b94f088bcbcac4abe06e610a4b1ec39659868bff25fb8de228e71f5ea540c7f8a1fb69a0550a18dcdadb8a0ba611635627746b45baf1620bea216b2613641ca3ceea465e215953679768696de92ecd38aebb2c1805bfd615c8657440b4ea5975566bf26d3cb19eb9eead9b91cacce90ec5c0771755250d1cd2fde39803648d81352e3dafb90a652d4b5af7c3190fc82873835b1a31d4a36a5d3093531ed615850b66aec3b5449423be54f17328e7a16127bcd1ad4cb304dce5955dd1d011d8d15d46ba4892a263dcd9be86562fc78151d32e491bb4e3b3a3596efa1344211afb9d5d0f205e69840f47f37e12e7fb7bf5735b8599d722ec8193241838f828799d5f5378e43d06aa7aa315f2b0185219ba08e563f82f4a50a32c8c6d7d48d45064b794a0c6d1264ccdb9712d39e33aedfc1d82c94a39701ef9f183c1239a03b012bc8cc3e8a40405cf5ac115898ff029d682197c7c349bf1cf9642497dce19a9cfe8a032e35b782efc8795741e9cb934ff07ed0358df888992134bf6d0b2d9feab05c67fd10dbd24d55148f0e825f673f3958282f7235e839dd1ee52e6d43623a557ce0152886f01bd65f309494ef4187deb2c6134db3649c5605c9fc5997bfe7c2f39f37f40b9a2ca0706008576e1c240dcab0280da226e0de697ee9a2de840bca9ac507894f1302b18c2de24bc77d8c0c3108289e403324fbc56888a750a0bfdc2a3c21c2f48a21bacd74e4fcda98033c5fa2daea57bf3af4f6c1e0aafd056c248f1beb48f17962e6a8113c22eeedb15997d2bc69467088dd4d7edcc519fb36d93fce07f13f53d32ea5ec781d7679f349ffe6490b0c1b3cd7cf822933b0383e639b145f578cc619fb98be6d55e373b4488441ce087bd78599ee1644ec7e0dc7c169c529e86cb4011698530e562910cedd840a9eb61849406b6a27b594cad486c57f50a67dbe456a9b7c1744e3e60d72891464770b7a50436b8115031fa227ab70170e960748fb05e9fc3fab51c78aee9d805654f19ac225807b5d3bf2fddc30e49361b576f11ab05ddaa854a816c04dc14376442d21657983b097d68c2324a21f2f0af304d378edd082e22c2609984ca96617e8c43cb5f1802cc2b350e0b4b0b768cac2f061b85437bddcef9c48f6fb9c6fc6b005d895fcb798bae8bb604d2a9fba5081c55cc11b96697ced4142a706945bafa111ad687215b4aa407aff3cd0fdf98cd56f5e8c7eb7768d63b16f20a5dd8f6d8a3951658b5ab48772a3876b633248872b2eb8341ba69489121f4354a4a9961a941da2a8246b2304d340ab1af105502eeaec973f5db55729d773430c14a00200766d175d1cc51d9768384495e319709320c6efe50e9acb1703ea79237cb6d7cb85ddfb6ba933498d8fa36f936ccaf8c85a82a28f214b04c0b419e444a856fb2fcf8c20641408e26a67f18c0a68132574c260b580b429d8740d074a3240bd0182641c8cea043e55bee357a798aae228a55e86924a1da2509a5ad0f7a243b81caeeb662cdb0357fc2a7feda430df1ac4c7d3716d680510d9faecbe152e64a8ddf65baafbf10c0ed442d02423ae63b17c88d630029d458782ddf224a28cfe7e9739e7fc5026640609806721612a47dc91e5a5d8f8375f4ff0eb186fb50000d4e5ba3af8a487ba8d46cfe65deb392ee628f30ab7c320b45a3724ad487c03fee0887a36a9d8f3950e84bdd6b802e01ae8e3f5459c73403e88624a0b3931eda800fb690dc0fbdc741d60d7de7b8f01031f8734b34041eaad2338dcd6cc544a2682ffe6e7c02613a8ffeec91fbf83cbfe75382f0dc6e7e9590eb0c961c6aaa6e78ec2760a0625548e59ba705b1c31f91595841541cefc2612ae76cb9a01f4cb38edff797470a414bdab7b28cd4441c5a960ecec11df7a017863bb7666d401e70918772c58269b6e7dd5ca4ba36e08d534df440d75f11400714bdc27af48093469a78e7c21f233bdc260b7ad3507622571f5b8c41429276582640c9348208ea080efae161ba1210237284fa6b4f19cf64d92aab1d6bba2bc4a0701a548d53fd997ee4505967a16ada03368236222bda00d6f961d33809153854b6a22f2ed447867a2151ab4842ee125be7705b4c5cfdc70a36d7d6244e20f9602f834194fe8c626881b6aa3335d7e000d767d3294ce945b7b38485db47aab142485dcbf70702649ee8cb84c3ac54bfacd2f309c5c6533dbece1d774ead1a857194239b07dcb14d97d3f416b7c942f1eca0b1d943889995dbb66878f50971be3a387e62325fe081ebc2f372a59043173e5669dfc34a61c7903c564eca80a04dda0d90276be186f89cf6f895e33638690d16d2e1df7b53ca0cbf1f707dbc078f38d171078c1cd8c759cb5914ba7711b6b3e5cbe1a404377a681b6e14bb2421751a8d908f3234766e34d2e834da4c88c3a9086818fc28d6e213a73025b0b4576be2602193e86e38c88c443e1b8fba8100e62aae84bd8e7af742d27f9ee1e680ef10d7f597532144be142e53d90f78c7f979c0fc1172d5ef066eeb71b60b7452b2fc6a87f81ed9defdc3418abc4bf9610162b2380c113f75143a4d85422a93b44e2d50ede6cf890b5b2d39f3844194d2e3f96c70907449568efe72549e923289dbf9f3068ede75ea5a07e051d54e91472efa8a006ef6894aa5f9704d1f536dabb8d6d7156e249b232b2d7e865b2f5a8c11d1e82805afc030a780c3a9696f4d88e8d81a7d77df019ba37ae6152715edd15144abe8c8e484c7ecfab0d624aeba8a939ce0fac1afb7465588012f91196172d62d10382635cdacb58af9a9b0b8a5a14955fdf0510b5a65324434d421abba887bc00f47ab805a85084e282f788b83dd9a64620358e0d7316590585d28e5f563bda56922a8749118364b8910204a1ab9c1e5e55647247abe63ef13d13413a667c63639d7c3394e65fa13de103b4f36255277c755d3fcc9ded573252b54eb13976bf39bab33d446edabd303d25d49e448120af5c23ae3b87720a337af52500d32341af8b8300c7c1815647a3974455f3b2836ee48ee558d1a6e596428c6df716f7f801efa11daf5aa33a4fe45705e395eae28cfeb29e4573bf14d5a6be3e8711f50c3eca66f37432b66e2c98423b4de95e9a61f18214ac8de1273149816185a5c3c797b877e41b0c96311f9187f0d1f4201b06e2520ca2187407381985e1b403bef07d9db6a45804fbf824c24bfe0454c733a71c8113e0961e1dd4cee765db8dd585f5cbc3d3e55b1a50a964a3a3e8a0164a4e74293746d2a7950728f8b38c7259c9dc62f78ff78ac9e632f6e6f0a8fa1db2508ab0c7bd85d7fc6260508106f8a2dbedd7edf159327d990b253a32c44051d2a41ecca4043048a974b0027acd2d736e67f4e5f0b9909b5a0f37cf440280e57ff2d5ed824300df6234d67832768308877416f5180f61c96a1b9a427f604402f3d031cf4315d01c62277514a8698b9476139a3e459ce0740ecc4e13f7351e46da49dfede9b6bf83b08f1e76d917e3a51c82dcb66dbb31958f3f086e70ab726f1db8115b77469a163fe3dc98c88814115c78551c011ec66da45ceefc07a8dc1fa724606c96d8020aa47e09d6bde8e3e29f99cf09d61fbe3fe2c0621a2f7c73e660c35f492775b6a13c4caf399d1e3070d11275c92497602d4eb05734730b76453e0033a1f31cde2c7b87989e81084cbb84b3a66d1d059f4892e2c6be2976db7b981bff440800246ac1062f9ae5ab8edaece3bba3e31683b14986dfee2d23e26b0390c5408c6c6b593a5b5b4bf9ced44ee174286f5a6ca21d9109b18984aea0c11f4bf091846d1db507c523aa42cb103fb2dd60c3ce030f0ebffd64cf129dddef80818efbd6506f053c4445c794677891ad3c9e864e7347fc1f456e3951a9d14d9a9be058b9f73947b65f1f6cd001c2b970d090bef270c52da18128f1c73c791a6fa3f31d2e527e6f3a3ffcb145c88899b3d04edb0214ca5ee5eb181a888d31141620493468e1b97430a0927150220925a16ca59ffe804af08c1ea12f706f7c463f379c3cb0af1311e356e25bd47eafd3a35fc8f0e6455847908c7ce7ea337c69c2b7cf1cd00648968acc669e0680438b9f92fba685ee09ffda9c4c21309dee92143d9772422fe51a1708a1ada5698503465f36cc13aa1d835f7379f7ce223f5c631538916940c440e375d22f1ec7897fe07cb80f40f5d7d8d3813694cc7729ba4299d01027f81ad0d6f3d628e412aea186e5508e8fa3071f2724cadb1d808baa27d20880d375c61090357f91da029953f424dc06f3efe744ecb7eb72f4fa150686d5407d326c4842ef146a0eff4852752c068e495487dca50a8e5b2bcc81612061d58de41baa3066642f10cecd173d0cf619d1b511915fe15800d0914ae75b7ad69591694ebd273d5cbe6680206c8884f9e41f948624aa762b88412dd3d99e1b11e76783effa23e5696002f44fa0494e94a5cf9b60ecebd5d9d64f0681b91ad0c9be5c58e4157020db5de81f06c2d76d3da574547aa0687a3913b69e088a97a1619651f5f2da1880d9aff817b8a33e16a709e255235692f8cd61dcbb2ca36b7e07d9b288506090a286a28924107c10306e14d2521402b54eb5142b2bf0cad02378cd271d4f3564dfca9c84ea1f5b6695892ca52498a72acaf16d1f24ea7247498e8bc09b1fe19477f45284a3d76648ac9d6b5fb28d265fda2cdce0977055da5f99dd39e0dc4821e21ee4b8aba6e03c9aa09f6c71f6cab0301bb565b7e20ee711dc7a849cca1b6266364375d6f045a57f55e74d21971778fcf4debb85671d42b6b0a146daa886d80ecbae7a51a3abd9b15b37832c988884f1820975d824c7d7cf71ad4af38f46befd91649141d65e30384181599e1b2543250d2cf37c8e0808f9a3813824f43a548bdb33b416c03eb8c98a12a8a21d54ee7632ed553a7bd84da1a6d41e3d42352ae15092c91bc743309fa4dc8fbc8ccc962949f7ecc45902e399633ae71a98b78ce48f9cc3599ff9731ef83f15529e040159491902bf1d5e1805c13aea94186e5bb0363dd61c9055574acfeb2a9a1d6ba80350f7f403b0748ef3df466d05c585d1ab4da3888cd48c66454306c9eb99a07295635523c9513759c9861ab25ac6e2d3ac4822f941e990764364a2bb81df79c055657f0a36fd9a8ec3020c0615c3747aa9fcbdf6e52c90c5d6074f6369e14c5d92d0c81f75acdbfbd5da7d8b49949152619d5ffd543ed5477aa76a8367807b7153eabbcdc2a01fb09da5cc46860cce790f2344625f524fc504e16595943c0f890ed161a89a037371011ba0a1f0f0e1184e3dc404c08353fae7c73f64f9aa0263da1138a6377b657e8f11eeef625f021a52f3fdd502cf02048d3c70ef42ba2c4ad48baa15f915f88e324dec2481080f6e2128ed1ff940ac5f412d89d693fc6cd38ff944b7f5a297b453dfa24aa326ed4e9aba97e72c8f48d346da6c1fe46c40f03ea21668870dadc160714499c8aa9e2f1d192d80a1d6165d471395b8b70af40d8f16cb3f27dd8165cafe11e089ffb06a5e11f3532fc512b2b36583f5f70cbda50894f97333a1473135c4ef4adb28e95dd8828a01b9d4812c91efb92026f71017c0ec004b8eb460391df501c329f4f9608d0b3ca342da857199e02d71d1d8f3ce3af7961f982c56ea62efcadaa629936ae0d94ab3726a0da893e9554233e8fd96f86918f98d9d416624a180092463d5597f391a4c234616d74828fc919f86fe6517321200988891736d76da16e7dba75e9be47971e5dbb75df4d976e5dd5e96eb6b4e7546f57b73fbaf42dbbbd74c4b034701721de6bb68bbebdaabbdebaf5f8386a81cea7e5f34f4bd1d732ce5662e4ba44defc8c2c1619dbb127f9d1156d912a8b382a13962fce0a1ca663dc3a5ad7d455b725d9c999638c0201353038ef1fe174ae0a317563ad7d6b9db98d9f2c424a8eee521b1c471730b30d1c9ecc04ea4095d5528989a6a133a4eedc2525f8d03d01c918954cfa4277092fbfbc68cb63838143b244d7a0fd1eb560b1e58c139d19ba49f2f254e286cfd42c6085b24c81cdcb65d78a1a6d47fd3049cab59c886aedcc9904447ce68aa98bf11bbae24db2134ad52327c04be2bfbdcc940653e8cb6577a26e53d282916c2a9af1faaf974ba9beda2e1f01c1d3261e702f53f6395046211f579201c3b6a893091d469b86b57c95488837a69cf84b38017e5fdfff7f2d5996ead893951120ed28cb083ba9b1162fc6628e805b4791f2e56dfeb21b5ba2bc2df9c30f7f0e67a417d37e9e19d252ec3b9f31c89723d5e75e4b2d49e85736253e3090558a4a505ab52292b8a1364d6e234645436825ff92ae0815101052406d5fc16bdf9a58d06ac7880bb791b18612a4aa64fedb6df61f05a751d944b93379ac178cfb1dd67bc42581d513eea04b25e1303d49a3cde3f4ad7dcea809780e473821667e2cc18238ce13020629eb8c2d8c8ac36deef0bf92599cdfa6797811d0e6bdb4d7eb68fd61d17604b8006781bccb5e5ad7c87d1e977677297828bd17608a2c37c122aa9cc7d4b8f6358aff73b490c06adda264aa02babb5b7e73a9808c4b8b84806c9b24b804da864ca9d93fb369406eae6845b622e7d5eb44070dd8e1974bbbd82934410812cd353bb909638689d11e15395487272806055a55717743284ccc017a5b27853070b4940e000c30c000030c30c000a811c068cbbdd901003441db006c4a4a4a8a1b17c34ad606c04204d64684c6c5740111088a08eb07ba67a01127375bffb5e871f44ea8a0a1459fdb9f1b52fa351ab6c52c1acd182219c3183da7b5852cfa890cf3c78c2c3ac61b046c118bc62c74fe47e4b895f1b0e8a17a8efe57cdd931f28a1ee5fc2ecd96e18a3ec4f1c63c34ed49af156d87cc91bdf8cd2503b66045ff185c94d2148fc99d55f4e92077a7f19f7cccaba2d90e19b224f3e81049451fc3587769d0985222a868520665e6a153eb75f0147dfecc1ffb28d43fe54cd1f67accaf7a6652cb4ad1c4841822a85f4e1749d1ac44c5909daa1a83a8b718451729e4603e7aa1008ba2c91ece73d60c14c1960c78052958c002104080048c60051430818fa051f02cf8c316a1e853c393c4c99bc75125822dedc016a0300b6cf189c653ee144692a58c99819ee884d241cf63b80a27ec6cb189365c8a7c1015ff93e8c7852d34d1447a7cc6282b3b8e99e853c51909513a4c7429c6fc29b8bb97e89159ebc330329567b444ab96730c21836a54a2efac12b9ec5aad1975c21694e892e38dd9ad934de4338926c4e48dfcf954743692d82212bde77448c6a1d3c5f2256c01897163b18a38913ea28b9396e3fb6a92613aa289ede338b998ef65f6a891f39f0dc262446b2da97b324216d1e588102b12b9a13bb78522baf8225912a721852d12d14aeede8f5d0d611f8e88ae716758cf980cd31c87682c446a06cf0925a9628836c7148b50113d32dd2c44e7fbc0273ea892499310cdbf4b947dfc960e7206d145cec6287c8cf078ad236c218836a5fcf499903a659203d1698e8862bea6c1720b883ea34e5afe383a3f86ffa1f5fe7cfc9fa1cea5e8875e4ece232e57ca167f1f9aefb290e52ce3f9cc7ce82c2d4af4f929cf921cc2167b6854e39f06f79f74c919610b3d34e12cb87b9660953a9e875624af7ccceb7ea07cb0051e9a9f8d7fbd9c71ce5c66618b3bb455d92f698a595a2272852decd066ef24eabe2957c8963a34293639b08a7e10424587be7189745f65af3ece0a5bcca18bfceb7d071233c62b87ce71b82c9a2118842de2d03a1899f76d89865ac2a12b093f6b6d314ce390a9b0c51bfa9c7e292219e63cc711610b377421a358d9b26b869a32256cd1865ed73ae7c773f605890dfd86096a95dd71742cada1879da32bd3152d46aa861ef4a71c1bf2581c6fd2d03cc6f173fc72cff80b0d7dd8e0bffa7032a34e9da14991c2f563cec5e766861efc7f5e85bf0cede543df2c0e3ee64232b4197f0e951b1bce9e3c862606cf3b93b269c8be8aa17560213ecc181286d63d76792a09c9424660e852b4c3aebcd12f7429495b876a6fb6895e68534a8ee54da1916ad785f6a232ca7b588998a25c68cc349557b098541cb6852e834832edcf0b39635ae837c4efdcb3f9915b9a854e7b7c2df36ae3980f0bed46648390e921c9e22bf4b94f5fc343d10a7dc631c404ade89e64af4257de8d33675648ee132af4e220f959d0065b294ea15db56425c95229f46b793d438fd98e411a853683bf9ce2388342f39343d47ad5b169ee094d7a2e0fea9ed173684ee8c2a9e6a874bd09adc588a771c2c387d399d0c99bc857ce7d315e5d421fa366fc95a1435d5395d0777c24daaaa924b4129fa2f59e67cfca21a1772c71f2a923e68bed08bd84135735ad8cd0869858b4905166fcb3083d6a14f3a470392a894468265b9e0fb9cc81867d08cd49528b214b27ff09854045c72bd2132c41e85385f9941971924309103a7f14a29784fc8362caf78933a3b0850f9a7c904365ca8f2d6edb83b6f4332f1ea778d086489ddce4603ffedc411fad2169c610e64fa33a683cc85f548bd9283e2a07cda47a92164fb7c0419f632aacca477cef788b1b749a23c59ebc3851f2dbc2067d4a9919966557d41fb5e8a16f2cb1b48e75cf68d15774982b8a9986d8e82c9a3c3925cb8b5316cd67c5f1903ffec6ecc6a2b9d8680c332addd0102cdaf1d070d16c7945a37b59216a85ae68834ad6d4973c71e3de8adee25e94b2866592b3a24bed712efb649595761548ec8f57495a51451fbdf17cc61ea5a1c452d1b669650921e555ff0b156df89c71589dccff949ca2774fcf3e0e3d486bca149d07536f18e2a77c9a2d459f2304bfbc1d1df385a468634a19b9a8e5565e3f8a5e7d3b2ac3208aa2539387a19ee43ca75828fa8c7bbaf1977be1018a4e826438a3a7394c353ed1ef34b43cf259ea31e589d63322bb3bf63583db891ee30ce9bed93cdb839c6882a49768fa83f1dc6ea2ab2e8b1957eb5aee144db415c28694f2cc99483c7a829868a25a6494bc217527f912bd3cd269733f13b1de127d6ec8e6293956892e6e8e6ca2aed5d01c946892374cfa59a911369d447b9acb53a84e128d4ca3b0ab55d6dea1481ca65651a53248746255a119eec13d858fe8e225c78ef3c3ca2bd3117dce58f344c78550f236a299d0911be69aaaae31a20dba0fa7a15f8b6824e6ac67354d116d9caffc72a2aa9ddd44b4e32ebec144cbb38c8826365c2ca6ae58640ed1b7ba054db9c6ff2965883d3c4aade22916a2e9503185107de4642134677785300fa2cde0d3f02a4355a4a820dab896c2a5b428104dce30ae86dcac267b01a2f5071fb4f16cfed0e5488a1317e2391af343730ee4e286870ea7217de81faac80789d39973980f7d66958d6f7c1abe617b389c7e4e21038beba1d55cf9f02776575e9587aea13c508d241efac7eeefd6f9d79fda3b341222412643349c4e7668f5d27a354e4ee88f7568d41bfff707df8f5fd1a13dcbe8193d27c544630e7d6a903a462e4e475972e8f5636c8b1e322a8b2f0e6d869cb099a3b741dcc0a18f9807b11cc7af56f00d4daa14afb9b22d69446e6845b52a5ea33bd449bd21006de8b256489f94d2f3f5168500b0a1effc986415412c4eb3862e83e01d354e7838ce8c206f87fe81789f47920cc6e73a74a12beac48971533a8a0e6d568dfe9f2d5812499943e3e11fab727ce4d843e4d0ab68ebffc7d37c968c432779a91eba7c67f385436f41b3e9594a6f685f3f439f881d1fc7e486ae4cdb3bc3dc86def5655a1f57ee87980d3bcaea9e35f45ad9a38de14b840c574363d528945e76d3d0436fcd791f5987103568687522ae4fde0c8f816768d6db1d26f70811276e862e455586af61bb1aab65e8413cb2ee910ab30c2243f35932632652a4451f43173dc44619e53f5e85c5d03fcef961f3b4bb832f0c3dcede3fbe2176082a83a1c92093dd93e867c8e30b3dc8aa93175ac79ae3c6771251005de8321f85594a898f2524822d8c8200b8d077a45839c7901b52dccc04b085f6a344de90cfd14227d9a33b33e452cd4b161a710939c429077a591b26002cb4f9ba71b8cec61f257385662c2442773febc88b060158c1aa18e42b3447f89855a11431a654546663eda8503cf62e491935f69ea7f0895c9491b8259659299017d753c8339a2838953dff57544bc6120a651c2372c33d66ff8462cac03a23cf09bda523cd8c8c4a2608a009bd54a360e9ae2122250026541d9fdf1a5eaa1d670967ac1123431cc9f4a98461f846742a034375803417082009ede5d8b1fdffa1537924343199ae04990f319a2482008ed07a945897e84c35040118a1d74851f14b31698e3110045084662ba74c1ec7a417727c1000117ad8539e53267f087d7a6811b5e887ad4121b49e83244be1435e574579104010ba8c7d751a7b4ecad4c6e00d0a3e50566f1000109ae85c296feb07a920801ff471398478297e5010800f7aef8c9a1bb1ec82007ad05b9ec8f1e15846cf1516000f4c25399ae738612e5b10c00e1a0719edc87238778975d087c951f54da61cb4256116727c71d0e30e7296d338e3b884057083b63bae925ee3c6552d55110460835622ee766ab1166d0c89526a118df14669d17810ddd6fcffd92a3e66d14399378dd10fc99349010810e07f052d10c30b59f4f8a43b7f6587a09f7906582cdaec2cf7e94f0dc388b0e831dc4d629553c6ef06e1c52b8cce065b0ec6b2cb22bd62f3ffaa75a5acec8ac67b35b664aaec9f4a2b9a90254ac8ab6156f43055ceb8dc234f625d05dbd132b134265c78a18a3e46caa951f87c3c9a118217a9684b5336980fe6d98df281519d78818af6247bca39c4c4245eb9c28b533439464bd9c53536335378618ac662aa6c042a700400195e94a2cbd0fa3346f85513408004c8e08c6005af8108d8b94035b0823741795382920213907100c8c20b52b4a3b2da99611f47596ef06214fdabfce4bc709a49aa17a26872bee885128f7937065d8002b040072f42d1eac36fd1e4a963ccf402146dea98f155d66e7ea14ff4215c349c2a4b95c7f5441f53e4093b318996981fa84e741ac9a7d362e304d79682ac964679041fa8da4df4919b935ec453045b32201f304341060a50009385179ae81b6a78c70dfd235c26822d05d08b4cb4914534062fed3832bfc0441763eefe0c834a5be97589e627e843978896c53f23bcb0441791b36c437ff06fa14a9492bcc295f57f3e112f28d175380e29755749caae400a2f26d18fa54c8d0ed7d7a03759bc9044975c2eba7965fa831791e8cd813d780189c3c6286696e747b4272251b7d4252cae8ee8c483cca8a4e30dc9042690c10a5ad0882e545c8fd93da77497e5032d781664125e3082bfa0163fdafce3b7884cbb377a5fe5caf6f042117d37b418d3332bfafa44b40f723d7262c590a888f002117dc6cda09e521cc18b43f4d93b3e4644b8decfbbe05d5081340abc304497bd77fd31300d934108072f0ad1676cd08b199385dcab092f08d14f0e3942a724837f80135e0ca27f8c41a444d1d8186604d146ebfc1349dd22791e883ec4d9dc38338c19a718107d8ad9a1e768f8c133fc437331a92d777898c5ca0f7d652509172b5a5cb082165c60032e78d18756b733fa820fb987d3830b5ee4010fb581177770fb736f5f8002f80a3050b78a1776d833b2e614d9a93cbf827f41f316295ed4e19827c348615bc3e274d0cbd5d21fb4aec77c0e85241242438eeca7be90437a713a4279ca97ce0426f0c22d70410450b0800abc88430f7562b53898ea901c0e6d3b0c0d7973788994bea173a0f966a973d8488d1bda98a12f8cc7ebe7e55eb4a1c98b9c98bb5286e8d00b365895691ef125d19e650de234e40fa99d2a075eaca147d13535344a08b1c2176ae8b22297a5f893c36f9f863ea7896cc8c1a3ba945b7881867ee432cfdc9349709033b4aded69514d6386d65ac6a28547e51b7e199ad78a551136a3e4284e863e7bce96d02ea2eb2e62e1c518fa2817b55f73a7f5a75e88a19dd4be1aa2a1b355270ccd47868e34af9ac859c0d045b9e8554b1633ce78f1852ee25f94d98cfdf1910c2fbcd087b0cc295e332cc478179a8e9faca77371a14dc957e9595115757bb185a69259c40d31656121165c59185e68a10f2172c4c73f29436fb2d054af874879debcb863a19df81e3bac34889fc9021480062faed07af889112722ff94d6821756e8f244c8679e8fafa00b50005fc1b3043af00116bca8429f2148f29e7330155a8b1f29fd09c1ad2322d84a410b50e0801753e8738a7e72eea1d12662c0bc904253ed2177c8a2d221df1751782b8b8956c6b2922dc0023496f0020a7e9271949b65377c022b9952e47811fa9e13f4cf9de2af8ef77d5a1ebc6802be608215005f2ce1f830e3f43cae793a25507933e38821fa7a4d2a2dbc48429b3d8e82684ad6d2233ae00512bad0d981a5a08d2258ce119a6e146172b538eeef18a1711cf2f195e5bcca7c115a1f0dadd25973c7f989d0e5bc12b9722c3a67cc10deea4c0dddc9170d085e08a1d1fc9124664f49245e82d0868ca715733c53f70910ba4c21c78c611a98c47fd04c726fe0193de2317cd069d4369f5207929af7a08f7290de604336fd79d05f8776f09508e7baeea0f73469ac66ee3184a983d6e7311c49e19fb9e6a0e9d8a92da2486fc6210efa5021c38b9af2556adc0d5a738b16b2725ed8a003c72315e98b412da95c14c10819a52442af1ba2ccc2f2211c1742e83aefa328baf2f0f4c7175810b808021740e8818410ea16278ba9fc833e68789037637be3f73e68b2667b7fbc637c0eed4163595d3e233c681de67e716439e939b4831e7fe6a00e72c22a223ae8fc1f4f893448a95225077db0ca9c1ce928e13a3868524a68387e6a2125fd067d230ba29171c7850d9a8cbba1697a9c4e886ad144b8c5f58b9c3b3492166da485a0ab39c54cd12cba6e20939232beca0c94459b9127c4a7e610b632b168633ee34fcfb08a8c8245df5a5182e536ee4ef3154d683f4c111df67e5c5cd1f9b8f86eca1eabddb5a2cb31b89ca6ee99d02e2b3a0f25b3d1718239ec57d189548b449bae8a1e9679bce66b53d1c5ddd988ba1df11aa86853caf27992cf3288e6299a38552ab37153347da1f35ef1bf3b4ea5681c8be5e4a9d318849e14ed9f79eaec3b19453b2a151df349249f90287a601172c3bf4a61cc118af6ad3b9c88ea4fe81c287af0913c65e74ff4d6efb9215ad60b21c4138de5ad488f90184be39de85c3d780821c4c5fc83134d499f74cea94d34a79f3dc710323b21d5441f763c895af846c828136d8cf951e6e82f267af3209372eb76896682e78b18af32498a30113725a9124d0e1d52ca30a41c9d90124d4c07176f129a442b9e4386cb8c24dabf6ce12375ccc92d25123db858e19366e7490c89369ae6e33857b54e9a47f4a92791376e46083f3ba20f91fb1abb1d3fb478235a0f79232b55cef6d230a28b1b91fb4c5652fc2ca22f09df71a2c4aca93145f41ede1523e88598e825a279cb7810c91be5184388e8b1c55ebd1caa734bf810edfe684e5e0c165763883e63eff75cd179bc55219a8d216b8964fd0cdd428856c463acca9c83bf3c883644f335478e1dd59420da4a19458d31ab6b2507a2d19d9e8cf462c7cf2840741e9a514453428e2effa10b33b1cedd28dd38e5873efa74849042b333c7fad0a6141aaf328aefc8333e7439775ae71e6fc912df43a37f792dbe2447dad4439bb14c74c61062ddc379e82c344caad141d47f141e9a88d943f4412aed68dda1edd37c49228fa79c658736a8c79aa68798fa31ead0475506e153e65392930e9d690a3d0ef23887f65f3f6c989ceb930e39349b1ae68168461cda8fe3197a3e929cf387439b62342ffeae4a0abfa1cb8e672eb6916ecad80d6d87aa6530f19ce42c6de8e364fe95e4316ff09e0dfd7f0817f2641c1ebcb78676ae420ee929357732d4d068b5c79332c7395c340d5dfc0e9e19f31c87dcd1d088bb9ab4464aeef93f433f9b3d787ef64dc7a319fa30bd9347d72f388696a1f398eb31c1a4bf572243ebe162d2f7bf4acbf818da8c8d34c54b2962682be49c817bbecec647189a4995b353bc08863e63c43055cdf3cfc92f3461fd73d44c122fb4213b2efa4746179ad020f89c7c0e49c2c9857eaefa5d2cc30a916c0b6dc8127363a94c0b4d68cb94a311fe17bc2c746e162242555bea14c1425f1edb8357675ca1ff90a81e72f058a1d51f4d92be39438b8f2af4214163caeaa7a77143852e83dc22392bb7418a4fa1cbaf99e69d53293431c3ee90518617ad5914daf5fc29a3cb50e8b378aba49b674e8a3ca19fc87a1ad95d62734c045b51188013fac89afe3197e590f135a1c771529e09ed37cc0ea7716c90d45f42bb9633eae988081e2e25f430e67778174b999493843ec376e933d94cf23148e8a57bd7a16c6cee851ca1ed8c3316654dff1d67842e3fca9974ce1f895c8ad0eb83dca01c7e86f87922341be61f0407b137b61b4217de11fa326728a6a5109af9141556821c843ea6486cf02c19f9fb40e8d2d7d73b6bf4079d37feb238417a32321f346995fba83d85ce690fda14396c748ca69c7196078da869dc080f3c553877d055598e5fa17374d0756f740c2679eea7680ebacce42fd59fb91ce6e0a0f58e8faf5937860cf21b9c217f4c5f42ca006cd057bc6c8ea1cab568559286a5ec2d2d5ab3c69132aafcf27c66d1c69f1491837ab604872cdad78f8d93cf63a3a4c6a2374fb9d9dd8fe2270e8bd6424a578821c4f490f28ade4198f611cb0ed263aee8223a8c39e60f392d525ad1768a0ccc333caed0162b9ae8d37e155d6390f4fa53aae8a7753d64734e45df30ce231deb64c1345474593de6df48de50937b8ac632be1442f08a299a721c191e4b8666922f45d7317b8a1c723b7f3b48d17c66cafbee1933166f149d03cf9a51589c69df44d1a514bf1b36cd628c53283a8dea2037bf7a68c780a2adfc1f2fb6e4299df8273acbfa8f634e33debe3cd1e5c9a83e97fb3f1aa7134dfe8c49bf62f88fcbe144ef48e6f3a7946ea29d8c33248bf9728c9b69a28fce2886661c3f99954cf49aa3668aeef9b935c5441b216c7a78b72ed14567e7c8d2184b745126c7a41d231c6f5a897e5b525c6d901be3a69468ce73d4af709e1bab3389262e58079d183733d624d1669e6821bc5fb8ea8c48f4e292819af90312cdab6793890dfd63668f68e22a672696c6114dfecc949672a6118deb65c661ed9ff960443b9617394a5ef5fd16d15be4fee5dca422badc334dd21f5295e24474dd2186bc55952d328c88d6c1e68c2f557b88a6b3f1bec6f74a8d7743b47a3a1fa288669c520bd1564829e479fca8c32d42b451331cff55f79b9c8368f2a8e3ceef7b29d11244b3f94942786604a28d77bc61da16cf2b02883e88be23891c4e8305ffd0bcc6caace3fcd05fc6e76b6d621ffad0ec31c8c71cafccc387364bffc78410c2e61cf7d0a9c72491f35e0fbdfc9a68e8966439b379687db24f4b7ac620d1c143334935f5c3f4f0bac13b349f0e274b95cb6a19a9b583e8dcc828a2c9269961d0f7d2f8a312ba4844bf7a1a5d519e1e2588e8bf7be63c8e26f09202088c6f401787e8253354c8493454340e115d18a293d89d1a49a253632a449be9c0e3bd2382e882104db008dd92f906d1ae07f91e6f1452f376852e04d1bf8e6af7484eb75a02d16f8a9443638a03a2919d5839aa577752c22efed085698f255a9a1fba904c26488e29c42efad09f465407f91c3eb41e3eb9996ede98dadb432b53e153f69e8a6b165aa10b3df463e6fee9b06284ed4330828382149497441779e8b26bac637fd4090a07a826d0051efa2099a3abe2458e29b9ebe20e7df0d78e513374286fefbab0439bf95bc9933c9c0ae295a18b3a349f752fe722c70d5de9431774e8439e6f92289752cc1b1fba98431772c83b25a2b1498684b46c39e8220e5d9c6b309e277a8aed403c7401875e1b9f38ec8bd16bf10e5dbca18fa199f253fe324b961dba7043933be42f4971e81f5355872edad088ee6c65cee7fe1d3634153de4e5d421ccc235f419bbc2f3b7e5154b0d6d8629e48c3957529c4e1a9a559f0a792966cce5a3a15191768df8bdd69b33f4287ca3ecb9b01eb3c40c3d0c9eb3562ccd19f932b4b964757e839856cc20438f3ba520d92e92a2c3636836acab72c21543fba922bac38e86a1f3f81b3a316e2e130543531ab63a9ee70b9d749aa954c86fd1f742f31353d685364455ca3155d7e4422e349125632765b685a6417955f6bff05995167a6c21f10ebac8429fc26590bc8dc475dd3974818563c89e41e6f7d5eae20a8da68877a02947c81d267461854eaea2e2837c56a199fc3719dddeb6dea8d085f4d68c634ac9c263a6d0e7376818246643e78e14daac11953334f158311285b62b9e9883568bf71c0a6d0e4155e292e3096df2eff9b8972ee16427b459b55276c7acae689bd086945f3ea5993ece6b174ce8416358799aa34b686582c34f35ab0b2518b12693a29a23098de99f9585f3ee6c31116c0dba4082e2a79bded3a39b2f47b02abbe58a1961cd95db3a3a772749045b2e60c107ce0b5d14a1ddec31f31c4cf0065d10a1f3938c2956c434e86208bd69f438aa3cb99d1c42e83c3b861216d5372a82411741e83f6eea74f2a80c930584fe533408ae979e3246bbf841ab250d27aaacfcc4e583d624a70665d98c41173d38fafd522f28822d4642173ca05386262167e59cfc10bad841133363a554897c31870005e8a03d5fb7941c37fce3a4052c48010544d082116c80055de4a0ddf82e9d8267cd9b5d1c343bb3adf11fc75c3e3728f47abebb1fa60b1bf4fb41437825c91ed36bd145ea18d23be7a4a132e582167d3689251e634e2eebcca2ad081f77ab8286fd03de0213bcc9222e64d15e1691e4e9172ebab1a802c0a213f1d9941e62d24979045cbca275d1ce352bab50b941b87045a3123f06cd8fa1638b6945ebadc182668ffe215758d1794a67c879b3abe85b538c41443f935e45156ddede7c31261c64bca7a217cd9d62563f50d1e7f8eab03de34adef129fa141737f4c3d41da4550d70618a26eb666456a570518ade43498c8f3a04ebfce18214ed75f45845cf113aca32f015acc0f3045c8c02b9108572110ae4021455005d2e3ea1838eb953e26211acf9e22ab8800cfe018c79092e3cd1673031cfcb8430a26e27fa94fead21eae8b85938d1540e96926e996748392e3691052e3461f0bc992506cfb14cb4bf7ee5a9719a37f660a287f1c28154e8ec70fc257a141ac7dc2198264f164b342986389eba65ab3cbb12e8c00748c04525dadc11729c980daf5d4a34152ac557999cc93c9f44fb0e35558a19368e6848a24bcb1d427b78fc9647a2cf0a8f53d0df98543124daeb97acfe1f7dc4db171a73e629b970441f5cd671e675e32c9a3f70d1884e5e827a8a8db3354e6144bf9ede61b52c67941f8b687bfd3464dd8ad3f3ac3e507b7ce04211bd5ed239c97f94f3337c082e12d156fbb57778e8558f83820b4474197d4adfcddb53ae021400eb0345c6c521bad23c21b5c7ac21e7e4097c054e0114a460043318c10946d002154ca00005f88026b830448f45726810553f2ea60ad17b72dca95274f7c00521ba96bc10dd3b6507d1658f7a1252bb68c31441b42fc1439e73e412b90d4497993d21c6c999717280684df79206c759c662ca005cfca1b3f889ac21ca51dc1c3ff4d79d25f127c44989f4a155911c99cea69127ce87ae1cba5476871d55dc3d742165ece39ef3d812d543b3218a87df18eef2e6a18b7ed987fd7933b2e2020f5df46f13a914d7b2f959e0e20e9de338f963e6d64ad5d8a11f4d294ef020a23daa15b8a843fb302a72636673e0820e5d85649798d9433c0f99c0049e8005e8818b39f432bf39538a5bca8eda19b89043e31a3e7314c9cd0a713f70118726c5acbadf6072c3b94ce0020eadfe064d7ee91733242c8881b18b03176f683a857666947fcb3482810214e00a5cb8a16f07f9e7416b65d49dae818b36b4924dfcba5747aa418c0d5cb0a199a0297214efdc4a4faea1c9151e579cc851432f997b19a63a5a5609388071c069818b3434526ee618580e9fa25482920208a0a1b914eba8baf16124242c707186b63566338adf0ced6492b5d0b82a031765e871e8460e894ab9d08e810b32f438568eba951653cef931b49631f665cf8c2524590c6d909093571975a36086a18d934a3fc3ac21b5886068542c87b0a41a527fbed05e4a9ec9b18c0b2f14a707b8e842ff2f1f3f3357e8f20e17aa00cac516aa00a7855e92846472b971c8052eb2d09b24cf39a4a2c45ccc0803175868c37fa86cacec3ef15ca18bf1dc2a936c6ed9d80aad8ca7783c1bad42dff02acf635589b21f15fa0f2fff383b0c3ac19a421f297986ac5f7444090326052ea4d06f87caef74ced5fd89429743f9887b83a1d085acf0a70e33e74b9527b43166235c8e2924f775425f19840d1e37725d73885c34a1c9792f348639c6085c30a1d3d41a2ac4867e86e2127a1c6364678811442e94d079c528a1fde32209edf9a348d11ba3be8a20a1d129cd31db272332e3089dac7cbc181afec57d10810b23f4088891a8f4ee4402b240241088c3a160300c068db31fb31408001824268b0663a12007b4c10f1480033e1a1a362628162a20141414161014160c088442c1701808068302826020100a0983c4f02858f8006e46c45e7c8595611e80f12b06c584b131749360fa200db4e50ef80967c1e9f17799a7984f3f49c546f61ccd8d0b435a58cb82c69a6e226252af826c9fc08905a2303efa85c4ee29fbc680b72b10b5077e5192d40c8452aab118ce40b481a02ed5d331c293563d67aeca8d920c09068da55142f5cedac8a5eab088cb48507ea827c7e6544a9bea023c7f892a04cce976608d588fd98724796131c5e171dee344e53e0dde0ca4660489457b6b9d67bada961f2b910d0211bd03159f02df3fd9dcaf5a614b0f0def0ecd01a810407766e2b218b6bc65c8071001e1d640c3c93c5d609d5fbe97bb7851eeacfb74ca570512c03f65f07ec9177e1bdde66c087f62eba911226e20240dad162ef765304ebae279aea8eb1597d0d72475814aec822f57012ca443f8704d01b9eabcf5da6580e69287c18bf139725b84310e6dcb6b35b697129850d2827d548722f904e880d9854f45c12887c61007c6d40417383e043efa36fad4363823183d4a8787961e5bb5d5acd0db3eb3b46989e366c6a8b87ecc8aa2d6839a353554394d4aaed28c0a05ca88e3c562205a5a412c33771b5da0680559b74a07f3d7eb8d5ae1246cf3f9f98fb828981b5a111ce9873bca6c941143851d9e384f0795a7aeea2e825b457539f9210b8ae1dbfd134a0b3f41bbd017fcaa886e8a3e2e8cf2a7cf05e478630db7cb184219a4ea23df306a11c4c94d0fc0397f32223a63abbdeb2e81d0a966a78319653ba2d4e7349b03e51c441c4cadd49302124624d014cccd0825835b013b70b0026e378820a577c6f8c51242447ad1a19573feb953852d44845d6905982519d8205d6b7fbdcdb96bcca4422826010cf5fea2551169e760086feaeb07f24f30fed84afe4058041f14c0518c6b2b1b34c8cb8ad2502184f63f03c6976f79dbf811144e47eeac102866348356b5a0c431583b7a531c814943d56aa700f2ad1dde01b67cd6491284954fdccb8b8eca7f92360c14b82a1c3ca0d94a273fc6868587d1ca3723183c3313e1cf0d30f58fabf38e4c034de97aaf652231669fa760506d4800e9a5376371153ed9e10f6ced99a9d2c7a4762df8ff25d8ae6c31aedd06bdb6293f41d802ab0128efcea22354e58a8802e11a54fc6fea5fb95ea646b6b629b0879a6bf7d340249e480c404edb0d238607c69b217de9f87ca3ceb259bfbdbf7cfe3fb8e4c1ab85f7245387eb1eccf1e7e0953ab7ebd71638b69b6a3e0dbf9d90b1351d60c809f4b522d7835befb5139e04c7a3e435501c7762f4c52c523a3151e0b8d3fb3974b4cd35413d60be69fcd1b64c351e6ff3007750c8208e88db45541272825f561cd0747d462f5338b3eff447ae0a2d3c0c0907c734fe7d2c6cbffb7b128efdd72ea729897d3c832c5901922671d77a90c2de4e11e01dc1395e4aac381bde312b5d6dcb99c460765da04b4aa6889f7665c16277e7e78690ee08e3e0e40bc837ba96403863e1dee0cf7ca899ae9cb77e871e078d700ed8e4ae2ad047ee22c01941448cf370e640568164ac81e81af1fd8f07d6014831ad9d5e6637a1b0765fcb1406e25244e5b8d48824a7b86aa57e49c5d75469cf6092e320398e2b4738e6a03cb6dc3203559b864defcc146e43d00785459435200d3d8000170405cb8fb9d43ed59a48370c15436880b61f83c576929ec4f338b84ddc524c040070c52b13b9d24192714800932d1ac08de6087af871ab6f0486b25b6cf2e3b5c9041ef096f7cdf15fd5c5b185088cf792b5ce9eefbcedc1244008d1c534b030c88762998d4c4cc1b5b886820a67cefc0baed7b25afc37154cdcc90dd0cb0b3025ac737543fc1048cde4b9a20fad0a29402ed31fd40d026a04f318813e72324a7d9324d325c8a8455adb2f90fbe67b43dff0029cab32162b487e257e555ca4bc683ed455ef1aa08aabe82dd67193cbc4ae4894e96676120b68139ce6718a5b167036ed23c90d89733124754ac8b95c2d90af0c881a83bcc8c2e0ce70e4f8d338f769a19b7dbb93850daf236c02bf1189b9f0ae066a91ddd136006121a50f2313284d51a5607ebdec64d00a8cae210cb3c21eaf40f45ad26caf20844e0990a96db5128df48744a74e74cdaaa862c516e303b6b343048046adaa1f88e5ae039ade3660302eaabb0296d394fbebf0fa37ef3d3a88b26794b8c75980281887d2e07c75ba6118032b454e3959a4cf9678fdf9b406474296fcccd32e291638a08a5cfa33b2e8a211568ee5fe5c18c1f18c4102110d332ec40eb5df374ab6fa60405e9ef928b00a99898eb42c59db25636ef6568ef209a515ac89392f759b604a5ce7c90a59cdc36f66e5cb3327631b2e52788567f292506a096bea8a58663c312954b19a2b787ec21d5ca533aea07a5b739ca1fb6bf1dda747fa094cc4087a6d32d48244229b966ddacbb0b461d9332e7e4fd6b6aaf770809b6fcf8cff335a1b6e26ef784e5b6b4130b136a10dd5a6c78dcd7066f78a06e78a34f34f6224f2b942030edf760e86ca553cc2d62b54c270bf4cc891487dfc9425d24baa3f28ef130454ea0b9fcbc2646b3ef59f6723ac0cb69f47a5ed7b3d1d3a8f3be2787f9364517616e372daec1464612dfc2c468c06526edb747018999461916d09acb9d2b5d20b6bbe612f5203887f49e9b1c978fc04beb8192df45e2076a91298f8d438a55ed5b52a31862d13ecf9419fd68c048b3577285c800747b1fb70f1a4b3ccbb6225560e17e9d9aa2b9b25a6a0bf46a9a4c64d502bd2ef24319d53b7283b8055eae090db8d93f84bfd8d1f1d5f3a81391f709d9610576e0b2ad167ab3ed0c49e942ab4a2ab61d95365961096d681c37a8255114a09e29c0f24568f56ec23863dc4f03a40a130289142c5416844f47149b9501fd438d485420f149092d252209e7250184521290e2a134a8382a058280c14024aec28609c85d31c304a07ec05aade4c144d6a0a513a62300c0f0315a13a52d43df1dcc5090eea80da50bb58940e711e91ba42e54101fd2a8a8337afc37182ba16c5fcce040a88d97f361a0fd5370cc8f572a8f1a8beebd3f3329009cc2cd4f0a280867c13b6c5102584fb3064a98994f5a8578a06c540c1a1b8a3a2524828118a0ee53c0a958a42598d724ae150001411ca874a430150361407148582a1aa505e2806058782298af9dd17af3828a86685b2d8d6eb8b26a1c489c2a42828209407558262a11c280c280c454005a1fc50b887ea63b80f1c2ba8060dd507323deb0354ee45017f8626cc71a0741823967e87d2a08a07a5c32171ce504115504016054c044a26e7a0ee3d5f82d538a13250009494a1fafaf57e407250ee88027efd90a79714b004467dd514580a4a040007bf256bed36a816ea0d3541c55008280c0a81224355508408d577c0c5580328461e457bf37a472f28c35196140f4aa4a2ee715cd2a974a80dd4196a110af83090e4543427e0c90144b9c92854e9d561fd02c5a094a04828010a0005433150290f05b49c35585dcfca227e14d036bca7b166a038545a096f01d52cc5fc2e194a04243b8c770215400da17828311400854321a050281a2ad541dd035ed262f05009d4188a975040b6cb0f1417541cf1fde08a1b0a856aa170a814285305d527e260c80dcadca080cc8e6b9d80d28111e9d24f8e2a985262a474408de38048a830d43ca21485f3a6a11d8a84d2a070282c14e450ccef06b6726201e5818a360a1832573e7636503a90959a7a8152a0121b258293255a2605d40935801aa122282e14028541b1a13a28d245f59d6407fc1a8a2184ea4301fe1a1f5402a2fa54bd97fa59150742dd782811d0261b7813ea54d42e8586d24279283a140d450d45a0b28d022e404c4501ac39b48202f24528c41150f158373127187ade58cb2c440c254b8fccefd18be1bb791e301dab06c8364a270bb406c8235cfecab3a43286acff4b0fb08eeb87506e40f210fe30f45d79002e291c91c4000e03a373c4999671ee146b34f7d6cc536bdaa40c21244d5616589295440a150691720d2bd99c1482f74d8d8649569e29f210a70440df052c810ca134d69c1a6c510ee3d0f2cf55bf5af9ced6170351c0c9f49f16224bcd25e548e2827cb247f3a14f95e4f748dae0ac7eb9378422edf8ece4a50152433393d744ea92ec4c2de3dc2904f2ce552843693d011824d32b2b2432c9829564a530057401d7cbb2d6cf692768f599ee84b3de535c6332c09dc85a879a4a514dedee97aef6e95044c4f307bf175d5fb0629b91a92a737f221b44a64ca5fa37529bc9e70edd3c722f6f316c08f81ee95a299ce2b661a1c5e1feefd489765d9aad67dace086d92c5fb5a822a8076118a60a84a486ce89e453c079da505ee5fa047f133243e700c182eb5effa9a308775529ff6b24061e3121eacbfd3522017a610cebf043f0a2f18e7ad60b216490b22a95c480fe55e7d483a68575433a91fc006468d5f0e2cc8fb39706300d961cb4a4a33e479bcc1ecd40f5366b424bd0b70577eba4481d5d4e0157ec9aadda368e82140ffd1b95431a003903f6fe329f7d7c18cadcd17e21ba715e2bf79653005771b68c506c7c393ec438b8cf03244b020db82d22196df1b2d4311e6556b6512d1c0965555dfc8767ac0e97b1fe3ec40fecb31e0a43639160191b98f7da0dae06326df0a16ad4377209aebee2c8f4eb26c3e89731d59af75a5f85a9c82310c10429992f62998b7fd5de8b6ef68f3a6f847cf9945bd97ec285d5c573e48ad88ca573322e1eb3360f3ccf188e5a290b4f4ad9fe088d49b974ca2358cbec20c2707a9cf55b80a77d61538c90c9c4f8f5668310bbd7bb511974600120a8d2b0f3c975c1f417b8fccf8280f2e39ed117b8752f3691958c1e3210a0c206ed990a6c671bbf665f9229b6727ea76539641ff36789cf131b2fe364119e5c80701761cc2319a7fc461a77bac8d780781236534a374662726e94012cdd3272990ce6bdcdd04c0bcb8313c130d8194d60d445734b6ee1b835fa4c56396604912a4bd771c89f52d854c0fc49f5f33c0d5fc22cd8dc8b7471a75e419e93f025a2e4572e1916ab2e8a45bfa15ab7373536051bb5ae84aa185023186ae8bec41e80bbd565a77742ef4566d1bf2b4d0ee725539d6fa61ae731d4833a23f1ab3d684585ea4631098d3582b50789d1bbaec7cccbfaf06ab5078e8a7d20f293cf3a3622d633fac533c6dde632ba82e6e1fa0c1978a0cc5e8eb3277f566005eb90102968c64acc19ad2015f2dc00050b3c01429510a8b8f1d80172b1208f9f2a4d6d41b61ed293b0db5968dfb182b2e13f98de895cf90d080ca3a7a9a3803d9e1205f048811885cef0ecdf94ef678e22cc55b9e695dbe3a2261601e706ca9753dba1eccdecdf24d34256732c9928a48cd550c0e17fa38446bd6462f31631c3a2e712fa386dcd55a5607fd2252e0a29e0be055d3bb3a45dbcd961a5e04c0dddb9bc466437fa119095db04f40ab51391b691e29ebb13a437e8e9d7fb57b31ac6a8dde832384f56dbfa187f53a2aafd679652acbad0d9017b90cf4cf381f46068b17c80ad87b1bdeb4b254acda337f4fa5bbea2e27df8abc2f1479fdbf255773b3d6c78a6426b39b38f87c020f9f7da074ca6646023891a7327755400b37db0e463c432253536572072964babc600205bee47f5d906114ab642b3c2411719381a8a5f9f97fae5ca4a13e8958457400d495292b0906a33f390a7ecc3d574a339842c1d7d84485fb8bf2d22302300b4b8d8c755143928266878f94de5a3708370adb69a4d97e660c20d2bba533a01ce963e1178761802905e0f502592f380999fc22e096b5def281653d22c4c9b44f04984fc385793dde3f36915a9b526e2ea1d506371d61c29c1e01ed146b1b15fbb248a6c44be240d0cce1115327ece8cee03b4524f1cf62aa9d95341c817c1568ba2f7a82100619d633a82909543899045b18600d9285811be68f33fcf7e4552a04c198a85eb145e361d99470a56936e2bb96539f7c0be614b6a81c7d861af0a6802283a1fecf8e57db5d304ec151b595d95c3da38d48cdb29ae1f944ddab4a6d9880bbd72b1842d56ac26bfbb29e6ff881e1ed0c9e6e61304dcf84306b76fbd291aac7ed99b64d6d9c430e4b67d8f5e52b3f253d8e9eac57db23ccbd83471785c494f5980d2c094aff481d4d909735204ab8090836c184fc2178ccf5704812d38c18521219924c1691efb3765ade214759d11cc680c2b84f2b9603b657e4d3d84e715ffb982b518156210ed79f78b6e4d166110d66ac0a32c1eaa6aaf365c93ae103b0f465d6499084f86a0d0b86ea5080ff9b2249203259af40d4a0cf84559252ee0251123393961cab5269904d88adbe18da72bb050e9d8ae0815933ced2ae52fe79b6b0659ebc478a945ee20d6ddf0a13a4343939b36b54366e281501354c40778b203b5cebd340d451cd1cb7032de304ce290254e0b7595092cb95a0bab292825e14a59c48352cb5679aa4b07651951dda606efb851afd483e5352d0129e40f5c101d111d58e9a3a647afd10d54651d0f79b0dc89af5133fedb1e2ee499b1407c709102cf8c7fcdfe3eac94ea44c15b991ef90ff1985857d4482b6b890ae64f92b7002b8e55bbb3708e880c4cc968ae54bd1629e0fe3b181143af0276637f1b2f51f11e07a856872b26b4994e233728fd0c896ba884c6da979b04517161185df790baf7f857ded591887eb64cf1065342689ac84d6d40573b8eec7e9b824a53bbde1492216cbadc1db42ff88d4c62a58e758534321bb12e7402237c6b54d3669b305e320471788c864f3df66c8155fe44942b40701140edb4209d3a2e024d4b7f364e024c5edf5ad7d49e809889fd1ead6da7f06c3180dfd6c5d40379d00c4e7653d47a8f1b3998788ea1b9e0b1124cc2db4d0350b070d616c1143ca9e9f965c5c60824c277b5afa243a068b226a1b6131af8c39160abd76c0dda2ab18699609ba487d357c13750631c73027acd5030d7139496e2dd18834da59a5aafac6e09b1af23679132152d373af232f8628e88fda6df5e6348895d851ca5a4bcebd417d184a54e78f38f04749bae54b475943891f696f5da7b59eb250a895bb4ad9992a28597e782215abac9bbcddd0bc99eb2f208669915af4ecb2422ab4719dee7a7bd594c7cd99e7f79d13371ae538529e796f7a74b97528dfdccbe3fe724a7ac52868f3e8f4e922182c938dab8a161aa3e16e3c7eec8a4b413a738ec8a0e6f02d65fef0c3c408e846a3480afd359e2337cd6f938d42d5ef55efa6f9c9a2f575327484b4fa2b8ada9753cf94010143135af37fa3ad398d962ca3a5e7f815c2ae2e5b660945102d53018ec62f03b75e944e13d7feb6466aab40e4ecb4e0d82d35297117bad252ed244fc9499eccab16e05ddaf13df64fb69d87db78e18a85879a116f5346e1d45990d16556d1c356bce4fe2c6fecf090d7fd5e14f7827ff09b75949c596492ca829257253ed312f07add55a7e27b8687a2040a91a86f6e78fc16b9e1da8be2208c0e9bb1c332fc6b21d9d029081ca3081461c6ad1f2998d27152e52540cf2162aa045d4fd4e30fda3005822a5e230597c7b621557dced1438d12643b7a59e7c45574b9cf3e8db7fa93945bbd477369f8020cf67e060055503bc8aae6dc719b89f7b868a4dfd3877793b7c530d814f41d89a8c8ee5d809dac870088564c5f581bb9a50a0aba88931135364bdc67ac0900600e35a4e99e69091d6041f40aadd669b5b07fc95d6d2428b4cbd7c50adf2a398d1f344e79f1cb39f79a3df5bae0a15a7167278f832123894b7a34289ddce8abe8c1ef23107af300601b2cd707fcff644c357d1eccb000af628ed655bbd43b1549fd01128a796c7f4a8aef258d252dc6134fa53df5e278d8c8098d5d859ee5ce9c4a677990790f61753c51805e35687a6f6e2ed6a4d34541f31aa5c4e67e14289a909e236fb4099efaea8a7ef128d883ca0b5a054ded235f429be3af69d3b7a3209ced2da1673f286bbeb0e69b6b1e151daa0dd583f2504828060abe83cab61995351516b0ec81baa1c445545fb024ab19ca4951a84653f80f0b5409f5873a50582828140505a1d28da87bb0fdacac40bd500a8abf45f5ddf01cc3018ac9a3744c43deea1d4a41a92fa87bf0a7060cf50b6541812a4a8711312d4841f150a308459bcf23d720a04e18b5499d5009a1fa78cc07fd375407a0802f98b26947d497e626c183357fa173053b83ba97b408110a350215426d040514f0a2eca427e96979a243c9507880d28106ffddda501ca8b9400155dc04f2a540dd4bd97d1a00144414ad14a4a8f54686074d38a81f5407b58102a11c282e145643a12a52b25e08d4f8a222a90705840a41a9a02814ca4201a9d569c182e2a0568a7b1f41cec6004a93229bf31965598f81ef1cea83929f02968f45e98a94d49850b4a530aa4817a8035584aaa1ac1e14f0edfde77e146d0b0f440e050a8028d1a7bc14e2282081761a0618281db233a47871eddb8262a02618d5d72f30e5a85054358a762e150dd4a14e501dea008529aa2fa7eb6b684145739408a036b0ee02f581b2a14828351406554309a03c28020a3614b05c2f7ae45204a09d68771ee3be3e7ba2a92423373db0070724083178720252ac0cc502fee144760c3750b2a4d001c33f3f3f3f3f3f3f3f2ff0bc6dc1362b0a5bd85226f2ea3665f3de94524a29a554068005462384b4c602c20680c3280007029f0c1e0c5e0c3974e0a8c11683183f2846f70c426a76184483069723860f8a7153b5c3439cae57174870e0c8f1014b70e0c80106aa22460f0ce36d5a638550cd6d0c1e7c3e27bb89f661a2bb48fc606237e6e4a1f2c0872e968f9b73874f596235b8389ff0918ba2499b11b22796e8b33f705192f74caaf012a14f076f715529ef51da47a794f8b04561999aa155a5596b99bd95f6673a96d0ee79c4472d4a92a6eb2f61539592c4e5f0418be2e75bf334a531c8963e66518eda316f50f2c6b8199445e98495e65d9b143226f98845416b50ab175edfb7a28e0f5894367827f956a4f9092d31f0f18af28fbf89cf3933b5665d513eb165af94f2d8a283ad286f28b983e7efd71bf5072bca277d492d257eae38ed6315e58df3796327ee4c92f95085d99af655f2ba23966177d2a4f4eb6bb055200408e02bc1472a4a6772c939b4866c13c30f54946fb53da9cbbcdec6a7284731399f464567fbfb618ae229a173ba7e75ca94e58d8f5214a48930515b9b55922c091fa428273159a9def07e8ca224f4cd97940d8dd1ce87280a6f3d424eecbdaf1285a23c2a359ef897e94deaa02809a7f526e7fe5c9bdbc727ccd9365713d93bb132bdcf356a1e4f4c2ba164c7f0e189626cd32499dc98573646c34727ca3173c97af1fb41a64982011b94a3c207278a1d3dff3b9bd69b5bb5f0b189620cdff145dcc5c91e6aa2fc9e6c935013a4783ef9c844617468cf13748e3c810f4c143396f6d0d6fbb693f9b84441ebc44b8dede77b630c3e2c51d09afe5a4b64eae6eba312a5df24df93b2519e8f8cec482fb09111005ce18312c51651da57a1793eb993285f8e94bf3549a298c93fc713dc4795d47f44a224b498feca093f2051feb8a369b4c66ece691d7c3ca214324b8969339c245e868665e2c311c5f8d8e8f1eb3332628a8f4694426a9824e660c2433482f0c188e2bae9df9dd12a4ffbe06311a5f1ff924ba78512ccc187224a3b6a2c6bfce492e3a9c1e685df0f3e12516afd64b2acfb40c49961937aa7f410a5cd135b74d64726e5a8147c18a2982493dd39c9a28f4214f4fe9fa8ca9f244611214a6a94ccb5657d0ca260f1a9df6265b5b3461025c9c3a70e9bc31f8128e9763a3549d43cf80044f1ba939af2e0c1ab3a1f7f2809c26487dedc96e7fa871f1236e98b6509267d28e66a499126e7689d4af8503031b5f43e7b7787d31ecaf9e22628fb204d68480f25f1bbe745bc6ecde7e4a134fa6173c8efa84d62f0507edd6b8fd9aec4ca983b944c4dce76e9de6dafb143398ecebae32a2a37df752867f79b4c22371d0a32a47649a194483df11c8a2f4aebc92d5ad55b9543e935549e096fc6a1a044b76d7ad072ae261cca5df5267f43399f1862abf7c483921b8ae19ae4bed126fabc6d28a8124767c7ae8c3bb221133f61a619aea1bce5a6dae39f546e721f6a28c63229a32655d3508c7255a3624dce248428f84043491233a566d392e6d3c9198a73fae7a727d5c58acc5092df74cd68f34fea97a124aa8611136afe204339b9fa8a38e184c9723fc6e08cd8b9cbce76698ba72bf92697bceb7c88a1a04555345f357b898f3014c3263d4268b715a5c2447c80a1604289a34207f5e30ba55332c449d9f1041d99051f5e287ccd7ba6ea99a04914c747174ae3e22736a76912c6b4c907174a72eecc310962ab57fbc716ca65720c7ba208b550fed8fc68aaa6ac64ed230b1f1f58a081808f2b2ce0c30af551051cc917366850610a0af89042023ea240c306181110f980828c8f27847c3881c68c8f26d098f1c184057c2c41093a443e92f0858de4e30309313e8ea0c3e3c308313e8a20800f2214e0630803f81042003e8290800f2010e0e307340af0e183f259c853f25c8743c71738de6cefa30725131f111ea3721a7cf0a0989a35e38ecc5ea3361ebb2809257f92e4777451dc121e946ca1af81472e8a69374b8811a573aa8c8b929f204caaf0a8c72d4a623dbf624627e143ec618be229b137d3ce8ec9985a94a4d02254fbcc4394092dca37a746f39ba459945634a86831a92c4adfee73aa34e6cc61138b9292d3eb7d1ecf9a1f58144e50aa4fac737890fd15e5ce38a2b4957e86125724bbae7bf3d76e45c1daa44ee277cd8ae269d3a0f155dffde72a4abb73324b9f3acb58a9a22464ee4937a95349532a0aef71e2e6aabf5d4e5051fa0c27d4670db92de95394547ecf5849f32022539453cfcf58975b8a92f67c3a75f690a2f09ed386e739259faaa328a689d19c46aea7b94e14e5fcd4a737b6e9f0084579a38ab0f3a0620f50144bac95b1f43f71c79dd331e7853c519031797a69f79d2875dd99e58cdc8dc9e144726e26f1b4ef9b285b6dba65fe3f6192ae8972988d87926da545da9928668ca80df7f149f38b89b2e8a876b63e2f51b2912597922126d57e9628da9bc6ecbb17911bab443906599ec7a42729cecde141897257084dd25a096ad94fa2ecd935b7e794cdbf614994736ecb3d99838a6a3712454fcab6752ddfd30b89e2c9f1329c2c329bab3ea218cf43499ba7744479c64f2c5525265964641a3b3c8080116c0001322861ecb071c3cc40066964240c93238781814723caed66a3cc54073f25c38882f092e4e826bd069b17e946ba51bc483752075240c3782ca26c6a62d66479be1e8a608f44a80722cee310c5563749be13356b67507a18a2709e41b489a1bef5b5367814a25c77e3f2334abccbb5081e29692f2d1c44c1a4cb94498e5d102531ef093d9723eb9607a2bc27e3565b2bdf641210e568f7fb72728cf79ffb434193d4493ed93a3f14cfee479baa4d95bf0f2579bdc3247dbaaee4e6c187a299ea49659d79b44f121a683a72a4c48b3f015b261e7b288712cda4915dbddcb741e0a1875b81471e4a729de8ed9ff66e27091e501d4553c8f0d89dc71d4a1f93a053c8a81d4b7e6bb07d916aeca081be30ed61871c498f3a1c1d4a72c796aa5fa6065bd9123ce6502a71cd3e6164b4c94935d8e450d40f6ba3ba9471380f3894d4e724ea26cb4cdfeaf18672bcdde68d1d7c33a46e285d5fbd670fa623cec481471b0a6ef28853d2d4c88662bcbdd4d56af924de494772c0630d45afedf5202dacc186f8031e6a289eee7c5692896ab09d471aca7e9fe6c2c4d618b6e12cf040838d9c0b3cce503ecf72ea9b83699c2032818719ca23f4273967b030c99494c1830c4553db64e2c70ba5a311468e1d57028f31946327dd9fb226958a654003c70e31943fdac6f7936fd27e57830da51a8147188a169faead73d2ce7c028652dd67d3b1a3ff8592e7d5f7c9b16dc2425e78946c25d639c977a1e8a22b93fcb9f927e9b950bc12f4a8c8eeb750fc2e8d53b276fa6c1a2d144389257fdcace5b6ce4269be447a149bb150f252999aafdc2b94cc2fdc24bd415e6c6b85727af7369da327cb5fab501af94ca1268918d3930a0599639acd9a7b5227e1144ab922f49b8ebe6b31a18187148a7163126e37a75f6f1885627293cee38d8e85060a2599613efe868790b5793ca1a8e97c336e07f1239a8713caebdfb9b3c4a38cb63c9a5038a183a7cc1831692c087830a1a8d146db7b12ed37c9f1584279b4cc49d3e1342859bbc14309c52f53d731271dc489198f24e08807128a3e5f92b69e93a772aec1a6630637c0c831031d6927f0384249b63e693d36f3069367bd2f3c8ce03cf0284231c6a877256544c38308c5dff97513738b8ec975c26308259d392dddb7a6613b427808a1246dffee9fb8eb22e1118482d29cff79f5727e42878407108a39c969683eaf175d5a8f1f94b45d4e54bed66692a271100d1d666dcdc30725fd7b676da5d37bf735d89c032323347460606484860e2f12101e3d286e1e0d21c2e3e998ba0b544003089800022ee06ff0e041399b8aca3d498ea977ac5de72e0ab71b9e5bbe4388f97451b02a1d3a4a3cc63ab928c8b41a1af4091d64c645b9e4fe31694eb86f32b945316747ffbb098db649b628d90725a679f82449fd602dca26095a671b935c722ad1a298c1c4c6344dcfa238f284b398ed6cb208c9a2b07173728ca11a1727b1289e70a3e3bc29f17444b02898bde6e4e163623253bea2389e4f49f275d576d4150513f98c7766af26795a514a3d1ba5a164585112231a36868ee9f36e56513a17f99bbb2564335745398bd8f0fd18b3a990c15494f3b56f4c327936284145595b664fcacca728864eff6f628a2c394d5190ff50a3d4272da324b314a5ff2034c6cc31294afaca32e357ab4a7e475112ec4d7ba4898a82d1941e4fd2170a4541e9fa189966c24aa3a028e70e272e4cae2a57fd44b9fc9490a74a14cd58f244c994d04ebea14a8a5076a234a2ee4cce1742960972a21cfbf6fe66bfaa3fb7899288cf41ddc7d1d4b3a326742bd97e2af5cb44f1547a7d4ea2f39912c344b14d4ff674ee319420bb44b16c8479e8f91fcf181ba41d33f0a2c60e1b3568a361004b946e44bed73bc8e0a355a2584ace91d125fdae579428471332fbbe841da5348982d796161dfbc4644aa2681bc424a557278ca891288e2a858ae6becd251e40be50fe1c3be72462d76003c38b1c356820b32f6c981a13e0168078a13097a5c524f7185476e400d285f287ce583dbb9a199db901840bc5ab6b4d53e7569fe4806ca1f578f5f0baf46e1db19ecbb87c173fb525102d944451a6397bb24f0d205928c84f8212ce7e4c49b2090b4513253489a9a32b14dc2d74d2192d959963856275a9d3529dee66e32a1464ed548c8ca6e4b01f0815ca9f44e79960029942d994fb7729afda4d5f0ae53d614c129b7d724e2a90282cef3557b76e9a25f3fd3996c56e205028e90eb725d7aae4bc19c8130a267e3815fac49d5056175dfabcd489e1bc269436eff4c9ac291026143bc97ed895d304a600b28482faa78ea5d5a4149303a28492ec59de6a3b8324a19cb5f24fbfbf54f30b8284926dd665d261ffbc24811ca19c4d4bb6d062f2349a18a19ca5afd2aa4cca248d0a528472de9aecf721e420442867d1f462e7268901902194aa9465cc70726aae580805fd0fd2d44bab5b29418250ea3f294f63ac5ebd1b04082559a1565726f64e3cbb00f283e27d105e1f5ec3241182f8a024dbac4ab215dd81f4a098aea7a19f6994977807c283f2e899b61a0d426ee66e1705d1cfe6a6e3ca4aaa580532745172517ebacb45394b4e9dcfc6940519b828af686c9f9e26d5e1b94579c3e726354aeee4bedba294e95edf47666b51d2db1ca3e9abb64c8d1625371193ab7485286316059329c6dbc32e4316e54da5745f3f4531c88845a9454c3ccae6686f2219b0289df4f93a9a12eb9b9b8c5714cd45dfe68d0c5794946d3a490cd1e91964b4a2e49ed4f6c5c6cee9560519ac285cb6c764a29eb03eaea2247f5ae9249c36d3b165a8a2d4d946885ea96c7e2f15c53cbabda24db59598230315a50af78c491a5d1be4bb21c83845e9ca635dab29bb3c4fae0c539404a1fa4be377b94908324a51d43a613b87f90db75f06290a23ffe54ed88a8c393b10648ca268e31f26bafd3aa8900c511473fa1835898cca0845f18350a227eb1cbdfecb0045d9a434f1dc38f113c5b44ee5a7d751836f3c51b8f594677aeededdea4441668893417adf7eb832385112e2acb4c773fd0e4fc6268a55a3dd257a902236265313a573d31ac63d6a09edc944492db5737478fe9c4a30516a4d6af28afe5ca2d4a9046919c44be5c9c8b0445957e39566ff16175d6625ca2f636b62862ed19ecea444594e8635f946ce9c44a973668eea26f1f2e34c4994e73794d8ea2945e73e33122555a74f8e7ac209150d248ac9e2648ee2f6238a952332c8242fc311a572b54eaffa1b517055156d3a9597bc31a2dcefd5277aadd996691125d1d119ff2cb4cf9e88321451dc1639b965ba44144dc88779ef9c46e5c911511819fa4bc98c5b907188f2986ab4bf924b33b788320c5110f396a14d5092a41e23ca284449b2919ef1b22444d932f6ffbf6809d3a24114a49bc99bdc4409a2398228e93c6679aa71198128bd959fff6a79723b6500a2eca5c48ec93e7f7628c9f843e98469bb91f1c8f043496934994d468ba7967d28a9a9b23b53afaecdb80c3e14e4dad589a2a1ccc5a6828c3d9494162d5561aa6963848153197a2895d99be8498c51909187e2ccd789419c6b1e25b604197828071dba57773bc997ff4ec61d4af2893186933b47861dcae6a743c9134d96cca78c3a9474ccd164cf4e22830e2511199d467dd494d1aec126630ec5ff24bdfe733e4ed0caa124671ccf10fa8a437175bcecdc4a666f090ec5ab389d1ff4fb8672dec59d1c5e7b7b536e28e9933732c6bc1a3eb4369494ec34a194c72463ccb1a174379a94a434bf8652754753cd93da4f5743492cb973b8c8d422364a4339c7674ffa3a5a9ed4a2a15892f44dd1d99ca15c72f89e13cacf5483cc503c513c89d7f15f829dca5092ba4c6b12e9b9276cc8500cdff60fbe4193a4248da1d4b59d2fda8aa1b8315d76aecbc350d2f03945ec2c030ca54dd649da2064b68c898c2f14844e25270d6fa9a11e195e2829915de2b376968a25a30b25e5a1a38b8a51ba1e86820c2e946d841077824942999a750ba5ae915a279af426c8d042e142b45fbe9bef4972441959286cde1ee13185300932b0501cf9314d4e733f4c9016645ca1f89ec3956d5677ee8c150a22b398f250929f4972aa5012fa73fcff91e1cad4543074c4690a29ea299457b3acf6f87552af91424949a13e4267eaaf3f0aa5d50d9a2413b47a3e29148af1996a4bfe89257bfe09a537f939bf3e57764f4e28b79f9053e33937ebd78484f73631a1e47effeb7a270923cd25944e7f9c66123ed5c7aa8462c896b4a19e4d4269b764d50d5d8284829df420fc4b76d8701ea1a4eb2f37ea4e2394b59372fb24660ed37d11ca172626939fe029534c8462a8ba87b8bc10b1dd10cada269e5ffa2784c27627993e2e5f69c241289c0ea1744f4e13358e8050f8cee62d9b8492a1df1f14740c9bfb4fda07c5e0a5946062667a5076134dc97691cbe041499bb42fbe1da7aa25bb28f7bece8ae6eeb0a7d74569ff772c4e664f77712e4ac2ee4e858c372e0aefe9e9d1e47e8baf47a76b87756c511a6592895d7ad7a2e059b2694f4a981605a5243b25468ff5ebd12c0eea374c106551527af494e46a23c6a2b05fa5cecd3a8ce71c44589c639f2c32534e315e512cb1c7f3efa6677d4f1262b8a2e07135e9abebf220f318ade818ac28f5fe78fc90711d637c15e59c4e8e41c55655146ddf64cb7b7b12833c1525196192e0b7a98350a2a2985b723e6b87114a7d4e51d01ea6449f0dd79e39539433899fe37bee1cd4a64b5132fdfd277a92cc3c4b8a6252d2aa5a6bcc49cb388a626649ea4df81266ca248ab28c6512c27d3d683c43519264d5566b5e415112133a09a546346f27f944495ef772cfd7149f644f14f443f79820bc189d28d665e8a9501d278a21435f9fa04edff66413c5faf56c26af26dd9b26cabd793366e9ef9ce32813e5cc234a18253c4bd02326caa149a68ed194d2f8da258a9bfbdc8485c6ef972d51ca36ddf8499b54a2243a29ed4a8f23d43c9428f7c85c929ce5bd32bb49943b7318e5a92949944ffa6463f267ba3e51248ade7bb31a350b89f2686811a6a7d442ad8f282619f6fdb64a8e28e993694bace3334ba811a53e25b6d586d737b16684a7a2335d44f1c4a8399850ff1983ac8854ad669d3aad1351ea581e4ce4dc9ccc258828bddde792d496621ca29c77931c4df29f7b098a6188a28e9039369e14a2546922cb5326497eff310851d4e0ffe2b2699289d0200a624ba8ef518fa39ec51084f96fc64498307e06a251e53b621902a25419a388ec127438298df1877de54caa4d3a64c9c7f043152246084bedf39c1a6c17a30fc5d55d6e9859dcb8a5b96bae1f1b133bc80fc7e043c9b39c1893e469be598ab1879250f91e74c9223d1477d3cce68c9f3bedcf4369f6e48d9bb388cb128387c27a9834c983e59cd21dca1fe38970dbd81dbab643d9e663ccd3b3259ab37528c69b0e9364eefbdb930e59c9d4bdff1c0a379ea3f664e5a0598c55ccc8e8b556cd28d1e492d46a3a0ea5b714b9fff81e9a4ee050d2240916269b9244e992371443ef98463329277b891bfc244369b8d69836944a949f1cb3a82741cc865207bf101d54e9f053d750bc92734e77da637b490de5301127eebfa4ff36d350568f9d5f366631d0f08693995bd3a8629ca11cd566abe42b71529c662809cf3339537c31ca50d2294e267dd5c520433974aa884c952777b43bc618ca3b62929c73fe7cda670c31d8488c30149424f24cadcb8ad6135a186280a170a3ed253f4e31bec096cd557ec7eb16c30b4593255bc2eded85185d28e789f7b9fb6a262a1b1961440c2e94cacb3baabe9d85a9636ca118b2a4bee7248ea1855249a624412e565468c79b4631b250de16257bac667c743c31b050d26e9258f7b75ed680185728e6b0994f940e32f54c6258a1984c990cde7756a1acb98492af9f4baa53e3c92006150a42a8dd935b62a6ffa631a6e05f783ee1779248a16067926442d865d694a350aedbd82ac94a4ed50485c229bd7b9d3b339c376ed88801f620c6134ae29c184dc912fd20a7bb410c271483f856d66f4847138ae7ff9a3b870d9e8493098513b4798c2bca1b333049424b28aae6d4efebf969e65a183194500ed2844c326c94a7ca8883184928e9c9c613b4bd55735368831848288a88ae9cde6c92b3c311e308c590f2259fcac4644a3742a994542ae276735e534f478c22945c6f3cfe83aeae5012a1782384cc23d44e36874937be6fc41842d14d12afdb1b474c73f72286104a9b93cef14a0a0ff2e4bc2008e5f89c7973f22e693aa363611003082579f3e72cbde9481ba5de467c694e17ca49a7103949479446b950ba0e2d1963f292771d36da74dcb0b163060e10d942f9939ee6249a4a12056820a28562aac949dc468ecce9ce4249aa90f9a5197b37c7582867eae9b0b626c7daf20ae50e6b9dd4a42695ff5be14acf954bd3ba7bd50c72c32a946eabc47ffed3399550a1aced26327c7fa650ee346b72f8d448a1a04d7c3fbdd255d1a14814ca721b4acc3a08d18c43a13036235f236493c62bf284920cef9239c89c2fe389130a2ef6be75ff19f763449a502e6f4f2df798cc348709c5cb5ce7a72bcd52c72594e450629a7b0d4fa289514249aff30935fdf897b948120a4ae7f9acfba5de4716414241b50825e652f2224728e6f18cf13137c67b2b62844db74bce4e6cb75cf5f4fc735a7fc8ba458a50bad5ee241ecb800811cabb49d4d9fdd1ef71141942f9f336bc33496b828e611aa62242e0ae3bcd3575ccb5ebc35e283d42224128ef08a5277ff3a3230242f1e54f68d9d56bb0991c33d86174e4edf8c2068e0fac99210d911f94735266f27e624510f141f1ba4e378c7811651f911e1464ffa7b6938d31453d32827610e141417c5e6e8fc63cd14cc82e4a17fa2faea4f35835d24539c642eef45a673521b928989f68e6a7eea574878b82afa96cf19d9bf5925b244753f229ab726d51d8d3aff9049dd49d94d5a274bf7127a6ba79d3295a94eb4e8e5776f42e9b675150bfcd4cc296b2b063cf754dd776e5ad2dc3946f3a9da3e4d46351ecf02a5f1f7a766f9a542302382c5053088145c1545a96183637c97ee515425e51d07bc29c4cdf1e26d3ae28a6cc2686d2dd0b21d3ad2858085582865535e14fac287fbda9fb953969c55b45399fdc6db2d99f762f5520441505fdb14a6ec80dde31c3869054942d3e5f975882810ea480068e1054146f378406258c8bde1ee19840e721e414a5d3204784a84ebd6914628a62d0d0719390c6990d300c0d2f74981a3407424a5190316689e68e93a2fce3f9437309fa356821a328655b7d96d62e3d9328d8b2757b17b1b78c1f694abf9de4261a8a82d83cf1a25386f4d98480a2e8f6b9514eba219f2807f51bcbf8d9cf7f433c513825db58e8d589a228ddf1c2a385d637cc1739d20e3e1d3a72cc60023ad28e3024e09c289d980ea31fc2f2541bb209e77b444982aa93261d219ad845c4dcdddcab624f3b339e52675d6562428799b8104cb49fa771f566f2a199c5d4c90d9b904b1484963e379974d4dd6e89c26997151d3d5c4b682a51facc0f639bd3ddf4a2045ea376a59db6e2597726089defe4924bc49c4461b38e1e25ba9960298648a2983b6927ef0f25bea190481444ce448426314e928443205178d33cb2ac67d466d203421e51927e55367237e7f02347946466d9664d0d25c81ed28882550665a22991ff358730a2f46153f3da5d791e6de6224a82f8dfa4398bac0e934c4594e4d4e8662685d02e32c44414534d29314676f21d250f4144d9e3be8a9efe1384ed87286e6c91351eb5f32879288418a2e8e16cc65c733734ee3d08294451efd7a4dfa87949720851ea2d492b7be389ed1e32886297b97ffac6d4b65510c5ffe0b91a36dc64dc8404a224dc2895fb61bbb64a2180289a2475c6f0491bf28782d6cff7c850881f4ae2e59bdd270fe23f8dd887d2951c4df521848c5b08e14349a84ce359478ae9b4410cd94341c6c9ae351e0fd143e974ba3399531f9287921cef0f5fafadac31082178285b85759b7d521b97ef501c5bbf19134fd212447628c8ad8ce727ed4e50e23a94b4aa4eae1b910ee5340bd99a4365e376e6500cbb7fa55743cfcc54851039947aee73ebe383ccd81421240ec552a35ac2dd835e4fa9100287828fc6b0fd9341dca76f28c7125fed4b7e4f9276433983aa3a21bdfb34d73614436df63e8ecc6ca76243d9ebac640de50cb7de4f520809216a2846d3bbfa1bd31e084943494c323267ff0d32ce090d651f194deabc4975533e4349c7e8e9a7d733611d33944346e8a09d3a34fe2a0326baeed615ef5a756d69397b4227133c870c8c503a68faeb3b8662923ec6a4c397ca18436228ba5ca8a75f3f0cc5f864f287e9f89a660386d2cc082d3ae612f24ed5215f28f868a8fb8ad80be5eb70e25ec649178af1c43d974cd326b5e642c98496933b7c49a6e4e5215b287b92844fdbd2d142b1543c8cac7337f9b31d21240b059d7a9ba945988ca2c5427964ee1979671a33ef902b94846d9518647718930bb142d1d48fc611b2e4fbdd2155287aa8f8dc768d9b5e542a94c4fca3b3bccee6ff35640ae5f64cba721fe5cdd31029943cc92685bedb8444a1f4254f9fb8957d1fc41028145bdbb36d4f5a71cd439e50ba93df395274520e1b14b04288134a2174468dbb18597aa24d086942a9c47aebad924129796d258430a1a083f0ccae494f67bd6a30762005344642965094b70cfa4d946ab0d5d031831b896620440905d3281a54e98b9067d6607b018e1b189284620e6d25c9d1d4ebc48cf922318e0d20a1abb84bd52f57ed7477ed2f4943ebc4d231492f78018e0d8081a30323232fc07143438e50eeffd5d839978c50104a2893791aa54048118aa976763f9c44285d8fce12ad5dad2f838290211473e3ee663511f2632e849228b14b84ce0b13f50e098297d662b1dae6d696997dd2768a7febec307608100a9a3a8e0739579710f283c29d3ce19d94185d4cea5808f14149caf8892729f9fe39ec84901e94048df13eee94986ccf85101e944bfe19fb5d0bfb18d500d94531ae96c6ec989500a28bb2c91a6312dd7cb6f4e7b928e620aea683c7677bb868f33ec5f36b64f4d23d5433eb6f79265121f3050e1b5ed8b8e120b728f5ba8c959c45ce44df16a593ac2499eb37b52849aac3549c8b12ed3b4600a145498999361ad24e3a4c8d0f300d0b03641685b5d2ef41b72a8ba299bc994e9ef10451e6485f00894531c86a198fd1438735018145b92f45ba8f277ded5f511a4de12b52abbd37c334cc15c5934ff55e061311bc0e1b5e24482b9283501bc62cfc1c660616b8619c15259d4d7c338d56e357ea551494524d22a61642d3abc1a68ad297d00ee2754c7335a928cdff06add9e52276b20e4050518c614ed0a15a66f7740a198098c234ab16d5dcd1b6b85c93c4b04b51da68723cb9c40a1dae2245e14569937f4209c828ca697e3e5dc7b5d4b841445112a37c8d4932588bce86a2bbbd31cb5cbd7299570f26e79b4b0ba52350147e4bf66cd289cdcee5274aa2bbaedc98209e287612b78474fb309e459d28a77bc6f5bb5b838dc66e200212f0c0062cb03b6c90767c81e369ac71a2248fdcb425c9de0e1d386200b28962abfa08796f16ba7e4701441305fdbc0a694af85cf24787b9310197024826caaaa941296974734991f9c0c8080d03c144714cb579f6a46aa1f49728766e36fdf3b6f145098825caf21faae4173d8254a2f056f623fcd449aa94400184124513e166268a6ab609029944297694304ace410b2347f7054024515077214a9b9cba9478a11bc946054646746c183bce0b209128e7b71e53e9b1a4062151cc2155554598f586e811e570be994aeca9d37103e288f2094235ddba8c4e7dd2888289cd7ca8944bdb9f11c538cfb6d1d3f6dcf9220a4a6d9d3eabd5543a2ba218375ed207b9b81373798928f9865c784751d2c37a8a8882cbefe92679276812563d4471ecd3a49b983a8f980d51d87e8d9a4449a96a21ca2574ceb61d97ee7a6a1a4008512c51212343dc54add783288c69d90d76662686ba0451928412f79817d3a9633410c5922b931fa46f8edf8028aa9bdce3eb39893f1dd53f946563efe951e29d0e0dc78e2f30303212468e1d3a6cbc20e5f001881f4a26eb4e12a4cb75ec3fad046d3901903e144dcf4ede58e7e7beedf8c22c1f8af1393bb2346934181949a301eea1186bbc44d9ca9247da1cb0014604d468a046036403881e4aaf3d5f1ecaa2745e7cf0d4776e0282874c7fd32c766d903b94ab4c099ff1be1e80d8a118f79d444d3491ef79903a94abc64e7692322074e0e4ea8469de8f39d3207328a8e692b9a4aa92ab1518618ce0032323378ed9910307188d0510391484899afbe1dbffe4d1c8881840e2509017699a31ac9c5af10361ec0863c75d01040e9ccc6c6db8a86dd6568d8bfe390b4d2f1d1840de50d48da3f9c4dea83e017143614ebe927d93aba1d394e30309d286d2ee954ceb7e15669240d850f224497afc3f644cf2bd86c27ada5bdf2e13b6936a28b9ade9f4df2bf9b408928672492174dce42428b184d150ececb6724f7286527a68f5384de2a8d640cc50fa5c9da579739224e945014819b22e7db396cb9ccdcab60ab91b435c329483c9c5472f41a6f0fc1709640cc53e416ace4932e95d8f183c133911f3b894176ffd2cda774be82409da3094e48866feb79e3eb1beb091e80002868214036628f69a9cfeecb1392f4349cbde079bf1246a92a12c3ac58927b66994c6504cf5d9caf327f9491443f16343ff6a34f9d10b43418c8d7f55cac61018ca416b9650d1f00bc5603ac953ee412f143c6e4c6b0d73d5a42e14d46dafe38bd5671217ca9fef9318634cd361da42e1c2c7e563490b2541ef62ef04cd12cf42d13c2613a733c81863a1709acf4b26a5f55d7485525f27dd21f3562886fb15b59a5385d2fc86aef6b0a2939c0aa577d7ef6aaf3f319f423183b4d8183a278572e5ca565aefd6b517859286bed3f4f3db3f0f0ae535d1d3bfc94dd7dc3da1a04c18ed9dec5ef3764e28af2641fdf5f3a6d8ae09c9f5b16342514fcc6e6727f163b484a2897a8dd149899e7f2594e47ad73f3d6523f3492869f66bcfa5ba44ed91500ca54fddca8b34217384f249a2e77f527c148d110a4a66f9bd986c21572b42396fdde9188412b755234271e4372971b65f42694328886c759bc999108ad19424e61c93582a0a42b1e37f480f72d63c09100abe3a3af4930e17273f28284126997d261f144f932e31714c9f7f801e9484cf415975d4fdf7003c28675f3de9a4162bf377c1ca09be2e8a1bbdb54a2e4974d4e4a2e8d77165548e8b92e49bb673ee5b9462f49489a2db99c4b628a9eed30fd98d49676b5114dba0e46aac6d132d8afd7f2f22c3f8c8cca264c266917d22d4c9aa2c4a4a12d3dcd13fbe83b128888955af76b028fe7749ba47af28ae49b37152349c1c734539c878b092561453ad4e6a69062bca412693ac24c964c62acaf3a394789a255baaafc1965e9003477268e7aa2856f95baf9bb8561eeb9a918a927a9cbf37cb74062a0a329c1275cf2c3d8612d55394b3e77ce2b57ae9983e39c314a5971367e489210c600e1b34c0d091368719a5289a28414613a91e834e328314a59149c75c7d255c09f3288aa73c6cfcd56d12bc1545418ef9ffa6e7a431d65014c7d3d9fedec8e634ce0045d9cc63da8d267fa29c6378537b0f2f08333c5134b9d94f9cce933c9c086146274a5ba7a93fd5a91739274ae2c27ffb45661345cd6a66829c68a2549e644e63b9759d431d99289fa432c79c3b87cc66c244c13c9a70728e9de424d34b94cfe478d0a9d34dc7184b143fee97246e095fb2a54a1474fc28254af2e329a52d6f6338d3248a26a8d52cfa45a937257692a8744c4aaedff845c22caf8c8bafcbcc6640a2a0252725ba4b660d763fa2ec26423f9d876e80e10506c290800e1de6033f32628e28ca261d7f54f56473dc88f2bce64d723849ce378d11054b39f94435661125f5257ccc3e1ddbeeafc1b68a289d34e55b5b42a912ce1a6c896846224aeae733c70fa74f4bfbc00c4494a418956d2b0b59265a830d2fd9c8b1230f51ee12f22491bab6316d88a249db498d495b0d362fb610659fdb9884931673926c924e8882892935c9f9bad2cfe54114c634adf4478931ef331a36c051831d2d88e27a8ac664258fb867f502512cafdd76ed58191b5483adec055fd8a8a1c3d4600ecc00444136a3ad7fd49c4cbcf50fe530a3da4d78925525a9cc0f255b2f0ddd1dcdf2ad1a6cfe3a6c78917d28a6d298a64c30d9b0976d0433f85012a72709a34e7c2891ead843a9af3bc913e4c44c92e9a19877264f4306714f661e0a3fa7a49244d66c4c8235180f25bd262664b0f90e2571691ee5e490f13b5866d8a1a03bed9efe2872b3dd3a149387cf5869a1379ea543d94af3ccc3c8e8756a0fcc9843314bcdc46fbad5242b95435937e7e6f2f7d62c9b068d2f72dc0566c4a16876b2ac7e9998736f376ed8d0c0c8080e1b34c0d0a170405fd8a8c11733a0f1858d17a42380196f28ac26a1ddcdca33fcc80da512a49669d28c2d199cd106adb3765c4ee3ebf6b624e126edb406931a2c81196c28789589b44c4d621499196b280793ba57b23769c56723497206374c093050810a8c8cdc0c359474d07792c54913a1d58c3494eeb46c940b1d0dbc75a8c766b85ab57bacdc76c7757bdb93d367f0247d628dd68f3135c30c5adc985e6dc7b7cf9aa0d3e9b01b3c2e98518672d75e5dedc9e1248d93a19449db9fd01babc3555a983186624c279949426aa8927a1d4498218682b5bb991c113a97492e0cc5d1e26d2eff926006184aff497cc6541d4d27fe4241cd49f7dab02e1af6195e2828c9afb232fc6a841d82195d2807d5a964f3dfe7b26770a15c6a25535dfd334fce164ab277ed33b4a0cb8abba95d768cf7e954219394a1429784195928799824a704b5f179923768243070bc0eb45481195828d6edc94db6a13e06255728867cd3d1f74c073193154ebad7375528099d33a375cee0c1cc195428c694efcdb7dda227c98c29b81a5aaeefaab55b3bf7c17474c96ef26d7c86148a27fb397614e5aaa504258e4229e7347f6dc93de97fa6614607faa43b980185c2a726a957a3abf5d68c2794fb241bfdb20e223c35c3090539654a12219e0d1c25581ad684921457ba69b1a9c10c2614e3ab986cb9bed924c33037d2054646900d528d194b28cb891f19b92e66b5cd5082b7367abbba79e99d1b9b1f4f3213bb8327abd28b1949288acc7ddf70531eaa9c8184820eb293f5f999f84e728472ecbc61da24f1f58c5092bb214e47e69358a72214d53d93189359c2dc3e8308e5b23053da3c4fd02447c28c2194e4e851afee5763fe720f6608a15c32cec5fe974128690f2243892598b7d84028c924aeae2773db2fd98c1f9447274bab0f194684b855878ec6b1038c3072fc3260860f4aa263b29b4fc2f95a23233b8c173970243474e8483968b4ea408ec18c1ea04e77f860ab5bff60060f4a2f2ae36dcef50329c72e0a57c29bce6c2ab77545745136493e88589b45725166aa5c6b68bddcaa665372cc5662a5082e8a26863ebd9fe46f518e6de99a525f933cdd16a5d09251ebf67115e25a94574bd2923eda9c7f9a0722b42826af3c99519e26671f0922b32829b9d03a32f20e1c37443032c2344cc70e1c3774b489c8a27842a9c7c660bde3ab482c4a4a8c7bf8acb2af994404169e7610defb723a2bf20a342e652f3fb52edc56664f4e3b3ff94950fe8bb8a2241b94924508a519b3482b4a6a4cecb4666445e916ab57f7f2221f931c4a64ab2849d2fce6cfd19f04d1c006420a789f79aaa2e8663da6c4841505915494f6ab75115494ee4deba67dfe5a6e4e5150326da9dde7a62896bb8949d4a41a4e264b5132bd762f6f9d14056d576272e3f7f9dca3286bda98247b6ca2286d12be2773cc9cb39484a2a0325567aab7cd730b14bda5cee88e8bc5dd9bcdc9cb9c7429ad41fd094d90499df613634646aa20e289621a159367279cccdd1736d01733c0c197db9d28996bad7f4cd169e18d8c340d4e944da59670ebe3043651925475bdf66755359188268a79afc494f5fd8a934cd808264c2f6123229628772aa953995279caf42295289a4a134294d49121935062d35ae6159b9426c1ea6668ea55c678d5e59ba45398364d566e9244a9475b7cadf2b2486ca1646e0689e298c91c79ab0aad311d11794449b0f592e4ef501131d760a3618354832d8788234ac2df8852ba57b33b74b84823ca364ae77ebc0e8d18a40406da17228c288bee1863c7cdacd9fd46c0082c605208d2dbb82182911a228b28868a5f8f6b9fbb9583e1858d91111c364646bec0a1030634b405228a280977dff91f5293683d1105214bd89f0e6f15999374208b20a2fc23deff74fa523a260f510ef11ad373d0a618182fca54c410ec5dadd88a58ebee7ed7bc0793ae329a8a931a6c5ee0d8a16306bf35102944c1840d1354644efef2498108218a394a64e4751c573f890ca2bc1bec4e7e9f2cca4f228228a63c65db1b736ab0e1b07127120816880022edb091c3047f285b9727a9276ea3a13581881f8a9a42555ee329d287a275566cd49817e1c36154ec9c52377e61e36c0fe5fa2469773ea9ea7ee481f485074620a287e28aa692bb9392c29987b28a2c413de7524ad398be2081081e4aba2fe2624d4c3207e51d4a97fdf9a5ea59262f0c88d8a12c3a5c7f971426326d7528dec8ee133d4b9f7adae9508cdf4e72963d615f631b7328a717d95a1dda47ea470e0535cd7f259e395ddc3814f4ff860eafed24281d0e997ab4366320f286f2266d720c278e0803113794a35f87f7283f32657403078ea37a43a40de5f513446689d85012a2836937c14e67c3226b285a6813b3848786306d0944d480756dd5c8d957b5876946d951557991034705bcc88123e11c3bc04843e1c62d94dca413414341094aee5eeb3db34e32226728fbfd8e8e8977a208cf0c6ea41c60708b98a13832c9b2a14ffa128498460dd2176b1210294339469ab9072ff17a823576980f648d1d068c0c63c7a50819cad5ceddd4f48e11d797b992c3acb16387c8180aaa969fd4c888a178aa36dfc9d341aafe226128e68b29b935f747100143e9a450e246448928b143912f94637e9334447cd7c639125b8ed41d10f142f9248cf8a8342ee622e25024120704c280301406087817631308001840200bc582c1603c8fa4e5071400045d2c1e382a28202222141610200e0a05e26018100687c2603020180a07c3a07060889848a13cc84a465924120ed7ceb69ea9b4098b722d7dd09432be77f5e1807c0cf37d9cabd472e45825b01d523c9f625f3015d69ec37630284183e3934398af55e45ba2c7890e55515dc24dcd41c9f84d1712d2c96bd9bff8e486f9f87580baa23820464244a92aa08ff6605deb60c245f6e102f245f86bb530e918290e8e6173112a6c90ec31612c66379e4f79b63327ad8dfeffe8a6d3caf1eb006545814348321f473e05797a7aaf45c4eee9748072549d72bf545b9de82a852bad73119274e0bdcd53daf917e5dad18b328b5014ab95d61e3a8254a13a29aaeb9e35d053ee0e780dce9cc2202c11ae2d7839e9cff3ea112d7fed0fceafd7c90fa108b3db0353144633c05308fa5226915d5774e21ccce31292bee1756da22ac3e93fc8b373d89970c601c2aab0266420fce15b02aaa558ffe3f174a17f8ebbcd1f56ef873933a82c69963386035ef8c846391bb4dbcc6abe3441d2ce5771c476370a6d6f79bb365bd4b0927fdb1876b1577ae1f46a73b69b320fcabbc0cb36e4187cda4229b0259ff42178e4651e0b0f7145aea331f45a2a46c09e9092a6666c3d523cadb41dcde8ee927cd38d04aa6ae07310a2878a4c6d074d2b08e5d82a0a3f3a5d4f594cfe2c8f439ed132eec9052460439f23106b1b386904f6de602d2aae1b7f959ba5c9adbd8acf26738e272adcdbc23ca535de78a5aa8780edab7a37057da4bfd9e40a3fb22259d3fb0e7ba4139275ad4f3fa5272ec2572dfe1a3c2fa1872f6c88bf00f377fcb2dabc820bae4a30c6b880dd6fed190455f501db1421240fab0ba7fbce9d59800ff6f4819111f35be8aae8d0794f410b7e88dba392d6820eba407a34b797c5c7ace324961cc0e4acc67bd0f66c3e924107ff53ffef850822ebf57c21383ca3bd40bd5f8c6eebb46c4795512fd0e2a2da14154d0c57cd84e761a410f7cc68f5445d998e8973b6e4ae0330d0e72f0877a15bcc046ceb0b35428302e7138eafa5687a8bf9f1b5034ba1c0906d77ea591c75a1132c7c9155b1096b2a6e726914721e60b31ede0c2eb1a7774ecb684256dacb05c791aa73819be13f0cd744c422b8146168522b818ba6ab5c8c52ad333d888e2d54158987e84544d36c760abd0d5c16a1a27e949e422b02eb91ce192456d448426eaf1c652bf8ec0bc3d39442a53b62435662298cd421099c3930450970c4d62a37d460c25c512568d94213521e0c9bd41165ad133c04cf4102419482d6eaa4523b25caec01e398d97027c0890aa113f29716c046db743c285addacc176277816c63a73ee486f346ac2b7d6428e53084937d8d6a68365b82105ec37914bdb042becf5154d92646d13885f9ff1fece955ded89c7265b950ad2774d2310476e678984e0562f731f56913a9919ac2ad81c57d8725694c04818e64c54303e1abadc864f0d694d912894969298e8f1bc078876677518e38327911d46b9c559e6602801ca4181515d810ac477eb7ee99ef8ff24c2380c3f76c3b1e19e1f3e3434018683fb0054e9c6ae238f69728174e1188d2a6bb46ae187780b987abd86c3271b9502660f34b9043a6b6092b0b0762910ae706332b35abb588a0260cd62ff5ca4f1cf210758749902e447e0e1b6de7d0d8d2fb4df7bd98cbb8fab0dbb7aedb3178abeafebf6ebbd3080a146a46111b19e099e4c2d83de232888aa25f6501121a04a0c94fd9b9adcf151bfe7fe20dc2c908696fafd38f7e2ab03e2635cb81786eaa225be282a45741dc820ef176a50b6dd1f8cf99cae3a41901f3c1f3580b6212039d7180bdfab291cf6eeb430b183e69924ec706c148f92aa6e038b3cb76c18a18a5797fd959a493eafcddc0971837f22089ce69bf88038170acecbdf5a8105706b1ddc15028571cb4c9b09bd01d90f384c067e78151fd87db988dd50a3493a1a898ef43a621f1053d427e8b20198717adf2f7700407008a0b8be44be5cc54afb8fa43f1ed028b253f4c52745d5e3050be6f8be07afd12a011e07c2383614bfece97e44e624b5e60bcab5756867fd2311f1db8804c87d5bdd1f846edf8396b2a324ce82774f1bdbb8772fa3da6376eca4c7a5c5b91b0e2d1038321eda4b598d45c2afbc285f48124a2d2687647822aaf11fc23a55b54501c4fe13b8beb0f390676a09687ae6f9f890ce357359d51fc5b1bb1ef3bf8314ec4115336adca10e3fb7689ee97a9203915eb59a3b0c70c41341b34fda31831d8470875101fb1f3c819c9e88f8af550aa36d5e20b54a78d21999a066502a6791f0ea67564afd6205a578b00927fcf6e07e9a45583d9f981a6d640e20ba6a99b9a45723051a9bf7b85becfffb0f652525a046181dd930370e0debc158de1387e6b738510219a3b331ca5905eee3948fed9bbb8d6662926a0e492dfc8c9a92b30a33d9c05d76ff32e38a48bc0041bc960330881d04f7229a401c3a6da64863748dc1f40ede9c25997558b4cb268033eb420264806441d030c47235f008135c20db999d028aa38c8df7f1f9b5c9304c38518c52be922d56cebbdd281ad2803a81eecb38bb2c025d0be123366106a2c82cd8ceda11e7e7375fcfa93634240c41506f9b1a2947de44a04d2ebaca6a11f930412771d67a241aa388a9db2732da1974606872240260881329cf23ea6233b923acab2565438fa42704a9a873f759fe845a6e6c96cb53692fc526fa20b22a33667c5777c71a91ea814e1fbe83e324902d54713dd6a9cb15ed8443b77525f75ce922be2b61902cc3ea5682932f925ec05882610e4434a0d2a8a3cbf7874bd0f2d95dde3c9b68322560576ba8c40166fa6baae98e0eb6d211705d25f0a3285a53bd212a7e5d5299396fd8200066a88ca9d6cc66ec4a43f49e8ec9c2465040ab5ba90f346a08230b0a02ee10379d2ecce245d85c49e75d62bf865588c021c408206bb18cd67742306b9d44c786b6ad9a99da2b319f78d19a3da02b5ea597e208c0020521653a050ed39ba49b24e084e4c98d52ab0c946086387b36b320f8140963fd9477b9271a60323a7f8928c5fb44abb6a62f9998b0f672fc7f28627ab761b6258095861a9e620d50dec416d2fd0b8f0d81c8fc794364232ec93f557adda65681487724ac6445c56dab03e584a755bc1242ae5210aa77c9ccc16250c612ff66f1efe3af262d5c9ee6b89bc62d99dd7686e370052f1c6da49e500a5cf9aa90c7dbc2c65dce2f74e2a754974b01bf8dcc066429ec044494f8c7332fcde675a8ab36b622fddcfec0989740812a3456443a70a274ec6abd01e9aa64d0246915b93443e7a516db548a0a2071b1fae220d337c0a444ecfd9769c7a03c251839300210f2aa621706a21d110f8139241fa0ded38f88fdeba549e0ac8d683fc8921fd3342a91ae0c1b30a15dddd32adcfef6497d264564c6b595143ae972033c71ccec92f90c4f09769a24d6d225dd4b958ceb044db512e870b73c84d5aea636e98926b072544c8e64582bb76a2c259aeae4d0674c85530cd021b234957de14da2998278baf587b19fb987909014791e133a5bc03170fb1e474b1a8c12b4794f0038b912c5883b3190ef07cc1ad14b1f86989bb8cf245c7596705e52ca4bd0498014f880714173b3610d5279110895611f9a8dcd3b653012d0523d411993e164a11401285bbe007224d9cc86aa01763f3a4ee02a13864984482f61050b23f57f15028eee973784aa03b4a6a6f6468e3e9c03f26ae2c390946c736dc50832dbaf9740c59f954552c497a61784629b5c09decbcb91cc7005527bb38144443a2019e46e0729ce956ce4f7b9c56a012716183798de658daf4f82f9337260ad0f8f32805b2d88190a19655b74ee43a6d8af6aecd71ad32f5d0dc2312da6a2d446623c01f687bf9fe0c09a73f3bc583d22a4ee9d97eb78c8e18d44d8113173b553a8f9ac56407a39b49d394129fffa20a25953e17643c6d9d97aa7a0ee6b9c23aec54e3a842e96ecb6512c8b6c43dcacb4a03792d555018a38ffcd3c915b98904675e09d177cfe7590b2e469b16755fcd8896c462b8038bfe94e3668f4a8d0a1fc44ea95a2009c0e0e5846df663fe1eb0d1374800b4f0c87321c7905aa5c61be0c0a934206ed412a4e9b4d08ee7215b933fe0807d8b95e174297d4787d26d12df268d20a1500d787d2080601e8a2c1a7c7a57c889d7d7b08b71248825eb0297e524ca3f6d5935ce4749f8ed09c52718f8008bdd8a5581308e6638d4b97bcc8e10401d97257730998c366d829fe96f82b339854553f430ad419f89742fe06115f757d742bf6d3ae630905a9106d2addf5da2a9dff21e49962f4b37b3477e2308914605bdf7185733cc0ec50cf9b9c02d55c9e520c07ff8ad4941885975bdde0d48e9aa6539187464c02db071d575a9f6a95a9d25301e12cf88d4141241099ff670d1d1a5b1d152ccd1f1c0ad9ec0d72ab68cf6b53244f00fa33140059409d4a1f1ac604dcdda0ee6cde7259f8ae32255209c19b59c8d8b24349e02e092a48427192a2c3b8e2ec6b5a1a8acff40ad186f4a7026b17955db315090237b0c5fa68538b5c7c313b91cac115d0a76855eefa8ba84ab85ac03be9e1220f3942b518785f23ed330f913ab13bff1a092c85942334e69c2edcd117d49b785d935340fe60099e648edc43d3b17c54add1097f678362c7e2dc615c513a4942bf4e65e57f6105d6b0b44e8a7c34d6f15f710be6ebf3019b7a4af447fc6e77fb174e2b9a7c922b6b7b391ac14c344db53ea90a0e47459a134052c822d2d853652d1a2a26efda3bd70f5db50934ff96480df5e3317852ae1e2866bfd5920911dd369c33067c9065c6569c0c750f147809f6e05c09cc2d17ea79c19491443f476133d22b88db39235966be720f040a30c0aebb7124119069c7acafd02338711f1342e2f16f8a531bbc2af5fa58de49ecfeb1d4a2fb59e785ac7a076627a8a83406592d4e8156304be368b9d1a5d4d566d18a4a24bd8c520886a69b4149b7ac08215356b8db0eb952aedeca6255f2263cdd8694855eafbbd2a20b2e7b42b418a7828ae37b5698b9afc35cf00d28496955768a3d9d9450cdd6ef514f9bc781270c635c8f0e1d37c75b2f41c35c218b55147feb49a695d9528a2d406263919471a163ee93f1a0b43a245bc676a5d09f2d5171de63844ea1381dee42c152fd26d2d858ec2b4ab34f1d5713ad35419169170656e90a1ae2e2feee208c9a2063083174c9222ee2e33ed0210858992c417266d729ab583d5288093b29a1e530a7f3a95626cabbe8b010f694d01ac3afa60f54fb3222292c6660f3011116ee96720aba018bb695ee373c9bb60dd6671599078db77bbcd3f365c3ce2b88ef01b89be8568c17b384f0ae388799d0489974679e365d304342a3f278249f024d7715b26292905070c1a8e4d23f47d1f51f15a2671c6c466c2003b3af8daca0eb678c78d15c70f0ab61e967e6a7d8b35addfc2f2f363887cb9156ff632e790e6e2fa1d422f6135bd63cb0318bd1a63df3552e40793db508f7fa0ecada2ff7cf0825ea9980158aeada8600406a292f7db5d05719a1d3c42629840424785f37fc9c9417e82135449260ed2c3688fdf1e08958a4e764e30b0b05a5ca6a480eed3e1a2d78aed03383e2f07aa6976faa70bb4ed36a92b138890662f8844946ec6d23efba0689c00a2853641981fccf52780fba03a24fd4dcf40011e2353a88ced001ca2cc6058eb72672629474bc5d267c3aeb615cf5f1521607192fada480a670e2868364996802e0559e1ad0b07b2a05601a11fce3d27d095e99eee507734ad6dc2cea8e56769768726801fc13f3d01c40c1212efe19eaac4990350275eac36100a511ed82a60ca88e3bf731a257f0b66f10390c6b067a43635b6fbbd7308b2dda078189359c70c9bcefba6c0d6b0489c2490248ac9e053ed00289aa6ce618d7160958da7f66f9fe59766e6cf246f585e583082a51cf29a524847386ee83d3436a13c49f0b6484932cf2e4a69957f41f218333ce0dc5c905208dc0cba181eb608aa23f9fcf07893f8cc9434f7d163862e1aacc0f79855f20f122f998a2f634c1a88e0126c79e4b883135c41b4af65164292839e200d83f73ff1505e85a202fd9401cc2451e036195ff860ac012409911044b5a13673bfdb10716b10300f758ddf91d9eaed1287a9f94aae6b54465f3d35468b0d78d89257a36a969bc25155450e900e0ed8854753b16a8a743b89583fa24f52a25028dbe8fa2714396dc6610b242f1c1d362e44b39855667510555bead00be5a5baccf99073870d1367a527eebeb32d0c40da80449ca951e27d41cb80ebf4c53aeedbf0f2a008ee04d3e990018e2d7092c2a4f4110a148496bcbe8fc0f043d352de135b9675ca06c9e473d1640c7534f36325f54b2d71e2d54eeef8c58984cc9b5f3129dcb3717b87e85e0ca743c235fd540f751f4b4836040bc138441f88c9a8bd21ae2329604646c7d0efd663240839e1d143f660058031f85cb363c2d00812aa084f4e6392570a757417276167c498a2af66f9514f1295065ac794073d238b107c18ac480f83a988e1d782c6f21634a913cf3e8e1c8520aa8decaa2c853edf1b8d604fc9b69b5ea11ae217084d0b336e4b2da8b9a8c3680761dca802bc61aa790630d1cb3d80e1684fddd43720480fe6f21c011d8a0e0f7b9d8749571b77e050dab18587b43254f4fa2821350e4946d5891803639da942810f20c98165a5614d77a1c622067843bb40055d990ecba8122fe18b5ab50be26d006b4de9c0cc1f096cff2437443b6005881a0e534de1e019410311401761578cf93691d9fca5c63727a949bf5a09f3d9f8805715df84a735aeaed726e00746913dccd81f35495d44a28570d863496b2753d7d7432f99776a6cf4aa2fae3373ad8f1e267993c2b3d1eecc299cfe272e64b9250e3e05b3639ab648b510b2ef6f92a2ef428d8171364b63feb31662867bf5f80b464ce79e5cc2c914c2b5a18f496975f232de27ab265d805ae906dd5fa973569a56f39261d9a01d67fd14c0fff1fb30359af2428e869067958be1c4349896038db61cdcb84a87c5ceae01fffa6fd4f49b6383bd1dd72dbc254a907054ad4c34c4ea2ed96b48822f0f3451b5b8dc88c3b87062a2e2489aef45efb86311c2ad0c9dc362861e347f41858f84e79991069b5a2662f826d56f5e7329b70135759a6b106b2b8fd80ef962831994c701c74d4e6ce09433437022744cddca30112e6dbcc9e07cd078a716613abc9de5a7c92a30652e5c74c4f14b8e327966c638e9a630112abf1139912c12259f6ba401de71fbcc94c09bf680d06118354c1412469aff8541aad5b16d39bb60bd08a576d53ae1cfc32a34e3838869208239d99808caf56cf810c29bac613e940aaecfbeb389e78d95db8f410749bc3aacce58b842aa765fc02d820fc0c62317201ca1f9b3686a08d3c2f6e5ae5fb4a26dab4b215e0010642c8a08f02ce5795be2da317161b57657a9f0ee14b3fb5b52016e65c9799e2c85b70af4ec05b50d19b0b4ff69009437df6db762f847fe47257c6d0b435754922118de5810b2279664d67ae0898ff235e1073dca5c36b533ae29983efc0f08d67dae85c97ef76f6051aee294081849a04cfeebf89cdd049270ac70f3d88751f9c354aebd9caba94120ea25f81e2a2ca9bb910dbacceac207dc7b0a1a87802f48d664723166abb052d9db3b811d98238f0d1d4a504007ccad3e821ce1a4750bbe0c05f9bdea66bc207b9bc678bac4da816bc2a5ec9079ce995e884b4107194051f6ff570471dee9fd9e628ac8858499056fdfe752282632dbdf84a70be8ed265966909336f3c5c86c38ba4887c4f198cd9d7d04ced89506d039e5693db71569381f028b0c7aaa722c0a9e5fad662a4347006f314a90b69d0139dc03603db6ba5aea88f6b515a32bc7e86dc558a9c7f94a663da13862447004266b6ad1fec40316b5cd40b7a3f3f7b7532acf66c9d887f4419f421aee2e299c27579b5341619428e199861db1b7565a0139a198e0b179223bd765023479d4ec3b7e29ca85ae8650245e8bcc799b3e56f2960cc40c040318a0afe517a7ace32874a1b27f66219e06fcf0ee3909dddad8c050e2a0708fe007c23d5e6b64b2c4ac0e3eaf77dd25b7d9c1829eb1ba0d5a6f065d9a923d697d6ebdbbc885f1b242feb9472654920750a0467883c42416cddbbfd40d8d02a9a9530d9b547e6669b593c4e35f84d0be638732908643a86105448d39fc9602f890eb4503b0547004727b06033c13ccb2c6e6854bc1d35c5483286d34e13490089381b59eaa681b9a27b27d70df81da0b4c05414e03ef8ffcd08005ec5fffff036b5c8e68534190542ed9a5161f90ed0fe7da74c0edb685d34457bed81660b67e900af064302043f3b410d8664da67e78e1ab6fd54bae558c6520ab154c53d6631691bf7eebce1bd08dadbcbed946ee0a23a8a48f1240942bb6d931f3067f9d3507e3960b73404b6971a98b6a2e288c726ac3cd03b70e4760b46e9562a911a3cd98234a168aa703f28486635ac54e37d817a8bb63d362ff8db5d41b7cd235663c2c37667e7b10e3a473c0d5c620c3377f5481dbf59ad255a25493ef846e43088f22ea66cee369f488bd479e6fa718052155b39ea498f3daa6bea009324465860318cad62f5d5c9f1ecbd5dc8daeca28079f33c82e93ae9da915320484d7524f59f0733e1ce5fbb140bbdda5bd289f03aa3283d5912df7950890e93ad9318588dc242d3eb43d719712bbf16235f7575f3c226784dfc1e3795e55e70bc8ce3853e5e13655cab5ec77e41072b9297d4febabef0826b1ff442e9d5d52b8217a1e5eb180536c6b57dafa3fba0e338dfeb388d42fdc9d645a32b4221a13f91afdb9fc250e7b7f8f61e734fc45e030e287e46696200702e6222c639841876b35143c659f85cad1aad1e32fa178b0cf1ce6b243971f3d429ef7c604baf5437d174296a71b988507c410915e55227b9c5e108359da2764b41820211aa15140642e990caaf94afb7562a9062094508460143324498cd45f5a1e6a46b6f287f15ea1ef05fb02880920c550c54f780bad79b6e189a424d812a12d45645011bc22207281a059c2cecdb4a100a381a38e10b7b7201aa1f54538702628c3c02ae8d0252214000d1a280324b0cb38c1e052c7342331416d577fa40967443511305045d9e9de2c6a29abe0c8b17ab85e09fc5d70e2048e024a4d358e166f40c8f6b43ed817ef0ec4331f4131e2baf19ac9d057914a7e0e3eeab7c3db2b208e2509d71c147f86a9f3be50282713d55645f88af7a15be87615d4495bd2dc6a8fb427d232a8214a850ada00e270a9b14f350bd4061a7281d922af14b09144250ed3a0a083a032e3d4e244640b534a921543ea35890ea050509d568a87507a54326e8fe690425010aa125aa0f438b9506a8eb1054df0f7cd40154a20fa583f18c1c3d8132172a9ba1fa3eb58b9222c24b7e84c248a8becf3d2ada0475eea38072f268647c72a212fc25469197164b81e9e37f9b83410b516967b8132b6c44695f149f812806fa540762448b86a5473e1ce550e7f966e453b4efe4cfa52a7d84f6626b1ebc250b45213da1d7d8b04a35e5020c9bfb946b1bff1fe0dc47834ac60ca55d7adbf957100aaedefdcb5384b1ac4a1138699116a4586a672578886349426e834c431650aa69f7f045a5c2f5aeb25d3bb7201d5e17355380e5fa78005fed18818d43382afdac8c11d350533b9bab8845c66afba0b9f2cea83e66273351f5d5a20f94b34587d71fb1862fa036cb7e001b06c088b8a4029187c1896742172d1ff9cac5be32225871dfd7f9a7d86392fa09f3fb413ea229255274d6c46d6ba7b8db43d7f7530a7390f9112461eaeca3dc10077f49bb8f67b43176a4982c2e7b6eb905ef2a864f6781f4c543880ead514f03a783dbbf3e29852f99d0719dac27ab5282e66b3933d858a0c627d215dafb89895430da6f8620b9df8e71d433bc68efac086cd490cc331502c822bb1cfe12104b4271fdbdf3fc83462865c5ec3465acee9a0451429331a115f63509b5ecda5fadb866df81dfbc3155110201537fb67b356d823cef5c23465362e24fd1221039ba7531b49053173ae3427b5305bd7d7a78291cfd00b3adbecc73051fd6e38f133060ea4164295a43debc0dabfbc2bfe144775e04835f3fa5e3431e85c66dc4677201ac0d497898a8c126ab3ca41388604b4bc2c6ad24feed9825b2134a80de1df788e6bb61a9fee2dcc10f6232682ce7e0b4513cf63566900ba69604ce80420a46e04cfc784f3200145212b5b9c87f37de88c8c70fc4dc100004f64d31561b7984cfa6a144dc8daf0aabc5474542afa664f6b227606de89004c3e9c81d4d1098e1b26a6bd20689ffa36ca8464f4f410fa371b0b51538053cf6c0bfb83f6047875a37ba0d979909c4b79549098057a953f6168df99b8393c5f1b4a925830eb7ff085f58340fb5b7c2291e86c35f9012282b6e7b4ea26926e13f89eaa960c2a3338634375f55a0bd7141120b004bb767106d0174c5d5a129481437e7b381745ba094a00548ab30bfa58457319333410b318d92934977c406166522750b523d17b0b5b76f6cab8d15d6314ef8ecea61506e1cff1547e14212a045b86aa38d98d2e3a6cc932674a4541daf848f998421bf044ff8bb4e0cef0481d1c955155939525f0031bb15e9a7535bcb75d7a6f48d3da0229a5a9dafa1114c46a8d0b960024d461b50d03b52df4d4a61988e799b62328d20c0691c3b2ea93d990b60d1d357d02fef1a1919c4df20a36174ce097c124952e103517da305901d0cbe73d9e5721244e1ebef4a1f1e564781099050400404f9c730c50d68040cd277ab6250e2d8e6c1cdb7cd0f6a12c5fef0fae0ae31e9f1cbaf6ffaebd1ac9e9a5ee3d4951b277a5ab3752ec69e551f6d0265161d1ee233c931be066c7922f1b2c0d7728f36ac95dfdc62de49f7d21206d9c2b237c096c93305d6728114958856ab6dc3cac125dc1b9ba148b5860ce98542645847757e2a6b25830b864de20be2d971ce56894beb10e91296872a22e1294121c5b7438601f62c6e374e880f530da3b8d34fb7ca0ddb79bd8b23d8cc4b6ded4d5f840bc5831ced1814178e774b706ed296e0516529a6a8a6afb31679a5bb6ed0f8f58be9a293f1a9529b26675da05c14354111f0c49c5307abb8c1413596dc183a54017a9c8f2428b80d4d8277d95cfe3124b17aea25e28f0bdaff55e443d0d97e7468477d4b89edc0808da7e2f167182090900905a258e42fc32c9af6513789e6fb6f3ca792bdf691ab00838b79be43d6e537485af9934497d4138055c49c24f94caef989e2b738af4dc34b67d95a65f0a956ee4f81a1db335e92682ea6bcc7c72aa1dac88ebd3e8b1334ee77a0aece4e992fb6f4d822f6e8108eba420df73d185279a8559df1751521b8415875338443f5c6566d5e8246b19c690ca1771c1aca226fc26f372cd0fee2e2a87067ce6ef3c6796e78c61f491860bedb2f699699746c9d37302ffc9381982f17cc88d0e402d84184c417785a7326b8fd24ace351ec97b0f3491612d5a33e11df9b3b37b740658067878f696fa1fbab6c2eb5fb50f1b759cc8e888c3c2945314749fbfe1cd7d2c1bc62657003e5c7cc4dad6e00f5b3d2b9b6a6569158805409bbfc87eb385121c3e3992325b1a8bd50fddc237a40e0994d78c39fc9b517ee5ffa70ed8a785e40b453250f08d1c5fecd28eb121de2005a0c3b030b23fd5f0ab120eab7932e316e752ce4a2f328bb715caf12d82113ec7e4e60ffcf1252d48a78d74cb7e7739efe3516d7ff9c7b22bef729617727b4de7b309e39a1b0dd7954dcf9e3e6ae387c66ac4d0c88627619ec25e2218a993e45aaeec23e257fdbfa3c48c5c05e46d2b02dc890de9dc69027e5bdf8040edbdb7007f00a3036346c8db331162fee34b4d61f244497e9e611e2316cc5be715a1206dc1619f5bf2de851dc5cccb8b388e74d0f36ceca4f6dcf5061ecff616f1e743e132d8a55f1cf06c788ef50de070ec446dd48f70b278705a9b45e2f8c788a807df8dddf5e5d8b69f24c4009b69f7f5366441049a50099c6bfbe51cf8397458e7e2c0c058fef0e6ccaca709474eda08f08f458d76f1b43cf10e1879a1905b7ad3d7f70247bfd76583ede143cd279d19252b97e912b9f62c2e3ba249f337c0246e6ca358ce825698af2e00956159e4559d61f53526fd9e3e03621b182f0d62aa10dbd138a13586cc00e22e789f28e76b64219ea2c0a744acc12a0fa90eb06249e82680205e4db92b08e2d2ece25f6fa49d5be31b780867860c0c3cfaff76a8118a167053c1343a218e981760f90c69301d07a70dd3b5407a91040359003086903c43ecc9cc8005802206306b82b49da5c724605dae7a572e2db6fa63a3515c910b81015c4f295d82e84db335e190040b8dcee04d6ba3cc97cdf3e1021320cd99f8158116c03c593f69caea5ecea96c9eb5e07862c3c0b0a535b282788cfd4945a2ae7b1e4ef5db7210d5b42e3653d92b80e18f375849bff5c18855e0da1437c89e0b6623271f3b0026abca69fd44f606d9b07a38fe6b1c3553745062939c4eb7d1f314eb3012f31832801fd74b4437635d5504cf515a98a7a2e47792c19e511dda055a51227097872172d09dbc96ebb02348376922b433d56a4af9772e1b6898a2525372f9f0e69054bc45c3ad1ea97fa3d5f70a013f687280ede6a4b24979f954efd14695ac661642f30a7b841334365f3f4cc95e74d3701de1b71084f60d40e84b9b41931e0a048ce8c742d0c2f866e93ce3dd079219f251e74d4c36d9abb4df5ec7086c0b19e92efaf1da85d777cca341b0726d43825d1a57d8b8b3e611bffc8416075b2691e7f0123d7668795c4b5eae2578f562970637afcb8d2df4372e5edc646d9da6447b39a6187897ecc4f4dea88f93472040c443165286281df7b729579977da34c8a4a8ee25b9c7e7b93e17f6684bff827e48b8b3192fefa8edc6a276ab44d11f0a3c76a6021989eb788bec353c7bb0a2513370849c825d7b0c4f58855ece67e308c5a194bdbb9a5fdff961350c4ad163af8dba19f54079de9b08274513969251d2ac63f10eafad0955c5946961d95ad84a1aae0fe9a880c5472b5742c69406cd586ea500bd530017c1b40231523801d69a773518cdf0759d03a85876d22219e49426e48065736c081b086da99ee171ad2da88bad8b141215eb9958af43a91bba6d0690077ef1a49ceeef7942954a1f9f8c2fa15aa2030d463a8b940b3394f0ec413e86ee6d5dff7b688d492e05a996c8bc5e99823b81f9cd19f3531273dbdce2ae5067b3d3a15ce618001ae80f71dea281320268a3a941457c2f4c4d1b8f69b11ebf27b6b0492dafeb83a8770afb038874a9b54ed2d205ed8bee5d893896dfb9814aa713731fa3bf6270126108de6fe9c28f46a30a69b881d7d10cc0336ad1a72495c89c7cb13bb50b7fd229b60921e0dbcd5ac0b8e955fefead53ee03b12ab3a4b0db9a477296c753ee200d2417797d29a7389343fc4a7f306ee11793cb080d4c925aa7e695f17be035c45289a572daaaa42480000d732eb800346362af97d2c5d772497ef5563ee9987f9405ac80605ba82ffdb7189d1abc4ad5787eb40d55bcc2511c9daea03453b0aa150e47365cfa1b02f61ad6fd03a9faf4c089bc0360e08a0e15bc29d18e298552edba11352b4810c30f67344350c0e27aff690064ec5590d5782fcdda9b17cbc6b716eaeb0710ec04d3a52b87ccbe40e006acdf6e5a630d66f7d4016ccbd8e1f1cc602210333fc45908a37856fe6f77e6d839874988c93d4800fd5ecd8836306637e0fd4a0c3703dce2d747618cbde702c9b67b0d48d397bbee38717fb4cc08350e2317106ec3d5899442e4555026e31c49a0a3040f26439ffffffffffffffffff68ddd3d6eced97494a0107a00494c34d29a594528a54ebdee4ce7c86fd0cbb98cf5c85220a6b0a840a8ec614aec1468e363ae25098902fc64ee65822d20e3854b6151263c2a95aed49b6bbb43469e2e978433985f966f32444103aef7043f9ef3289929f3f1f74b4a19063b0f38cfb39c682d0c18642b44b35255dd735944feedf7e08b7430dc5ff91316bf6c78f49c51f74a4a1187bd63ff5c734a3b7103ad0506270a0e30c253125e4e36dcc2544af3bcc50909e5a4aec8394b352a30c3aca50bebdcc21851295f163c8509239dacdea32ffe93d86c295c91046e994aa698aa118ba3e36c61cc404fd75b5d01186429435dd1da2868c2dd3460e4a07184aa57c5683921e3b843847c7174abda5937fe63105ed05ed3578a6698977a1dc72a5aca4ec678d36d25081c9a1830bc5edb0109751d479e8d842396af893fbf2af3b3a2d9474f29dcf10fd1c3ab2504c2173d431314add8646197e461ac70a0ba5cc5c265574a8c8efafc000d17105a4ffa6a97b8bd661855244cd89216f8520e8a842b14bb375279f9a9d34154ab11ac145783c8572b610e937885fa76aa55050be5a969b614714ca1663fa7faa5aee35502809617ad4b65ebfca2794ad747ed6908b4387134a392ab3e4d0a33be49b5096fb1acd907d261453d6ac88c7897c553b9650f624b664929e3b94505af56d97905eb3ea2809e5644aa65b9173b7294542314a0ecf96eea7b573472899cb66d37d9af396c1a0c308c5cca263fcd7cf31c85884924819d4526e420aa97510a1183e889010f53dc41802816158d6e2915acee65b5496951002c228664f1bb3348e4bfe8351d0a36406cfa571ea074629364bec5af38be2686797a55cc9d5be28c69c1a654246b2cebd28c62fd91b722ed598e545495706f5e91ac36976514c7f7baefe7153a6ba2807d1ab9539cc4531472bb5481b2e4aa26f2447b7165d57ba456994cd4e2ebd4c62255b143fabc389df1bd393548bb259a78b9dacae2392685108b9cb46e424cda2985793781579d9509245494b4822123d4c73522ccae14b820cda437c33c1a29c43870e6293d445ff8a52ff781e8dbf2bca3123674f93df4ff7ad286cdc6913fa643345ac28e4fd0f317a3fc70aada2a0b6b466888899095245713347cb2ff166a5938ad2c79032530491d51d5414de32e78d161af4daa728c59d560f49dfaf98a6286ddda89b91396784a52857793e2136aa228ea428e8dcbc0f9d789ac151944cf47c5367b748de8ba22436ecbfe82d14e5d27ba7746e5bf1d483a218b3e4147fee9234e43f5134395e3a889c8469e43d51ce342d39226fbcff3b518ee18426a1399c28c8b8eb52b5d1a3f64d1474744d3699d8bc194d94c3c374da70268abeeb9ac22cef56c64429432edd2c6d3ba54b94b6473f09bd6ecdd71225cfb3ae08afe94f9528beaef5b5afecfd4a89d2d866473b731265efe4a3a54d499472eb3cfd885c9f3012c5f3d22aad7cd39e834431527eda9c31dd9d087a441f26c848724a8e3062ca53230a4148751f8949a8f31951aab198bc3b9a45072da2741974fbb4e4a02ba488b27e18d7ed9335cf494479a26cdecdb62cdf20a2205e363b825fe5c81ca290636cc7fa244c89b0218ac1c342d9bb461db710252f2d93c38733d32921cadd3362cace4114644cdee7d964f53c41143fcbb3e8d0bb480a44e9c3c691a94ab6ff80280815bd273f836ee70fa50fb1b5ff3698a7cd0f85a0b55dff3f8910ea43612d536efe1a1d3f7c287cfbf5e8df9424ab3d1433940ca925470f852892e45e270fc5b8f58e61466435090fc538325769758ebcd11dca1b42dafe14214bde0e05a16f22e4dbf81de3752895663febd74c0bd1a1e8a33b954effd1d63914c469efd8f9d6d468e450caf1384ac910fb6fc7a17cfae6b4a73a4dea854339c9b49e5a557f43c926071d1e71754329638ae93da1944dd2db507a0d416a529963f6cfd950d2f9e123f3769ada7c0dc57513f22bc33c85cad55012724f5cec0419a2e569280619b663bccbf960391a4a42ad3fc62c32bd267e869226dbdd1c43b6e9c90cc59f53e9df57695b2a43215988ae293d190a765e9dca2fdf3b3f8692104dd2845c75ecbc180a327a630c51257977c250cc63a249d2959eee6028a88ed21395971e355f2824d5133944cacca7f6424967c9ede5eb9c5077a1e01a719208ed124ecc85c207539e4972caff780be5b0f5ac9f25d5e9ab8562e5c6e81a5b3567f793a7f35d64ad5828bba8bcd91d9d33d32b14e2c40bf5971b6244ad50b8ce263be909a7ffab42d93be9b83f5bcdda51a1b81ff446e579a868660a25a574d22ab78c140a7224a6afdef4592c1385c2ed874df341c3a4080a8538c14275e43ca1304269849139b683dc09a5fe984c88903c41f72614743e51a1a13b9e76261473cea52175b3847227cd71547ce874b6128aa5f1c4e496104ed249287c5f973875915030b5924388a66a847a8492eeb93f0d427c9025048c50ae944f6db31e378c1028424963ea07e13242930e024428eb7a9de6133e1bb61e4641b4e5071d542d8c826cf7bfca6fc74a3a18c50d754ac66e9bbc0f8c82683cff0ff52f8a1b43740c4a72d4185f14c46cffb675d0089e5e94356bd67e0f7951486a5fdeafefa2f06a23364f2c99b3d18596e952c69496735112274992c4f619ed322e0a9fbe448a49f916a5540be9631277a2c9b628984d909d437f5222c9b5280669daa6f7bc3f089916858d9925b3e32951139e4539282d1bda93888b902cca97273a3d8ccc86a05814ebba9476f99c2b826051fc2a95c9a5834ce9794549b76ddad09dadade38ac26a455a8f1d74ffde8a82975b6d6dd69fbcb3a26c726dad2c6d3ce8ab2884f0ee37e14ae868545170dd1f5995d95414cf4bee6d5667897a5151104d5e1e6f94eeb97b8a72dc7e31b139040dd93545d973e26651dea699dc521453c5c914d95c521454aedcbe271174c61d45a96398bc1d39a1425c51142dae94d6b34addd486a224ef3f71b4fea7bb161425911bb4f7e87c9cd0278a2e26fa749e06553a9e284b12d2df44c37dfa74a2bc1e92c4242386248d72a27c9e5644f82053a9573751ca78ba66bf3d4aaeaa8992953c6de239a685a999284fd05e16a362a2ecff2f7aa2e78ff9258a6922a4fa38f968254b14ee75346c0e19edff4a942376b43ecf1e5f3b250a5b2164e8b127519e1c9b240949a218e46a5cfd90c3e670240a4ad5a9c8935ee68144b93609691e57d9e94714c2e5defb9b8e287775c70df935a21c747cbc5f2f1951c8db1b4fc9f6a064968b289650ed6f114b459452b34c2b72fa52aa4c44e9f37ab7a814fdda23228a333327bc54cfe81c3c44e1d6fa5f53e38d7ad0100599748998ddb93ce460218a15bacaba640eca5b244431b8490f51bfce398a83289a8a4832c78782285c7e98dcc40e371906a258ea35b5a6fa0d9f21204ae284675e174f1613fc43e1459b926ded414608faa11076c36587fc1cc2a90f65ad50e222339bebcf8792e6add166be1f25bf87b2e5c49f38b77722d243419bc71c26c4dc9c4279288451edf8fa59dd3f7828c7cc25a3b9e90e458b305a4470ffc8713b14ed7e339ae4dbcdbd0e85382266984c7bf31b3a947653ce3b26cd19f51c8a79f5232e9743316445be516294693a0e45978f1a3bd2a49c150ee5d2a963ca37c6ffdf50cc596f2547c88734cd08b58ef788881b645f2885652cff51db6e78a1206312399c9cac31ee7376a30be78edf525ae5a35d03c20d2e9444bd77d0a63ce41c3b32b6d08d2d74b9a674762ca99ab171430b8810cfab27d3fc290bc49831710f2f319fa4bffa347a030be54ca3eaf3dd154a42c4bcc8ad9a15ca5a1faa1183da6e54a118bb753f414c6e50a1a0f2db1b42e4d48be4c6148aa5496d124ac7e6e07a8e3adc904251c495cc5144c275d26a196e44a15c42a4d451b6de1a8238861b50286592fde9db4f87db9e50cea0646ceb56f373957ce186134adaffa24d856a7dfadc6842418746126966936e30a174d5a321df664fcff124c38d259443b756ad7eee8612ca39caaf7d904105861b4928c8d87bed21f462b88184e28790b09b3d7df2fc8d23946377e4911841b4c67a037682117408e28611ca9a51dfdfb3b8c9b06e14a1149ecc35948a521e4b48871b4428eee78c7952bfe6321c438daacb1181619464c490f93f88ad68100161946c924d1049080f5e3a608800fa64e76c3da5616014b329ed75ed73ea6ce38508fca2789fe5b661a6436c17015f945d5e55ce3a4424c723d08b729b70d35f1d23c08bb29c485254966997392d02bb28cfcc4a947cb2a93f480d11d045b1fe47dc446e79889f5bc3043388402e1c397ae5e2df13015cdce29fb16fa44188c02d18dbde9c5d7266feda88802d0a398b7cf52a99a284522dca23eb35b3356ec2e7694192d3289b3ab7c46751b40e5b9fdae2535976cc88802ccad9343c9dccc5a2782f233a849c8c002c8af7516c3d651c1b8d9c118157d835f7f2e961716e123cde766ab65dbf48045c5190bc9ac4874f6a45313d738f3e0fa9a74aac2855083d253b4f0e39b38a529777cc3d5913c57e55e063b15957b2a928d78b300de9b64b464521868c938966652a3d45310865a33a53e893a3290a263eb54f1231a2c84a51522e31a479d4ee0f795214237c349d5736c73b8da2ac9f3583b80889a268b5c1aa430f45d9b2344848971d7d501425286127b35bfab34f944f878a8e67503b29e489925575f8a07ba4264f270a1fa9326950cd8a3027cab133af4f5c7d9d7513e5bceb1bfbd3e690a389b2f5dfabaa690ff665a2a022c89da821e669eb60a23caa52644c86e910bd4431775d6998d012654f6df910e49528da6d456e917133274e8972081394cebc3e8962292543efac772c5f12e5fb181a84ed9128074dcd9ccdeb3be290289598d7c60fddddcc230a6aa1279a8cf86f6a4714db4255ed29b99def461474d3c4c8ce25a2938c2887fef8a5cc4514d3dfdff376883175461125d350fa1e4d836f661251aa789310474f882869fb24bbb447243f1da23442b8767ca62ed31ba2b45d91743e85289968d9d97dfdfc31210a329f2d7f826e8fc14114a389bd1d6d4d22491005a94977decc7520381342b6feab064441698876de6e1272fa434156f9c651b26264dc0fe58ca3944c267242b8fb504815274ea6e94d36f95052eac38608713de7710f65b7132d6ea5db3d643d143bcd043f551eca214e6e9d84f0df12c643c94de67ca414d99b3b944b86cea1ca3fe9903eaf244f1d4a673a4810f725eed34b8782e62c7a738cedcebd7328cf5a8527edae1cca9b71528b87f8ae228d43c1c243c78f7982ed46e1507c312124a6fa0d25312187d3cd1a7c5f3714e3c4d48fc9e531576d43418bea093f496a4655d9501a95b549c5c850b25f4341a793a0536e926ebb1a8a397ca4eef43f22cd692848c81fb63d086b75d150ec506a74b75567a467287a38954126e76042966628e629d9a3fe3fe9916519ca1372d7aceecd88243214735093444cb2fd161a43b94c4eaed690139e8ba1b82544fa2419d4ba06c350f6537fbe9fb7dd2f0443415675ebd7499e24ff426944c6dff18d170abbd93fafe613b9315d28cc7aa83df972a12454fcc907cf73b36ea1284a44d0f1a5168a7ffd917aafe46c2c0be5ec1054798e1c168a490813b2637a85a25f6a966e8dd1266985824892948acc5bbd477c5f0db22532a34239d4e790fd42080f4253288bd56e881b7672f848a11082d891d3c9e7f5289427c9187f93eedf8843a1ec5a6e3286ebfcb97e423974909326896821612714c434b54663dc9b503c3fa579993af9499950d2d13759949aec49b984c2a40f1e27e69c44664a287f765a3f534a4212a92494bc4fd72ff6fadc8484424c93cbbba3e7c9e808e5382ad3e8f18d103f46287aed88ee3939d375118a49f2d585dedd106d048850124af95cc889494bc3285ce668a7ffe9f4a6c228bbcbebe64fd1486530cae99fcb237e10fb1018658b5425e3bd360715e9f845418698aa79643c0fabc6c85146ebf9c20e21b58d7dcb9bb817458e249a311f325b991927f2babd3955fae474f0a2114d32bbddec8e5d14dd3c87a90d21cefcf9840e5d14334e3695f7ab2317e88d6936efa40329e8e01774e082bcd17424657e8ac8d842ebb845a22d1e1bdfa15e2172e3c8ae830e5b14e67388e1ec74c6c9cb3930848e5a94cf3594dcadf0493a8816869cc69877db6c7b9d6d9abb933b4137f3338be26a9498e366f3111f248bf27e129dddf4b3d0118b6276d77042453279a35503160531f133c6b98e7d59c72b8ab9bba972ea4496bd3a5c510ef164fd933bb3fca615e5fd2f91e3c8fb17ad5941b6ac9814c1be3d2ebe462d84aeafd95c1b5f4571d3241753dac11a6ba8a29cc4248fb964bd88a05ea1231585f3db58cb9be0fd2f2a4abb1927f1cc3a7beda7287e30e5a9426a8af2c556a528cdd56d12bfe65f1a2245c14fc9a844eb46519d96a68779d6243bed124296a43e89a23c22c8f591bf2314e52d2fd5c1c30e8a5227fd90476f9f285dfec73ddd1dfc64f34461a247f4bdbf34f964274a66e263f8f4f426f366a8d1c189bbea4ee36653d29a7b6a7f8610b7e5e94d79878e4d10c49d1075bab4646cf5e071a006b1269a38eaad88a0df4a9d08658297affad4b0b62c9370f61184dc858992f978f0ddd4fe67327589ff2567ffcc1a1d96c82e52a4893139b2758d6889481d42262d69117454a25c5e9bc9357d1938420725ca3926a13a9cb9a4f01831c44042c7244a1b49a6123ac393d49c240a22265a32f3d9a37644a29884c9983d4634899b3a205152c226be99dbdadf48c6561a6c8c81c69b3146d9073a1e51fee4353ae6cf92e3d50e471425a9f7c7c8fb2849ec6844b93e6af977690a397934664479ed5a2b248c32a0822b3678f0b7818e45eca12639d56bbb458612932b37e215ca418722ca95125deeded39108a2aa8433130d8dd51aafd638923409a5317623a26ced499b52d3f09b443b7834c658238d31b8ae4ad07188d265c4fbcd9c4e79a686505398db281502dba83f62ce4a673b11a21c1274c7ede4e918c432496bb44ac6abf3c4c40d79f3a8a8a4431025912468d2bf0dd0306b8c61d4c831468eb701fa319279721d2bf0001bc60665e8c0a0c1aee80844f135b8e95ed1b14d66d450a30d4014c39af49ceb438a30331a6da4e163acf13b48c38c8e0d74fca19823a99724b2c90fa5d8ebce16dacc44471f0a314569f9505c4fef3946e8d41ff18e3d94f3c92ca6d3df9c909fefd04349ceb55ae59bd7d5df918742720fddb959b6466936e8c0431a1e51ebe64e443fa752dd0f2266e81d0af9c3c793e33966e246a5c30ea5f5a063af696bcda61d75387c27bd928d339275d0a13041860966d2c3935076cca174aa3225c8601dd388a1d02187e27f4c4a8d0c061e6220febff7cc664979e229788481c190c3e30b2af0f0824717dc13b149d926f32f079e223cb850543b530de77983fa881e5bf0d082d2c0230b6c786041cb2a53396bad8c8bd5b83cf14c22798cda35f0b84259d3cfe79f88b34ed50a851c6d84491f8baddb3caa50ce1141d3f40451a12c693ec49b182d35bd29146692f58ac849fe7d8e62c1430ac5cf692d841a8d47148a7e25acee268756f0804241ed7734488c1133a9c713ca5ebe2554c37959f07042e9b74bc96c59b2b51e6c42b145c6ce301d31aa3a0f26944644fee89e4bdcc62ca118ef45dc9a899450d2d89a3b7f699250bc8d94debbe9de348d84927c92e95f8277778a3d8e50126b53726635424908a5494dc6e85b393d8a50384d9dd3ae6a3ce04184831edf8eab700c03f131e7d2b954cebd2dc0210c15e008463a740826435685c6c06803c72fd217ba5c248bb7129bdbb61725a5730c727c933878514ce741fac577765108396a7fd9aaba284d180d7eba9994569b8bb2a9f967cc49cfa3dec7818b8238fd99c6fbba4549e3a9efce16e54d4a879e9cb1643aa15a943e6dd86c9ab373020e5a14ef730cd3fcd4e02bba9b45c9b4a42bf1349e2ccaed1263be451c993f6f093890b9b3c553a7f22e71c0a2904cd6e9567f0cafb79180e315252154c9a025f77d89da15e5d3ee210711a2e7a0dc56144fad936b44119fe75b1170b0a21c23627a6c844d323f52c0b18a82694b92eda3220825c221e05045b1c4a9667d1b254ac871a4a2b8f1d9438ac42c0e5494a486d1d9c3341ca728c693a7c74efa8b876ca628b56651a396bd1962689421022b4539b53ddd64e89b1cd4468a826ed00e22ef8e378a92b65c9a85a67ecc9e2c0e5114e26ae8776cc9041ca128c859bbd33d39384051b40edae7afd24f947f833ecdeea9b141e5896210694d4fccba13a5d0b2595e7af2468c878313690a1193129713fa0a706ca2f29c21284f9ab4d5d1811474f01d7068a294d157fc7b7f3c4f08195b6288713ae036aaac802313870313382e819628c6a89fd7c354899246cd3f2f75ea92744a94435e5dd1d8f1b6f33d8962be8ed0f85e133a842581d01dcd09b2d94894bc24d9bc6b87e8101285ac59d2e2a467da943ea224334bb0d17e19ea7d1c8e28fcc6f7583f214fbbd888e5347e7466949c630472563536735693229bd7a70f2f6993887c882da294b1c4272594aed586c0a18862a80832abb9c95ffb89288d7d7e493561e384d21d010722caf6aa9a515682eecf87288be88fe1e757e33bc5618872ce7963981215a224d994dcf48ea15d1d218a97e53596a74395781005cd7709bac2df35523804519220b37b8920e2084439d28e5abfdd0051d011e52641ad697811ff509ce0a9374813151470f8a194311e6d4b275e7787a30fa533b7aff0529327e0e043b14444194d991c03c71e0ae163f492fd61c3a187723e1965c39418471e0a326889e11f9259c0914c12825bbea98fe30e05d9d9f43a3fa162531c7628c9cd103dc78f4989ff5c01471dcafd13354428b5b7933a35e0a043319386d012d4ef8d1e6b0a38e65012d3f21d746ed80c3729f0010e3994cfe4d3c55b8cc9fc6aa600471cf00638e0508827573c2cdd5b5d52061c6f28e87c95d09c565428251c6e289a0e12545644f89e0f8e3614929e989a44bdad4c0e071b4a918459773ef1d1e521634b71acc130df7415f96da6cc81430d79f0fafc8dafbd91b1956ce0488349c664b8968c2d1c68289c47ac7111961965b800c719d80cb623b3bf946f86f2a4d18c24c3a8f435d90047194afa9ee4345637c9242243e1a4085f1162196e1a4349d43fa5d98510713e62c04d2cdd2ecc3e7c378edd66d3e008434989bc2459ebd3ec1c188a41262144c5bc38be5062180e7078a178bd5173dee45a7aa60b251336271efbc424b972a17c2263b6971eb750901d4cd86a66add8d43a0e2d14f4c93cf518268ce93f0bc551aeafa9f3cb24a562a120b433662a5da5d64f1c572878ce990ee623e3ac638582d4b2d5ef72cf90af423999aaba7e4c3a6962a8f0a89a9698f2e0984221a91919f245676f7738a4500e5225c63e21bbb7c41185237aaa45ba332d8bd7a4627f0f7040a11c44828c7393b473869f50489741f96c4c2325c49c5074096a3478b6fdf7ab09052b15fd9e31e34126389850909e43bd4f3e2da11c224ddc3053e250423987741d722879752d8e24149212aaefe7314868547dd0133eee2314931e37f364fa3a723642216586fe20b73ad4af388a50ec1cc66af3b35a5f868308e53989fe7baaac4c88dc184631839e519abfbf7356710a37845188a974cf9a860a1531c128db96acb27d9d2fa54368bc0a6e00a3d4721e9ffd4bfd07911bbf28f5c6081ef4b68650fa0bdcf0453979d0dcd3d350a65e9425bce8ccb7ace8cf8b52e74eefc174d22e0ac23ee6a0ee41a68b424ced398da033b37e2e0a3a2d463b4352c91d17a5ca74daea47a7b4cdb945496ab69a9c7d4e9be7b6287a6eeeac63a5dad4a616c5acdc3c1bbb6951483275eaa0c9d486cd6fcca234775ae2368409a665591426c947f975bd7b7363519074a54c6bae4fd781453169ed1cb74ea8b5385f51d8205ce28d2e35d2465714731435a544e738fa6945d16cf3a585cce872b3e2186fd4487af356515c116ba3c2a48a422eb3d4efd2b671572a3a21e142dad7858a624f5ceb3aa1ffc3e814e58f70c2c4ecc414a5fb70ea8389d7cc7679e146290aea7f669d9b365f45a428cce6883326836cb66714a5b6897972892039ff2e8a82708db921323a44be43b1c70e59a9a50745d9e34679a7dafab13f51ce253bfc52d2881fd313a5f1c8f93e9c30099eeb4479be5227648927b244cc38515ef5c9a3426f44df7d13c5709d12c36d242d9d9d0ea2704313e5798faab339b991899248dbc9e9e42fc20d4c94a3969e95c4dca971e31265d1f5b36dd9b2fdd912450f26e759dadfa844692b4492d31f53c60629513ea1b1ba7bfdc13d796312c55d7bd13f26ffbfaf23dc904471efb3e8bdd2d5ee2a156e44a2a07f6caf242471ea2748e023fa99abdaf06e38a2a46183868ae65c234aa1846be81699bbc18894f69db990a6faf28d45701e6a275f21dfd35ed54e965ef986224a8c44941876831b8828c785879c0f9ba64575e310254daf29ac6f4b686acd10c51c52bcfb568da58cb810a6068ff712a2a875e7b5217a1d4449948ceb3f273c7dce53100521527b437573732e0c44c93d7ad5e6c60f1f4b7703109aaacf7fe30f2506e2e0861fcae971a55746dd87a2c9f44d6f69be39c8eb0337f8b046b8b18792045572629639e149ee6998618331d028830c36cad8811e523237c9d40d9e79f464e468438dcd43e93aede659d1731833c6683c943fe57c4fb6576d63947195a34370e30e6cd98911f1398937ecc0577858b5a6565b8d7d6585ce4fb72e6974d0e8410e5275286ea9f8b4a9a195234287e298ea3f493f1efb437328e418fe9b1ccab6b964460f1e6763c72c0e2529bad6456efb88689bc1a13437aa73c7999c413d666f28fa68896da5b953c868e68682a9cdeebcbb897964ccda50fceecde82933ba556dc686929c9cd91aca31e4ac6e4f93a9a1fc1f4f288f27374b43419e6f9c244fb3c4d46ea0a19827cee9e7cce919ca13e45544c722cc46cfcc50acda8cfde2316f67c96e94a1983e8d4ca339758ad0da0d3294c389e6fb9c105472888da17c6283e74ebf9fdd1043715427ea8c58175d8b8c1b6128e498f24f9d68a481c61839cac82276821b60288bd4036cf0e02b80860dcac8818009e4a8c09be1868d36ce58c0040490e3d768830df3698c055000001f5715a8aac019b107f4d1dafe5e8f07103170c528071c3672b4b1460102d003af800200c0468e3652408000bc0d4c1b3640c398810001e458e34f1b288d35d44800097294a186514000da0080000000a1f16ce4f81d5400030be0000072e47031082000c3864162142000860d83d258438c030060000d48401a6a8c818363d8c831c6180b0040001870802b830d1d9481da18638c044820093d5003090790c011d438e39cf16718400246b832d858838c1c668c3146022450841b630c044880086c7c8e33fe0c037c0ca31872b01ddda5f487241546f9f7439f48224c9c8f05a3b4693532564c7650b233fe8c3de3cf0046e1377b5052eb811ae78c3f43cff833f2e31757061b669091c38c3146023e7c7165b081d238a38d31c648c0472f8a9ab34f4ca23f23ce2363d9aa0dab337e8d317450061a0395715e8d1c5d6ca051c6e540a30c36cc28a30d1f638d37a38ce2453128eddb318a67a8d211dcc00946d0d181147458e26317c69f9841578cd4b02ecaa6b494a5e610c6e40ec1472e78172f2fafb5d74eabb3f2972443e726b963e2a2b4616467da399911823e6e51f6c9b32525870c348c192778944609d816c5121db36869994ff7d7a28b7955af3bc961631ed3a29833dd49f37c612af62cca1b24077dda22d88e289541468ecea1461a63900f5994efd2d74568927e2d2afd884516176b5722afeffbdde3213a58143c795755ee5a9a675f51ccf3b5516eb6d695b9a2983efe49f6edc6994ac6d618080d6386b123c2472b8af174c65bf3b9eac7c0624539c8cc6cf52082dcbe3e565188b9640c16e39b3d44398c1975830f551494f2bdd538ff4845f1c5c773f21da981e775d01fa82889ac1fe7455bdbf4e84cf0718a62a8d8dc5d6fe618363bdf820f5394bd4f899c2072646c8e5294ab675486904da4cb467a33f083146551539b4d6f928f519473d27d5635f9d5639ea2e02cb28964bae15be32314a5c89921537f5216280a3eeaaaba1e33940e6123c7186994400c31de0cf732aa3e3ed19a85bac8d85b6b6b99d79c0e4ff93879d5c1631967a481460fcc48e304ff1d60f344f1c7d55e5e44e6ac3f3a5194d87d523d74be36ffe044b1d327c4f02673305d7d6ca2ac65123b7ba51f9a28879fe7db7c42992854d54526044992236b576deed01bba57f48189c2be2899e7645077f18a21860f3e2e5138a5c397c7ddce0d131c9c34cc604be041c8646a9eddaec1861a9530d5f5694eda84849950a2a4f2f79374cb842c419328c868fa8c04d33907591225ed48717ae39829cf22619c207c247c08a15f32b63e20d1b876a7e496d85d9d564bfc9d901b46c35a8d33cec7234adb279310f921e786b0e1c31105d3ba31c77f9124845023ec0c21d3a9c91c4694d4dd640ff1219cf6f563118d4d3297d312fb3e14510c3246489b9912ff438940442292da6ac32b6d4b8ff5ffbd8bae107f1ca2fc2753c7641d43143b4bb4d53d717a1e2b4431b47ba368fd48699e0f4294a4cc060df7a9053e0651ce6c9a66af564b659020ca9bf39921e7d31a9f1f8128c765ca09f771669b06c4c71f0a623d94fae8f9d3c522632b071b3c7834728d6703046f83359e04676b3c1b65c8e0c30fc5d0216f852991333efac007bd7773b469c8d8aa3d2867f51bd207b95a42157ce8e1230f25ff1a7b91928312268207336ec4ec26898d8a786a2aa563d4901c84c8c71dca51c29a86116f3139fc6187a2ea6d6bf68cab92e0471d6ad55a512f4f5b395da6218ed894a10f3a3422a93a3dae2d6564c2f8e65e73db0dad081f7328c43c217bf698ff904321a9c412951e44d01cff8843e94aed830a19ef83287dc0c150d58de52963c918f38693a6aed0968b587babe1c30de51c944c6a1f4b7af4b90de5a4574d49562da53e3694ac4359a7d0d512a4670da5afd2412999c34612b61ad06b21b369289abed788fad9bfe93ed0f07186f2462aa14aa699ade43ecc808c89f1abbd759a3258dfaad9766676d25d92b2f598de7f90a1142a3dbbc45f7b0e570a1f632827f1e1e488a473ae4a0cc513a9c49d28dd47180aca22fc474a157d1ffd0043c1456ee88728faf84279bb7cee23e731a57d32b6d028e38c03c187178a953ff236728c813e051f5d30c9e8985482cd5d646c3d0e0c1b639861cc8c0f2e9422beaca989570b3eb650ce5affea611992ced142e136a34d921d42a39e4af09185f26a45dc1c6212195b58592cf8c042292fb2e94e7ae6ba5d64461a1fa0c3c715f8081f56b84fced429a1f05105b7bf8403b30231c4c8f1418582eed0acebda1054842ff89842414b628841eb35ed8d52e023adcc668dc997c647140aeabc376c27af091f502875fc8961840ee7aaa3271483483a6fe891f97042612bcdc36a849a50180dd3900da1fb44fec184b2e479bfcda59eb191fb5842c9d55c9350993f9450d226ae1fb1c44b927e120ab6ba39e536089d4f0809e548b761c4feb68a6c3f8e5050dbb6993ded9ad8e4c3088c66cbb04f6d7e14a1a0f523368896edd92602fdc407114aff2fbaa744b4c4581a46795bb5652cdfc4e4d9431805d93a1f53deb36cc8c128c7b4a69b7a3ee4371518854fc276ed639c93d4fda26cb9eb7daf79f8a26c13fc2509ff7b51cc1c4cf7e0456945627617e5d249e910c44d8738395d946283f639dd3517c5338d410f5c143e95a69a48ced324bf45713b8a8889253d9e981eb62806a5a324e1aa7ba34c1eb5280819227f0ca225c8b0072d4ae119723627e9dee979cca2301357cfafaf43c4d44316c530d95427fdb24194dc231665dd51b133e29d1a7758948466b72ad1f21585682392ee0d56bec1f3704539cbe6f491971b7c3766ad284c8c5632ab88a0d46f66ac280617d39dab378e8e6c15c54f9bfec48aad8ab24419db9b7f5351cebca123b5326f574545418968d9c136b7e6bd4e511e5396412c440f53381a43d2b759bdd941a5c84ecdee3c4554c37990497b6e73abc9d8da8107294a9aed45b6388aa2276bd75ad1431465917d61265a92b135865dc70a46d061c782ab367884a2a0e7ebed3555e9a022288ab92bcd3387d63e51d8d1f5214a10f144d963923b19f3dd89f2d6aaf5e69fc6e42f27ca793c7604d3e8260a5123ab281511ed9cd24499b6e1a4954a3c3251f4bcd2161af355b685e78189828e49261193d07eb23c9728c94f3192d227478e901cbd050f4b1443bafbac91ffdd6fa6c1a312c53631d9124ce4e62494286a943ba521b3314acc4da29046ee6bc367f7a49d8724d2d0736d76d946a2783d9aca4a072142a29c2e36a64e4abaa90f1e3ee25d13919eaa537c506a20031e8e2809eb09fa4c7754174f1a8f469494e40f153ac830a2a0737f28eb95902ee6333c16b12ef05004aec0231188f038c4b22e31b33c535286289cb80f15273fa8896b218a7b327cd2e499e447888cad5f6351e04188d2a4fdd5fcbca32e52973c0651ea2fd1e7deba3a121744f93c42f8d872200aea46cae8ba1c1d3d0344b964ccf91f4aba1a6d3e78f8a1d8373a8fad6cb995f43cfa50ce392893d9ea1ec284cdf850c84168b68a51923699720fe5ec22742e6d3e79d3f5d043a55deb33db4ffae41182471e8ad6ddfb396709e5ad93b115030f3cf0dd216dc9a665261662d9a1782f7a5bc3485b931c8f3a9493d050b2e4860ea5ed1c244e4c2268f46c0ea748ca1ce1d400c8c1430ec591ff6cdb2e71061e7128897bb816d712f14c8be8018762ba13e1b3651ebf51f4784331f665a4bee98a921c0f3794e4892472e977108fe0d186724cb2ce50b5fe1a71f4604359f44cba58a4d750feccd94fdb720f35144ef6ec94568f471aca9b4b359b2ccd9c51f64043b16eec3aa8c65133efa1c719ca1e73278f6fcfa896d1c30ca590dbfd575122083cca50bed8b89517094a5c460ed68007194a7274c964e9e135d4308f311494b687a89e27e524a9218b50a824ae0622692c128845e28030180ec469a78701f31308000038228c8682c168a06992f201140003492218362a2822241c10141c1e1a22120b83c17028100a85c1803020140c0402e1b04defac0f40a9a01f865815f2df8f9132ec9a4e7c45842a9d367cafaeb3c90bdb573869bec39f0e0271ac5e95a4becd9a1767d3c1fcffd1fcfb368002da7d0154f37368894c17e1e0d38571a8785c2883e7fa066ccd2f13f20f5f18fc82babf04bb9ffe573d58f69e3526f7b118ac8f26f3c751aa5d099966a32c3258d7ad2fc8da566035aa7f981f28f46542d8ef62c910b509356ec5ac4a81dcd64d5f19b43fa2a8929c944e31e7ee4b771ba6dc12c673c7883022a94ca02fa034dce32e76d84dedc34ffc92b4fa439c81a62f830cce980a02ea56697b7bdc335288fbdc823b395c3042d5c31ff105115dbb096a4594c46dd298ad2177184c4839d0f5afa5f83681f7f581e83cd917da019c01adf5208384321c164aa32a6f4ab7e801fe667eacb6f6a6b4a02b565079055ce46a99d074e168bca04456c384d19aef20a5ccf570eb03e756132c37b7a725d6660c51299495448a3bfa112743def697da199f44dfa11911e230d52b5fc7367d58a4a96140f711cf2d9bf61f05153528ed3d253b50da219e91881ad6aec3e2bb936529227d1c6d580ddb0c0f1c284889f1d8364a77f6143993d5f5e0659d533a90c8e9cb5d8d9a0543d8669a145966ff4a2c584fa1e1d648e8da520d8e7dd76d9c8d1a89000e0db7f5c8418441bf941ace3ebacb88e8e825e3b0c4740b19b3a137ccc9e08dd4e7222fad61fd3fec18524c44d00500883fd1ba044a982be7ee4734e3693761e6ae8b515cba146fd87225bdead0c2bb54f9ec256478ae2973eeab34a660df0feb2ec0614d57911c1ad4cd125b127f40f27d7f5b6ca5ac540d886b227050e64bc50a006dce22d8dee6f64c50333f33da7068499c12fbe0ac5d76d339689f50dde3c674ebcab985e90304b2d194a0c682f9140cfbca6a0bfa5432f96cc7fb66cd7bfaa84b1ba13d086f20e7bc8416bd01c342b3a4b184cfb93ff85a79b8135640d3c1a5907e259836b63434d21d36115c33e6e10df209dd1fe30520f664b65d0c0918e01370e19da3a72add89653b28663860ca2ce7cbe72af59e460ba1d1a244120f5e977290cd8522a98a2a401b170a12bfeb0de0bbea128a53cc03da8c191569ccfd82562b8c2a6a52fff20c7b0aa604a4f9f195f17a5d3fad581e0cafcfef43bdebb0ae6792325cf9c46c6820cad8ec9a4bda07a94c5e9c6637a2edd891543cede49d9de3a75c6306d8e57176d4d4c346d964524865f33069c22375e1735709030f4a80362cd5b2849b29cea9d3a9730b9167795cf17da83271358618cdfca307829d3a321ce42119b3aa2be752fefdae278f180778ca66349751aef60382fb714737fe2fba9884c945876f675e516d7a157cee9093e8213c057495e16fd49582a373de85f01af3c7ae779f96d94a9e8c4886ac2ed8efeac17f43a5497449b4d790b806a18241e9143ec1fa5f232bd0dc4da423eb821a9849a66691a5a0115a2b90019b57d11bf49036ff9935cdf9e7ecadd9613296ace0f43b077f3240cc010aace39ceb4a2c97e8c84111563b6e79e32ae98415e76a5d37178e673cb0b75633ac33b0061379803004b104eb55c8c5a7ef2de8324a9070dcfe73b5b21544a6c51e11e2c46f115b92e31063ddc2ac9ac79f21ae64aac664929e0e6449423d6da371fdd29960a221b63185fadb7c662965eef9ed0c560844006dffc9866b29a4c4b65240974e0e8181aa1e1e1090ef576e2a7d92c62e6958ab308d9b158245f1b27d03f17b68fbba16bf3f5c6df79387ce4c8dfc7157e6e0ae93450e15b813f78b09bbf947fde627120f1b200363536dd96d402e32323c8dfd1c09bd9ecff99b4699f7996e40063d47956fcce4c95a0494ee22b1f6a5894165eae66052d7bed3caabf2c879bddec2298b4f4dfdf8efd8949a7047450cbf651cfe5e6e051c5dbd1d00c3b1699a48e0bd9cd80f1d000a172a8737412bcb2a4acadf2700b2f3df64479b3dbd333e4916600649fcb91c477720968733047c39f1a273aedc71599014bad6296bb50754bc895a1a459d942924664a99291f7c24ddf83fd2ee93adb54412bc06aa2216d011e6776ef52ce5d49540cfc736410600893ecba510979a74c32a5c01f62a1e0ca5785eb78947f5561f87d964892a64966b9f8d2151bfb1be19a11826fef43d196d8781207631bf9ef7ba6d5ac011f16346e47ef770ee1eee002c477c9f79caa4aad7ee225e0756c7f3d0eb05ca56bf86232ee6cb261eaaeb853b1501ef4199f5ca12a3e5be5d0b3937e740a6e440b3d8eeae9877c41a5fadb672556b5a8ffb85ca9c4dad2667a23274ed0754f59b3fe93fd200e71cf9062e191e9d6544944ecd5762f932376ab350edae1d767e7bc4ac43bc10f20bf751f85ebcd03a471dde9b47a7acf611411a9cbe29a9e739af560656e0cc81c0d9b575509253044eeb39a0b78e7ed75d91b813f12721961cd5fa910c57a8645d40f505eb8ee328caafc0822f3b17812d290de611549beab9408481f2176221a4a7485653107fbe5964f97b37c49799946c393370558ff1511678fa3d545ee604b4102a2ff9d2fa7d67a241bba2f50168e19d5ae33435b4c2489c71fa66f9fb4fe7f131eec05591fdedce8c4f0a84717ac6506babed27c915ccb5cfa331e7f5605deadf2372aa60f0fd5e9e7be2d93c035f83f4d636e15820397009f36cf7faa42dd62afa48c0d57e8fbde5ac20429fc1717dec1a3242ed76d495c22f643526f6c387e325dc59e8b8acc478a068b8a315a756d98bd371135921ddd870c29d44c53289a5952cf4943f97191c047c0d891690da29501ec4aded5879c32841191388a4544185cd6c87453de28152709a0cbd659ae17e2802519ca35efeb0b08addbc3a1dcd8c97f96de1b4b1a1433477704630a3b264fb177af952f43ebad4ece29339cdde9f316fd21d736f3f2e13c017cd23948bac849d87100f62617364b75486c0f259450ead543dc3f4bfc2f2480c1e1950e73b889597c21d52a4ddf0e2923841785762cec61d20423ba476812e2c3d0eac00c51250d0c1e81b11d010c4c8a07d7532459900f602b0a24b0e74ad91c5beeb94c3ac3f98b79b818d8689f9dc735963fa1b2efa5e1b2bd327420c55b589c1f6c440d9b5bf8850214211b3966286c6b67721a77e02b220b43c6c0b65b926a2b41ddf53bca345559f926a751bf03895cbafcc1e23cc7d3b59634ee35ef5e0e30e09c1002f92444eb7dbd202ae6425cd3e67fc51118e54a2f7072008a162983a1dd804085ab6870b626d121a81553003708e6db86146a1cf7d4d3b7719e733a1d71d2ae82f15b32fede9a96f6f85d887e7362afaedd4fb2cd74283bbf4cb9b80624717d146f69de93cbd02dcaa56448b516f04455e079e04ba24d0358a0d1747e25d0cf8c5f57e2efa98e2f1be52af0e7dbc48b813f082b1140fa131faf0d0c34cc89026f504cdd619c4946cbbabc400983d73aff9f35ca296423df2d34f415bc7e6365abb8519f1f6c6c9f7b018eb2612abd827c96d1c14e27ef0e0422b6bf3823b66f68c10139a7692366522a999f9ecee27cec29be7a0358fbf6671dd9498cbf6c50f7a00b696447c51293f8012d24cfcb5b49937ff9a61f169c837b68848404b47575957bdf3c12373ce7035eaf15817490b2b23fbe8bfd6f865a9d70adf9372a3bcb3205a311f1868a974144059d936d374cb14d2b2024bc1fbe88cf48cf023d0def31c6abf80614d601b635c379d9f8739700e1e8b2796ce2e023f790cfca2ff0c742cae0f24a47d31782cb229fb98fd0a3e4106ec9d0f711c8f8aea7226c259792e8201da1aede1e909b63ee7fda0a4a71f0b36556d3a35431893bb48f3e3dee81db5256133d6d205eac2a799d94c6a4763fb7434512d899cfb479c2e318b947ee81fade83481fc504c0058c9d2593d1362f28ffe0d27705272236316735bc3f930b4d9a99b5e23ddd52c61f6917ed347ecb59b1910b39f4cbc22797c12a3fb572314dca1670d8d701d653ca4278d8a27e59bc2aff298882aeced3c9508f402f7a9ee9b77b3c0eb9ba2a321679234453429a567f6a1b7a0de0dd0487712a53f1b499a756a6849a5c1d7fd8c2c2e8e1888e0ddfaf2a2b6cf8d2fb856db04eb4e4acc40e4d87aeebf8e08ddbf2445c69d79b04ae2d4c0eb25ec1ddb8c9fe90616aaace858acaf8686adadbc81e0f3ac2314e4bbf5fdbb97d0da4d8b4eda5f951dd553bad64a19f754004c49f8a074b0f90d9d9a3451d11c4cfbfa5b0084edda65aaeae2cb5010904ab0f46182642a6c421b558f6ddc63c6e902cee0caf72bf2a503e286311e1cdc8e21ee2e685ad8fab9185857dad90e3ed9465db49b3bc5689a0dbe0bf801be58e0f3e8f7299e1572499f1a06ee2f3384851e9e6ec999dbab705882a1883e18fe05c56b992a6d8a220fa7144b4cd620a77cc03f201a28fac0cb4c8fd5790e9921d32bc4c3e1cf662965d81bd0d47e5852c9d27452a208057979a28dd358b9f8c6c2c64aa5f196608782286086fc638e5c1a255085bff3b971b93ce87f3a3e9ec85c2f6efe1e1659b20f8c32bd8e53a94cb1e97ea6a6484e7117411b5465cceaba0033d1bde642216db596e89889be57c2b1cefa6aa74f23ba04c2dc2c1683806bb6b8c140a52151cfdb98c965b2808cbacba3d9f9248b684ea4740bd9ec24792527998d31c61f84072dd846f3be0e895baa3f89506d6edb19038b726059c136de7bbaa11808e8589962131aee81674b47a6e309d396c0aa7a4256896c76e14947e5cdbd81473fa5a907d2a49252fdb210193285b4e9a17b7c4565aec10a2c3b0a143763eb8a6cdec235448fd9ddcaa716ac794dac9ac540512768553d9514fd3b3c24a53579014166b7bf265bb7e13f79453b71f4339ecd48e8685b9146ca24a21380e7655102dcb8147f60b483ce8914354964df71213fb4495269a432ec2f73242de2f7f245335814d23e8012b568700d46728d000161a8d6c80a3670d18ae3d7c2a98124e4628b1a36346a228fa7c9dd43404a2ed15c4038902649229b2e5f1772ce96a3cf141c153cd184043d7e7fcd4d17133e67af4c631841699e1d0dff123252d67f6586b386b307cf842a0e125a00f9063a9abe0e9d201440974fc4cfcf12829e444f2027b1c5735de713cb8af5696b40949b5e265319496f61039abc62411d0b5112d0946bc4e324ffe423739a969f3a83808da538f4ffd05d8c37d747b104d80dcd508bff88575db324bb96752da9c13961710abaef7ae5e29e76cab698b358d61e2fd995886984d40208a2ad3d69553eae2e9aab1989a32751b9d4ec645d89407d801b41aa1148054684e89264775564b996071964870a52c4ab2d8d64158ebd3fc948b0770d2b3e3c1d24051e39d9a8ce88df9dad46b5228a3eb1a5d4d16b2bcda1e9daab28797e12280306f8c8544f961651dd8e80260324df1fa68a6862af3fed9014538d3e28e5e1f039285899f396143076a46112e6cb0b89028638efb8e3a3c9062570c355f56e35dc6f2d4e98468b067964fc9a11e182b1796da16a41287a70ee27c1ba54002e4c0a792861b1ddbdaf61ce40d8c340512ff4a642c29e157c03077d8ddc8da54c46a28ce44a923732c44b32377ab3b1123de07c0638840871c7cdac663521f43d420484c8d14f7c972985271bc59712f17c2fbd401e242ee0c7095021328365c707e8ecffc630843d8160d71b934e6503acdd4cd08ced11b5dcf2d08137d1c0113d36b3636aceb8ffcde8d1f44d519691385f33b282750771da65788ce759d31ca158d85920f1e33af5232b90ede49caef50bca28430ee310a46ea81a6d58cba45c62a10cc8cca181ded9093db489f5e0f8d626c74a10b499b79092f58a2be97d76de018e1d961d64ebd2348dd396762c3f99c7a9cfa76420f71b79ee8a1e4dfbe7558bb86180593c525df26213b739a919d99d19266eb2fc6a4fe4a88a1d8dabe19b82fd6c2043d493db5d911fdb6ee06305a1c8141bc601a04258ae498477d130550b3510dbfcdb1408a52a9bc9876a25cd47bb4a50c0338cb91d9d5496fbe23b5dba137d21373586024ec55e6089bb0d1e7c772fb564f25d65cfb59b6d1761aeb47e67057890ae5838a2d82b4e80c20cee515065e0a5c0ff014a9e569772e68f58899a114420971967964382aeba7c58d7ecf33e4d8d894b3d326d3718284381cf29e0ff6b5e7370ea3e1e5c02584cffd6098a427c1bc406f4b87436845017cabbdb4d6038b89fc1984fc0cd95d98afeb46c817471b62cdb7857890c2968e34de6f377bac138fbae7adafd434d67dc792bc0f15914f12e4c3b2bd98569b486094a07a51a453ac8e0bbd2556cfc707a57c5f9eac500e16e1f89343e2bd3ce98042df87feea31fe3053b4307b4478d6dd30074366af05fa1e1212256bbb049e5c72115f9b7a8d5d5b052b4cddf5aa02fd6f8b7eac483452ad0b717c3d2ae683b313421ba5c767fafd53570a325c4020141f81065ef61268dda35e727a3a284506e15ad958270cb42cc4e326f61301a2a82b5696462e62169d58296a4c088bf1465a48a268201e791a88082dc75fd1f10bd4905eb0a8d77127bdd88070d6c69ca8df2470d7e04d2e37a047b4345a93139efd0f72d66c64d5f7985d90a62bd406ff778b0d1d6a330011dfeb55a14dc0aa2a51205638a7c8599e913ef4afc6986c40923201a5def91295c94985e3eb77d64311c97318a84483118ce2090a9dac25843c08529965632e0302634ab7906e46d2db4002197154c95c7d97946048fa887b7ef2ae3e14e9dec7a2552a57ad95a3fa8d773b192262e6136a3df5aa3bf8fb2b42a9d815fbd42a47e6b443a88d7512ad984a7975000533f7efca0dea7316afdc9c9ecd74183fb3a1966c5c478dc4907bd441790fbebea82159013780508cf5d523972882903dd7a893cb8e77492c64c89d9e7858637384b3c8c2dba298a77441c13b0d1d73f46fb72f32f3adf1766782c9c424fa990f93129642e4fc9ff25e04185459bfa12f0197d346bd079f3516d5ccfa37df9523edbc350c0b93835cc24275b7d8d704e244594bd3ce6d2af58211c4e0f25aeb7a669af938e7cbce395a8868d771fe91d41e1d144123d0f149511582e141c10501bb7a694d95b81c655338934f1a5febca2aae60d96707334134a0f051fb06b5b2c22b23096199a4606be514cce6a1e82e4d589aa4f876d7b7ceb3b386684c9fbbbe1995973f7ab54389a087c1617a9443d144dff1bda6c2e9f6db64e9ca672523fba4745a54d88c854bc256935e5e0ece66bde507a65862fd3bf9059458268492ada6545cdf53c5e84c169784b21a01a4b2273d79036d44b13ed5a1e8a439625b3245e4be58a5919bfde7f5aeb76a012ea9fac83cb08d1bf444fee572a39127d3306630437b986d594581278e34fbc427fff2dd3069d294a58b4b86e10fbf6d6dca43c13399247ea6708b54bb48799533ccfce2ef1b46d08dce79cf127c23d06b2e5c41cc6378d2b187afc36de1bd0fa8b9022da88b732ca39a118c0609ad68ce0315f544fe633e802368a28bb7a5c31937af3669174b23a16ac092034ae052db9c4c3894f08929d9d5a4f951a2d3c042b6dd11f550e5e726fb806d7a61e99528c158a58e32d834a181def489bc37f00e2733d547fc08cda12051006c77b0a2627b0a55b93ddc9003eaca6296e57a3b7d74bfd2308d835637187969c87d1a22969e41ed629a114091e0dd82397c0c0f0098f1a411252e70871c2a3ba274c0df305e43b21af1e6cadc78ca0df3eb32e6cae0b1d113cc50efc3d53c65125f14e1b475918c65dd4f8e271a47c5d3c2cb452b8ae5d508cd80fcb6820b18419115c774233400f8fe410fbfdcdd7c62d16bb91264601cff45fadaeb0a49e9697b75f5c9bc2a7a3019415eda76e67d712079bfce8189f918db213de05504d2b08bb6a7e9f4643f12f4ef66201393019c79df380d3ab0eff405d3ab8ec7aa5229976b4c912f2ace265a86c8bfa4ba7093ac9bd3c5d2bd04b4a1700b0b3a19c1b07d54a8566fd4fd5ef5e18c8d808cfe93d29393bf476d1ed5400462d1f0ef34276b85b1908a1c7c7b403bccbb9a5702e8976e8f2228f235b7b14002abc1b0eeb9e8ed9e0675e87ef4b9073291af44ecc8387b86d6cc5acd2981a7640adaeffe5144c94e8ffd33669fa90675f71785074cf1c0075a155e660d0c2d83ee9296d4657906e46c805ee54551b6ab5a6985e833ef3fd82a143505311125de4a885ae64926fdea61cd99d4b242ae26ba063e6a71cca9da6d2d95189e3bf885fe01a4ce13c19949f91786c0138e07932c25f7213a4e847e4f02b7a13caebdb7f133b5a67618ae10a4c87114184cd198c7035affcb08ffa78bffb6c7ff9639ff5af4cf1ce0dd6485824b1d282b6aa4e11a58cb1c67a8ab5f206101ff10ff0d22ee7952e311fb6136db8e53430f2a3c2a6850988af50173cdf47d2be89e44c9d6c935e2a65f705108be889fa63ae6b093f8ecbbbe40bb70824ecd8d51144287451542a82819b5d8677e7b9b48fd43bc2e6cf3031e1894b01b3744901d4cade23321ff92dcdd33beb337922f3239fd272ba133533d22dc15fc421679db49c2f5d640fc2be813dacbc48c3f613d1ceb0534047f7fd7728ac87754debb37a75ee2dc09d53f3d7d37a99f9f22e448bea8ad7bbc096ae6e977f3d2f77bd2b33bb2ee7f23665bd09c776cf9d9178e4bc08b7d44cbf9c68ee5129fcc4ebc4fb0aa2765d1afa610a932229ced27487ecd542c58ea27310e5e9ad47ff6705117d62ea21d891cc80c5c044b62117100ac5f0044e8d2953e3047aed3eab19914ef0b831e9a7bb35529548b26b01cb4540aecccadb429a7b0efe1f429eba0c80927de754759cd0c4d67f24709339c8d37ba12d5c2b5f347f2158810a81cb7727046a16782c5c34d7db2135077552ac948130974cd417428c13e9c5c3aeca02c970c159d45817605f6cd8b13bfa644b0f0708e440c316dfb6ce9904e365dab8f0e39c5fa1e69515684d2f8b7d4017ebb22e5a46ceadcc26e75e01020d15652da53ca490106d751ea68e0879bbbd43911b9c8eefadcaea005a72f6de39ed768a651b2b69b2f74d02ba2c945defe38b5ab8d3acefb474f50bbd9da4da712622102db1518f152434720f74919e8ed000b56c34a7aa3523fb3b31070b6d8e8e91ebace4ccc639d79e8e31a89a55c8d8ec9138fc19b8813f654f91e97234c23533656c09a97e2b8df4d21ce20e61aaf051965f417da0cd709155d424eb0bd93f2d6f9eb3abc611f738a58db55a9b5bb2ef731cb564bdf7f15613c2ca913c28349e8f1fb9bb4ee6dd20d903cebd02b9b8530dd908282e7155fcb30b9f0f8aee2ba56be3ea2f51f99bf0ef5ab871c140af2cd5b3041d29d4d0c6919b348b8cfe69e1b9a0dbd23887da0752ba1482ca7e232fe79d74e05f97f12c9742dee722369091142b2dfadd49c4c31669992edebd3db8e991c330ebd23db4cdfce2b551cdca08d061d97ace56c0d2fae80eb6f27b8222717d10d1ab8495fbc66b22cde1740a7a0bbe0fd1b449ac39abbe21d226d38670c50b01bac44490c9af9cef697214dceb1110f3a14579cb62430446a53688cf0c7f0009f7ed7598bc9cf4bdff54fe98682aeb2866124b6b33a22d37ee9a82808c0c5ff9c6d5361f917c8c20e338849b2ae32fe4692f012ff319a50fc9092fbbd252ac32804a08490cbf5fa76a7bea9edc1c14f20b12c57cce0a641d8dcc50670ff87c227b031232c266b0cb36684a0667bc1e1c667ade5a7e089ede81c7450d7f6752813b35366c516e299c742bc01d5c181609946af531191611af0f1bd54ae4d67b56fdd64adf15f06b082f310cbe366ea3575a7da1dc838511ea950a9cbfeef9f5ef2738b57e4c1f6f0bab3bd5e62349240b63381dd10ec6fa5fc8de2abb8a4a58660a7f28ece32c136698a7553d074c4e7d164681e63215f9cb75c5fb561f5b3b114ef965636d90f4e4441b7fd087d6d98cbd9f5c1e226862114353234e7aa9bea849fa448cfbd02e9e81b152fc63191874bbe0fe20c48e1cea50826d43afa2a72a96e9f24fa97a9d69925d554e663adf65a9fa24c4a2b1b67bc7e4b76421cd5ffe9e20105dbb302f20982c0957814506053b543233a2c7590d0480cdb0b3438e0b548520f0fc2711c22a1f767d354d8c38b425774275df6de4b407b91ff8b30dccc9c6db9b851fc660e1e21d0935836b4728cfe45f51c3da2c39898de35f0e5b4ecd0e0c24f98d9d6bf7a846d078e2e7c2ef0fd14d0e31bbb6e4554d6d9853caedf08a224240acdcc67a8c28a0062623befadc038060588ecf6de5af498784f5e0f8fd2bc5f6e6baef5831ffd27ab1dc35f09b0159ba74bc834c30c88e8ebe0476b38535e78cd6837a87471d1e9ac0b684b70a04c7f69ccb0acfd4ddb2a7e2613cfbb959fa87bd16461c6aadb01af448f8527b0bbbc6395a084aa6c1bd3c775d413dbfe95713d162017846aa7f05493869d34f0114c24833b46daea03705317963e662df4824ad7c4c6b46ecffaac0415f496639517c09261cc67fd5e098c341a8c2225ad411379a938cc0098fc30661e1bda1459c50036112b21a4a90afd0dc7ba085678d9c3118b0fa1197105672e8579866656240a2fc3a12ae3ba44ea1fe87a40c22d632402afd2eae70127748badf13f7b2d2c57856ee6e8389910e639806ed00e4341a76687c65207a6795855a6e13303c94c4bdf8caaf77404b3b8ad6c2d3e9a8a6789ae5393b1dd2b86fc7187f6aa6d6482078a4ccbbd09590f1cfed30e4529c12db2cd681ae2c748bb956132becabf5bd1edfb559ff8cf3947c23e61a11cf4ca7e82852ad4f1769993e5e6687e453125d5c2773da4f0fe6d9bd881f349fef305fde85b8d855bebe0b71b9eb7c790b07c92c428bdc9301a73b6dd6510f2ba408bfc0f3da9d1cac75ea1df87e923fe39c7dd623e339255f232e430cf601ffe425ba6b382b53510ac1ae9337dd25030dc118c89809e079278f779d2fef725ce94a5ffce5f304d17acd19f3ef69d0b0139b32c7b2634686e794d4351368542899f2d1fe8448c97141969dfd2d13fb32fb7a5ea84dc9e33e03e86b2523cae600732a910cc9491d299290c494eec4965deda04409f99617ed2c4feb644efa799cdb299fbed3738394c69277af037df9d763692c6cf9224d5d5456f3b78f4e990846d6559edc29edb010a1bdc9c9759e7c1ff63b1b68fa03767bdaa1f33a1cc2caacf3ad8db2d4a51856cd6640ac5b5daaed29e479768c95453219c3ac7b8d5a6497b35d41d2fb5279511ecfa62510099186fc97e2f93cddf93ecdf33a9df37ece3033bb26bf7812217dd3998e6b5d0d2e39711792d0325aa5698dbefddbb10b1dd0009d1f99dde87aaabc1156ca9cf193c3148556ba93a9dc071501b81ba5cb7863fea8c095bf7d97f5149957dc35f18bf03dd60a88bebd766ce8e1e6a0a050d2911e594838f9494c05b1455d0d06d308f1293fa52bd8d55fce8b5de98b676706bc5940fdec6ef54dde811ec4b042cda949ced3329fd4d581a2c120", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0x3c311d57d4daf52904616cf69648081e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x3c311d57d4daf52904616cf69648081e5e0621c4869aa60c02be9adcc98a0d1d": "0x084acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28bc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c", + "0x3f1467a096bcd71a5b6a0c8155e20810308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0x3f1467a096bcd71a5b6a0c8155e208103f2edf3bdf381debe331ab7446addfdc": "0x000064a7b3b6e00d0000000000000000", + "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x45323df7cc47150b3930e2666b0aa3134e7b9012096b41c4eb3aaf947f6ea429": "0x0200", + "0x4dcb50595177a3177648411a42aca0f54e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x57f8dc2f5ab09467896f47300f0424384e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x57f8dc2f5ab09467896f47300f0424385e0621c4869aa60c02be9adcc98a0d1d": "0x084acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28bc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c", + "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x79e2fe5d327165001f8232643023ed8b4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7b3237373ffdfeb1cab4222e3b520d6b4e7b9012096b41c4eb3aaf947f6ea429": "0x0400", + "0xb8753e9383841da95f7b8871e5de32694e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00000000000000000000000000000000", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb333f71360101c6556bc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c": "0xbc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3fe54f28cc5d1fc584acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28": "0x4acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28", + "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950133cc54b617fa6116175726180bc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c": "0xbc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b8cd4c3513e0fa5761757261804acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28": "0x4acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x084acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28bc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x084acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe284acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28bc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252cbc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c", + "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d84e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xe38f185207498abb5c213d0fb059b3d86323ae84c43568be0d1394d5d0d522c4": "0x04000000", + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000" + }, + "childrenDefault": {} + } + } +} diff --git a/cumulus/parachains/chain-specs/people-westend.json b/cumulus/parachains/chain-specs/people-westend.json index fa29853c70b05e47df50445935be42a4637f240d..29fa0c9cde79c0daecbce029c8fa377ba1ff6918 100644 --- a/cumulus/parachains/chain-specs/people-westend.json +++ b/cumulus/parachains/chain-specs/people-westend.json @@ -10,7 +10,9 @@ "/dns/westend-people-collator-node-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWGVYTVKW7tYe51JvetvGvVLDPXzqQX1mueJgz14FgkmHG", "/dns/westend-people-collator-node-2.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWGVYTVKW7tYe51JvetvGvVLDPXzqQX1mueJgz14FgkmHG", "/dns/westend-people-collator-node-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWCF1eA2Gap69zgXD7Df3e9DqDUsGoByocggTGejoHjK23", - "/dns/westend-people-collator-node-3.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWCF1eA2Gap69zgXD7Df3e9DqDUsGoByocggTGejoHjK23" + "/dns/westend-people-collator-node-3.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWCF1eA2Gap69zgXD7Df3e9DqDUsGoByocggTGejoHjK23", + "/dns/identity-westend.bootnodes.polkadotters.com/tcp/30532/p2p/12D3KooWKr9San6KTM7REJ95cBaDoiciGcWnW8TTftEJgxGF5Ehb", + "/dns/identity-westend.bootnodes.polkadotters.com/tcp/30534/wss/p2p/12D3KooWKr9San6KTM7REJ95cBaDoiciGcWnW8TTftEJgxGF5Ehb" ], "telemetryEndpoints": null, "protocolId": null, @@ -79,4 +81,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index fe5e24ee6079e6e0483efe7455ab86af21ae112e..ebc9f822beb2c0069276876161158243501ab288 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } -log = { version = "0.4.19", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index 15b090923d501b3769a18efe1916a146d4474f42..a9756af7aed245ea792d12addbbb2fff529eedaf 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -45,8 +45,6 @@ where >::AssetId, >::Balance, >, - AccountIdOf: - From + Into, { fn charge_weight_in_fungibles( asset_id: as Inspect< 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 8f586a46a75cb68a7ccdf62d2f23a1865dcf5d9c..c1e030466559e86f126640a3ee2a97e3fbf5a8a5 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 @@ -16,7 +16,8 @@ mod genesis; pub use genesis::{genesis, ED, PARA_ID_A, PARA_ID_B}; pub use penpal_runtime::xcm_config::{ - LocalTeleportableToAssetHub, LocalTeleportableToAssetHubV3, XcmConfig, + CustomizableAssetFromSystemAssetHub, LocalTeleportableToAssetHub, + LocalTeleportableToAssetHubV3, XcmConfig, }; // Substrate 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 45e1e94de0100bf8a765b22163f519d0a54ced1c..55437645b0523b577c2e9d455952f5526ba9df0b 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 @@ -25,8 +25,7 @@ use polkadot_primitives::{AssignmentId, ValidatorId}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_account_id_from_seed, get_from_seed, get_host_config, - validators, + accounts, build_genesis_storage, get_account_id_from_seed, get_host_config, validators, }; use parachains_common::Balance; use rococo_runtime_constants::currency::UNITS as ROC; @@ -71,7 +70,7 @@ pub fn genesis() -> Storage { x.4.clone(), x.5.clone(), x.6.clone(), - get_from_seed::("Alice"), + x.7.clone(), ), ) }) @@ -79,7 +78,7 @@ pub fn genesis() -> Storage { }, babe: rococo_runtime::BabeConfig { authorities: Default::default(), - epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), + epoch_config: rococo_runtime::BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, sudo: rococo_runtime::SudoConfig { diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs index e2297100a4525e6d26cb469f6f1458023a12b82c..700b80e63f6cf68e6095b7e02d84bb285ce720f9 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs @@ -26,7 +26,7 @@ use polkadot_primitives::{AssignmentId, ValidatorId}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_from_seed, get_host_config, validators, + accounts, build_genesis_storage, get_host_config, validators, }; use parachains_common::Balance; use westend_runtime_constants::currency::UNITS as WND; @@ -72,7 +72,7 @@ pub fn genesis() -> Storage { x.4.clone(), x.5.clone(), x.6.clone(), - get_from_seed::("Alice"), + x.7.clone(), ), ) }) @@ -94,7 +94,7 @@ pub fn genesis() -> Storage { }, babe: westend_runtime::BabeConfig { authorities: Default::default(), - epoch_config: Some(westend_runtime::BABE_GENESIS_EPOCH_CONFIG), + epoch_config: westend_runtime::BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, configuration: westend_runtime::ConfigurationConfig { config: get_host_config() }, diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 381e4110f908a5669b20acbaea44351169652ade..721c58fd86481ca7269db8567c1cc0fd3507a92b 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -14,6 +14,7 @@ codec = { package = "parity-scale-codec", version = "3.4.0", default-features = paste = "1.0.14" # Substrate +beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../substrate/primitives/consensus/beefy" } grandpa = { package = "sc-consensus-grandpa", path = "../../../../../substrate/client/consensus/grandpa" } sp-authority-discovery = { path = "../../../../../substrate/primitives/authority-discovery" } sp-runtime = { path = "../../../../../substrate/primitives/runtime" } @@ -25,7 +26,6 @@ pallet-balances = { path = "../../../../../substrate/frame/balances" } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue" } # Polkadot -polkadot-service = { path = "../../../../../polkadot/node/service", default-features = false, features = ["full-node"] } polkadot-primitives = { path = "../../../../../polkadot/primitives" } polkadot-runtime-parachains = { path = "../../../../../polkadot/runtime/parachains" } xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm" } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 4bbb4701e43918f5f34b250a23c4c483f2b2d4d1..c93484829fe8193c69a4d9475e81201e3607796c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -265,7 +265,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { $crate::impls::assert_expected_events!( Self, vec![ - // XCM is succesfully received and proccessed + // XCM is successfully received and proccessed [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { origin: $crate::impls::AggregateMessageOrigin::Ump($crate::impls::UmpQueueId::Para(id)), weight_used, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 546f81ce8254e3565ad03987d4376da7971782cc..1a5cc1f6fea6dde1882180d8389e9bcc7773d023 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -20,6 +20,7 @@ pub mod xcm_helpers; pub use xcm_emulator; // Substrate +use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; @@ -36,7 +37,6 @@ use polkadot_runtime_parachains::configuration::HostConfiguration; // Cumulus use parachains_common::{AccountId, AuraId}; use polkadot_primitives::{AssignmentId, ValidatorId}; -use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy; pub const XCM_V2: u32 = 2; pub const XCM_V3: u32 = 3; @@ -152,7 +152,18 @@ pub mod validators { ValidatorId, AssignmentId, AuthorityDiscoveryId, + BeefyId, )> { - vec![get_authority_keys_from_seed_no_beefy("Alice")] + 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), + )] } } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 01a376e4dbf8cb304b55951540613b167996d4c8..d3bb3238a3b4308ca010cf1fa5fe8cd65ab2b74c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -76,7 +76,7 @@ macro_rules! test_parachain_is_trusted_teleporter { $crate::macros::cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } ) => {}, RuntimeEvent::Balances( - $crate::macros::pallet_balances::Event::Withdraw { who: sender, amount } + $crate::macros::pallet_balances::Event::Burned { who: sender, amount } ) => {}, ] ); @@ -90,7 +90,7 @@ macro_rules! test_parachain_is_trusted_teleporter { $receiver_para, vec![ RuntimeEvent::Balances( - $crate::macros::pallet_balances::Event::Deposit { who: receiver, .. } + $crate::macros::pallet_balances::Event::Minted { who: receiver, .. } ) => {}, RuntimeEvent::MessageQueue( $crate::macros::pallet_message_queue::Event::Processed { success: true, .. } 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 50f47ab970bad1de098bafe66f1adc998d64c93c..d2c3a323256c193a3af6230c0a0b33ae3f54198f 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 @@ -66,7 +66,7 @@ fn para_receiver_assertions(_: Test) { assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -82,7 +82,7 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, @@ -101,12 +101,12 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { vec![ // Amount to reserve transfer is withdrawn from Parachain's Sovereign account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_penpal_on_ahr.clone().into(), amount: *amount == t.args.amount, }, - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -143,7 +143,7 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } @@ -160,7 +160,7 @@ fn para_to_para_sender_assertions(t: ParaToParaTest) { vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, @@ -184,14 +184,14 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { vec![ // Withdrawn from sender parachain SA RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_penpal_a_on_rococo, amount: *amount == t.args.amount, }, // Deposited to receiver parachain SA RuntimeEvent::Balances( - pallet_balances::Event::Deposit { who, .. } + pallet_balances::Event::Minted { who, .. } ) => { who: *who == sov_penpal_b_on_rococo, }, @@ -207,7 +207,7 @@ fn para_to_para_receiver_assertions(_: ParaToParaTest) { assert_expected_events!( PenpalB, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, 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 218234cc78eaab2801d08f4fa34b99eaaa5935b9..dfb5061b55f053b51e0ceedee3f8df0edbb7b8ba 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 @@ -28,12 +28,12 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { Rococo, vec![ // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, @@ -54,12 +54,12 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { Rococo, vec![ // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] @@ -88,7 +88,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { AssetHubRococo, vec![ // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, @@ -105,7 +105,7 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { AssetHubRococo, vec![ // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] @@ -122,7 +122,7 @@ fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { PenpalA, vec![ RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, @@ -149,12 +149,12 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { vec![ // native asset reserve transfer for paying fees, withdrawn from Penpal's sov account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_penpal_on_ahr.clone().into(), amount: *amount == t.args.amount, }, - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { @@ -221,7 +221,7 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { amount: *amount == expected_asset_amount, }, // native asset for fee is deposited to receiver - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, RuntimeEvent::MessageQueue( 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 851d7be6ec9a0af133c13d7fb0d6aab8ae3411fc..a29cd10ba8338c9ca560bad29b18fba3a94b4c4d 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 @@ -70,7 +70,7 @@ fn para_receiver_assertions(_: Test) { assert_expected_events!( PenpalB, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -88,7 +88,7 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, @@ -109,12 +109,12 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_penpal_on_ahw.clone().into(), amount: *amount == t.args.amount, }, - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -153,7 +153,7 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { assert_expected_events!( PenpalB, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } @@ -170,7 +170,7 @@ fn para_to_para_sender_assertions(t: ParaToParaTest) { vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, @@ -194,14 +194,14 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { vec![ // Withdrawn from sender parachain SA RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_penpal_b_on_westend, amount: *amount == t.args.amount, }, // Deposited to receiver parachain SA RuntimeEvent::Balances( - pallet_balances::Event::Deposit { who, .. } + pallet_balances::Event::Minted { who, .. } ) => { who: *who == sov_penpal_a_on_westend, }, @@ -217,7 +217,7 @@ fn para_to_para_receiver_assertions(_: ParaToParaTest) { assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, 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 01498f7bb4e3b525d5edff164a7fb18a035517e4..0dd1a1533b55904e4fb99dd0d9e3c6face43b19d 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 @@ -28,12 +28,12 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { Westend, vec![ // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, @@ -54,12 +54,12 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { Westend, vec![ // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] @@ -88,7 +88,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { AssetHubWestend, vec![ // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, @@ -105,7 +105,7 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { AssetHubWestend, vec![ // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] @@ -122,7 +122,7 @@ fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { PenpalB, vec![ RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, @@ -149,12 +149,12 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { vec![ // native asset reserve transfer for paying fees, withdrawn from Penpal's sov account RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_penpal_on_ahr.clone().into(), amount: *amount == t.args.amount, }, - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { @@ -221,7 +221,7 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { amount: *amount == expected_asset_amount, }, // native asset for fee is deposited to receiver - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, RuntimeEvent::MessageQueue( 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 a203de0f8c930a43c1848bfa9179e0cba40689a9..787a82ed32f7376f1c94c584711098c15d4da198 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 @@ -184,13 +184,13 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { vec![ // WND is withdrawn from AHR's SA on AHW RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_ahr_on_ahw, amount: *amount == amount_to_send, }, // WNDs deposited to beneficiary - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == AssetHubWestendReceiver::get(), }, // message processed successfully 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 a33d2fab7536cfffe46a57548a21fb5e7f0391e4..6d7b53c8fdfdb3660a4888df5dfd380bccc9d0dd 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 @@ -68,7 +68,7 @@ pub(crate) fn assert_bridge_hub_rococo_message_accepted(expected_processed: bool BridgeHubRococo, vec![ // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Burned { .. }) => {}, // message exported RuntimeEvent::BridgeWestendMessages( pallet_bridge_messages::Event::MessageAccepted { .. } 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 5e1a2af660b0c8ae56cf7f760785052918ecd6d3..ff069e2d3443ec13d8cb17a18c7127f48b6f34ef 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 @@ -18,6 +18,7 @@ use codec::{Decode, Encode}; use emulated_integration_tests_common::xcm_emulator::ConvertLocation; use frame_support::pallet_prelude::TypeInfo; use hex_literal::hex; +use rococo_system_emulated_network::penpal_emulated_chain::CustomizableAssetFromSystemAssetHub; use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeHubRococoSender; use snowbridge_core::outbound::OperatingMode; use snowbridge_pallet_inbound_queue_fixtures::{ @@ -253,6 +254,16 @@ fn send_token_from_ethereum_to_penpal() { (PenpalASender::get(), INITIAL_FUND), ]); + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]).encode(), + )], + )); + }); + // 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(); @@ -478,7 +489,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { assert!( events.iter().any(|event| matches!( event, - RuntimeEvent::Balances(pallet_balances::Event::Deposit{ who, amount }) + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) if *who == TREASURY_ACCOUNT.into() && *amount == 16903333 )), "Snowbridge sovereign takes local fee." @@ -487,7 +498,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { assert!( events.iter().any(|event| matches!( event, - RuntimeEvent::Balances(pallet_balances::Event::Deposit{ who, amount }) + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) if *who == assethub_sovereign && *amount == 2680000000000, )), "AssetHub sovereign takes remote fee." 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 c2a9c008902222f9d9a1206b59b3f510147ddbea..5b0990973d2103f7fa606c4abcccd41a893067d2 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 @@ -182,13 +182,13 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { vec![ // ROC is withdrawn from AHW's SA on AHR RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } + pallet_balances::Event::Burned { who, amount } ) => { who: *who == sov_ahw_on_ahr, amount: *amount == amount_to_send, }, // ROCs deposited to beneficiary - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == AssetHubRococoReceiver::get(), }, // message processed successfully 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 186b96b3976926b6f75995cc47e8e4c9c63b6f48..3074435e8e4e03e561388e5fb0bdf00d5b3f511f 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 @@ -67,7 +67,7 @@ pub(crate) fn assert_bridge_hub_westend_message_accepted(expected_processed: boo BridgeHubWestend, vec![ // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + RuntimeEvent::Balances(pallet_balances::Event::Burned { .. }) => {}, // message exported RuntimeEvent::BridgeRococoMessages( pallet_bridge_messages::Event::MessageAccepted { .. } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs index 58bb9504dbd6bdaffc25c4f8b96424a96309d20a..87adb363e022b3c21fdfca052bb7a3019658760c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs @@ -366,7 +366,7 @@ fn assert_reap_events(id_deposit: Balance, id: &Identity) { PeopleRococo, vec![ // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Deposit { .. }) => {}, + RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, // Amount reserved for identity info RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { @@ -392,7 +392,7 @@ fn assert_reap_events(id_deposit: Balance, id: &Identity) { PeopleRococo, vec![ // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Deposit { .. }) => {}, + RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, // Amount reserved for identity info RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs index 42c7e310b2628eb97011ff36f6c8db2b3dbd130c..0a12277395d739b032d8de032dcdf9f405eaf158 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs @@ -25,12 +25,12 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { Rococo, vec![ // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, @@ -51,12 +51,12 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { Rococo, vec![ // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] @@ -85,7 +85,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { PeopleRococo, vec![ // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, @@ -102,7 +102,7 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { PeopleRococo, vec![ // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs index 246c612a6810c053c4912c9c15f12c8e051eb06c..8d63c8ceff6efea9825cb0d009da74d2974ba40b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs @@ -368,7 +368,7 @@ fn assert_reap_events(id_deposit: Balance, id: &Identity) { PeopleWestend, vec![ // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Deposit { .. }) => {}, + RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, // Amount reserved for identity info RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { @@ -394,7 +394,7 @@ fn assert_reap_events(id_deposit: Balance, id: &Identity) { PeopleWestend, vec![ // Deposit and Endowed from teleport - RuntimeEvent::Balances(BalancesEvent::Deposit { .. }) => {}, + RuntimeEvent::Balances(BalancesEvent::Minted { .. }) => {}, RuntimeEvent::Balances(BalancesEvent::Endowed { .. }) => {}, // Amount reserved for identity info RuntimeEvent::Balances(BalancesEvent::Reserved { who, amount }) => { diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs index e9f0158efbf5e7c344125463991072f3fe77c02f..345663be99baa66fc3e871abc43695f8c681308f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs @@ -25,12 +25,12 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { Westend, vec![ // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, @@ -51,12 +51,12 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { Westend, vec![ // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] @@ -85,7 +85,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { PeopleWestend, vec![ // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { who: *who == t.sender.account_id, amount: *amount == t.args.amount, }, @@ -102,7 +102,7 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { PeopleWestend, vec![ // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { who: *who == t.receiver.account_id, }, ] diff --git a/cumulus/parachains/pallets/collective-content/src/benchmarking.rs b/cumulus/parachains/pallets/collective-content/src/benchmarking.rs index 943386a842766129c2b5d429dc3a9648249ea73f..3d6bf073778a294e39287285ddb8379d57d36c8f 100644 --- a/cumulus/parachains/pallets/collective-content/src/benchmarking.rs +++ b/cumulus/parachains/pallets/collective-content/src/benchmarking.rs @@ -16,7 +16,7 @@ //! The pallet benchmarks. use super::{Pallet as CollectiveContent, *}; -use frame_benchmarking::{impl_benchmark_test_suite, v2::*}; +use frame_benchmarking::v2::*; use frame_support::traits::EnsureOrigin; fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { diff --git a/cumulus/parachains/pallets/collective-content/src/lib.rs b/cumulus/parachains/pallets/collective-content/src/lib.rs index 7a685858accb67868837e734ba9808741a4f7ea1..b1c960ad6a0d337d6b84aaaba59f7fa0625a8124 100644 --- a/cumulus/parachains/pallets/collective-content/src/lib.rs +++ b/cumulus/parachains/pallets/collective-content/src/lib.rs @@ -59,7 +59,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; use sp_runtime::{traits::BadOrigin, Saturating}; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); #[pallet::pallet] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index d1b302dc6d4f3bf3f51fa6d444c288f78bfefe7e..3eb63a24b74e9eee4ded63cc591ec6ba8adb136b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate @@ -119,6 +119,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -130,6 +131,7 @@ runtime-benchmarks = [ "pallet-proxy/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", 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 553c70bc5549ea869e924f34b4f8ac9c61f197e2..32966ab6341d7bf4b2efae0cf008cfa6dfb67275 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -113,7 +113,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 14, @@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 14, @@ -178,6 +178,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>; @@ -234,6 +235,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! { @@ -383,8 +385,8 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2; impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = xcm::v3::MultiLocation; - type AssetIdParameter = xcm::v3::MultiLocation; + type AssetId = xcm::v3::Location; + type AssetIdParameter = xcm::v3::Location; type Currency = Balances; type CreateOrigin = ForeignCreators< ( @@ -761,6 +763,9 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { type Fungibles = LocalAndForeignAssets; type OnChargeAssetTransaction = AssetConversionAdapter; + type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -948,8 +953,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, @@ -961,7 +966,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 = ( pallet_collator_selection::migration::v1::MigrateToV1, @@ -986,37 +991,37 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions { let mut writes = 0; if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) { - PolkadotXcm::current_storage_version().put::(); + PolkadotXcm::in_code_storage_version().put::(); writes.saturating_inc(); } if Multisig::on_chain_storage_version() == StorageVersion::new(0) { - Multisig::current_storage_version().put::(); + Multisig::in_code_storage_version().put::(); writes.saturating_inc(); } if Assets::on_chain_storage_version() == StorageVersion::new(0) { - Assets::current_storage_version().put::(); + Assets::in_code_storage_version().put::(); writes.saturating_inc(); } if Uniques::on_chain_storage_version() == StorageVersion::new(0) { - Uniques::current_storage_version().put::(); + Uniques::in_code_storage_version().put::(); writes.saturating_inc(); } if Nfts::on_chain_storage_version() == StorageVersion::new(0) { - Nfts::current_storage_version().put::(); + Nfts::in_code_storage_version().put::(); writes.saturating_inc(); } if ForeignAssets::on_chain_storage_version() == StorageVersion::new(0) { - ForeignAssets::current_storage_version().put::(); + ForeignAssets::in_code_storage_version().put::(); writes.saturating_inc(); } if PoolAssets::on_chain_storage_version() == StorageVersion::new(0) { - PoolAssets::current_storage_version().put::(); + PoolAssets::in_code_storage_version().put::(); writes.saturating_inc(); } @@ -1034,15 +1039,79 @@ 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, + xcm::v3::MultiLocation, + xcm::v3::MultiLocation, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter(seed: u32) -> (xcm::v3::MultiLocation, xcm::v3::MultiLocation) { + // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. + let asset_id = xcm::v3::MultiLocation::new( + 1, + xcm::v3::Junctions::X3( + xcm::v3::Junction::Parachain(3000), + xcm::v3::Junction::PalletInstance(53), + xcm::v3::Junction::GeneralIndex(seed.into()), + ), + ); + (asset_id, asset_id) + } + + fn setup_balances_and_pool(asset_id: xcm::v3::MultiLocation, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(ForeignAssets::force_create( + RuntimeOrigin::root(), + asset_id.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.into(), &lp_provider, u64::MAX.into())); + + let token_native = Box::new(TokenLocationV3::get()); + let token_second = 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] [pallet_nft_fractionalization, NftFractionalization] [pallet_nfts, Nfts] @@ -1051,7 +1120,9 @@ 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, ToWestend] // XCM @@ -1091,7 +1162,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -1300,6 +1371,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; @@ -1334,6 +1406,7 @@ impl_runtime_apis! { 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: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1353,8 +1426,31 @@ impl_runtime_apis! { Config as XcmBridgeHubRouterConfig, }; + parameter_types! { + pub ExistentialDepositAsset: Option = Some(( + TokenLocation::get(), + ExistentialDeposit::get() + ).into()); + pub const RandomParaId: ParaId = ParaId::new(43211234); + } + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = ( + cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >, + polkadot_runtime_common::xcm_sender::ToParachainDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + PriceForSiblingParachainDelivery, + RandomParaId, + ParachainSystem, + > + ); + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -1363,7 +1459,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between AH and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -1371,17 +1467,13 @@ impl_runtime_apis! { } fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { - // AH can reserve transfer native token to some random parachain. - let random_para_id = 43211234; - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - random_para_id.into() - ); Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, - ParentThen(Parachain(random_para_id).into()).into(), + // AH can reserve transfer native token to some random parachain. + ParentThen(Parachain(RandomParaId::get().into()).into()).into(), )) } @@ -1433,6 +1525,13 @@ impl_runtime_apis! { }); Some((assets, fee_index as u32, dest, verify)) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } impl XcmBridgeHubRouterConfig for Runtime { @@ -1467,13 +1566,6 @@ impl_runtime_apis! { use xcm_config::{TokenLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; - parameter_types! { - pub ExistentialDepositAsset: Option = Some(( - TokenLocation::get(), - ExistentialDeposit::get() - ).into()); - } - impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; 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 0000000000000000000000000000000000000000..ed2c5f3056e3c44601fee945ccda3eab35444e12 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 fa9e86102c619c9ff68316cae2a27a7f79fea2e6..134b5341a401ca0f0918d3f04a79d2a4d1d9622d 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,7 +19,9 @@ 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_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-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 0000000000000000000000000000000000000000..0a639b368af2248bdaf1efa7538d58a935dbe2e0 --- /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 0000000000000000000000000000000000000000..035f9a6dbe5167cb651736f705b817d4ba9027c4 --- /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/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index f8820bbb58cb24afe1afe034e131414368089444..51b6543bae82ba496998706ab6c2aaf6e0ff604b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-05, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-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("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 25_003_000 picoseconds. - Weight::from_parts(25_800_000, 0) + // Minimum execution time: 22_136_000 picoseconds. + Weight::from_parts(22_518_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 88_832_000 picoseconds. - Weight::from_parts(90_491_000, 0) + // Minimum execution time: 92_277_000 picoseconds. + Weight::from_parts(94_843_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -118,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `400` // Estimated: `6196` - // Minimum execution time: 138_911_000 picoseconds. - Weight::from_parts(142_483_000, 0) + // Minimum execution time: 120_110_000 picoseconds. + Weight::from_parts(122_968_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) @@ -148,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `496` // Estimated: `6208` - // Minimum execution time: 146_932_000 picoseconds. - Weight::from_parts(153_200_000, 0) + // Minimum execution time: 143_116_000 picoseconds. + Weight::from_parts(147_355_000, 0) .saturating_add(Weight::from_parts(0, 6208)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -170,8 +170,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_081_000 picoseconds. - Weight::from_parts(7_397_000, 0) + // Minimum execution time: 6_517_000 picoseconds. + Weight::from_parts(6_756_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -181,8 +181,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_007_000 picoseconds. - Weight::from_parts(2_183_000, 0) + // Minimum execution time: 1_894_000 picoseconds. + Weight::from_parts(2_024_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -208,8 +208,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 28_790_000 picoseconds. - Weight::from_parts(29_767_000, 0) + // Minimum execution time: 27_314_000 picoseconds. + Weight::from_parts(28_787_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -234,8 +234,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 30_951_000 picoseconds. - Weight::from_parts(31_804_000, 0) + // Minimum execution time: 29_840_000 picoseconds. + Weight::from_parts(30_589_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -246,45 +246,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_164_000 picoseconds. - Weight::from_parts(2_311_000, 0) + // Minimum execution time: 1_893_000 picoseconds. + Weight::from_parts(2_017_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:4 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `162` - // Estimated: `11052` - // Minimum execution time: 16_906_000 picoseconds. - Weight::from_parts(17_612_000, 0) - .saturating_add(Weight::from_parts(0, 11052)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `159` + // Estimated: `13524` + // Minimum execution time: 19_211_000 picoseconds. + Weight::from_parts(19_552_000, 0) + .saturating_add(Weight::from_parts(0, 13524)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `166` - // Estimated: `11056` - // Minimum execution time: 17_443_000 picoseconds. - Weight::from_parts(18_032_000, 0) - .saturating_add(Weight::from_parts(0, 11056)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `163` + // Estimated: `13528` + // Minimum execution time: 19_177_000 picoseconds. + Weight::from_parts(19_704_000, 0) + .saturating_add(Weight::from_parts(0, 13528)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `13538` - // Minimum execution time: 18_992_000 picoseconds. - Weight::from_parts(19_464_000, 0) - .saturating_add(Weight::from_parts(0, 13538)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16013` + // Minimum execution time: 20_449_000 picoseconds. + Weight::from_parts(21_075_000, 0) + .saturating_add(Weight::from_parts(0, 16013)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -304,36 +304,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 28_011_000 picoseconds. - Weight::from_parts(28_716_000, 0) + // Minimum execution time: 26_578_000 picoseconds. + Weight::from_parts(27_545_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `206` - // Estimated: `8621` - // Minimum execution time: 9_533_000 picoseconds. - Weight::from_parts(9_856_000, 0) - .saturating_add(Weight::from_parts(0, 8621)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11096` + // Minimum execution time: 11_646_000 picoseconds. + Weight::from_parts(11_944_000, 0) + .saturating_add(Weight::from_parts(0, 11096)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `173` - // Estimated: `11063` - // Minimum execution time: 17_628_000 picoseconds. - Weight::from_parts(18_146_000, 0) - .saturating_add(Weight::from_parts(0, 11063)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `170` + // Estimated: `13535` + // Minimum execution time: 19_301_000 picoseconds. + Weight::from_parts(19_664_000, 0) + .saturating_add(Weight::from_parts(0, 13535)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -349,12 +349,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `11105` - // Minimum execution time: 34_877_000 picoseconds. - Weight::from_parts(35_607_000, 0) - .saturating_add(Weight::from_parts(0, 11105)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `212` + // Estimated: `13577` + // Minimum execution time: 35_715_000 picoseconds. + Weight::from_parts(36_915_000, 0) + .saturating_add(Weight::from_parts(0, 13577)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -365,8 +365,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 5_370_000 picoseconds. - Weight::from_parts(5_616_000, 0) + // Minimum execution time: 4_871_000 picoseconds. + Weight::from_parts(5_066_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -377,10 +377,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 26_820_000 picoseconds. - Weight::from_parts(27_143_000, 0) + // Minimum execution time: 25_150_000 picoseconds. + Weight::from_parts(26_119_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `160` + // Estimated: `3625` + // Minimum execution time: 38_248_000 picoseconds. + Weight::from_parts(39_122_000, 0) + .saturating_add(Weight::from_parts(0, 3625)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 693fd7c3fc78aaab44d468fe355090c6455b1404..2584dbdf31062f4c75f03714ce803d234ced0be9 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 @@ -49,19 +49,18 @@ use testnet_parachains_constants::rococo::snowbridge::{ EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX, }; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, - FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, - LocalMint, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter, - SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, + IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith, + StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -114,8 +113,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -223,7 +221,7 @@ pub type PoolFungiblesTransactor = FungiblesAdapter< /// Means for transacting assets on this chain. pub type AssetTransactors = ( - CurrencyTransactor, + FungibleTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor, 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 cff2290222c35a07034d28c731cbe552130c8f4c..38c118dbb4b25fe2e345e9247a2a253d0becd613 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -22,13 +22,13 @@ use asset_hub_rococo_runtime::{ xcm_config::{ bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, - LocationToAccountId, TokenLocation, TokenLocationV3, TrustBackedAssetsPalletLocation, - TrustBackedAssetsPalletLocationV3, XcmConfig, + LocationToAccountId, StakingPot, TokenLocation, TokenLocationV3, + TrustBackedAssetsPalletLocation, TrustBackedAssetsPalletLocationV3, XcmConfig, }, AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, - MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, - ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, + MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, @@ -49,6 +49,7 @@ use frame_support::{ use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}; use sp_consensus_aura::SlotDuration; use sp_runtime::traits::MaybeEquivalence; +use sp_std::ops::Mul; use std::convert::Into; use testnet_parachains_constants::rococo::{consensus::*, currency::UNITS, fee::WeightToFee}; use xcm::latest::prelude::{Assets as XcmAssets, *}; @@ -85,6 +86,52 @@ 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::v3::Location, + Balance, + ), +) { + let existential_deposit = ExistentialDeposit::get(); + + // setup a pool to pay fees with `foreign_asset_id_location` tokens + let pool_owner: AccountId = [14u8; 32].into(); + let native_asset = xcm::v3::Location::parent(); + let pool_liquidity: Balance = + existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000); + + let _ = Balances::force_set_balance( + RuntimeOrigin::root(), + pool_owner.clone().into(), + (existential_deposit + pool_liquidity).mul(2).into(), + ); + + assert_ok!(ForeignAssets::mint( + RuntimeOrigin::signed(foreign_asset_owner), + foreign_asset_id_location.into(), + pool_owner.clone().into(), + (foreign_asset_id_minimum_balance + pool_liquidity).mul(2).into(), + )); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(pool_owner.clone()), + Box::new(native_asset.into()), + Box::new(foreign_asset_id_location.into()) + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(pool_owner.clone()), + Box::new(native_asset.into()), + Box::new(foreign_asset_id_location.into()), + pool_liquidity, + pool_liquidity, + 1, + 1, + pool_owner, + )); +} + #[test] fn test_buy_and_refund_weight_in_native() { ExtBuilder::::default() @@ -1056,7 +1103,8 @@ fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works( mod asset_hub_rococo_tests { use super::*; - use asset_hub_rococo_runtime::{PolkadotXcm, RuntimeOrigin}; + use asset_hub_rococo_runtime::PolkadotXcm; + use xcm_executor::traits::ConvertLocation; fn bridging_to_asset_hub_westend() -> TestBridgingConfig { let _ = PolkadotXcm::force_xcm_version( @@ -1081,27 +1129,135 @@ mod asset_hub_rococo_tests { } #[test] - fn receive_reserve_asset_deposited_wnd_from_asset_hub_westend_works() { + fn receive_reserve_asset_deposited_wnd_from_asset_hub_westend_fees_paid_by_pool_swap_works() { const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32]; + let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); + let staking_pot = StakingPot::get(); + + let foreign_asset_id_location = xcm::v3::Location::new( + 2, + [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Westend)], + ); + 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(); + let foreign_asset_create_params = + (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + + asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ForeignAssetsInstance, + >( + collator_session_keys().add(collator_session_key(BLOCK_AUTHOR_ACCOUNT)), + ExistentialDeposit::get(), + AccountId::from([73; 32]), + block_author_account, + // receiving WNDs + foreign_asset_create_params.clone(), + 1000000000000, + || { + // setup pool for paying fees to touch `SwapFirstAssetTrader` + setup_pool_for_paying_fees_with_foreign_assets(foreign_asset_create_params); + // staking pot account for collecting local native fees from `BuyExecution` + let _ = Balances::force_set_balance(RuntimeOrigin::root(), StakingPot::get().into(), ExistentialDeposit::get()); + // prepare bridge configuration + bridging_to_asset_hub_westend() + }, + ( + [PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)].into(), + GlobalConsensus(Westend), + [Parachain(1000)].into() + ), + || { + // check staking pot for ED + assert_eq!(Balances::free_balance(&staking_pot), ExistentialDeposit::get()); + // check now foreign asset for staking pot + assert_eq!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &staking_pot + ), + 0 + ); + }, + || { + // `SwapFirstAssetTrader` - staking pot receives xcm fees in ROCs + assert!( + Balances::free_balance(&staking_pot) > ExistentialDeposit::get() + ); + // staking pot receives no foreign assets + assert_eq!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &staking_pot + ), + 0 + ); + } + ) + } + + #[test] + fn receive_reserve_asset_deposited_wnd_from_asset_hub_westend_fees_paid_by_sufficient_asset_works( + ) { + const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32]; + let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); + let staking_pot = StakingPot::get(); + + let foreign_asset_id_location = xcm::v3::Location::new( + 2, + [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Westend)], + ); + 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(); + let foreign_asset_create_params = + (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, - LocationToAccountId, ForeignAssetsInstance, >( collator_session_keys().add(collator_session_key(BLOCK_AUTHOR_ACCOUNT)), ExistentialDeposit::get(), AccountId::from([73; 32]), - AccountId::from(BLOCK_AUTHOR_ACCOUNT), + block_author_account.clone(), // receiving WNDs - (xcm::v3::Location::new(2, [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Westend)]), 1000000000000, 1_000_000_000), + foreign_asset_create_params, + 1000000000000, bridging_to_asset_hub_westend, ( [PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)].into(), GlobalConsensus(Westend), [Parachain(1000)].into() - ) + ), + || { + // check block author before + assert_eq!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &block_author_account + ), + 0 + ); + }, + || { + // `TakeFirstAssetTrader` puts fees to the block author + assert!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &block_author_account + ) > 0 + ); + // `SwapFirstAssetTrader` did not work + assert_eq!(Balances::free_balance(&staking_pot), 0); + } ) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 415c8c1cb062b25e51c593f167ec13c011dc470f..c10e02bd8a6c54d36969ca1f259892ce685b2665 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1", optional = true } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate @@ -110,6 +110,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", + "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -120,6 +121,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", 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 409a5f1177d8ea036d9487ff444485c6d9b7e117..5246828da310ad51e167756b0f12fe814acc6fff 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -110,7 +110,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 14, @@ -162,6 +162,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>; @@ -218,6 +219,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! { @@ -735,6 +737,9 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { type Fungibles = LocalAndForeignAssets; type OnChargeAssetTransaction = AssetConversionAdapter; + type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -920,8 +925,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, @@ -933,7 +938,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 = ( @@ -1037,17 +1042,17 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions { let mut writes = 0; if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) { - PolkadotXcm::current_storage_version().put::(); + PolkadotXcm::in_code_storage_version().put::(); writes.saturating_inc(); } if ForeignAssets::on_chain_storage_version() == StorageVersion::new(0) { - ForeignAssets::current_storage_version().put::(); + ForeignAssets::in_code_storage_version().put::(); writes.saturating_inc(); } if PoolAssets::on_chain_storage_version() == StorageVersion::new(0) { - PoolAssets::current_storage_version().put::(); + PoolAssets::in_code_storage_version().put::(); writes.saturating_inc(); } @@ -1065,14 +1070,77 @@ 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, + xcm::v3::MultiLocation, + xcm::v3::MultiLocation, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter(seed: u32) -> (xcm::v3::MultiLocation, xcm::v3::MultiLocation) { + // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. + let asset_id = xcm::v3::MultiLocation::new( + 1, + xcm::v3::Junctions::X3( + xcm::v3::Junction::Parachain(3000), + xcm::v3::Junction::PalletInstance(53), + xcm::v3::Junction::GeneralIndex(seed.into()), + ), + ); + (asset_id, asset_id) + } + + fn setup_balances_and_pool(asset_id: xcm::v3::MultiLocation, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(ForeignAssets::force_create( + RuntimeOrigin::root(), + asset_id.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.into(), &lp_provider, u64::MAX.into())); + + let token_native = Box::new(xcm::v3::MultiLocation::new(1, xcm::v3::Junctions::Here)); + let token_second = 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] @@ -1083,7 +1151,9 @@ 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] // XCM @@ -1123,7 +1193,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -1378,6 +1448,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; @@ -1412,6 +1483,7 @@ impl_runtime_apis! { 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: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1426,8 +1498,31 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + parameter_types! { + pub ExistentialDepositAsset: Option = Some(( + WestendLocation::get(), + ExistentialDeposit::get() + ).into()); + pub const RandomParaId: ParaId = ParaId::new(43211234); + } + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = ( + cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >, + polkadot_runtime_common::xcm_sender::ToParachainDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + PriceForSiblingParachainDelivery, + RandomParaId, + ParachainSystem, + > + ); + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -1436,7 +1531,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between AH and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -1444,17 +1539,13 @@ impl_runtime_apis! { } fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { - // AH can reserve transfer native token to some random parachain. - let random_para_id = 43211234; - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - random_para_id.into() - ); Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, - ParentThen(Parachain(random_para_id).into()).into(), + // AH can reserve transfer native token to some random parachain. + ParentThen(Parachain(RandomParaId::get().into()).into()).into(), )) } @@ -1506,6 +1597,13 @@ impl_runtime_apis! { }); Some((assets, fee_index as u32, dest, verify)) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } use pallet_xcm_bridge_hub_router::benchmarking::{ @@ -1545,13 +1643,6 @@ impl_runtime_apis! { use xcm_config::{MaxAssetsIntoHolding, WestendLocation}; use pallet_xcm_benchmarks::asset_instance_from; - parameter_types! { - pub ExistentialDepositAsset: Option = Some(( - WestendLocation::get(), - ExistentialDeposit::get() - ).into()); - } - impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; 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 0000000000000000000000000000000000000000..46f4f2bfd9668ce7316bf1a4a7a0c71833fd7f7d --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 2f1fcfb05f39151e018d74e8587faa0e79afd8b6..691ed2e57304a1829de76b030a4ef5ed4b3f436f 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,7 +18,9 @@ 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_tx_payment; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; @@ -31,6 +33,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 0000000000000000000000000000000000000000..8fe302630fb9510d0e1c01ca9de37a1bd0be3a4f --- /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 0000000000000000000000000000000000000000..b4c78a78b489073648156133730bd39cd3c68497 --- /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/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 504731f4a9ef743e62090582901a63f7aee78829..71facff87d35f350114850653acfbebeb5c29529 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-05, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-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("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 25_482_000 picoseconds. - Weight::from_parts(26_622_000, 0) + // Minimum execution time: 21_630_000 picoseconds. + Weight::from_parts(22_306_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 87_319_000 picoseconds. - Weight::from_parts(89_764_000, 0) + // Minimum execution time: 91_802_000 picoseconds. + Weight::from_parts(93_672_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -118,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `367` // Estimated: `6196` - // Minimum execution time: 139_133_000 picoseconds. - Weight::from_parts(141_507_000, 0) + // Minimum execution time: 118_930_000 picoseconds. + Weight::from_parts(122_306_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) @@ -148,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `496` // Estimated: `6208` - // Minimum execution time: 144_241_000 picoseconds. - Weight::from_parts(149_709_000, 0) + // Minimum execution time: 140_527_000 picoseconds. + Weight::from_parts(144_501_000, 0) .saturating_add(Weight::from_parts(0, 6208)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -158,8 +158,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_392_000 picoseconds. - Weight::from_parts(10_779_000, 0) + // Minimum execution time: 7_556_000 picoseconds. + Weight::from_parts(7_798_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -168,8 +168,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_088_000 picoseconds. - Weight::from_parts(7_257_000, 0) + // Minimum execution time: 6_373_000 picoseconds. + Weight::from_parts(6_603_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_095_000 picoseconds. - Weight::from_parts(2_136_000, 0) + // Minimum execution time: 1_941_000 picoseconds. + Weight::from_parts(2_088_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -206,8 +206,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 28_728_000 picoseconds. - Weight::from_parts(29_349_000, 0) + // Minimum execution time: 27_080_000 picoseconds. + Weight::from_parts(27_820_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -232,8 +232,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 30_605_000 picoseconds. - Weight::from_parts(31_477_000, 0) + // Minimum execution time: 28_850_000 picoseconds. + Weight::from_parts(29_506_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -244,45 +244,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_137_000 picoseconds. - Weight::from_parts(2_303_000, 0) + // Minimum execution time: 2_033_000 picoseconds. + Weight::from_parts(2_201_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:4 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `162` - // Estimated: `11052` - // Minimum execution time: 16_719_000 picoseconds. - Weight::from_parts(17_329_000, 0) - .saturating_add(Weight::from_parts(0, 11052)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `159` + // Estimated: `13524` + // Minimum execution time: 18_844_000 picoseconds. + Weight::from_parts(19_197_000, 0) + .saturating_add(Weight::from_parts(0, 13524)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `166` - // Estimated: `11056` - // Minimum execution time: 16_687_000 picoseconds. - Weight::from_parts(17_405_000, 0) - .saturating_add(Weight::from_parts(0, 11056)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `163` + // Estimated: `13528` + // Minimum execution time: 18_940_000 picoseconds. + Weight::from_parts(19_450_000, 0) + .saturating_add(Weight::from_parts(0, 13528)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `13538` - // Minimum execution time: 18_751_000 picoseconds. - Weight::from_parts(19_130_000, 0) - .saturating_add(Weight::from_parts(0, 13538)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16013` + // Minimum execution time: 20_521_000 picoseconds. + Weight::from_parts(21_076_000, 0) + .saturating_add(Weight::from_parts(0, 16013)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -302,36 +302,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 27_189_000 picoseconds. - Weight::from_parts(27_760_000, 0) + // Minimum execution time: 26_007_000 picoseconds. + Weight::from_parts(26_448_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `206` - // Estimated: `8621` - // Minimum execution time: 9_307_000 picoseconds. - Weight::from_parts(9_691_000, 0) - .saturating_add(Weight::from_parts(0, 8621)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11096` + // Minimum execution time: 11_584_000 picoseconds. + Weight::from_parts(12_080_000, 0) + .saturating_add(Weight::from_parts(0, 11096)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `173` - // Estimated: `11063` - // Minimum execution time: 17_607_000 picoseconds. - Weight::from_parts(18_090_000, 0) - .saturating_add(Weight::from_parts(0, 11063)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `170` + // Estimated: `13535` + // Minimum execution time: 19_157_000 picoseconds. + Weight::from_parts(19_513_000, 0) + .saturating_add(Weight::from_parts(0, 13535)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -347,12 +347,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `11105` - // Minimum execution time: 34_322_000 picoseconds. - Weight::from_parts(35_754_000, 0) - .saturating_add(Weight::from_parts(0, 11105)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `212` + // Estimated: `13577` + // Minimum execution time: 34_878_000 picoseconds. + Weight::from_parts(35_623_000, 0) + .saturating_add(Weight::from_parts(0, 13577)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -363,8 +363,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_513_000 picoseconds. - Weight::from_parts(4_754_000, 0) + // Minimum execution time: 3_900_000 picoseconds. + Weight::from_parts(4_161_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -375,10 +375,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 27_860_000 picoseconds. - Weight::from_parts(28_279_000, 0) + // Minimum execution time: 25_731_000 picoseconds. + Weight::from_parts(26_160_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `160` + // Estimated: `3625` + // Minimum execution time: 37_251_000 picoseconds. + Weight::from_parts(38_075_000, 0) + .saturating_add(Weight::from_parts(0, 3625)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 01437534c1fde75439546a0c84275b83db796099..50865c0006117ac619a757fc48ce5cf9db4516b9 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 @@ -45,19 +45,18 @@ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin, - FrameTransactionalProcessor, FungiblesAdapter, GlobalConsensusParachainConvertsFor, - HashedDescription, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, - NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, - TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, - WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, + FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, + GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, + NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, + StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -107,8 +106,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -216,7 +214,7 @@ pub type PoolFungiblesTransactor = FungiblesAdapter< /// Means for transacting assets on this chain. pub type AssetTransactors = ( - CurrencyTransactor, + FungibleTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor, 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 5f6e4c007cd9824f10d4b324513366a84ed1acf1..aa8c3cf2f14db33e119a355bff2e61ccc9a2c23d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -22,8 +22,8 @@ use asset_hub_westend_runtime::{ xcm_config::{ bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, - LocationToAccountId, TrustBackedAssetsPalletLocation, TrustBackedAssetsPalletLocationV3, - WestendLocation, WestendLocationV3, XcmConfig, + LocationToAccountId, StakingPot, TrustBackedAssetsPalletLocation, + TrustBackedAssetsPalletLocationV3, WestendLocation, WestendLocationV3, XcmConfig, }, AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, @@ -50,11 +50,11 @@ use frame_support::{ use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}; use sp_consensus_aura::SlotDuration; use sp_runtime::traits::MaybeEquivalence; -use std::convert::Into; +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_builder::V4V3LocationConverter; -use xcm_executor::traits::{JustTry, WeightTrader}; +use xcm_executor::traits::{ConvertLocation, JustTry, WeightTrader}; const ALICE: [u8; 32] = [1u8; 32]; const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32]; @@ -86,6 +86,52 @@ 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::v3::Location, + Balance, + ), +) { + let existential_deposit = ExistentialDeposit::get(); + + // setup a pool to pay fees with `foreign_asset_id_location` tokens + let pool_owner: AccountId = [14u8; 32].into(); + let native_asset = xcm::v3::Location::parent(); + let pool_liquidity: Balance = + existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000); + + let _ = Balances::force_set_balance( + RuntimeOrigin::root(), + pool_owner.clone().into(), + (existential_deposit + pool_liquidity).mul(2).into(), + ); + + assert_ok!(ForeignAssets::mint( + RuntimeOrigin::signed(foreign_asset_owner), + foreign_asset_id_location.into(), + pool_owner.clone().into(), + (foreign_asset_id_minimum_balance + pool_liquidity).mul(2).into(), + )); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(pool_owner.clone()), + Box::new(native_asset.into()), + Box::new(foreign_asset_id_location.into()) + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(pool_owner.clone()), + Box::new(native_asset.into()), + Box::new(foreign_asset_id_location.into()), + pool_liquidity, + pool_liquidity, + 1, + 1, + pool_owner, + )); +} + #[test] fn test_buy_and_refund_weight_in_native() { ExtBuilder::::default() @@ -1071,30 +1117,133 @@ fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_rococo_works() Some(xcm_config::TreasuryAccount::get()), ) } + #[test] -fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_works() { +fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_swap_works() { const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32]; + let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); + let staking_pot = StakingPot::get(); + + let foreign_asset_id_location = + xcm::v3::Location::new(2, [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Rococo)]); + 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(); + let foreign_asset_create_params = + (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, - LocationToAccountId, ForeignAssetsInstance, >( collator_session_keys().add(collator_session_key(BLOCK_AUTHOR_ACCOUNT)), ExistentialDeposit::get(), AccountId::from([73; 32]), - AccountId::from(BLOCK_AUTHOR_ACCOUNT), + block_author_account.clone(), // receiving ROCs - (xcm::v3::Location::new(2, [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Rococo)]), 1000000000000, 1_000_000_000), - bridging_to_asset_hub_rococo, + foreign_asset_create_params.clone(), + 1000000000000, + || { + // setup pool for paying fees to touch `SwapFirstAssetTrader` + setup_pool_for_paying_fees_with_foreign_assets(foreign_asset_create_params); + // staking pot account for collecting local native fees from `BuyExecution` + let _ = Balances::force_set_balance(RuntimeOrigin::root(), StakingPot::get().into(), ExistentialDeposit::get()); + // prepare bridge configuration + bridging_to_asset_hub_rococo() + }, ( [PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)].into(), GlobalConsensus(Rococo), [Parachain(1000)].into() - ) + ), + || { + // check staking pot for ED + assert_eq!(Balances::free_balance(&staking_pot), ExistentialDeposit::get()); + // check now foreign asset for staking pot + assert_eq!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &staking_pot + ), + 0 + ); + }, + || { + // `SwapFirstAssetTrader` - staking pot receives xcm fees in ROCs + assert!( + Balances::free_balance(&staking_pot) > ExistentialDeposit::get() + ); + // staking pot receives no foreign assets + assert_eq!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &staking_pot + ), + 0 + ); + } ) } + +#[test] +fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_sufficient_asset_works() { + const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32]; + let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); + let staking_pot = StakingPot::get(); + + let foreign_asset_id_location = + xcm::v3::Location::new(2, [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::Rococo)]); + 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(); + let foreign_asset_create_params = + (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance); + + asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ForeignAssetsInstance, + >( + collator_session_keys().add(collator_session_key(BLOCK_AUTHOR_ACCOUNT)), + ExistentialDeposit::get(), + AccountId::from([73; 32]), + block_author_account.clone(), + // receiving ROCs + foreign_asset_create_params, + 1000000000000, + bridging_to_asset_hub_rococo, + ( + [PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)].into(), + GlobalConsensus(Rococo), + [Parachain(1000)].into() + ), + || { + // check block author before + assert_eq!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &block_author_account + ), + 0 + ); + }, + || { + // `TakeFirstAssetTrader` puts fees to the block author + assert!( + ForeignAssets::balance( + foreign_asset_id_location.into(), + &block_author_account + ) > 0 + ); + // `SwapFirstAssetTrader` did not work + assert_eq!(Balances::free_balance(&staking_pot), 0); + } + ) +} + #[test] fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 74e5e44ce15581e8e4df7ad6c49417c2b0fdc756..c9252375cfbf019c27a1ce0d5dc38f11db30cac5 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } impl-trait-for-tuples = "0.2.2" # Substrate diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index a0c912b6f0fe3643f1f516b311fdfd5d401db4d0..fa2752179eb6fd238eb8596d8e3ebddf947680d3 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -371,7 +371,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/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index f1b3953ce473bf5dc27d63eb9a9404fb9086979d..883c93c97b4de6774e86ee83b84d246dc1427f7f 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -16,8 +16,8 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = frame-support = { path = "../../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../../substrate/frame/system", default-features = false } pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } -pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } sp-io = { path = "../../../../../substrate/primitives/io", default-features = false } sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } @@ -56,11 +56,11 @@ std = [ "cumulus-primitives-core/std", "frame-support/std", "frame-system/std", - "pallet-asset-conversion/std", "pallet-assets/std", "pallet-balances/std", "pallet-collator-selection/std", "pallet-session/std", + "pallet-timestamp/std", "pallet-xcm-bridge-hub-router/std", "pallet-xcm/std", "parachain-info/std", diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 4007d926983ed97a8cae705428c1d61184173cb7..53e10956bd0d1d233555a8e4df1ae23fe351c678 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -70,7 +70,8 @@ pub fn teleports_for_native_asset_works< + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config - + cumulus_pallet_xcmp_queue::Config, + + cumulus_pallet_xcmp_queue::Config + + pallet_timestamp::Config, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, AccountIdOf: Into<[u8; 32]>, @@ -350,7 +351,8 @@ pub fn teleports_for_foreign_assets_works< + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config + cumulus_pallet_xcmp_queue::Config - + pallet_assets::Config, + + pallet_assets::Config + + pallet_timestamp::Config, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, AccountIdOf: Into<[u8; 32]>, @@ -701,7 +703,8 @@ pub fn asset_transactor_transfer_with_local_consensus_currency_works: Into<[u8; 32]>, ValidatorIdOf: From>, BalanceOf: From, @@ -826,7 +829,8 @@ pub fn asset_transactor_transfer_with_pallet_assets_instance_works< + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config - + pallet_assets::Config, + + pallet_assets::Config + + pallet_timestamp::Config, AccountIdOf: Into<[u8; 32]>, ValidatorIdOf: From>, BalanceOf: From, @@ -1093,7 +1097,8 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config - + pallet_assets::Config, + + pallet_assets::Config + + pallet_timestamp::Config, AccountIdOf: Into<[u8; 32]>, ValidatorIdOf: From>, BalanceOf: From, @@ -1422,7 +1427,8 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config - + cumulus_pallet_xcmp_queue::Config, + + cumulus_pallet_xcmp_queue::Config + + pallet_timestamp::Config, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, AccountIdOf: Into<[u8; 32]>, 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 4a0f31c449ea61d00b04110008d9984e5e87cbd7..1cce3b647cf0446a2246417b5383594fb501e600 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 @@ -30,7 +30,6 @@ use parachains_runtimes_test_utils::{ SlotDurations, ValidatorIdOf, XcmReceivedFrom, }; use sp_runtime::{traits::StaticLookup, Saturating}; -use sp_std::ops::Mul; use xcm::{latest::prelude::*, VersionedAssets}; use xcm_builder::{CreateMatcher, MatchXcm}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; @@ -71,7 +70,8 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config - + cumulus_pallet_xcmp_queue::Config, + + cumulus_pallet_xcmp_queue::Config + + pallet_timestamp::Config, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, AccountIdOf: Into<[u8; 32]>, @@ -323,20 +323,22 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< Runtime, AllPalletsWithoutSystem, XcmConfig, - LocationToAccountId, ForeignAssetsPalletInstance, >( collator_session_keys: CollatorSessionKeys, existential_deposit: BalanceOf, target_account: AccountIdOf, block_author_account: AccountIdOf, - ( - foreign_asset_id_location, - transfered_foreign_asset_id_amount, - foreign_asset_id_minimum_balance, - ): (xcm::v3::Location, u128, u128), - prepare_configuration: fn() -> TestBridgingConfig, + (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): ( + AccountIdOf, + xcm::v3::Location, + u128, + ), + foreign_asset_id_amount_to_transfer: u128, + prepare_configuration: impl FnOnce() -> TestBridgingConfig, (bridge_instance, universal_origin, descend_origin): (Junctions, Junction, Junctions), /* bridge adds origin manipulation on the way */ + additional_checks_before: impl FnOnce(), + additional_checks_after: impl FnOnce(), ) where Runtime: frame_system::Config + pallet_balances::Config @@ -347,14 +349,13 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< + cumulus_pallet_parachain_system::Config + cumulus_pallet_xcmp_queue::Config + pallet_assets::Config - + pallet_asset_conversion::Config, + + pallet_timestamp::Config, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, AccountIdOf: Into<[u8; 32]> + From<[u8; 32]>, ValidatorIdOf: From>, BalanceOf: From + Into, XcmConfig: xcm_executor::Config, - LocationToAccountId: ConvertLocation>, >::AssetId: From + Into, >::AssetIdParameter: @@ -365,9 +366,6 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< + Into, <::Lookup as StaticLookup>::Source: From<::AccountId>, - ::AssetKind: - From + Into, - ::Balance: From, ForeignAssetsPalletInstance: 'static, { ExtBuilder::::default() @@ -382,88 +380,31 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< block_author_account.clone().into(), ); - // prepare bridge config - let TestBridgingConfig { local_bridge_hub_location, .. } = prepare_configuration(); - // drip 'ED' user target account let _ = >::deposit_creating( &target_account, existential_deposit, ); - // sovereign account as foreign asset owner (can be whoever for this scenario, doesnt - // matter) - let sovereign_account_as_owner_of_foreign_asset = - LocationToAccountId::convert_location(&Location::parent()).unwrap(); - - // staking pot account for collecting local native fees from `BuyExecution` - let staking_pot = >::account_id(); - let _ = >::deposit_creating( - &staking_pot, - existential_deposit, - ); - // create foreign asset for wrapped/derivated representation assert_ok!( >::force_create( RuntimeHelper::::root_origin(), foreign_asset_id_location.into(), - sovereign_account_as_owner_of_foreign_asset.clone().into(), + foreign_asset_owner.into(), true, // is_sufficient=true foreign_asset_id_minimum_balance.into() ) ); - // setup a pool to pay fees with `foreign_asset_id_location` tokens - let pool_owner: AccountIdOf = [1u8; 32].into(); - let native_asset = xcm::v3::Location::parent(); - let pool_liquidity: u128 = - existential_deposit.into().max(foreign_asset_id_minimum_balance).mul(100_000); - - let _ = >::deposit_creating( - &pool_owner, - (existential_deposit.into() + pool_liquidity).mul(2).into(), - ); - - assert_ok!(>::mint( - RuntimeHelper::::origin_of( - sovereign_account_as_owner_of_foreign_asset - ), - foreign_asset_id_location.into(), - pool_owner.clone().into(), - (foreign_asset_id_minimum_balance + pool_liquidity).mul(2).into(), - )); - - assert_ok!(>::create_pool( - RuntimeHelper::::origin_of(pool_owner.clone()), - Box::new(native_asset.into()), - Box::new(foreign_asset_id_location.into()) - )); - - assert_ok!(>::add_liquidity( - RuntimeHelper::::origin_of(pool_owner.clone()), - Box::new(native_asset.into()), - Box::new(foreign_asset_id_location.into()), - pool_liquidity.into(), - pool_liquidity.into(), - 1.into(), - 1.into(), - pool_owner, - )); + // prepare bridge config + let TestBridgingConfig { local_bridge_hub_location, .. } = prepare_configuration(); // Balances before assert_eq!( >::free_balance(&target_account), existential_deposit.clone() ); - assert_eq!( - >::free_balance(&block_author_account), - 0.into() - ); - assert_eq!( - >::free_balance(&staking_pot), - existential_deposit.clone() - ); // ForeignAssets balances before assert_eq!( @@ -473,27 +414,16 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< ), 0.into() ); - assert_eq!( - >::balance( - foreign_asset_id_location.into(), - &block_author_account - ), - 0.into() - ); - assert_eq!( - >::balance( - foreign_asset_id_location.into(), - &staking_pot - ), - 0.into() - ); + + // additional check before + additional_checks_before(); let foreign_asset_id_location_latest: Location = foreign_asset_id_location.try_into().unwrap(); let expected_assets = Assets::from(vec![Asset { id: AssetId(foreign_asset_id_location_latest.clone()), - fun: Fungible(transfered_foreign_asset_id_amount), + fun: Fungible(foreign_asset_id_amount_to_transfer), }]); let expected_beneficiary = Location::new( 0, @@ -510,7 +440,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< BuyExecution { fees: Asset { id: AssetId(foreign_asset_id_location_latest.clone()), - fun: Fungible(transfered_foreign_asset_id_amount), + fun: Fungible(foreign_asset_id_amount_to_transfer), }, weight_limit: Unlimited, }, @@ -544,19 +474,10 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< assert_ok!(outcome.ensure_complete()); // Balances after - // staking pot receives xcm fees in dot - assert!( - >::free_balance(&staking_pot) != - existential_deposit - ); assert_eq!( >::free_balance(&target_account), existential_deposit.clone() ); - assert_eq!( - >::free_balance(&block_author_account), - 0.into() - ); // ForeignAssets balances after assert!( @@ -565,20 +486,9 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< &target_account ) > 0.into() ); - assert_eq!( - >::balance( - foreign_asset_id_location.into(), - &staking_pot - ), - 0.into() - ); - assert_eq!( - >::balance( - foreign_asset_id_location.into(), - &block_author_account - ), - 0.into() - ); + + // additional check after + additional_checks_after(); }) } @@ -602,7 +512,8 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config + cumulus_pallet_xcmp_queue::Config - + pallet_xcm_bridge_hub_router::Config, + + pallet_xcm_bridge_hub_router::Config + + pallet_timestamp::Config, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, AccountIdOf: Into<[u8; 32]>, diff --git a/cumulus/parachains/runtimes/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index cf617db730dd7faa19d932dbe6a0406b7a0c15f2..c858532295ddce7ad1fd9a57a19d752201b78abd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -89,20 +89,18 @@ cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-paracha cd # Rococo + BridgeHubRococo + AssetHub for Rococo (mirroring Kusama) -POLKADOT_BINARY_PATH=~/local_bridge_testing/bin/polkadot \ -POLKADOT_PARACHAIN_BINARY_PATH=~/local_bridge_testing/bin/polkadot-parachain \ -POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO=~/local_bridge_testing/bin/polkadot-parachain-asset-hub \ - ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +POLKADOT_BINARY=~/local_bridge_testing/bin/polkadot \ +POLKADOT_PARACHAIN_BINARY=~/local_bridge_testing/bin/polkadot-parachain \ + ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml ``` ``` cd # Westend + BridgeHubWestend + AssetHub for Westend (mirroring Polkadot) -POLKADOT_BINARY_PATH=~/local_bridge_testing/bin/polkadot \ -POLKADOT_PARACHAIN_BINARY_PATH=~/local_bridge_testing/bin/polkadot-parachain \ -POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND=~/local_bridge_testing/bin/polkadot-parachain-asset-hub \ - ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./cumulus/zombienet/bridge-hubs/bridge_hub_westend_local_network.toml +POLKADOT_BINARY=~/local_bridge_testing/bin/polkadot \ +POLKADOT_PARACHAIN_BINARY=~/local_bridge_testing/bin/polkadot-parachain \ + ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml ``` ### Init bridge and run relayer between BridgeHubRococo and BridgeHubWestend @@ -114,7 +112,7 @@ POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WESTEND=~/local_bridge_testing/bin/ ``` cd -./cumulus/scripts/bridges_rococo_westend.sh run-relay +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh run-relay ``` **Check relay-chain headers relaying:** @@ -137,10 +135,10 @@ This initialization does several things: ``` cd -./cumulus/scripts/bridges_rococo_westend.sh init-asset-hub-rococo-local -./cumulus/scripts/bridges_rococo_westend.sh init-bridge-hub-rococo-local -./cumulus/scripts/bridges_rococo_westend.sh init-asset-hub-westend-local -./cumulus/scripts/bridges_rococo_westend.sh init-bridge-hub-westend-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh init-asset-hub-rococo-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh init-bridge-hub-rococo-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh init-asset-hub-westend-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh init-bridge-hub-westend-local ``` ### Send messages - transfer asset over bridge (ROCs/WNDs) @@ -150,13 +148,13 @@ Do reserve-backed transfers: cd # ROCs from Rococo's Asset Hub to Westend's. -./cumulus/scripts/bridges_rococo_westend.sh reserve-transfer-assets-from-asset-hub-rococo-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh reserve-transfer-assets-from-asset-hub-rococo-local ``` ``` cd # WNDs from Westend's Asset Hub to Rococo's. -./cumulus/scripts/bridges_rococo_westend.sh reserve-transfer-assets-from-asset-hub-westend-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh reserve-transfer-assets-from-asset-hub-westend-local ``` - open explorers: (see zombienets) @@ -171,13 +169,13 @@ Do reserve withdraw transfers: (when previous is finished) cd # wrappedWNDs from Rococo's Asset Hub to Westend's. -./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-rococo-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-rococo-local ``` ``` cd # wrappedROCs from Westend's Asset Hub to Rococo's. -./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-westend-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-westend-local ``` ### Claim relayer's rewards on BridgeHubRococo and BridgeHubWestend @@ -190,10 +188,10 @@ cd cd # Claim rewards on BridgeHubWestend: -./cumulus/scripts/bridges_rococo_westend.sh claim-rewards-bridge-hub-rococo-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh claim-rewards-bridge-hub-rococo-local # Claim rewards on BridgeHubWestend: -./cumulus/scripts/bridges_rococo_westend.sh claim-rewards-bridge-hub-westend-local +./bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh claim-rewards-bridge-hub-westend-local ``` - open explorers: (see zombienets) 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 920e7b1571c6f83ee241700ad30c57a10c76429e..242627815d3a5ced13a99d9f7f7c075e55c63200 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -17,11 +17,11 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = "derive", ] } hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = [ "derive", ] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -242,6 +242,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 6dbf96edc2ab0360385b8e04bf1dc52732abd9ca..323e6ed65e69c22ae6be6f80bb26b4e6455bbb94 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 @@ -40,7 +40,7 @@ use bridge_runtime_common::{ XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedGrandpaMessages, RefundSignedExtensionAdapter, + ActualFeeRefund, RefundBridgedGrandpaMessages, RefundTransactionExtensionAdapter, RefundableMessagesLane, }, }; @@ -168,7 +168,7 @@ impl messages::BridgedChainWithMessages for RococoBulletin {} /// Signed extension that refunds relayers that are delivering messages from the Rococo Bulletin /// chain. -pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundSignedExtensionAdapter< +pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundTransactionExtensionAdapter< RefundBridgedGrandpaMessages< Runtime, BridgeGrandpaRococoBulletinInstance, 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 5d55d7afbacfdb22f6939c88e87eaf64321945ff..05d1aa188d2d3abd114431e6ee388473dca8f982 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 @@ -39,7 +39,7 @@ use bridge_runtime_common::{ XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + ActualFeeRefund, RefundBridgedParachainMessages, RefundTransactionExtensionAdapter, RefundableMessagesLane, RefundableParachain, }, }; @@ -173,7 +173,7 @@ impl UnderlyingChainProvider for BridgeHubWestend { impl messages::BridgedChainWithMessages for BridgeHubWestend {} /// Signed extension that refunds relayers that are delivering messages from the Westend parachain. -pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundSignedExtensionAdapter< +pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundTransactionExtensionAdapter< RefundBridgedParachainMessages< Runtime, RefundableParachain< 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 0d4c1defa37b57ea058457545139cdb3a0fdd7f7..16e3b2e8600f6df3721926b3ab597023d443bccc 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 @@ -73,8 +73,6 @@ use testnet_parachains_constants::rococo::{ consensus::*, currency::*, fee::WeightToFee, snowbridge::INBOUND_QUEUE_PALLET_INDEX, time::*, }; -#[cfg(feature = "runtime-benchmarks")] -use bp_runtime::Chain; use bp_runtime::HeaderId; use bridge_hub_common::{ message_queue::{NarrowOriginToSibling, ParaIdToSibling}, @@ -104,8 +102,6 @@ use polkadot_runtime_common::prod_or_fast; #[cfg(feature = "runtime-benchmarks")] use benchmark_helpers::DoNothingRouter; -#[cfg(not(feature = "runtime-benchmarks"))] -use bridge_hub_common::BridgeHubMessageRouter; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -119,8 +115,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, @@ -138,7 +134,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 = ( @@ -172,12 +168,12 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions { let mut writes = 0; if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) { - PolkadotXcm::current_storage_version().put::(); + PolkadotXcm::in_code_storage_version().put::(); writes.saturating_inc(); } if Balances::on_chain_storage_version() == StorageVersion::new(0) { - Balances::current_storage_version().put::(); + Balances::in_code_storage_version().put::(); writes.saturating_inc(); } @@ -206,7 +202,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_006_001, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 4, @@ -266,6 +262,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). @@ -328,6 +326,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! { @@ -369,11 +368,15 @@ parameter_types! { impl pallet_message_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_message_queue::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] + // Use the NoopMessageProcessor exclusively for benchmarks, not for tests with the + // runtime-benchmarks feature as tests require the BridgeHubMessageRouter to process messages. + // The "test" feature flag doesn't work, hence the reliance on the "std" feature, which is + // enabled during tests. + #[cfg(all(not(feature = "std"), feature = "runtime-benchmarks"))] type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = BridgeHubMessageRouter< + #[cfg(not(all(not(feature = "std"), feature = "runtime-benchmarks")))] + type MessageProcessor = bridge_hub_common::BridgeHubMessageRouter< xcm_builder::ProcessXcmMessage< AggregateMessageOrigin, xcm_executor::XcmExecutor, @@ -732,7 +735,7 @@ construct_runtime!( // Message Queue. Importantly, is registered last so that messages are processed after // the `on_initialize` hooks of bridging pallets. - MessageQueue: pallet_message_queue = 250, + MessageQueue: pallet_message_queue = 175, } ); @@ -759,12 +762,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] @@ -816,7 +821,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -1065,6 +1070,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; @@ -1095,6 +1101,7 @@ impl_runtime_apis! { 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: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1111,6 +1118,12 @@ impl_runtime_apis! { use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -1119,7 +1132,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between BH and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -1142,6 +1155,13 @@ impl_runtime_apis! { dest ) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } use xcm::latest::prelude::*; @@ -1298,7 +1318,7 @@ impl_runtime_apis! { impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { let bench_lane_id = >::bench_lane_id(); - let bridged_chain_id = bp_bridge_hub_westend::BridgeHubWestend::ID; + let bridged_chain_id = bridge_to_westend_config::BridgeHubWestendChainId::get(); pallet_bridge_relayers::Pallet::::relayer_reward( relayer, bp_relayers::RewardsAccountParams::new( @@ -1465,16 +1485,16 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{SignedExtension, Zero}, + traits::{TransactionExtensionBase, Zero}, }; #[test] fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + 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(), @@ -1488,11 +1508,11 @@ mod tests { bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ) - ); + ).into(); // 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, @@ -1503,8 +1523,8 @@ mod tests { ); assert_eq!(payload.encode(), bhr_indirect_payload.encode()); assert_eq!( - payload.additional_signed().unwrap().encode(), - bhr_indirect_payload.additional_signed().unwrap().encode() + payload.implicit().unwrap().encode(), + bhr_indirect_payload.implicit().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 0000000000000000000000000000000000000000..99e3d6aeba02349af3f4413a2e35d5a81a2a5073 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 aac39a4564fb600d9c4f623aa3ba27c78fc8f5fc..d97a30db9541bb01919f0a7a054f42d95816e875 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 @@ -25,6 +25,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; @@ -36,6 +37,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 0000000000000000000000000000000000000000..71d17e7259f72c023be3d75f37300c1a45c41d6f --- /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/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index 5faded42aa82df52f403b68de2a470ad4a5a17b7..a732e1a573439c4b658191697024ac3c396c9de5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-05, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-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("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_683_000 picoseconds. - Weight::from_parts(24_199_000, 0) + // Minimum execution time: 18_513_000 picoseconds. + Weight::from_parts(19_156_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 89_524_000 picoseconds. - Weight::from_parts(91_401_000, 0) + // Minimum execution time: 88_096_000 picoseconds. + Weight::from_parts(89_732_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -126,8 +126,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 91_890_000 picoseconds. - Weight::from_parts(93_460_000, 0) + // Minimum execution time: 88_239_000 picoseconds. + Weight::from_parts(89_729_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -148,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_152_000 picoseconds. - Weight::from_parts(7_355_000, 0) + // Minimum execution time: 5_955_000 picoseconds. + Weight::from_parts(6_266_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_081_000 picoseconds. - Weight::from_parts(2_258_000, 0) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(1_961_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 28_067_000 picoseconds. - Weight::from_parts(28_693_000, 0) + // Minimum execution time: 24_388_000 picoseconds. + Weight::from_parts(25_072_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +212,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 30_420_000 picoseconds. - Weight::from_parts(31_373_000, 0) + // Minimum execution time: 26_762_000 picoseconds. + Weight::from_parts(27_631_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,45 +224,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_087_000 picoseconds. - Weight::from_parts(2_243_000, 0) + // Minimum execution time: 1_856_000 picoseconds. + Weight::from_parts(2_033_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:4 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `10985` - // Minimum execution time: 15_142_000 picoseconds. - Weight::from_parts(15_598_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `89` + // Estimated: `13454` + // Minimum execution time: 17_718_000 picoseconds. + Weight::from_parts(18_208_000, 0) + .saturating_add(Weight::from_parts(0, 13454)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `10989` - // Minimum execution time: 15_041_000 picoseconds. - Weight::from_parts(15_493_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `93` + // Estimated: `13458` + // Minimum execution time: 17_597_000 picoseconds. + Weight::from_parts(18_090_000, 0) + .saturating_add(Weight::from_parts(0, 13458)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 16_624_000 picoseconds. - Weight::from_parts(17_031_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15946` + // Minimum execution time: 19_533_000 picoseconds. + Weight::from_parts(20_164_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -282,36 +282,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 26_398_000 picoseconds. - Weight::from_parts(26_847_000, 0) + // Minimum execution time: 24_958_000 picoseconds. + Weight::from_parts(25_628_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_741_000 picoseconds. - Weight::from_parts(8_954_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11026` + // Minimum execution time: 12_209_000 picoseconds. + Weight::from_parts(12_612_000, 0) + .saturating_add(Weight::from_parts(0, 11026)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10996` - // Minimum execution time: 15_306_000 picoseconds. - Weight::from_parts(15_760_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `100` + // Estimated: `13465` + // Minimum execution time: 17_844_000 picoseconds. + Weight::from_parts(18_266_000, 0) + .saturating_add(Weight::from_parts(0, 13465)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -327,12 +327,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `11002` - // Minimum execution time: 33_127_000 picoseconds. - Weight::from_parts(33_938_000, 0) - .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `106` + // Estimated: `13471` + // Minimum execution time: 34_131_000 picoseconds. + Weight::from_parts(34_766_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -343,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 4_290_000 picoseconds. - Weight::from_parts(4_450_000, 0) + // Minimum execution time: 3_525_000 picoseconds. + Weight::from_parts(3_724_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,10 +355,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 26_408_000 picoseconds. - Weight::from_parts(26_900_000, 0) + // Minimum execution time: 24_975_000 picoseconds. + Weight::from_parts(25_517_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 33_761_000 picoseconds. + Weight::from_parts(34_674_000, 0) + .saturating_add(Weight::from_parts(0, 3555)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } 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 b7d170707cfd42c66870fe249a10bcb3ecbb73d3..55c78477b5684987fe07eaaa87d45d8900e74661 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 @@ -54,16 +54,14 @@ use sp_runtime::traits::AccountIdConversion; use sp_std::marker::PhantomData; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; use xcm::latest::prelude::*; -#[allow(deprecated)] use xcm_builder::{ deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, - FrameTransactionalProcessor, HandleFee, IsConcrete, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeToAccount, + DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, + FungibleAdapter, HandleFee, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeToAccount, }; use xcm_executor::{ traits::{FeeManager, FeeReason, FeeReason::Export, TransactAsset, WithOriginFilter}, @@ -96,8 +94,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -285,7 +282,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; + type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native // token where allowed (e.g. with the Relay Chain). 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 e14755c89d4d8ba2b103cf43d60ef4d96f2166a1..46c5df18a1586e77d0bc0f9eb5f9ed19fa689f59 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 @@ -20,9 +20,9 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, - xcm_config::XcmConfig, BridgeRejectObsoleteHeadersAndMessages, Executive, - MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, - UncheckedExtrinsic, + xcm_config::XcmConfig, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, + Executive, MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, + TxExtension, UncheckedExtrinsic, }; use codec::{Decode, Encode}; use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; @@ -51,6 +51,7 @@ fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys( + 11155111, collator_session_keys(), 1013, 1000, @@ -69,6 +70,7 @@ pub fn transfer_token_to_ethereum_works() { #[test] pub fn unpaid_transfer_token_to_ethereum_fails_with_barrier() { snowbridge_runtime_test_common::send_unpaid_transfer_token_message::( + 11155111, collator_session_keys(), 1013, 1000, @@ -80,6 +82,7 @@ pub fn unpaid_transfer_token_to_ethereum_fails_with_barrier() { #[test] pub fn transfer_token_to_ethereum_fee_not_enough() { snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 11155111, collator_session_keys(), 1013, 1000, @@ -95,6 +98,7 @@ pub fn transfer_token_to_ethereum_fee_not_enough() { #[test] pub fn transfer_token_to_ethereum_insufficient_fund() { snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 11155111, collator_session_keys(), 1013, 1000, @@ -102,7 +106,7 @@ pub fn transfer_token_to_ethereum_insufficient_fund() { H160::random(), H160::random(), DefaultBridgeHubEthereumBaseFee::get(), - FailedToTransactAsset("InsufficientBalance"), + FailedToTransactAsset("Funds are unavailable"), ) } @@ -135,12 +139,39 @@ fn ethereum_to_polkadot_message_extrinsics_work() { ); } +/// Tests that the digest items are as expected when a Ethereum Outbound message is received. +/// If the MessageQueue pallet is configured before (i.e. the MessageQueue pallet is listed before +/// the EthereumOutboundQueue in the construct_runtime macro) the EthereumOutboundQueue, this test +/// will fail. +#[test] +pub fn ethereum_outbound_queue_processes_messages_before_message_queue_works() { + snowbridge_runtime_test_common::ethereum_outbound_queue_processes_messages_before_message_queue_works::< + Runtime, + XcmConfig, + AllPalletsWithoutSystem, + >( + 11155111, + collator_session_keys(), + 1013, + 1000, + H160::random(), + H160::random(), + DefaultBridgeHubEthereumBaseFee::get(), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event), + _ => None, + } + }), + ) +} + fn construct_extrinsic( sender: sp_keyring::AccountKeyring, 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(), @@ -157,13 +188,13 @@ fn construct_extrinsic( OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), ); - 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.clone()), - extra, + tx_ext, ) } 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 f11954cf165fdae2ee36377456b2bc4b2d6755a6..565343c55a5b66d4e2510cda01ba521ba6eee850 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 @@ -22,7 +22,7 @@ use bridge_hub_rococo_runtime::{ xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, EthereumGatewayAddress, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, SessionKeys, SignedExtra, TransactionPayment, UncheckedExtrinsic, + RuntimeEvent, RuntimeOrigin, SessionKeys, TransactionPayment, TxExtension, UncheckedExtrinsic, }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode}; @@ -48,7 +48,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,14 +64,15 @@ fn construct_extrinsic( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), - ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + ) + .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.clone()), - extra, + tx_ext, ) } 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 4cbfde91d00b8911a833afca2457940fbe998e6f..b5fe093b8be79c21e3298548e07b8327004d2a26 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -15,9 +15,9 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -204,6 +204,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_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index bce722aa5f87d006af0ec71429d6c84eeab4972d..934dce5c2c481092fed1a73162e3f7b1f0967a11 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 @@ -36,7 +36,7 @@ use bridge_runtime_common::{ XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + ActualFeeRefund, RefundBridgedParachainMessages, RefundTransactionExtensionAdapter, RefundableMessagesLane, RefundableParachain, }, }; @@ -190,7 +190,7 @@ impl ThisChainWithMessages for BridgeHubWestend { } /// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< +pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundTransactionExtensionAdapter< RefundBridgedParachainMessages< Runtime, RefundableParachain, 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 6188b0acd7d1a4a5c434891f9be1be20515fceee..86ed8b2f488c1c7d9ac389582754d05019a3e45c 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 @@ -69,8 +69,6 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; use xcm_config::{XcmOriginToTransactDispatchOrigin, XcmRouter}; -#[cfg(feature = "runtime-benchmarks")] -use bp_runtime::Chain; use bp_runtime::HeaderId; #[cfg(any(feature = "std", test))] @@ -99,8 +97,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, @@ -115,7 +113,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 = ( @@ -144,12 +142,12 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions { let mut writes = 0; if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) { - PolkadotXcm::current_storage_version().put::(); + PolkadotXcm::in_code_storage_version().put::(); writes.saturating_inc(); } if Balances::on_chain_storage_version() == StorageVersion::new(0) { - Balances::current_storage_version().put::(); + Balances::in_code_storage_version().put::(); writes.saturating_inc(); } @@ -178,7 +176,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-westend"), impl_name: create_runtime_str!("bridge-hub-westend"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 4, @@ -300,6 +298,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! { @@ -517,13 +516,16 @@ 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] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] @@ -567,7 +569,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -762,6 +764,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; @@ -791,6 +794,7 @@ impl_runtime_apis! { 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: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -807,6 +811,12 @@ impl_runtime_apis! { use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -815,7 +825,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between BH and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -838,6 +848,13 @@ impl_runtime_apis! { dest ) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } use xcm::latest::prelude::*; @@ -991,7 +1008,7 @@ impl_runtime_apis! { impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { let bench_lane_id = >::bench_lane_id(); - let bridged_chain_id = bp_bridge_hub_rococo::BridgeHubRococo::ID; + let bridged_chain_id = bridge_to_rococo_config::BridgeHubRococoChainId::get(); pallet_bridge_relayers::Pallet::::relayer_reward( relayer, bp_relayers::RewardsAccountParams::new( @@ -1123,16 +1140,16 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{SignedExtension, Zero}, + traits::{TransactionExtensionBase, Zero}, }; #[test] fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + 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(), @@ -1145,10 +1162,10 @@ mod tests { ( bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), ), - ); + ).into(); { - 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, @@ -1159,8 +1176,8 @@ mod tests { ); assert_eq!(payload.encode(), bh_indirect_payload.encode()); assert_eq!( - payload.additional_signed().unwrap().encode(), - bh_indirect_payload.additional_signed().unwrap().encode() + payload.implicit().unwrap().encode(), + bh_indirect_payload.implicit().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 0000000000000000000000000000000000000000..06f1114b4dea90cc9d830ff1f492428f3672b202 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 a65ee31d3e55ff8135fdd7dec35120e0a463409b..e23033e0dfd313c60fe53f64a49ad2237477ecb5 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 @@ -25,6 +25,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; @@ -35,6 +36,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 0000000000000000000000000000000000000000..92c53b918792257ddf932148fa10a4ba8016653f --- /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/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index 83e4260e77198355d23ea0c38481d7b8e68267c7..a78ff2355efaf06562e44828a8df0730481d4098 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-05, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-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("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_219_000 picoseconds. - Weight::from_parts(23_818_000, 0) + // Minimum execution time: 19_527_000 picoseconds. + Weight::from_parts(19_839_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -88,10 +88,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `70` + // Measured: `107` // Estimated: `3593` - // Minimum execution time: 90_120_000 picoseconds. - Weight::from_parts(92_545_000, 0) + // Minimum execution time: 90_938_000 picoseconds. + Weight::from_parts(92_822_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -124,10 +124,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `70` + // Measured: `107` // Estimated: `3593` - // Minimum execution time: 91_339_000 picoseconds. - Weight::from_parts(93_204_000, 0) + // Minimum execution time: 90_133_000 picoseconds. + Weight::from_parts(92_308_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -148,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_976_000 picoseconds. - Weight::from_parts(7_284_000, 0) + // Minimum execution time: 6_205_000 picoseconds. + Weight::from_parts(6_595_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_044_000 picoseconds. - Weight::from_parts(2_223_000, 0) + // Minimum execution time: 1_927_000 picoseconds. + Weight::from_parts(2_062_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 27_778_000 picoseconds. - Weight::from_parts(28_318_000, 0) + // Minimum execution time: 25_078_000 picoseconds. + Weight::from_parts(25_782_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +212,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 30_446_000 picoseconds. - Weight::from_parts(31_925_000, 0) + // Minimum execution time: 28_188_000 picoseconds. + Weight::from_parts(28_826_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,45 +224,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_037_000 picoseconds. - Weight::from_parts(2_211_000, 0) + // Minimum execution time: 1_886_000 picoseconds. + Weight::from_parts(1_991_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:4 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `10985` - // Minimum execution time: 15_620_000 picoseconds. - Weight::from_parts(15_984_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `89` + // Estimated: `13454` + // Minimum execution time: 17_443_000 picoseconds. + Weight::from_parts(17_964_000, 0) + .saturating_add(Weight::from_parts(0, 13454)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `10989` - // Minimum execution time: 15_689_000 picoseconds. - Weight::from_parts(16_093_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `93` + // Estimated: `13458` + // Minimum execution time: 17_357_000 picoseconds. + Weight::from_parts(18_006_000, 0) + .saturating_add(Weight::from_parts(0, 13458)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 16_946_000 picoseconds. - Weight::from_parts(17_192_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15946` + // Minimum execution time: 18_838_000 picoseconds. + Weight::from_parts(19_688_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -282,36 +282,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 27_164_000 picoseconds. - Weight::from_parts(27_760_000, 0) + // Minimum execution time: 25_517_000 picoseconds. + Weight::from_parts(26_131_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_689_000 picoseconds. - Weight::from_parts(8_874_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11026` + // Minimum execution time: 11_587_000 picoseconds. + Weight::from_parts(11_963_000, 0) + .saturating_add(Weight::from_parts(0, 11026)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10996` - // Minimum execution time: 15_944_000 picoseconds. - Weight::from_parts(16_381_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `100` + // Estimated: `13465` + // Minimum execution time: 17_490_000 picoseconds. + Weight::from_parts(18_160_000, 0) + .saturating_add(Weight::from_parts(0, 13465)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -327,12 +327,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `11002` - // Minimum execution time: 33_826_000 picoseconds. - Weight::from_parts(34_784_000, 0) - .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `106` + // Estimated: `13471` + // Minimum execution time: 34_088_000 picoseconds. + Weight::from_parts(34_598_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -343,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 4_257_000 picoseconds. - Weight::from_parts(4_383_000, 0) + // Minimum execution time: 3_566_000 picoseconds. + Weight::from_parts(3_754_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,10 +355,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 26_924_000 picoseconds. - Weight::from_parts(27_455_000, 0) + // Minimum execution time: 25_078_000 picoseconds. + Weight::from_parts(25_477_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 34_661_000 picoseconds. + Weight::from_parts(35_411_000, 0) + .saturating_add(Weight::from_parts(0, 3555)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } 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 d2f0f187a20dd60bcba1eedb626f870ab61302ff..e18df6feda82754d83db711bb2c6ea813c387fca 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 @@ -38,16 +38,15 @@ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -76,8 +75,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -233,7 +231,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; + type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native // token where allowed (e.g. with the Relay Chain). 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 149a3bbeb75d82ba7c35641428c7677d18297f8c..7ea22befe95f88233dca4bf95d77e3a13ac8afa5 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 @@ -24,7 +24,7 @@ use bridge_hub_westend_runtime::{ xcm_config::{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, BridgeHubRococoChainId, BridgeHubRococoLocation, @@ -65,7 +65,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(), @@ -78,14 +78,15 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), - ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + ) + .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.clone()), - extra, + tx_ext, ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index f2cf60354adc69e33f6cc19e86d2173f3e30c511..5f2a6e050d83c3db662f8ff4896d32dc8a28fde3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } impl-trait-for-tuples = "0.2" -log = { version = "0.4.20", default-features = false } +log = { workspace = true } # Substrate frame-support = { path = "../../../../../substrate/frame/support", default-features = false } @@ -25,6 +25,7 @@ sp-std = { path = "../../../../../substrate/primitives/std", default-features = sp-tracing = { path = "../../../../../substrate/primitives/tracing" } pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } +pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } # Cumulus asset-test-utils = { path = "../../assets/test-utils" } @@ -73,6 +74,7 @@ std = [ "pallet-bridge-messages/std", "pallet-bridge-parachains/std", "pallet-bridge-relayers/std", + "pallet-timestamp/std", "pallet-utility/std", "parachains-common/std", "parachains-runtimes-test-utils/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs index 4f634c184aa84faa6466102ef5fee30f254bad43..2b48f2e3d515f625532d9c5f50fabadb9a89517a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -197,7 +197,9 @@ where pub(crate) fn initialize_bridge_grandpa_pallet( init_data: bp_header_chain::InitializationData>, ) where - Runtime: BridgeGrandpaConfig, + Runtime: BridgeGrandpaConfig + + cumulus_pallet_parachain_system::Config + + pallet_timestamp::Config, { pallet_bridge_grandpa::Pallet::::initialize( RuntimeHelper::::root_origin(), diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index c16cee4fedd82dad622d2c6ec4eaafe7d2434bb4..32d7e97bc45503793672889e67177c249a3e6e7b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate @@ -117,6 +117,7 @@ runtime-benchmarks = [ "pallet-salary/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs index caf0cddec664a55ce080ed6052a9cdf42a5e2f28..e5b176fc77873805fb0e4ed6dba74d720ea3479a 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/impls.rs @@ -81,7 +81,7 @@ where } fn proposal_of(proposal_hash: HashOf) -> Option> { - pallet_collective::Pallet::::proposal_of(proposal_hash) + pallet_collective::ProposalOf::::get(proposal_hash) } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index d245576494f8271b56f277896817081c610f502e..3887a1d74ecce047f02154721414bf554e3274e7 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -117,7 +117,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives-westend"), impl_name: create_runtime_str!("collectives-westend"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, @@ -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 = ConstU16<0>; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -231,6 +232,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! { @@ -707,8 +709,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, @@ -719,7 +721,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 = ( @@ -745,6 +747,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] @@ -752,6 +755,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] @@ -803,7 +807,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -955,6 +959,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; @@ -972,6 +977,7 @@ impl_runtime_apis! { 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: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -986,8 +992,21 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + parameter_types! { + pub ExistentialDepositAsset: Option = Some(( + xcm_config::WndLocation::get(), + ExistentialDeposit::get() + ).into()); + } + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -996,7 +1015,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between Collectives and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }.into(), Parent.into(), @@ -1019,6 +1038,13 @@ impl_runtime_apis! { dest ) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } let whitelist: Vec = vec![ 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 0000000000000000000000000000000000000000..f3030cc4f6aa5acbeec612ae17eb0cf2b4663383 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 a9a298e547edb49738b9a0612d04d4141301d4ba..00b3bd92d5ef9ce0081ca9e95e43bd35098c6aa0 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_scheduler.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_scheduler.rs index cf5610df66574a38a388b7e36a56f87e41ff59c2..42e37b967e4c88acccd13c8cb71bd22b1bc2d3dd 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_scheduler.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_scheduler.rs @@ -1,42 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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_scheduler` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_scheduler -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_scheduler +// --chain=collectives-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,8 +54,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_441_000 picoseconds. - Weight::from_parts(3_604_000, 0) + // Minimum execution time: 2_475_000 picoseconds. + Weight::from_parts(2_644_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -68,11 +67,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `77 + s * (177 ±0)` // Estimated: `159279` - // Minimum execution time: 2_879_000 picoseconds. - Weight::from_parts(2_963_000, 0) + // Minimum execution time: 2_898_000 picoseconds. + Weight::from_parts(1_532_342, 0) .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 3_764 - .saturating_add(Weight::from_parts(909_557, 0).saturating_mul(s.into())) + // Standard Error: 4_736 + .saturating_add(Weight::from_parts(412_374, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -80,25 +79,27 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_172_000 picoseconds. - Weight::from_parts(5_294_000, 0) + // Minimum execution time: 3_171_000 picoseconds. + Weight::from_parts(3_349_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// 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 `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `213 + s * (1 ±0)` - // Estimated: `3678 + s * (1 ±0)` - // Minimum execution time: 19_704_000 picoseconds. - Weight::from_parts(19_903_000, 0) - .saturating_add(Weight::from_parts(0, 3678)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_394, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `246 + s * (1 ±0)` + // Estimated: `3711 + s * (1 ±0)` + // Minimum execution time: 17_329_000 picoseconds. + Weight::from_parts(17_604_000, 0) + .saturating_add(Weight::from_parts(0, 3711)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_256, 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())) } @@ -108,8 +109,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_359_000 picoseconds. - Weight::from_parts(6_599_000, 0) + // Minimum execution time: 4_503_000 picoseconds. + Weight::from_parts(4_677_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -117,24 +118,24 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_217_000 picoseconds. - Weight::from_parts(5_333_000, 0) + // Minimum execution time: 3_145_000 picoseconds. + Weight::from_parts(3_252_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: 2_406_000 picoseconds. - Weight::from_parts(2_541_000, 0) + // Minimum execution time: 1_804_000 picoseconds. + Weight::from_parts(1_891_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: 2_370_000 picoseconds. - Weight::from_parts(2_561_000, 0) + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(1_776_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) @@ -144,11 +145,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `77 + s * (177 ±0)` // Estimated: `159279` - // Minimum execution time: 11_784_000 picoseconds. - Weight::from_parts(5_574_404, 0) + // Minimum execution time: 8_629_000 picoseconds. + Weight::from_parts(6_707_232, 0) .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 7_217 - .saturating_add(Weight::from_parts(1_035_248, 0).saturating_mul(s.into())) + // Standard Error: 5_580 + .saturating_add(Weight::from_parts(471_827, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -161,11 +162,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `77 + s * (177 ±0)` // Estimated: `159279` - // Minimum execution time: 16_373_000 picoseconds. - Weight::from_parts(3_088_135, 0) + // Minimum execution time: 12_675_000 picoseconds. + Weight::from_parts(7_791_682, 0) .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 7_095 - .saturating_add(Weight::from_parts(1_745_270, 0).saturating_mul(s.into())) + // Standard Error: 5_381 + .saturating_add(Weight::from_parts(653_023, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -178,11 +179,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `468 + s * (179 ±0)` // Estimated: `159279` - // Minimum execution time: 14_822_000 picoseconds. - Weight::from_parts(9_591_402, 0) + // Minimum execution time: 11_908_000 picoseconds. + Weight::from_parts(11_833_059, 0) .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 7_151 - .saturating_add(Weight::from_parts(1_058_408, 0).saturating_mul(s.into())) + // Standard Error: 5_662 + .saturating_add(Weight::from_parts(482_816, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -195,12 +196,91 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `509 + s * (179 ±0)` // Estimated: `159279` - // Minimum execution time: 18_541_000 picoseconds. - Weight::from_parts(6_522_239, 0) + // Minimum execution time: 15_506_000 picoseconds. + Weight::from_parts(11_372_975, 0) .saturating_add(Weight::from_parts(0, 159279)) - // Standard Error: 8_349 - .saturating_add(Weight::from_parts(1_760_431, 0).saturating_mul(s.into())) + // Standard Error: 5_765 + .saturating_add(Weight::from_parts(656_322, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + /// 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(155814), added: 158289, 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, 200]`. + fn schedule_retry(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `159` + // Estimated: `159279` + // Minimum execution time: 14_069_000 picoseconds. + Weight::from_parts(14_868_345, 0) + .saturating_add(Weight::from_parts(0, 159279)) + // Standard Error: 425 + .saturating_add(Weight::from_parts(33_468, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + s * (177 ±0)` + // Estimated: `159279` + // Minimum execution time: 7_550_000 picoseconds. + Weight::from_parts(6_735_955, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `513 + s * (179 ±0)` + // Estimated: `159279` + // Minimum execution time: 11_017_000 picoseconds. + Weight::from_parts(11_749_385, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, 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_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + s * (177 ±0)` + // Estimated: `159279` + // Minimum execution time: 7_550_000 picoseconds. + Weight::from_parts(6_735_955, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, 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_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `513 + s * (179 ±0)` + // Estimated: `159279` + // Minimum execution time: 11_017_000 picoseconds. + Weight::from_parts(11_749_385, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } } 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 0000000000000000000000000000000000000000..5d077b89d56421a05cd64bec99ecdad445049528 --- /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/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index 50dfbffde01f21d1138f0fdaa27649f962e245e4..5d427d850046ff030c6c5b6247426849227e7ea1 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-05, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-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("collectives-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 24_540_000 picoseconds. - Weight::from_parts(25_439_000, 0) + // Minimum execution time: 21_813_000 picoseconds. + Weight::from_parts(22_332_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 86_614_000 picoseconds. - Weight::from_parts(88_884_000, 0) + // Minimum execution time: 93_243_000 picoseconds. + Weight::from_parts(95_650_000, 0) .saturating_add(Weight::from_parts(0, 3679)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -126,8 +126,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 87_915_000 picoseconds. - Weight::from_parts(90_219_000, 0) + // Minimum execution time: 96_199_000 picoseconds. + Weight::from_parts(98_620_000, 0) .saturating_add(Weight::from_parts(0, 3679)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -148,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_872_000 picoseconds. - Weight::from_parts(7_110_000, 0) + // Minimum execution time: 6_442_000 picoseconds. + Weight::from_parts(6_682_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_009_000 picoseconds. - Weight::from_parts(2_163_000, 0) + // Minimum execution time: 1_833_000 picoseconds. + Weight::from_parts(1_973_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 28_858_000 picoseconds. - Weight::from_parts(29_355_000, 0) + // Minimum execution time: 27_318_000 picoseconds. + Weight::from_parts(28_224_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +212,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 30_598_000 picoseconds. - Weight::from_parts(31_168_000, 0) + // Minimum execution time: 29_070_000 picoseconds. + Weight::from_parts(30_205_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,45 +224,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_090_000 picoseconds. - Weight::from_parts(2_253_000, 0) + // Minimum execution time: 1_904_000 picoseconds. + Weight::from_parts(2_033_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:4 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `162` - // Estimated: `11052` - // Minimum execution time: 16_133_000 picoseconds. - Weight::from_parts(16_433_000, 0) - .saturating_add(Weight::from_parts(0, 11052)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `159` + // Estimated: `13524` + // Minimum execution time: 18_348_000 picoseconds. + Weight::from_parts(18_853_000, 0) + .saturating_add(Weight::from_parts(0, 13524)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `166` - // Estimated: `11056` - // Minimum execution time: 16_012_000 picoseconds. - Weight::from_parts(16_449_000, 0) - .saturating_add(Weight::from_parts(0, 11056)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `163` + // Estimated: `13528` + // Minimum execution time: 17_964_000 picoseconds. + Weight::from_parts(18_548_000, 0) + .saturating_add(Weight::from_parts(0, 13528)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `13538` - // Minimum execution time: 17_922_000 picoseconds. - Weight::from_parts(18_426_000, 0) - .saturating_add(Weight::from_parts(0, 13538)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16013` + // Minimum execution time: 19_708_000 picoseconds. + Weight::from_parts(20_157_000, 0) + .saturating_add(Weight::from_parts(0, 16013)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -282,36 +282,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 27_280_000 picoseconds. - Weight::from_parts(28_026_000, 0) + // Minimum execution time: 26_632_000 picoseconds. + Weight::from_parts(27_314_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `206` - // Estimated: `8621` - // Minimum execution time: 9_387_000 picoseconds. - Weight::from_parts(9_644_000, 0) - .saturating_add(Weight::from_parts(0, 8621)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11096` + // Minimum execution time: 11_929_000 picoseconds. + Weight::from_parts(12_304_000, 0) + .saturating_add(Weight::from_parts(0, 11096)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `173` - // Estimated: `11063` - // Minimum execution time: 16_649_000 picoseconds. - Weight::from_parts(17_025_000, 0) - .saturating_add(Weight::from_parts(0, 11063)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `170` + // Estimated: `13535` + // Minimum execution time: 18_599_000 picoseconds. + Weight::from_parts(19_195_000, 0) + .saturating_add(Weight::from_parts(0, 13535)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -327,12 +327,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `11105` - // Minimum execution time: 34_355_000 picoseconds. - Weight::from_parts(35_295_000, 0) - .saturating_add(Weight::from_parts(0, 11105)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `212` + // Estimated: `13577` + // Minimum execution time: 35_524_000 picoseconds. + Weight::from_parts(36_272_000, 0) + .saturating_add(Weight::from_parts(0, 13577)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -343,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_527_000 picoseconds. - Weight::from_parts(4_699_000, 0) + // Minimum execution time: 4_044_000 picoseconds. + Weight::from_parts(4_238_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,10 +355,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 27_011_000 picoseconds. - Weight::from_parts(27_398_000, 0) + // Minimum execution time: 25_741_000 picoseconds. + Weight::from_parts(26_301_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `160` + // Estimated: `3625` + // Minimum execution time: 35_925_000 picoseconds. + Weight::from_parts(36_978_000, 0) + .saturating_add(Weight::from_parts(0, 3625)) + .saturating_add(T::DbWeight::get().reads(1)) + .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 ad19521898dd317b3d2df789a7553d062a1acffc..87f637d5b59a4c56880fed680eace7f5d108a46e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -36,13 +36,11 @@ 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::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, - LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, + DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, + IsConcrete, LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, @@ -61,7 +59,7 @@ parameter_types! { pub const GovernanceLocation: Location = Location::parent(); pub const FellowshipAdminBodyId: BodyId = BodyId::Index(xcm_constants::body::FELLOWSHIP_ADMIN_INDEX); pub AssetHub: Location = (Parent, Parachain(1000)).into(); - pub const TreasurerBodyId: BodyId = BodyId::Index(xcm_constants::body::TREASURER_INDEX); + pub const TreasurerBodyId: BodyId = BodyId::Treasury; pub AssetHubUsdtId: AssetId = (PalletInstance(50), GeneralIndex(1984)).into(); pub UsdtAssetHub: LocatableAssetId = LocatableAssetId { location: AssetHub::get(), @@ -85,9 +83,8 @@ pub type LocationToAccountId = ( AccountId32Aliases, ); -/// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +/// Means for transacting the native currency on this chain.#[allow(deprecated)] +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -262,7 +259,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; + type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Collectives does not recognize a reserve location for any asset. Users must teleport WND // where allowed (e.g. with the Relay Chain). diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 9f719421b9d52f8607eb425062ac554b5725b8da..747f75cf2e26326afcce5f2ab471777358a05a8a 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -18,7 +18,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } # Substrate @@ -158,6 +158,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 7b89f2df807734086031797915bde30b2eff77e2..171ac6a9528f134d9c22548500805ef36e9504f9 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -21,6 +21,7 @@ use frame_support::{ parameter_types, traits::{ConstBool, ConstU32, Nothing}, }; +use frame_system::EnsureSigned; use pallet_contracts::{ weights::SubstrateWeight, Config, DebugInfo, DefaultAddressGenerator, Frame, Schedule, }; @@ -65,6 +66,8 @@ impl Config for Runtime { type MaxCodeLen = ConstU32<{ 123 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; type UnsafeUnstableInterface = ConstBool; + type UploadOrigin = EnsureSigned; + type InstantiateOrigin = EnsureSigned; type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; type MaxDelegateDependencies = ConstU32<32>; type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; @@ -72,5 +75,6 @@ impl Config for Runtime { type RuntimeHoldReason = RuntimeHoldReason; type Debug = (); type Environment = (); + type ApiVersion = (); type Xcm = pallet_xcm::Pallet; } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 7d0dd43ea8892812e7261098808dc923c9cd86a0..8ce46ccd34f108cbc1961a0f1c6e0e0482f0db23 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -50,7 +50,7 @@ use frame_support::{ dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, - traits::{ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8}, + traits::{ConstBool, ConstU16, ConstU32, ConstU64, ConstU8}, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -58,10 +58,10 @@ use frame_system::limits::{BlockLength, BlockWeights}; pub use parachains_common as common; use parachains_common::{ impls::DealWithFees, message_queue::*, AccountId, BlockNumber, Hash, Header, Nonce, Signature, - AVERAGE_ON_INITIALIZE_RATIO, MINUTES, NORMAL_DISPATCH_RATIO, + AVERAGE_ON_INITIALIZE_RATIO, NORMAL_DISPATCH_RATIO, }; pub use parachains_common::{AuraId, Balance}; -use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee}; +use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee, time::*}; use xcm_config::CollatorSelectionUpdateOrigin; #[cfg(any(feature = "std", test))] @@ -80,8 +80,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, @@ -93,7 +93,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,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -205,6 +205,10 @@ impl pallet_authorship::Config for Runtime { type EventHandler = (CollatorSelection,); } +parameter_types! { + pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; +} + impl pallet_balances::Config for Runtime { type MaxLocks = ConstU32<50>; /// The type for recording an account's balance. @@ -212,7 +216,7 @@ impl pallet_balances::Config for Runtime { /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; type DustRemoval = (); - type ExistentialDeposit = ConstU128; + type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = pallet_balances::weights::SubstrateWeight; type MaxReserves = ConstU32<50>; @@ -236,6 +240,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! { @@ -419,6 +424,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] @@ -427,6 +433,7 @@ mod benches { [pallet_sudo, Sudo] [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_parachain_system, ParachainSystem] [pallet_contracts, Contracts] [pallet_xcm, PalletXcmExtrinsicsBenchmark::] ); @@ -461,7 +468,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -681,6 +688,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; @@ -698,6 +706,7 @@ impl_runtime_apis! { 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: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -712,9 +721,22 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + parameter_types! { + pub ExistentialDepositAsset: Option = Some(( + xcm_config::RelayLocation::get(), + ExistentialDeposit::get() + ).into()); + } + use xcm::latest::prelude::*; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -723,7 +745,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between Contracts-System-Para and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -746,6 +768,13 @@ impl_runtime_apis! { dest ) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(EXISTENTIAL_DEPOSIT), + } + } } let whitelist: Vec = vec![ 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 7919faf400f46f124aaadf12191a9dd3d17896ba..e8f3209eb67f627efccc9e8a798da03b6a2280c0 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -37,16 +37,15 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use testnet_parachains_constants::rococo::currency::CENTS; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, - NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, + DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, + IsConcrete, NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -79,8 +78,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type CurrencyTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index ae604da87a98392b2a69b3732e05e1b7f38eaeb9..70a6a81bdcfb97c96894b07a880bdadf0f39161e 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -15,9 +15,9 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = "0.4.1" -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -56,7 +56,6 @@ sp-version = { path = "../../../../../substrate/primitives/version", default-fea # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false } polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false } @@ -115,7 +114,6 @@ std = [ "pallet-xcm/std", "parachain-info/std", "parachains-common/std", - "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "rococo-runtime-constants/std", @@ -158,6 +156,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-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 3e47b1bc4cba9cbe679d1a648c935baf6f20c9c7..742dd50f6fa1f421d6ce4abf221e05f6902cc2ae 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs @@ -29,10 +29,9 @@ use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, use parachains_common::{AccountId, Balance, BlockNumber}; use xcm::latest::prelude::*; -// TODO: check AccountId import pub struct CreditToCollatorPot; impl OnUnbalanced> for CreditToCollatorPot { - fn on_nonzero_unbalanced(credit: Credit) { + fn on_nonzero_unbalanced(credit: Credit) { let staking_pot = CollatorSelection::account_id(); let _ = >::resolve(&staking_pot, credit); } @@ -81,7 +80,7 @@ pub struct CoretimeAllocator; impl CoretimeInterface for CoretimeAllocator { type AccountId = AccountId; type Balance = Balance; - type RealyChainBlockNumberProvider = RelaychainDataProvider; + type RelayChainBlockNumberProvider = RelaychainDataProvider; fn request_core_count(count: CoreIndex) { use crate::coretime::CoretimeProviderCalls::RequestCoreCount; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 8b952cfba229040400950534766495da8c25a397..9913e47a93ab940df330c9ab0a6bef9c90da6f2d 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -89,8 +89,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, @@ -103,7 +103,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,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-rococo"), impl_name: create_runtime_str!("coretime-rococo"), authoring_version: 1, - spec_version: 1_006_001, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, @@ -192,6 +192,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). @@ -251,6 +253,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! { @@ -521,7 +524,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -715,6 +718,12 @@ impl_runtime_apis! { use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -723,7 +732,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between AH and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -734,6 +743,13 @@ impl_runtime_apis! { // Reserve transfers are disabled None } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } parameter_types! { 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 0000000000000000000000000000000000000000..aac73680ad1296eaec9073277b1779b3b9f4d898 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 f1050b3ae636261ff21674c3bb34c05bf6d232c5..7b6ab611e6f3bf48c69b2945120c5f5118854808 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; @@ -29,6 +30,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/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 0000000000000000000000000000000000000000..29d48abab8956c79724b9544b99f06ef9303abaa --- /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/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs index 0e34cba4aaf5d9879dfecc97ffd736b985c98f23..c5d315467c1ed8b2aabf7ac18abe10931a02951b 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-12, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-j8vvqcjr-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("coretime-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=coretime-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=coretime-rococo-dev // --header=./cumulus/file_header.txt // --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ @@ -64,8 +62,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 22_669_000 picoseconds. - Weight::from_parts(23_227_000, 0) + // Minimum execution time: 35_051_000 picoseconds. + Weight::from_parts(35_200_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +84,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 64_486_000 picoseconds. - Weight::from_parts(65_247_000, 0) + // Minimum execution time: 56_235_000 picoseconds. + Weight::from_parts(58_178_000, 0) .saturating_add(Weight::from_parts(0, 3571)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -128,8 +126,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_020_000 picoseconds. - Weight::from_parts(7_300_000, 0) + // Minimum execution time: 6_226_000 picoseconds. + Weight::from_parts(6_403_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -139,8 +137,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_022_000 picoseconds. - Weight::from_parts(2_141_000, 0) + // Minimum execution time: 2_020_000 picoseconds. + Weight::from_parts(2_100_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -164,8 +162,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 26_893_000 picoseconds. - Weight::from_parts(27_497_000, 0) + // Minimum execution time: 24_387_000 picoseconds. + Weight::from_parts(24_814_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -188,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 29_673_000 picoseconds. - Weight::from_parts(30_693_000, 0) + // Minimum execution time: 27_039_000 picoseconds. + Weight::from_parts(27_693_000, 0) .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -200,45 +198,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_990_000 picoseconds. - Weight::from_parts(2_105_000, 0) + // Minimum execution time: 1_920_000 picoseconds. + Weight::from_parts(2_082_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:4 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `10985` - // Minimum execution time: 14_819_000 picoseconds. - Weight::from_parts(15_180_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `89` + // Estimated: `13454` + // Minimum execution time: 17_141_000 picoseconds. + Weight::from_parts(17_500_000, 0) + .saturating_add(Weight::from_parts(0, 13454)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `10989` - // Minimum execution time: 14_935_000 picoseconds. - Weight::from_parts(15_335_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `93` + // Estimated: `13458` + // Minimum execution time: 17_074_000 picoseconds. + Weight::from_parts(17_431_000, 0) + .saturating_add(Weight::from_parts(0, 13458)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 16_278_000 picoseconds. - Weight::from_parts(16_553_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15946` + // Minimum execution time: 19_139_000 picoseconds. + Weight::from_parts(19_474_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -256,36 +254,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 26_360_000 picoseconds. - Weight::from_parts(26_868_000, 0) + // Minimum execution time: 24_346_000 picoseconds. + Weight::from_parts(25_318_000, 0) .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_615_000 picoseconds. - Weight::from_parts(8_903_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11026` + // Minimum execution time: 11_777_000 picoseconds. + Weight::from_parts(12_051_000, 0) + .saturating_add(Weight::from_parts(0, 11026)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10996` - // Minimum execution time: 15_284_000 picoseconds. - Weight::from_parts(15_504_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `100` + // Estimated: `13465` + // Minimum execution time: 17_538_000 picoseconds. + Weight::from_parts(17_832_000, 0) + .saturating_add(Weight::from_parts(0, 13465)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -299,12 +297,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `148` - // Estimated: `11038` - // Minimum execution time: 32_675_000 picoseconds. - Weight::from_parts(33_816_000, 0) - .saturating_add(Weight::from_parts(0, 11038)) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `142` + // Estimated: `13507` + // Minimum execution time: 33_623_000 picoseconds. + Weight::from_parts(34_186_000, 0) + .saturating_add(Weight::from_parts(0, 13507)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -315,8 +313,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 4_058_000 picoseconds. - Weight::from_parts(4_170_000, 0) + // Minimum execution time: 3_363_000 picoseconds. + Weight::from_parts(3_511_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -327,10 +325,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 25_375_000 picoseconds. - Weight::from_parts(26_026_000, 0) + // Minimum execution time: 23_969_000 picoseconds. + Weight::from_parts(24_347_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 34_071_000 picoseconds. + Weight::from_parts(35_031_000, 0) + .saturating_add(Weight::from_parts(0, 3555)) + .saturating_add(T::DbWeight::get().reads(1)) + .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 8815312f3042801306b830a7a48ad659c12100a8..9f79cea831aed66a0d073109233731751cdf99ed 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 @@ -196,7 +196,7 @@ impl XcmWeightInfo for CoretimeRococoXcmWeight { XcmGeneric::::clear_transact_status() } fn universal_origin(_: &Junction) -> Weight { - XcmGeneric::::universal_origin() + Weight::MAX } fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { Weight::MAX 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 a11d049a3fc5c6e66428063a9b6c0a3626f1f6ae..719e7543e8886a803f773126eafbc77f34749ddb 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 @@ -312,16 +312,6 @@ impl WeightInfo { // Minimum execution time: 2_082_000 picoseconds. Weight::from_parts(2_144_000, 0) } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - pub fn universal_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 4_275_000 picoseconds. - Weight::from_parts(4_381_000, 1489) - .saturating_add(T::DbWeight::get().reads(1)) - } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `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 13816f8ce711238433b62400f9e1004ab34b7f76..1722e1fcb319ce1357acb20598778c8018ddf5ae 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -38,17 +38,15 @@ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, IsConcrete, NonFungibleAdapter, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, + NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -79,8 +77,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type CurrencyTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -195,7 +192,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index f85f6896cbe8f683e7f8b81e2c918d4ed53381b7..549ef7ce4d78f54ea8fa88711a00e25966179dd0 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -15,9 +15,9 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = "0.4.1" -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -31,9 +31,9 @@ pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false } +pallet-broker = { path = "../../../../../substrate/frame/broker", default-features = false } pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false } pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } @@ -55,7 +55,6 @@ sp-version = { path = "../../../../../substrate/primitives/version", default-fea # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false } polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false } polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false } westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false } @@ -100,11 +99,11 @@ std = [ "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", + "pallet-broker/std", "pallet-collator-selection/std", "pallet-message-queue/std", "pallet-multisig/std", "pallet-session/std", - "pallet-sudo/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -113,7 +112,6 @@ std = [ "pallet-xcm/std", "parachain-info/std", "parachains-common/std", - "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", @@ -150,11 +148,12 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-broker/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/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-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -178,11 +177,11 @@ try-runtime = [ "pallet-aura/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", + "pallet-broker/try-runtime", "pallet-collator-selection/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", - "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", @@ -193,3 +192,5 @@ try-runtime = [ ] experimental = ["pallet-aura/experimental"] + +fast-runtime = [] diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs index 60f8a125129ff1344a1799246e931acdb1d139d5..28dacd20cf305ebdbc57eb2a30e3c98e4f8853d9 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/build.rs @@ -19,7 +19,15 @@ fn main() { .with_current_project() .export_heap_base() .import_memory() - .build() + .build(); + + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .set_file_name("fast_runtime_binary.rs") + .enable_feature("fast-runtime") + .import_memory() + .export_heap_base() + .build(); } #[cfg(not(feature = "std"))] diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs new file mode 100644 index 0000000000000000000000000000000000000000..41cbc62fa2115ff3828e6910b750622a91ff0251 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs @@ -0,0 +1,249 @@ +// Copyright 2022 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 crate::*; +use codec::{Decode, Encode}; +use cumulus_pallet_parachain_system::RelaychainDataProvider; +use cumulus_primitives_core::relay_chain; +use frame_support::{ + parameter_types, + traits::{ + fungible::{Balanced, Credit}, + OnUnbalanced, + }, +}; +use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf}; +use parachains_common::{AccountId, Balance, BlockNumber}; +use xcm::latest::prelude::*; + +pub struct CreditToCollatorPot; +impl OnUnbalanced> for CreditToCollatorPot { + fn on_nonzero_unbalanced(credit: Credit) { + let staking_pot = CollatorSelection::account_id(); + let _ = >::resolve(&staking_pot, credit); + } +} + +/// A type containing the encoding of the coretime pallet in the Relay chain runtime. Used to +/// construct any remote calls. The codec index must correspond to the index of `Coretime` in the +/// `construct_runtime` of the Relay chain. +#[derive(Encode, Decode)] +enum RelayRuntimePallets { + #[codec(index = 66)] + Coretime(CoretimeProviderCalls), +} + +/// Call encoding for the calls needed from the relay coretime pallet. +#[derive(Encode, Decode)] +enum CoretimeProviderCalls { + #[codec(index = 1)] + RequestCoreCount(CoreIndex), + #[codec(index = 2)] + RequestRevenueInfoAt(relay_chain::BlockNumber), + #[codec(index = 3)] + CreditAccount(AccountId, Balance), + #[codec(index = 4)] + AssignCore( + CoreIndex, + relay_chain::BlockNumber, + Vec<(CoreAssignment, PartsOf57600)>, + Option, + ), +} + +parameter_types! { + pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); +} + +parameter_types! { + pub storage CoreCount: Option = None; + pub storage CoretimeRevenue: Option<(BlockNumber, Balance)> = None; +} + +/// Type that implements the `CoretimeInterface` for the allocation of Coretime. Meant to operate +/// from the parachain context. That is, the parachain provides a market (broker) for the sale of +/// coretime, but assumes a `CoretimeProvider` (i.e. a Relay Chain) to actually provide cores. +pub struct CoretimeAllocator; +impl CoretimeInterface for CoretimeAllocator { + type AccountId = AccountId; + type Balance = Balance; + type RelayChainBlockNumberProvider = RelaychainDataProvider; + + fn request_core_count(count: CoreIndex) { + 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, + check_origin: None, + }, + Instruction::Transact { + origin_kind: OriginKind::Native, + require_weight_at_most: call_weight, + call: request_core_count_call.encode().into(), + }, + ]); + + match PolkadotXcm::send_xcm(Here, Location::parent(), message.clone()) { + Ok(_) => log::debug!( + target: "runtime::coretime", + "Request to update schedulable cores sent successfully." + ), + Err(e) => log::error!( + target: "runtime::coretime", + "Failed to send request to update schedulable cores: {:?}", + e + ), + } + } + + fn request_revenue_info_at(when: RCBlockNumberOf) { + use crate::coretime::CoretimeProviderCalls::RequestRevenueInfoAt; + let request_revenue_info_at_call = + RelayRuntimePallets::Coretime(RequestRevenueInfoAt(when)); + + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + Instruction::Transact { + origin_kind: OriginKind::Native, + require_weight_at_most: Weight::from_parts(1000000000, 200000), + call: request_revenue_info_at_call.encode().into(), + }, + ]); + + match PolkadotXcm::send_xcm(Here, Location::parent(), message.clone()) { + Ok(_) => log::debug!( + target: "runtime::coretime", + "Request for revenue information sent successfully." + ), + Err(e) => log::error!( + target: "runtime::coretime", + "Request for revenue information failed to send: {:?}", + e + ), + } + } + + fn credit_account(who: Self::AccountId, amount: Self::Balance) { + use crate::coretime::CoretimeProviderCalls::CreditAccount; + let credit_account_call = RelayRuntimePallets::Coretime(CreditAccount(who, amount)); + + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + Instruction::Transact { + origin_kind: OriginKind::Native, + require_weight_at_most: Weight::from_parts(1000000000, 200000), + call: credit_account_call.encode().into(), + }, + ]); + + match PolkadotXcm::send_xcm(Here, Location::parent(), message.clone()) { + Ok(_) => log::debug!( + target: "runtime::coretime", + "Instruction to credit account sent successfully." + ), + Err(e) => log::error!( + target: "runtime::coretime", + "Instruction to credit account failed to send: {:?}", + e + ), + } + } + + fn assign_core( + core: CoreIndex, + begin: RCBlockNumberOf, + assignment: Vec<(CoreAssignment, PartsOf57600)>, + end_hint: Option>, + ) { + use crate::coretime::CoretimeProviderCalls::AssignCore; + 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, + check_origin: None, + }, + Instruction::Transact { + origin_kind: OriginKind::Native, + require_weight_at_most: call_weight, + call: assign_core_call.encode().into(), + }, + ]); + + match PolkadotXcm::send_xcm(Here, Location::parent(), message.clone()) { + Ok(_) => log::debug!( + target: "runtime::coretime", + "Core assignment sent successfully." + ), + Err(e) => log::error!( + target: "runtime::coretime", + "Core assignment failed to send: {:?}", + e + ), + } + } + + fn check_notify_revenue_info() -> Option<(RCBlockNumberOf, Self::Balance)> { + let revenue = CoretimeRevenue::get(); + CoretimeRevenue::set(&None); + revenue + } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_notify_revenue_info(when: RCBlockNumberOf, revenue: Self::Balance) { + CoretimeRevenue::set(&Some((when, revenue))); + } +} + +impl pallet_broker::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type OnRevenue = CreditToCollatorPot; + #[cfg(feature = "fast-runtime")] + type TimeslicePeriod = ConstU32<10>; + #[cfg(not(feature = "fast-runtime"))] + type TimeslicePeriod = ConstU32<80>; + // We don't actually need any leases at launch but set to 10 in case we want to sudo some in. + type MaxLeasedCores = ConstU32<10>; + type MaxReservedCores = ConstU32<10>; + type Coretime = CoretimeAllocator; + type ConvertBalance = sp_runtime::traits::Identity; + type WeightInfo = weights::pallet_broker::WeightInfo; + type PalletId = BrokerPalletId; + type AdminOrigin = EnsureRoot; + type PriceAdapter = pallet_broker::Linear; +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index d8087c05b736f41bdd9b9ea86e5a7c2083105396..1a330821d3fcac112426bb9f8591190ec0d6428b 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -21,6 +21,15 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +/// Provides the `WASM_BINARY` build with `fast-runtime` feature enabled. +/// +/// This is for example useful for local test chains. +#[cfg(feature = "std")] +pub mod fast_runtime_binary { + include!(concat!(env!("OUT_DIR"), "/fast_runtime_binary.rs")); +} + +mod coretime; mod weights; pub mod xcm_config; @@ -65,7 +74,7 @@ use testnet_parachains_constants::westend::{consensus::*, currency::*, fee::Weig use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::latest::prelude::*; use xcm_config::{ - FellowshipLocation, GovernanceLocation, WndRelayLocation, XcmOriginToTransactDispatchOrigin, + FellowshipLocation, GovernanceLocation, TokenRelayLocation, XcmOriginToTransactDispatchOrigin, }; /// The address format for describing accounts. @@ -80,8 +89,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, @@ -94,10 +103,11 @@ 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 = ( + cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -123,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-westend"), impl_name: create_runtime_str!("coretime-westend"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, @@ -182,6 +192,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). @@ -241,6 +253,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! { @@ -270,8 +283,6 @@ type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< UNINCLUDED_SEGMENT_CAPACITY, >; -impl parachain_info::Config for Runtime {} - parameter_types! { pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; } @@ -298,6 +309,8 @@ impl pallet_message_queue::Config for Runtime { type ServiceWeight = MessageQueueServiceWeight; } +impl parachain_info::Config for Runtime {} + impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { @@ -313,7 +326,7 @@ pub type RootOrFellows = EitherOfDiverse< parameter_types! { /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = AssetId(WndRelayLocation::get()); + pub FeeAssetId: AssetId = AssetId(TokenRelayLocation::get()); /// The base fee for the message delivery fees. pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); } @@ -416,12 +429,6 @@ impl pallet_utility::Config for Runtime { type WeightInfo = weights::pallet_utility::WeightInfo; } -impl pallet_sudo::Config for Runtime { - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_sudo::weights::SubstrateWeight; -} - // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -453,8 +460,8 @@ construct_runtime!( Utility: pallet_utility = 40, Multisig: pallet_multisig = 41, - // Sudo - Sudo: pallet_sudo = 100, + // The main stage. + Broker: pallet_broker = 50, } ); @@ -465,6 +472,7 @@ mod benches { [cumulus_pallet_parachain_system, ParachainSystem] [pallet_timestamp, Timestamp] [pallet_balances, Balances] + [pallet_broker, Broker] [pallet_collator_selection, CollatorSelection] [pallet_session, SessionBench::] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -507,7 +515,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -697,10 +705,16 @@ impl_runtime_apis! { impl cumulus_pallet_session_benchmarking::Config for Runtime {} use xcm::latest::prelude::*; - use xcm_config::WndRelayLocation; + use xcm_config::TokenRelayLocation; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -709,7 +723,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between AH and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -720,11 +734,18 @@ impl_runtime_apis! { // Reserve transfers are disabled None } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } parameter_types! { pub ExistentialDepositAsset: Option = Some(( - WndRelayLocation::get(), + TokenRelayLocation::get(), ExistentialDeposit::get() ).into()); } @@ -738,13 +759,13 @@ impl_runtime_apis! { >; type AccountIdConverter = xcm_config::LocationToAccountId; fn valid_destination() -> Result { - Ok(WndRelayLocation::get()) + Ok(TokenRelayLocation::get()) } fn worst_case_holding(_depositable_count: u32) -> Assets { // just concrete assets according to relay chain. let assets: Vec = vec![ Asset { - id: AssetId(WndRelayLocation::get()), + id: AssetId(TokenRelayLocation::get()), fun: Fungible(1_000_000 * UNITS), } ]; @@ -754,8 +775,8 @@ impl_runtime_apis! { parameter_types! { pub const TrustedTeleporter: Option<(Location, Asset)> = Some(( - WndRelayLocation::get(), - Asset { fun: Fungible(UNITS), id: AssetId(WndRelayLocation::get()) }, + TokenRelayLocation::get(), + Asset { fun: Fungible(UNITS), id: AssetId(TokenRelayLocation::get()) }, )); pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None; pub const TrustedReserve: Option<(Location, Asset)> = None; @@ -770,7 +791,7 @@ impl_runtime_apis! { fn get_asset() -> Asset { Asset { - id: AssetId(WndRelayLocation::get()), + id: AssetId(TokenRelayLocation::get()), fun: Fungible(UNITS), } } @@ -793,23 +814,23 @@ impl_runtime_apis! { } fn transact_origin_and_runtime_call() -> Result<(Location, RuntimeCall), BenchmarkError> { - Ok((WndRelayLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) + Ok((TokenRelayLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) } fn subscribe_origin() -> Result { - Ok(WndRelayLocation::get()) + Ok(TokenRelayLocation::get()) } fn claimable_asset() -> Result<(Location, Location, Assets), BenchmarkError> { - let origin = WndRelayLocation::get(); - let assets: Assets = (AssetId(WndRelayLocation::get()), 1_000 * UNITS).into(); + let origin = TokenRelayLocation::get(); + let assets: Assets = (AssetId(TokenRelayLocation::get()), 1_000 * UNITS).into(); let ticket = Location { parents: 0, interior: Here }; Ok((origin, ticket, assets)) } fn fee_asset() -> Result { Ok(Asset { - id: AssetId(WndRelayLocation::get()), + id: AssetId(TokenRelayLocation::get()), fun: Fungible(1_000_000 * UNITS), }) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_parachain_system.rs index 0303151d7f83dfc5957e7346b1c4ef2950b6dc01..1c9119361985cd541ca42dce6eb8d2f355a29c6c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -14,6 +14,31 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! 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: `[]` +//! 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("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=coretime-westend-dev +// --wasm-execution=compiled +// --pallet=cumulus_pallet_parachain_system +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ + #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -22,32 +47,31 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions for `cumulus_pallet_xcmp_queue`. +/// Weight functions for `cumulus_pallet_parachain_system`. pub struct WeightInfo(PhantomData); impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { - /// Storage: ParachainSystem LastDmqMqcHead (r:1 w:1) - /// Proof Skipped: ParachainSystem LastDmqMqcHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem ReservedDmpWeightOverride (r:1 w:0) - /// Proof Skipped: ParachainSystem ReservedDmpWeightOverride (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) - /// Storage: ParachainSystem ProcessedDownwardMessages (r:0 w:1) - /// Proof Skipped: ParachainSystem ProcessedDownwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: MessageQueue Pages (r:0 w:16) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Storage: `ParachainSystem::LastDmqMqcHead` (r:1 w:1) + /// Proof: `ParachainSystem::LastDmqMqcHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ProcessedDownwardMessages` (r:0 w:1) + /// Proof: `ParachainSystem::ProcessedDownwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1000) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12` - // Estimated: `8013` - // Minimum execution time: 1_645_000 picoseconds. - Weight::from_parts(1_717_000, 0) - .saturating_add(Weight::from_parts(0, 8013)) - // Standard Error: 12_258 - .saturating_add(Weight::from_parts(24_890_934, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `48` + // Estimated: `3517` + // Minimum execution time: 2_080_000 picoseconds. + Weight::from_parts(2_157_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + // Standard Error: 33_906 + .saturating_add(Weight::from_parts(196_603_239, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } -} \ No newline at end of file +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs index 124571118aa129e1489aaaf1ebeabbde41ed13c4..0b0524339aa761053a7c559a3a2ab725c0cb6c22 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,28 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// ./target/production/polkadot-parachain // benchmark // pallet // --chain=coretime-westend-dev -// --execution=wasm // --wasm-execution=compiled // --pallet=cumulus_pallet_xcmp_queue +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --steps=50 // --repeat=20 // --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,14 +50,14 @@ use core::marker::PhantomData; /// Weight functions for `cumulus_pallet_xcmp_queue`. pub struct WeightInfo(PhantomData); impl cumulus_pallet_xcmp_queue::WeightInfo for WeightInfo { - /// Storage: XcmpQueue QueueConfig (r:1 w:1) - /// Proof Skipped: XcmpQueue QueueConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:1) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 5_621_000 picoseconds. - Weight::from_parts(5_845_000, 0) + // Minimum execution time: 3_796_000 picoseconds. + Weight::from_parts(4_027_000, 0) .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -74,8 +76,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `3517` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 0) + // Minimum execution time: 9_990_000 picoseconds. + Weight::from_parts(10_439_000, 0) .saturating_add(Weight::from_parts(0, 3517)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -86,8 +88,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(3_000_000, 0) + // Minimum execution time: 2_394_000 picoseconds. + Weight::from_parts(2_493_000, 0) .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -98,8 +100,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `111` // Estimated: `1596` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) + // Minimum execution time: 3_283_000 picoseconds. + Weight::from_parts(3_388_000, 0) .saturating_add(Weight::from_parts(0, 1596)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -108,14 +110,14 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(45_000_000, 0) + // Minimum execution time: 5_974_000 picoseconds. + Weight::from_parts(6_166_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - /// Storage: `XcmpQueue::InboundXcmpMessages` (r:1 w:1) - /// Proof: `XcmpQueue::InboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) @@ -130,20 +132,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65711` // Estimated: `69176` - // Minimum execution time: 67_000_000 picoseconds. - Weight::from_parts(73_000_000, 0) + // Minimum execution time: 117_856_000 picoseconds. + Weight::from_parts(119_808_000, 0) .saturating_add(Weight::from_parts(0, 69176)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) - fn on_idle_large_msg() -> Weight { + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + fn on_idle_large_msg() -> Weight { // Proof Size summary in bytes: // Measured: `65710` // Estimated: `69175` - // Minimum execution time: 49_000_000 picoseconds. - Weight::from_parts(55_000_000, 0) + // Minimum execution time: 52_555_000 picoseconds. + Weight::from_parts(54_052_000, 0) .saturating_add(Weight::from_parts(0, 69175)) .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/frame_system.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system.rs index 46f8113939e4d4fa3f26ff03d665eec6b4120a6b..b4b7cbf05a5ec757bc3a60e08ef62678029b47f2 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,28 @@ //! Autogenerated weights for `frame_system` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-05, 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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// ./target/production/polkadot-parachain // benchmark // pallet // --chain=coretime-westend-dev -// --execution=wasm // --wasm-execution=compiled // --pallet=frame_system +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --steps=50 // --repeat=20 // --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system.rs +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,80 +55,99 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_432_000 picoseconds. - Weight::from_parts(2_458_000, 0) + // Minimum execution time: 1_584_000 picoseconds. + Weight::from_parts(2_117_975, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(367, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(384, 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_911_000 picoseconds. - Weight::from_parts(8_031_000, 0) + // Minimum execution time: 4_607_000 picoseconds. + Weight::from_parts(14_948_582, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_405, 0).saturating_mul(b.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_673, 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_304_000 picoseconds. - Weight::from_parts(4_553_000, 0) + // Minimum execution time: 2_681_000 picoseconds. + Weight::from_parts(2_877_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `ParachainSystem::UpgradeRestrictionSignal` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingValidationCode` (r:1 w:1) + /// Proof: `ParachainSystem::PendingValidationCode` (`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::NewValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::NewValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::DidSetValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::DidSetValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_code() -> Weight { - Weight::from_parts(1_000_000, 0) + // Proof Size summary in bytes: + // Measured: `164` + // Estimated: `1649` + // Minimum execution time: 95_893_701_000 picoseconds. + Weight::from_parts(98_086_094_000, 0) + .saturating_add(Weight::from_parts(0, 1649)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// 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_493_000 picoseconds. - Weight::from_parts(2_523_000, 0) + // Minimum execution time: 1_597_000 picoseconds. + Weight::from_parts(1_660_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_594 - .saturating_add(Weight::from_parts(663_439, 0).saturating_mul(i.into())) + // Standard Error: 1_871 + .saturating_add(Weight::from_parts(748_346, 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_492_000 picoseconds. - Weight::from_parts(2_526_000, 0) + // Minimum execution time: 1_625_000 picoseconds. + Weight::from_parts(1_669_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 784 - .saturating_add(Weight::from_parts(493_844, 0).saturating_mul(i.into())) + // Standard Error: 903 + .saturating_add(Weight::from_parts(561_709, 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: `68 + p * (69 ±0)` - // Estimated: `66 + p * (70 ±0)` - // Minimum execution time: 4_200_000 picoseconds. - Weight::from_parts(4_288_000, 0) - .saturating_add(Weight::from_parts(0, 66)) - // Standard Error: 1_195 - .saturating_add(Weight::from_parts(1_021_563, 0).saturating_mul(p.into())) + // Measured: `71 + p * (69 ±0)` + // Estimated: `72 + p * (70 ±0)` + // Minimum execution time: 3_306_000 picoseconds. + Weight::from_parts(3_412_000, 0) + .saturating_add(Weight::from_parts(0, 72)) + // Standard Error: 1_366 + .saturating_add(Weight::from_parts(1_138_953, 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())) @@ -137,25 +158,33 @@ 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: 7_834_000 picoseconds. + Weight::from_parts(8_344_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `System::AuthorizedUpgrade` (r:1 w:1) /// Proof: `System::AuthorizedUpgrade` (`max_values`: Some(1), `max_size`: Some(33), added: 528, 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) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `ParachainSystem::UpgradeRestrictionSignal` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingValidationCode` (r:1 w:1) + /// Proof: `ParachainSystem::PendingValidationCode` (`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::NewValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::NewValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::DidSetValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::DidSetValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn apply_authorized_upgrade() -> Weight { // 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) - .saturating_add(Weight::from_parts(0, 1518)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `186` + // Estimated: `1671` + // Minimum execution time: 98_682_277_000 picoseconds. + Weight::from_parts(101_609_257_000, 0) + .saturating_add(Weight::from_parts(0, 1671)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } } 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 0000000000000000000000000000000000000000..0683158a01a646315d13016d019c9f590f10ef04 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 28e708f0e2a33da7419fe821ab1fb72806c273b1..7b6ab611e6f3bf48c69b2945120c5f5118854808 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,12 +22,15 @@ 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; 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/coretime/coretime-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_balances.rs index 2fc1495c804fcc2a692925af8f53ac57b84863cd..c4770a7c94381cfca9404a6577c703164f215918 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_balances.rs @@ -17,23 +17,25 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-01-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-8idpd4bs-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --chain=coretime-westend-dev // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_balances -// --chain=coretime-westend-dev +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./cumulus/file_header.txt // --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ @@ -54,8 +56,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 41_147_000 picoseconds. - Weight::from_parts(41_829_000, 0) + // Minimum execution time: 42_773_000 picoseconds. + Weight::from_parts(43_292_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -66,8 +68,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 32_566_000 picoseconds. - Weight::from_parts(33_012_000, 0) + // Minimum execution time: 34_023_000 picoseconds. + Weight::from_parts(34_513_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -78,8 +80,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 11_435_000 picoseconds. - Weight::from_parts(11_717_000, 0) + // Minimum execution time: 11_685_000 picoseconds. + Weight::from_parts(12_103_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -90,8 +92,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 15_941_000 picoseconds. - Weight::from_parts(16_341_000, 0) + // Minimum execution time: 16_233_000 picoseconds. + Weight::from_parts(16_706_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -102,8 +104,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 42_592_000 picoseconds. - Weight::from_parts(43_111_000, 0) + // Minimum execution time: 43_909_000 picoseconds. + Weight::from_parts(44_683_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -114,8 +116,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 40_925_000 picoseconds. - Weight::from_parts(41_743_000, 0) + // Minimum execution time: 42_081_000 picoseconds. + Weight::from_parts(42_553_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -126,8 +128,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 14_117_000 picoseconds. - Weight::from_parts(14_418_000, 0) + // Minimum execution time: 14_413_000 picoseconds. + Weight::from_parts(14_827_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -139,11 +141,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 13_855_000 picoseconds. - Weight::from_parts(14_108_000, 0) + // Minimum execution time: 14_189_000 picoseconds. + Weight::from_parts(14_587_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 11_673 - .saturating_add(Weight::from_parts(12_675_264, 0).saturating_mul(u.into())) + // Standard Error: 10_909 + .saturating_add(Weight::from_parts(13_040_864, 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())) @@ -154,8 +156,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 4_820_000 picoseconds. - Weight::from_parts(5_152_000, 0) + // Minimum execution time: 5_218_000 picoseconds. + Weight::from_parts(5_562_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs new file mode 100644 index 0000000000000000000000000000000000000000..8727b9633b1f0eaca2bcaa5f7a43d832f6abbe9b --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs @@ -0,0 +1,516 @@ +// 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_broker` +//! +//! 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: `[]` +//! 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("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=coretime-westend-dev +// --wasm-execution=compiled +// --pallet=pallet_broker +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/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_broker`. +pub struct WeightInfo(PhantomData); +impl pallet_broker::WeightInfo for WeightInfo { + /// Storage: `Broker::Configuration` (r:0 w:1) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + fn configure() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_944_000 picoseconds. + Weight::from_parts(2_045_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Reservations` (r:1 w:1) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + fn reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `10888` + // Estimated: `13506` + // Minimum execution time: 21_158_000 picoseconds. + Weight::from_parts(21_572_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Reservations` (r:1 w:1) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + fn unreserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `12090` + // Estimated: `13506` + // Minimum execution time: 20_497_000 picoseconds. + Weight::from_parts(20_995_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::LastRelayChainBlockNumber` (r:1 w:0) + /// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_lease() -> Weight { + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `1631` + // Minimum execution time: 10_280_000 picoseconds. + Weight::from_parts(10_686_000, 0) + .saturating_add(Weight::from_parts(0, 1631)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::LastRelayChainBlockNumber` (r:1 w:0) + /// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Broker::InstaPoolIo` (r:3 w:3) + /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:0) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) + /// Storage: `Broker::SaleInfo` (r:0 w:1) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:0 w:1) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:20) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn start_sales(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12247` + // Estimated: `13732` + // Minimum execution time: 61_020_000 picoseconds. + Weight::from_parts(63_240_622, 0) + .saturating_add(Weight::from_parts(0, 13732)) + // Standard Error: 102 + .saturating_add(Weight::from_parts(255, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(26)) + } + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::SaleInfo` (r:1 w:1) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Broker::Regions` (r:0 w:1) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + fn purchase() -> Weight { + // Proof Size summary in bytes: + // Measured: `316` + // Estimated: `3593` + // Minimum execution time: 30_627_000 picoseconds. + Weight::from_parts(31_648_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::SaleInfo` (r:1 w:1) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::AllowedRenewals` (r:1 w:2) + /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:1) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn renew() -> Weight { + // Proof Size summary in bytes: + // Measured: `434` + // Estimated: `4698` + // Minimum execution time: 57_701_000 picoseconds. + Weight::from_parts(59_825_000, 0) + .saturating_add(Weight::from_parts(0, 4698)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Broker::Regions` (r:1 w:1) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `357` + // Estimated: `3550` + // Minimum execution time: 12_898_000 picoseconds. + Weight::from_parts(13_506_000, 0) + .saturating_add(Weight::from_parts(0, 3550)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Regions` (r:1 w:2) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + fn partition() -> Weight { + // Proof Size summary in bytes: + // Measured: `357` + // Estimated: `3550` + // Minimum execution time: 14_284_000 picoseconds. + Weight::from_parts(14_791_000, 0) + .saturating_add(Weight::from_parts(0, 3550)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Broker::Regions` (r:1 w:3) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + fn interlace() -> Weight { + // Proof Size summary in bytes: + // Measured: `357` + // Estimated: `3550` + // Minimum execution time: 15_570_000 picoseconds. + Weight::from_parts(16_158_000, 0) + .saturating_add(Weight::from_parts(0, 3550)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Regions` (r:1 w:1) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:1 w:1) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn assign() -> Weight { + // Proof Size summary in bytes: + // Measured: `735` + // Estimated: `4681` + // Minimum execution time: 23_329_000 picoseconds. + Weight::from_parts(24_196_000, 0) + .saturating_add(Weight::from_parts(0, 4681)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Regions` (r:1 w:1) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:1 w:1) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + /// Storage: `Broker::InstaPoolIo` (r:2 w:2) + /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::InstaPoolContribution` (r:0 w:1) + /// Proof: `Broker::InstaPoolContribution` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `801` + // Estimated: `5996` + // Minimum execution time: 29_288_000 picoseconds. + Weight::from_parts(30_066_000, 0) + .saturating_add(Weight::from_parts(0, 5996)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Broker::InstaPoolContribution` (r:1 w:1) + /// Proof: `Broker::InstaPoolContribution` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: `Broker::InstaPoolHistory` (r:3 w:1) + /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `m` is `[1, 3]`. + fn claim_revenue(m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `652` + // Estimated: `6196 + m * (2520 ±0)` + // Minimum execution time: 54_833_000 picoseconds. + Weight::from_parts(55_577_423, 0) + .saturating_add(Weight::from_parts(0, 6196)) + // Standard Error: 35_105 + .saturating_add(Weight::from_parts(1_267_911, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(m.into())) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// 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`) + fn purchase_credit() -> Weight { + // Proof Size summary in bytes: + // Measured: `215` + // Estimated: `3680` + // Minimum execution time: 55_289_000 picoseconds. + Weight::from_parts(56_552_000, 0) + .saturating_add(Weight::from_parts(0, 3680)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Regions` (r:1 w:1) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + fn drop_region() -> Weight { + // Proof Size summary in bytes: + // Measured: `465` + // Estimated: `3550` + // Minimum execution time: 39_736_000 picoseconds. + Weight::from_parts(41_346_000, 0) + .saturating_add(Weight::from_parts(0, 3550)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::InstaPoolContribution` (r:1 w:1) + /// Proof: `Broker::InstaPoolContribution` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn drop_contribution() -> Weight { + // Proof Size summary in bytes: + // Measured: `463` + // Estimated: `3533` + // Minimum execution time: 57_319_000 picoseconds. + Weight::from_parts(60_204_000, 0) + .saturating_add(Weight::from_parts(0, 3533)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) + /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn drop_history() -> Weight { + // Proof Size summary in bytes: + // Measured: `857` + // Estimated: `3593` + // Minimum execution time: 85_216_000 picoseconds. + Weight::from_parts(91_144_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::AllowedRenewals` (r:1 w:1) + /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) + fn drop_renewal() -> Weight { + // Proof Size summary in bytes: + // Measured: `556` + // Estimated: `4698` + // Minimum execution time: 32_331_000 picoseconds. + Weight::from_parts(39_877_000, 0) + .saturating_add(Weight::from_parts(0, 4698)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// 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`) + /// The range of component `n` is `[0, 1000]`. + fn request_core_count(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `3539` + // Minimum execution time: 18_128_000 picoseconds. + Weight::from_parts(19_061_234, 0) + .saturating_add(Weight::from_parts(0, 3539)) + // Standard Error: 48 + .saturating_add(Weight::from_parts(141, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Broker::CoreCountInbox` (r:1 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn process_core_count(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `266` + // Estimated: `1487` + // Minimum execution time: 5_368_000 picoseconds. + Weight::from_parts(5_837_005, 0) + .saturating_add(Weight::from_parts(0, 1487)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) + /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn process_revenue() -> Weight { + // Proof Size summary in bytes: + // Measured: `447` + // Estimated: `6196` + // Minimum execution time: 36_047_000 picoseconds. + Weight::from_parts(37_101_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Broker::InstaPoolIo` (r:3 w:3) + /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:0) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) + /// Storage: `Broker::SaleInfo` (r:0 w:1) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:20) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn rotate_sale(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12194` + // Estimated: `13506` + // Minimum execution time: 48_158_000 picoseconds. + Weight::from_parts(49_891_920, 0) + .saturating_add(Weight::from_parts(0, 13506)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(25)) + } + /// Storage: `Broker::InstaPoolIo` (r:1 w:0) + /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::InstaPoolHistory` (r:0 w:1) + /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + fn process_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3493` + // Minimum execution time: 5_911_000 picoseconds. + Weight::from_parts(6_173_000, 0) + .saturating_add(Weight::from_parts(0, 3493)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Workplan` (r:1 w:1) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workload` (r:1 w:1) + /// Proof: `Broker::Workload` (`max_values`: None, `max_size`: Some(1212), added: 3687, 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`) + fn process_core_schedule() -> Weight { + // Proof Size summary in bytes: + // Measured: `1321` + // Estimated: `4786` + // Minimum execution time: 30_140_000 picoseconds. + Weight::from_parts(30_912_000, 0) + .saturating_add(Weight::from_parts(0, 4786)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// 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`) + fn request_revenue_info_at() -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `3539` + // Minimum execution time: 13_684_000 picoseconds. + Weight::from_parts(14_252_000, 0) + .saturating_add(Weight::from_parts(0, 3539)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Broker::CoreCountInbox` (r:0 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + fn notify_core_count() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_718_000 picoseconds. + Weight::from_parts(1_843_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Broker::Status` (r:1 w:1) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::CoreCountInbox` (r:1 w:0) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn do_tick_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `398` + // Estimated: `3863` + // Minimum execution time: 11_771_000 picoseconds. + Weight::from_parts(12_120_000, 0) + .saturating_add(Weight::from_parts(0, 3863)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_collator_selection.rs index 2adddecab264945884d8b4620b9dff9868bfc4f0..2341890c314ec422aebf30b27111502a01909c25 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_collator_selection.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,28 @@ //! Autogenerated weights for `pallet_collator_selection` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// ./target/production/polkadot-parachain // benchmark // pallet // --chain=coretime-westend-dev -// --execution=wasm // --wasm-execution=compiled // --pallet=pallet_collator_selection +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --steps=50 // --repeat=20 // --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_collator_selection.rs +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,196 +50,236 @@ use core::marker::PhantomData; /// Weight functions for `pallet_collator_selection`. pub struct WeightInfo(PhantomData); impl pallet_collator_selection::WeightInfo for WeightInfo { - /// Storage: Session NextKeys (r:100 w:0) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: CollatorSelection Invulnerables (r:0 w:1) - /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// The range of component `b` is `[1, 100]`. + /// Storage: `Session::NextKeys` (r:20 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CollatorSelection::Invulnerables` (r:0 w:1) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// The range of component `b` is `[1, 20]`. fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `214 + b * (78 ±0)` - // Estimated: `1203 + b * (2554 ±0)` - // Minimum execution time: 14_426_000 picoseconds. - Weight::from_parts(14_971_974, 0) - .saturating_add(Weight::from_parts(0, 1203)) - // Standard Error: 2_914 - .saturating_add(Weight::from_parts(2_604_699, 0).saturating_mul(b.into())) + // Measured: `164 + b * (79 ±0)` + // Estimated: `1155 + b * (2555 ±0)` + // Minimum execution time: 11_038_000 picoseconds. + Weight::from_parts(8_347_616, 0) + .saturating_add(Weight::from_parts(0, 1155)) + // Standard Error: 5_166 + .saturating_add(Weight::from_parts(3_025_311, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 2555).saturating_mul(b.into())) } - /// Storage: CollatorSelection DesiredCandidates (r:0 w:1) - /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn set_desired_candidates() -> Weight { + /// Storage: `Session::NextKeys` (r:1 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:1) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::CandidateList` (r:1 w:1) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, 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 `b` is `[1, 19]`. + /// The range of component `c` is `[1, 99]`. + fn add_invulnerable(b: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_977_000 picoseconds. - Weight::from_parts(7_246_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `720 + b * (32 ±0) + c * (53 ±0)` + // Estimated: `6287 + b * (37 ±0) + c * (53 ±0)` + // Minimum execution time: 36_983_000 picoseconds. + Weight::from_parts(37_900_558, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 6_860 + .saturating_add(Weight::from_parts(94_160, 0).saturating_mul(b.into())) + // Standard Error: 1_300 + .saturating_add(Weight::from_parts(119_010, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 53).saturating_mul(c.into())) + } + /// Storage: `CollatorSelection::CandidateList` (r:1 w:0) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:1) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// The range of component `b` is `[5, 20]`. + fn remove_invulnerable(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `82 + b * (32 ±0)` + // Estimated: `6287` + // Minimum execution time: 10_432_000 picoseconds. + Weight::from_parts(10_460_489, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_803 + .saturating_add(Weight::from_parts(143_162, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `CollatorSelection::CandidacyBond` (r:0 w:1) - /// Proof: `CollatorSelection::CandidacyBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - fn set_candidacy_bond(_c: u32, _k: u32) -> Weight { + /// Storage: `CollatorSelection::DesiredCandidates` (r:0 w:1) + /// Proof: `CollatorSelection::DesiredCandidates` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn set_desired_candidates() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_937_000 picoseconds. - Weight::from_parts(8_161_000, 0) + // Minimum execution time: 4_302_000 picoseconds. + Weight::from_parts(4_508_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: CollatorSelection Candidates (r:1 w:1) - /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(48002), added: 48497, mode: MaxEncodedLen) - /// Storage: CollatorSelection DesiredCandidates (r:1 w:0) - /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: CollatorSelection Invulnerables (r:1 w:0) - /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:0) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: CollatorSelection CandidacyBond (r:1 w:0) - /// Proof: CollatorSelection CandidacyBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) - /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// The range of component `c` is `[1, 999]`. - fn register_as_candidate(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1104 + c * (48 ±0)` - // Estimated: `49487 + c * (49 ±0)` - // Minimum execution time: 42_275_000 picoseconds. - Weight::from_parts(33_742_215, 0) - .saturating_add(Weight::from_parts(0, 49487)) - // Standard Error: 1_291 - .saturating_add(Weight::from_parts(103_381, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) - } - /// Storage: CollatorSelection Candidates (r:1 w:1) - /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(48002), added: 48497, mode: MaxEncodedLen) - /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) - /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// The range of component `c` is `[6, 1000]`. - fn leave_intent(c: u32, ) -> Weight { + /// Storage: `CollatorSelection::CandidacyBond` (r:1 w:1) + /// Proof: `CollatorSelection::CandidacyBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::CandidateList` (r:1 w:1) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:100 w:100) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:100) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 100]`. + /// The range of component `k` is `[0, 100]`. + fn set_candidacy_bond(c: u32, k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `428 + c * (48 ±0)` - // Estimated: `49487` - // Minimum execution time: 33_404_000 picoseconds. - Weight::from_parts(22_612_617, 0) - .saturating_add(Weight::from_parts(0, 49487)) - // Standard Error: 1_341 - .saturating_add(Weight::from_parts(105_669, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `0 + c * (180 ±0) + k * (112 ±0)` + // Estimated: `6287 + c * (901 ±29) + k * (901 ±29)` + // Minimum execution time: 7_712_000 picoseconds. + Weight::from_parts(7_935_000, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 153_204 + .saturating_add(Weight::from_parts(5_173_626, 0).saturating_mul(c.into())) + // Standard Error: 153_204 + .saturating_add(Weight::from_parts(4_883_030, 0).saturating_mul(k.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(c.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_parts(0, 901).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 901).saturating_mul(k.into())) } + /// Storage: `CollatorSelection::CandidacyBond` (r:1 w:0) + /// Proof: `CollatorSelection::CandidacyBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::CandidateList` (r:1 w:1) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// The range of component `c` is `[4, 100]`. fn update_bond(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `306 + c * (50 ±0)` + // Measured: `250 + c * (50 ±0)` // Estimated: `6287` - // Minimum execution time: 34_814_000 picoseconds. - Weight::from_parts(36_371_520, 0) + // Minimum execution time: 22_767_000 picoseconds. + Weight::from_parts(25_594_856, 0) .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_391 - .saturating_add(Weight::from_parts(201_700, 0).saturating_mul(c.into())) + // Standard Error: 1_814 + .saturating_add(Weight::from_parts(110_451, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `CollatorSelection::CandidateList` (r:1 w:1) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:0) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `Session::NextKeys` (r:1 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CollatorSelection::CandidacyBond` (r:1 w:0) + /// Proof: `CollatorSelection::CandidacyBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:1) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// The range of component `c` is `[1, 99]`. + fn register_as_candidate(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `687 + c * (52 ±0)` + // Estimated: `6287 + c * (54 ±0)` + // Minimum execution time: 30_792_000 picoseconds. + Weight::from_parts(34_485_582, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_421 + .saturating_add(Weight::from_parts(152_013, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 54).saturating_mul(c.into())) } + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:0) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::CandidacyBond` (r:1 w:0) + /// Proof: `CollatorSelection::CandidacyBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Session::NextKeys` (r:1 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CollatorSelection::CandidateList` (r:1 w:1) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:2) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// The range of component `c` is `[4, 100]`. fn take_candidate_slot(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `306 + c * (50 ±0)` + // Measured: `855 + c * (52 ±0)` + // Estimated: `6287 + c * (55 ±0)` + // Minimum execution time: 45_538_000 picoseconds. + Weight::from_parts(50_758_223, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_779 + .saturating_add(Weight::from_parts(149_419, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 55).saturating_mul(c.into())) + } + /// Storage: `CollatorSelection::CandidateList` (r:1 w:1) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:0) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:1) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// The range of component `c` is `[4, 100]`. + fn leave_intent(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `277 + c * (48 ±0)` // Estimated: `6287` - // Minimum execution time: 34_814_000 picoseconds. - Weight::from_parts(36_371_520, 0) + // Minimum execution time: 26_356_000 picoseconds. + Weight::from_parts(29_910_328, 0) .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 2_391 - .saturating_add(Weight::from_parts(201_700, 0).saturating_mul(c.into())) + // Standard Error: 2_159 + .saturating_add(Weight::from_parts(123_421, 0).saturating_mul(c.into())) .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: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) - /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:1) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `155` + // Measured: `103` // Estimated: `6196` - // Minimum execution time: 44_415_000 picoseconds. - Weight::from_parts(44_732_000, 0) + // Minimum execution time: 36_377_000 picoseconds. + Weight::from_parts(37_121_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Session NextKeys (r:1 w:0) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: CollatorSelection Invulnerables (r:1 w:1) - /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(641), added: 1136, mode: MaxEncodedLen) - /// Storage: CollatorSelection Candidates (r:1 w:1) - /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, 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 `b` is `[1, 19]`. - /// The range of component `c` is `[1, 99]`. - fn add_invulnerable(b: u32, c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `757 + b * (32 ±0) + c * (53 ±0)` - // Estimated: `6287 + b * (37 ±0) + c * (53 ±0)` - // Minimum execution time: 52_720_000 picoseconds. - Weight::from_parts(56_102_459, 0) - .saturating_add(Weight::from_parts(0, 6287)) - // Standard Error: 12_957 - .saturating_add(Weight::from_parts(26_422, 0).saturating_mul(b.into())) - // Standard Error: 2_456 - .saturating_add(Weight::from_parts(128_528, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 37).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 53).saturating_mul(c.into())) - } - /// Storage: CollatorSelection Invulnerables (r:1 w:1) - /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// The range of component `b` is `[1, 100]`. - fn remove_invulnerable(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `119 + b * (32 ±0)` - // Estimated: `4687` - // Minimum execution time: 183_054_000 picoseconds. - Weight::from_parts(197_205_427, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 13_533 - .saturating_add(Weight::from_parts(376_231, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: CollatorSelection Candidates (r:1 w:0) - /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(48002), added: 48497, mode: MaxEncodedLen) - /// Storage: CollatorSelection LastAuthoredBlock (r:999 w:0) - /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: CollatorSelection Invulnerables (r:1 w:0) - /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: System Account (r:995 w:995) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 1000]`. - /// The range of component `c` is `[1, 1000]`. + /// Storage: `CollatorSelection::CandidateList` (r:1 w:0) + /// Proof: `CollatorSelection::CandidateList` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:100 w:0) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:0) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::DesiredCandidates` (r:1 w:0) + /// Proof: `CollatorSelection::DesiredCandidates` (`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`) + /// Storage: `System::Account` (r:97 w:97) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 100]`. + /// The range of component `c` is `[1, 100]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22815 + c * (97 ±0) + r * (116 ±0)` - // Estimated: `49487 + c * (2519 ±0) + r * (2602 ±0)` - // Minimum execution time: 16_765_000 picoseconds. - Weight::from_parts(16_997_000, 0) - .saturating_add(Weight::from_parts(0, 49487)) - // Standard Error: 860_677 - .saturating_add(Weight::from_parts(30_463_094, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `2143 + c * (97 ±0) + r * (112 ±0)` + // Estimated: `6287 + c * (2519 ±0) + r * (2603 ±0)` + // Minimum execution time: 15_761_000 picoseconds. + Weight::from_parts(16_078_000, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 270_522 + .saturating_add(Weight::from_parts(11_903_266, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2519).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 2602).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(r.into())) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_message_queue.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_message_queue.rs index 651f27e10e5c7b5d941d2bec5197fc06ed035fda..e9cdc2478766de88bfd3cc8765ba472bac61db30 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_message_queue.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_message_queue.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -14,6 +14,31 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +//! Autogenerated weights for `pallet_message_queue` +//! +//! 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: `[]` +//! 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("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=coretime-westend-dev +// --wasm-execution=compiled +// --pallet=pallet_message_queue +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ + #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -22,134 +47,140 @@ use frame_support::{traits::Get, weights::Weight}; 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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `189` - // Estimated: `7534` - // Minimum execution time: 11_446_000 picoseconds. - Weight::from_parts(11_446_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) + // Measured: `223` + // Estimated: `6044` + // Minimum execution time: 10_918_000 picoseconds. + Weight::from_parts(11_224_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) .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(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `184` - // Estimated: `7534` - // Minimum execution time: 10_613_000 picoseconds. - Weight::from_parts(10_613_000, 0) - .saturating_add(Weight::from_parts(0, 7534)) + // Measured: `218` + // Estimated: `6044` + // Minimum execution time: 9_649_000 picoseconds. + Weight::from_parts(10_056_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) .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(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `6` // Estimated: `3517` - // Minimum execution time: 4_854_000 picoseconds. - Weight::from_parts(4_854_000, 0) + // Minimum execution time: 3_134_000 picoseconds. + Weight::from_parts(3_197_000, 0) .saturating_add(Weight::from_parts(0, 3517)) .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(65585), added: 68060, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `72` // Estimated: `69050` - // Minimum execution time: 5_748_000 picoseconds. - Weight::from_parts(5_748_000, 0) + // Minimum execution time: 4_915_000 picoseconds. + Weight::from_parts(5_127_000, 0) .saturating_add(Weight::from_parts(0, 69050)) .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(65585), added: 68060, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `72` // Estimated: `69050` - // Minimum execution time: 6_136_000 picoseconds. - Weight::from_parts(6_136_000, 0) + // Minimum execution time: 5_011_000 picoseconds. + Weight::from_parts(5_150_000, 0) .saturating_add(Weight::from_parts(0, 69050)) .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(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 59_505_000 picoseconds. - Weight::from_parts(59_505_000, 0) + // Minimum execution time: 168_806_000 picoseconds. + Weight::from_parts(170_795_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(5), added: 500, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `5007` - // Minimum execution time: 6_506_000 picoseconds. - Weight::from_parts(6_506_000, 0) - .saturating_add(Weight::from_parts(0, 5007)) + // Measured: `171` + // Estimated: `3517` + // Minimum execution time: 6_413_000 picoseconds. + Weight::from_parts(6_797_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) .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(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) fn reap_page() -> Weight { // Proof Size summary in bytes: // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 40_646_000 picoseconds. - Weight::from_parts(40_646_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) + // Estimated: `69050` + // Minimum execution time: 52_734_000 picoseconds. + Weight::from_parts(54_106_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 51_424_000 picoseconds. - Weight::from_parts(51_424_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) + // Estimated: `69050` + // Minimum execution time: 68_400_000 picoseconds. + Weight::from_parts(70_336_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65585), added: 68060, mode: `MaxEncodedLen`) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: // Measured: `65667` - // Estimated: `72567` - // Minimum execution time: 81_153_000 picoseconds. - Weight::from_parts(81_153_000, 0) - .saturating_add(Weight::from_parts(0, 72567)) + // Estimated: `69050` + // Minimum execution time: 109_496_000 picoseconds. + Weight::from_parts(111_632_000, 0) + .saturating_add(Weight::from_parts(0, 69050)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } -} \ No newline at end of file +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_multisig.rs index 4130e05bf7c4233b5dfdd6fcf0df1295ce77db61..1aaf3f4a6fb9dd88f83042915080b08bb735e664 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,28 @@ //! Autogenerated weights for `pallet_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// ./target/production/polkadot-parachain // benchmark // pallet // --chain=coretime-westend-dev -// --execution=wasm // --wasm-execution=compiled // --pallet=pallet_multisig +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --steps=50 // --repeat=20 // --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_multisig.rs +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,110 +55,110 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_337_000 picoseconds. - Weight::from_parts(11_960_522, 0) + // Minimum execution time: 11_938_000 picoseconds. + Weight::from_parts(13_021_007, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(504, 0).saturating_mul(z.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(482, 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: `263 + s * (2 ±0)` + // Measured: `262 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 41_128_000 picoseconds. - Weight::from_parts(35_215_592, 0) + // Minimum execution time: 37_643_000 picoseconds. + Weight::from_parts(27_088_068, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 429 - .saturating_add(Weight::from_parts(65_959, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(z.into())) + // Standard Error: 828 + .saturating_add(Weight::from_parts(123_693, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_456, 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: `282` // Estimated: `6811` - // Minimum execution time: 26_878_000 picoseconds. - Weight::from_parts(21_448_577, 0) + // Minimum execution time: 25_825_000 picoseconds. + Weight::from_parts(15_698_835, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 354 - .saturating_add(Weight::from_parts(60_286, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_236, 0).saturating_mul(z.into())) + // Standard Error: 568 + .saturating_add(Weight::from_parts(111_928, 0).saturating_mul(s.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_421, 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: `388 + s * (33 ±0)` + // Measured: `385 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 45_716_000 picoseconds. - Weight::from_parts(38_332_947, 0) + // Minimum execution time: 43_587_000 picoseconds. + Weight::from_parts(29_740_539, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 554 - .saturating_add(Weight::from_parts(81_026, 0).saturating_mul(s.into())) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_265, 0).saturating_mul(z.into())) + // Standard Error: 771 + .saturating_add(Weight::from_parts(154_861, 0).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_557, 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: `263 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 32_089_000 picoseconds. - Weight::from_parts(33_664_508, 0) + // Minimum execution time: 24_966_000 picoseconds. + Weight::from_parts(25_879_458, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 487 - .saturating_add(Weight::from_parts(67_443, 0).saturating_mul(s.into())) + // Standard Error: 777 + .saturating_add(Weight::from_parts(122_823, 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: `282` // Estimated: `6811` - // Minimum execution time: 18_631_000 picoseconds. - Weight::from_parts(19_909_964, 0) + // Minimum execution time: 14_450_000 picoseconds. + Weight::from_parts(14_607_858, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 434 - .saturating_add(Weight::from_parts(62_989, 0).saturating_mul(s.into())) + // Standard Error: 471 + .saturating_add(Weight::from_parts(107_007, 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: `454 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 32_486_000 picoseconds. - Weight::from_parts(34_303_784, 0) + // Minimum execution time: 26_861_000 picoseconds. + Weight::from_parts(27_846_825, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 585 - .saturating_add(Weight::from_parts(69_979, 0).saturating_mul(s.into())) + // Standard Error: 714 + .saturating_add(Weight::from_parts(116_914, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_session.rs index d132ef17bbdb2295dcd4ee812ab62ae51fd6ff3a..b0d993d68a6a4e824c6050a3edef87870438e6b2 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_session.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,28 @@ //! Autogenerated weights for `pallet_session` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// ./target/production/polkadot-parachain // benchmark // pallet // --chain=coretime-westend-dev -// --execution=wasm // --wasm-execution=compiled // --pallet=pallet_session +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --steps=50 // --repeat=20 // --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_session.rs +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,31 +50,31 @@ use core::marker::PhantomData; /// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:1 w:1) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:1 w:1) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `297` - // Estimated: `3762` - // Minimum execution time: 17_353_000 picoseconds. - Weight::from_parts(18_005_000, 0) - .saturating_add(Weight::from_parts(0, 3762)) + // Measured: `271` + // Estimated: `3736` + // Minimum execution time: 15_149_000 picoseconds. + Weight::from_parts(16_053_000, 0) + .saturating_add(Weight::from_parts(0, 3736)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:0 w:1) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:0 w:1) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `279` - // Estimated: `3744` - // Minimum execution time: 13_039_000 picoseconds. - Weight::from_parts(13_341_000, 0) - .saturating_add(Weight::from_parts(0, 3744)) + // Measured: `243` + // Estimated: `3708` + // Minimum execution time: 11_159_000 picoseconds. + Weight::from_parts(11_504_000, 0) + .saturating_add(Weight::from_parts(0, 3708)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_timestamp.rs index 722858a3a4655881cdbedbe8e6cae419baefc190..ad8924d9ce7374c285ddc662c59d860707443bfc 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,28 @@ //! Autogenerated weights for `pallet_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// ./target/production/polkadot-parachain // benchmark // pallet // --chain=coretime-westend-dev -// --execution=wasm // --wasm-execution=compiled // --pallet=pallet_timestamp +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --steps=50 // --repeat=20 // --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_timestamp.rs +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,16 +50,16 @@ 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: Aura CurrentSlot (r:1 w:0) - /// Proof: Aura 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: `Aura::CurrentSlot` (r:1 w:0) + /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set() -> Weight { // Proof Size summary in bytes: - // Measured: `49` + // Measured: `86` // Estimated: `1493` - // Minimum execution time: 7_986_000 picoseconds. - Weight::from_parts(8_134_000, 0) + // Minimum execution time: 5_552_000 picoseconds. + Weight::from_parts(5_821_000, 0) .saturating_add(Weight::from_parts(0, 1493)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -66,8 +68,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_257_000 picoseconds. - Weight::from_parts(3_366_000, 0) + // Minimum execution time: 2_848_000 picoseconds. + Weight::from_parts(2_953_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } 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 0000000000000000000000000000000000000000..f159f877afe77d7b7b98524d726e3867c6f80588 --- /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/pallet_utility.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs index dacd469ebb7ab62eb7fcd7740bf6bf230aace7ee..0f5340843bd6481da855cb403b2b7d6442ed0a52 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,28 @@ //! Autogenerated weights for `pallet_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// ./target/production/polkadot-parachain // benchmark // pallet // --chain=coretime-westend-dev -// --execution=wasm // --wasm-execution=compiled // --pallet=pallet_utility +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --steps=50 // --repeat=20 // --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,18 +55,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_697_000 picoseconds. - Weight::from_parts(11_859_145, 0) + // Minimum execution time: 3_721_000 picoseconds. + Weight::from_parts(7_071_852, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_146 - .saturating_add(Weight::from_parts(4_300_555, 0).saturating_mul(c.into())) + // Standard Error: 746 + .saturating_add(Weight::from_parts(2_767_352, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_979_000 picoseconds. - Weight::from_parts(5_066_000, 0) + // Minimum execution time: 3_631_000 picoseconds. + Weight::from_parts(3_836_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -72,18 +74,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_741_000 picoseconds. - Weight::from_parts(15_928_547, 0) + // Minimum execution time: 3_817_000 picoseconds. + Weight::from_parts(2_683_003, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_310 - .saturating_add(Weight::from_parts(4_527_996, 0).saturating_mul(c.into())) + // Standard Error: 782 + .saturating_add(Weight::from_parts(3_059_987, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_717_000 picoseconds. - Weight::from_parts(8_909_000, 0) + // Minimum execution time: 5_463_000 picoseconds. + Weight::from_parts(5_701_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -91,10 +93,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_814_000 picoseconds. - Weight::from_parts(13_920_831, 0) + // Minimum execution time: 3_771_000 picoseconds. + Weight::from_parts(5_714_929, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 7_605 - .saturating_add(Weight::from_parts(4_306_193, 0).saturating_mul(c.into())) + // Standard Error: 740 + .saturating_add(Weight::from_parts(2_800_888, 0).saturating_mul(c.into())) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs index d96ee43463a316d3b8a0c5c8351045d7c340cd13..0082db3099d029c976779af8600bcaf4410e8a2f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -16,26 +16,26 @@ //! Autogenerated weights for `pallet_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-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("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/westend-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=coretime-westend-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_xcm -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=coretime-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,39 +48,50 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (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`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 25_783_000 picoseconds. - Weight::from_parts(26_398_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) + // Measured: `74` + // Estimated: `3539` + // Minimum execution time: 18_410_000 picoseconds. + Weight::from_parts(18_657_000, 0) + .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: ParachainInfo ParachainId (r:1 w:0) - /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `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`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 25_511_000 picoseconds. - Weight::from_parts(26_120_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 56_616_000 picoseconds. + Weight::from_parts(57_751_000, 0) + .saturating_add(Weight::from_parts(0, 3571)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -89,18 +100,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `496` - // Estimated: `6208` - // Minimum execution time: 146_932_000 picoseconds. - Weight::from_parts(153_200_000, 0) - .saturating_add(Weight::from_parts(0, 6208)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) + // 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: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -109,189 +120,189 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: PolkadotXcm SupportedVersion (r:0 w:1) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_707_000 picoseconds. - Weight::from_parts(9_874_000, 0) + // Minimum execution time: 6_014_000 picoseconds. + Weight::from_parts(6_412_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm SafeXcmVersion (r:0 w:1) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn force_default_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_073_000 picoseconds. - Weight::from_parts(3_183_000, 0) + // Minimum execution time: 1_844_000 picoseconds. + Weight::from_parts(1_957_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm VersionNotifiers (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm QueryCounter (r:1 w:1) - /// Proof Skipped: PolkadotXcm QueryCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm Queries (r:0 w:1) - /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 30_999_000 picoseconds. - Weight::from_parts(31_641_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) + // Measured: `74` + // Estimated: `3539` + // Minimum execution time: 24_067_000 picoseconds. + Weight::from_parts(24_553_000, 0) + .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: PolkadotXcm VersionNotifiers (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm Queries (r:0 w:1) - /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `3685` - // Minimum execution time: 33_036_000 picoseconds. - Weight::from_parts(33_596_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `292` + // Estimated: `3757` + // Minimum execution time: 27_023_000 picoseconds. + Weight::from_parts(27_620_000, 0) + .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: PolkadotXcm XcmExecutionSuspended (r:0 w:1) - /// Proof Skipped: PolkadotXcm XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `PolkadotXcm::XcmExecutionSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn force_suspension() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_035_000 picoseconds. - Weight::from_parts(3_154_000, 0) + // Minimum execution time: 1_866_000 picoseconds. + Weight::from_parts(1_984_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm SupportedVersion (r:4 w:2) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `10985` - // Minimum execution time: 14_805_000 picoseconds. - Weight::from_parts(15_120_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `89` + // Estimated: `13454` + // Minimum execution time: 16_425_000 picoseconds. + Weight::from_parts(16_680_000, 0) + .saturating_add(Weight::from_parts(0, 13454)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifiers (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `10989` - // Minimum execution time: 14_572_000 picoseconds. - Weight::from_parts(14_909_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `93` + // Estimated: `13458` + // Minimum execution time: 16_171_000 picoseconds. + Weight::from_parts(16_564_000, 0) + .saturating_add(Weight::from_parts(0, 13458)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:5 w:0) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 15_341_000 picoseconds. - Weight::from_parts(15_708_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15946` + // Minimum execution time: 17_785_000 picoseconds. + Weight::from_parts(18_123_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(6)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `6046` - // Minimum execution time: 27_840_000 picoseconds. - Weight::from_parts(28_248_000, 0) - .saturating_add(Weight::from_parts(0, 6046)) + // Measured: `142` + // Estimated: `6082` + // Minimum execution time: 23_903_000 picoseconds. + Weight::from_parts(24_769_000, 0) + .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:3 w:0) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_245_000 picoseconds. - Weight::from_parts(8_523_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11026` + // Minimum execution time: 10_617_000 picoseconds. + Weight::from_parts(10_843_000, 0) + .saturating_add(Weight::from_parts(0, 11026)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10996` - // Minimum execution time: 14_780_000 picoseconds. - Weight::from_parts(15_173_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `100` + // Estimated: `13465` + // Minimum execution time: 16_656_000 picoseconds. + Weight::from_parts(17_106_000, 0) + .saturating_add(Weight::from_parts(0, 13465)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `11002` - // Minimum execution time: 33_422_000 picoseconds. - Weight::from_parts(34_076_000, 0) - .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `142` + // Estimated: `13507` + // Minimum execution time: 31_721_000 picoseconds. + Weight::from_parts(32_547_000, 0) + .saturating_add(Weight::from_parts(0, 13507)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -300,11 +311,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn new_query() -> Weight { // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1554` - // Minimum execution time: 4_512_000 picoseconds. - Weight::from_parts(4_671_000, 0) - .saturating_add(Weight::from_parts(0, 1554)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 3_439_000 picoseconds. + Weight::from_parts(3_619_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -312,11 +323,23 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn take_response() -> Weight { // Proof Size summary in bytes: - // Measured: `7706` - // Estimated: `11171` - // Minimum execution time: 26_473_000 picoseconds. - Weight::from_parts(26_960_000, 0) - .saturating_add(Weight::from_parts(0, 11171)) + // Measured: `7669` + // Estimated: `11134` + // Minimum execution time: 24_657_000 picoseconds. + Weight::from_parts(24_971_000, 0) + .saturating_add(Weight::from_parts(0, 11134)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 34_028_000 picoseconds. + Weight::from_parts(34_697_000, 0) + .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .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 a14da7c7a38a54938bb390d5d2109816162fecf7..99af88812da2be05bd9273585ea7d186be9f8b90 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 @@ -196,7 +196,7 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { XcmGeneric::::clear_transact_status() } fn universal_origin(_: &Junction) -> Weight { - XcmGeneric::::universal_origin() + Weight::MAX } fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { Weight::MAX 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 eaf07aac52cefa88f524e6f3a2180ab9faf2b088..6f5a52de98c39fb7ff5de96c41652be063f56a74 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 @@ -1,41 +1,44 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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_xcm_benchmarks::fungible` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-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("coretime-westend-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./cumulus/templates/xcm-bench-template.hbs +// --chain=coretime-westend-dev // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::fungible -// --chain=asset-hub-westend-dev +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./cumulus/file_header.txt -// --template=./cumulus/templates/xcm-bench-template.hbs -// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/ +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,8 +56,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 20_295_000 picoseconds. - Weight::from_parts(21_142_000, 3593) + // Minimum execution time: 19_401_000 picoseconds. + Weight::from_parts(19_768_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,17 +67,15 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 42_356_000 picoseconds. - Weight::from_parts(43_552_000, 6196) + // Minimum execution time: 42_452_000 picoseconds. + Weight::from_parts(43_126_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: `System::Account` (r:3 w: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) @@ -87,54 +88,49 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `246` - // Estimated: `8799` - // Minimum execution time: 85_553_000 picoseconds. - Weight::from_parts(87_177_000, 8799) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `207` + // Estimated: `6196` + // Minimum execution time: 58_090_000 picoseconds. + Weight::from_parts(59_502_000, 6196) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `Benchmark::Override` (r:0 w:0) + // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn reserve_asset_deposited() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 6_166_000 picoseconds. - Weight::from_parts(6_352_000, 1489) - .saturating_add(T::DbWeight::get().reads(1)) + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } // 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: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `246` - // Estimated: `6196` - // Minimum execution time: 184_462_000 picoseconds. - Weight::from_parts(189_593_000, 6196) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 23_569_000 picoseconds. + Weight::from_parts(24_598_000, 3571) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } pub fn receive_teleported_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_018_000 picoseconds. - Weight::from_parts(3_098_000, 0) + // Minimum execution time: 2_546_000 picoseconds. + Weight::from_parts(2_674_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -142,59 +138,53 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 18_583_000 picoseconds. - Weight::from_parts(19_057_000, 3593) + // Minimum execution time: 16_889_000 picoseconds. + Weight::from_parts(17_350_000, 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`) - // 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: `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: `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 deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `6196` - // Minimum execution time: 56_666_000 picoseconds. - Weight::from_parts(58_152_000, 6196) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `106` + // Estimated: `3593` + // Minimum execution time: 43_964_000 picoseconds. + Weight::from_parts(45_293_000, 3593) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `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: `System::Account` (r:1 w:1) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 44_197_000 picoseconds. - Weight::from_parts(45_573_000, 3610) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 20_704_000 picoseconds. + Weight::from_parts(21_266_000, 3571) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } } 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 fc196abea0f5e61d746760e2b2bf5a7d8d0a476b..74254814bcafc7f67dd20d8fa5dcd8da4337f782 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 @@ -1,41 +1,44 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-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-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-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("coretime-westend-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./cumulus/templates/xcm-bench-template.hbs +// --chain=coretime-westend-dev // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::generic -// --chain=asset-hub-westend-dev +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./cumulus/file_header.txt -// --template=./cumulus/templates/xcm-bench-template.hbs -// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/ +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,128 +52,120 @@ pub struct WeightInfo(PhantomData); impl WeightInfo { // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) // 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: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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 report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `246` - // Estimated: `6196` - // Minimum execution time: 415_033_000 picoseconds. - Weight::from_parts(429_573_000, 6196) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 22_424_000 picoseconds. + Weight::from_parts(23_208_000, 3571) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } pub fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_193_000 picoseconds. - Weight::from_parts(3_620_000, 0) + // Minimum execution time: 1_194_000 picoseconds. + Weight::from_parts(1_306_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn query_response() -> Weight { // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3568` - // Minimum execution time: 8_045_000 picoseconds. - Weight::from_parts(8_402_000, 3568) + // Measured: `32` + // Estimated: `3497` + // Minimum execution time: 6_359_000 picoseconds. + Weight::from_parts(6_585_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: 9_827_000 picoseconds. - Weight::from_parts(10_454_000, 0) + // Minimum execution time: 6_297_000 picoseconds. + Weight::from_parts(6_661_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_330_000 picoseconds. - Weight::from_parts(3_677_000, 0) + // Minimum execution time: 1_778_000 picoseconds. + Weight::from_parts(1_923_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_947_000 picoseconds. - Weight::from_parts(2_083_000, 0) + // Minimum execution time: 1_212_000 picoseconds. + Weight::from_parts(1_314_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_915_000 picoseconds. - Weight::from_parts(1_993_000, 0) + // Minimum execution time: 1_165_000 picoseconds. + Weight::from_parts(1_247_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_918_000 picoseconds. - Weight::from_parts(2_048_000, 0) + // Minimum execution time: 1_173_000 picoseconds. + Weight::from_parts(1_275_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_683_000 picoseconds. - Weight::from_parts(3_064_000, 0) + // Minimum execution time: 1_247_000 picoseconds. + Weight::from_parts(1_332_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_893_000 picoseconds. - Weight::from_parts(2_159_000, 0) + // Minimum execution time: 1_170_000 picoseconds. + Weight::from_parts(1_237_000, 0) } // 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: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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 report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `246` - // Estimated: `6196` - // Minimum execution time: 53_116_000 picoseconds. - Weight::from_parts(54_154_000, 6196) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 19_872_000 picoseconds. + Weight::from_parts(20_453_000, 3571) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn claim_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `160` - // Estimated: `3625` - // Minimum execution time: 12_381_000 picoseconds. - Weight::from_parts(12_693_000, 3625) + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 9_105_000 picoseconds. + Weight::from_parts(9_365_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -178,13 +173,11 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_933_000 picoseconds. - Weight::from_parts(1_983_000, 0) + // Minimum execution time: 1_228_000 picoseconds. + Weight::from_parts(1_293_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) - // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // 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) @@ -197,11 +190,11 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 24_251_000 picoseconds. - Weight::from_parts(24_890_000, 3610) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `74` + // Estimated: `3539` + // Minimum execution time: 19_535_000 picoseconds. + Weight::from_parts(20_139_000, 3539) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:0 w:1) @@ -210,145 +203,127 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_850_000 picoseconds. - Weight::from_parts(4_082_000, 0) + // Minimum execution time: 3_158_000 picoseconds. + Weight::from_parts(3_275_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: 112_248_000 picoseconds. - Weight::from_parts(124_454_000, 0) + // Minimum execution time: 1_539_000 picoseconds. + Weight::from_parts(1_607_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_457_000 picoseconds. - Weight::from_parts(12_060_000, 0) + // Minimum execution time: 1_317_000 picoseconds. + Weight::from_parts(1_427_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_959_000 picoseconds. - Weight::from_parts(2_076_000, 0) + // Minimum execution time: 1_176_000 picoseconds. + Weight::from_parts(1_250_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_920_000 picoseconds. - Weight::from_parts(1_994_000, 0) + // Minimum execution time: 1_202_000 picoseconds. + Weight::from_parts(1_279_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_149_000 picoseconds. - Weight::from_parts(2_394_000, 0) + // Minimum execution time: 1_411_000 picoseconds. + Weight::from_parts(1_463_000, 0) } // 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: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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 query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `246` - // Estimated: `6196` - // Minimum execution time: 58_011_000 picoseconds. - Weight::from_parts(59_306_000, 6196) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 22_991_000 picoseconds. + Weight::from_parts(23_820_000, 3571) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } pub fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_031_000 picoseconds. - Weight::from_parts(5_243_000, 0) + // Minimum execution time: 3_534_000 picoseconds. + Weight::from_parts(3_708_000, 0) } // 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: `System::Account` (r:2 w:2) - // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) // 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 report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `246` - // Estimated: `6196` - // Minimum execution time: 53_078_000 picoseconds. - Weight::from_parts(54_345_000, 6196) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 20_025_000 picoseconds. + Weight::from_parts(20_463_000, 3571) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } pub fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_936_000 picoseconds. - Weight::from_parts(2_002_000, 0) + // Minimum execution time: 1_213_000 picoseconds. + Weight::from_parts(1_290_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_855_000 picoseconds. - Weight::from_parts(1_950_000, 0) + // Minimum execution time: 1_207_000 picoseconds. + Weight::from_parts(1_265_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_882_000 picoseconds. - Weight::from_parts(1_977_000, 0) - } - // Storage: `ParachainInfo::ParachainId` (r:1 w:0) - // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - pub fn universal_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 3_912_000 picoseconds. - Weight::from_parts(4_167_000, 1489) - .saturating_add(T::DbWeight::get().reads(1)) + // Minimum execution time: 1_195_000 picoseconds. + Weight::from_parts(1_231_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_911_000 picoseconds. - Weight::from_parts(1_971_000, 0) + // Minimum execution time: 1_182_000 picoseconds. + Weight::from_parts(1_265_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_990_000 picoseconds. - Weight::from_parts(2_076_000, 0) + // Minimum execution time: 1_165_000 picoseconds. + Weight::from_parts(1_252_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 e57a46877764381b5156614af20488368be7845c..b03c7748fe09181bc9db6da76ce2d8b2bf8cd353 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -15,11 +15,12 @@ // along with Cumulus. If not, see . use super::{ - AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, + AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, Broker, FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; use frame_support::{ + pallet_prelude::PalletInfoAccess, parameter_types, traits::{ConstU32, Contains, Equals, Everything, Nothing}, }; @@ -37,25 +38,26 @@ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, + NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; parameter_types! { - pub const WndRelayLocation: Location = Location::parent(); + pub const TokenRelayLocation: Location = Location::parent(); pub const RelayNetwork: Option = Some(NetworkId::Westend); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into(); + pub BrokerPalletLocation: Location = + PalletInstance(::index() as u8).into(); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub FellowshipLocation: Location = Location::new(1, Parachain(1001)); @@ -75,12 +77,11 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, + IsConcrete, // Do a simple punn to convert an `AccountId32` `Location` into a native chain // `AccountId`: LocationToAccountId, @@ -90,6 +91,23 @@ pub type CurrencyTransactor = CurrencyAdapter< (), >; +/// Means for transacting coretime regions on this chain. +pub type RegionTransactor = NonFungibleAdapter< + // Use this non-fungible implementation: + Broker, + // This adapter will handle coretime regions from the broker pallet. + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports. + (), +>; + +/// Means for transacting assets on this chain. +pub type AssetTransactors = (FungibleTransactor, RegionTransactor); + /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, /// ready for dispatching a transaction with XCM's `Transact`. There is an `OriginKind` that can /// bias the kind of local `Origin` it will become. @@ -152,18 +170,20 @@ impl Contains for SafeCallFilter { pallet_xcm::Call::force_default_xcm_version { .. } ) | RuntimeCall::System( frame_system::Call::set_heap_pages { .. } | - frame_system::Call::set_code { .. } | - frame_system::Call::set_code_without_checks { .. } | - frame_system::Call::authorize_upgrade { .. } | - frame_system::Call::authorize_upgrade_without_checks { .. } | - frame_system::Call::kill_prefix { .. }, + frame_system::Call::set_code { .. } | + frame_system::Call::set_code_without_checks { .. } | + frame_system::Call::authorize_upgrade { .. } | + frame_system::Call::authorize_upgrade_without_checks { .. } | + frame_system::Call::kill_prefix { .. } | + // Should not be in Polkadot/Kusama. Here in order to speed up testing. + frame_system::Call::set_storage { .. }, ) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) | RuntimeCall::Balances(..) | RuntimeCall::CollatorSelection(..) | - RuntimeCall::Sudo(..) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) + RuntimeCall::XcmpQueue(..) | + RuntimeCall::Broker(..) ) } } @@ -178,7 +198,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent, its pluralities (i.e. governance bodies), and the Fellows plurality @@ -210,13 +230,13 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; + type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; - // Coretime chain does not recognize a reserve location for any asset. Users must teleport WND + // Coretime chain does not recognize a reserve location for any asset. Users must teleport ROC // where allowed (e.g. with the Relay Chain). type IsReserve = (); /// Only allow teleportation of WND. - type IsTeleporter = ConcreteAssetFromSystem; + type IsTeleporter = ConcreteAssetFromSystem; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< @@ -224,8 +244,13 @@ impl xcm_executor::Config for XcmConfig { RuntimeCall, MaxInstructions, >; - type Trader = - UsingComponents>; + type Trader = UsingComponents< + WeightToFee, + TokenRelayLocation, + AccountId, + Balances, + ToStakingPot, + >; type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetClaims = PolkadotXcm; diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index e0ab9c590ba965a46915fc89f1e1b0702f36ff7a..199057c3764797bf1da194c8ede174e80fd5d91c 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -100,7 +100,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton-westend"), impl_name: create_runtime_str!("glutton-westend"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -289,8 +289,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, @@ -301,7 +301,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, @@ -316,6 +316,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] @@ -332,7 +333,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -439,6 +440,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); @@ -455,6 +457,7 @@ impl_runtime_apis! { 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: &sp_std::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 0000000000000000000000000000000000000000..e6efa76230823821019e593fda8c5e095e36d4d0 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,119 @@ +// 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() -> 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/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index 5e5e1e01606f9739b8777c5e8e1643dd017945fe..c9781639c3e42889edb5b6e046fae7319551800b 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -13,9 +13,9 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } enumflags2 = { version = "0.7.7" } hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -152,6 +152,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/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 652485a69fdf25a000aa2e52d1d449a447ea7e1c..c5e420785de54e908af65f2d4515d678b9b6f005 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -44,7 +44,7 @@ use parachains_common::{ impls::DealWithFees, message_queue::{NarrowOriginToSibling, ParaIdToSibling}, AccountId, Balance, BlockNumber, Hash, Header, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, - HOURS, NORMAL_DISPATCH_RATIO, + NORMAL_DISPATCH_RATIO, }; use polkadot_runtime_common::{identity_migrator, BlockHashCount, SlowAdjustingFeeUpdate}; use sp_api::impl_runtime_apis; @@ -63,7 +63,7 @@ use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee}; +use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee, time::*}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::latest::prelude::BodyId; use xcm_config::{ @@ -83,8 +83,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, @@ -97,7 +97,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 = ( @@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-rococo"), impl_name: create_runtime_str!("people-rococo"), authoring_version: 1, - spec_version: 1_006_002, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, @@ -178,6 +178,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 = ConstU32<16>; @@ -232,6 +233,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! { @@ -448,13 +450,16 @@ mod benches { [frame_system, SystemBench::] [pallet_balances, Balances] [pallet_identity, Identity] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_collator_selection, CollatorSelection] // XCM @@ -493,7 +498,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -684,6 +689,12 @@ impl_runtime_apis! { use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -692,7 +703,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between People and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -702,6 +713,13 @@ impl_runtime_apis! { fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { None } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } use xcm::latest::prelude::*; 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 0000000000000000000000000000000000000000..1ba2010991fef1dddcc37fa3fccef25599278d82 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 3396a8caea0599574da40135c74bc19f9cf52125..c4cea99ee5aa4bede0ceac4cece3614497bd7134 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs @@ -20,6 +20,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_collator_selection; pub mod pallet_identity; @@ -27,6 +28,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/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 0000000000000000000000000000000000000000..555fd5a32fa874f3f046cbf819a2a4e938b4926b --- /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/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs index 0f793524de9f5ef7da835090f9d81008ba756d59..fabce29b5fd9451f27364c38481d2dac98c430d8 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs @@ -1,40 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("people-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("people-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=people-kusama-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_xcm -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-kusama/src/weights/pallet_xcm.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=people-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,57 +48,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (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`) fn send() -> Weight { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_931_000 picoseconds. - Weight::from_parts(26_340_000, 0) + // Minimum execution time: 17_830_000 picoseconds. + Weight::from_parts(18_411_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: ParachainInfo ParachainId (r:1 w:0) - /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 25_691_000 picoseconds. - Weight::from_parts(25_971_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - fn reserve_transfer_assets() -> 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: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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) @@ -108,18 +80,38 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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`) + fn teleport_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `70` + // Estimated: `3535` + // Minimum execution time: 55_456_000 picoseconds. + Weight::from_parts(56_808_000, 0) + .saturating_add(Weight::from_parts(0, 3535)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn reserve_transfer_assets() -> 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: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `496` - // Estimated: `6208` - // Minimum execution time: 146_932_000 picoseconds. - Weight::from_parts(153_200_000, 0) - .saturating_add(Weight::from_parts(0, 6208)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) + // 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: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -128,189 +120,189 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: PolkadotXcm SupportedVersion (r:0 w:1) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_572_000 picoseconds. - Weight::from_parts(9_924_000, 0) + // Minimum execution time: 5_996_000 picoseconds. + Weight::from_parts(6_154_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm SafeXcmVersion (r:0 w:1) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn force_default_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_997_000 picoseconds. - Weight::from_parts(3_136_000, 0) + // Minimum execution time: 1_768_000 picoseconds. + Weight::from_parts(1_914_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm VersionNotifiers (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm QueryCounter (r:1 w:1) - /// Proof Skipped: PolkadotXcm QueryCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm Queries (r:0 w:1) - /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 30_271_000 picoseconds. - Weight::from_parts(30_819_000, 0) + // Minimum execution time: 24_120_000 picoseconds. + Weight::from_parts(24_745_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: PolkadotXcm VersionNotifiers (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm Queries (r:0 w:1) - /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `3685` - // Minimum execution time: 32_302_000 picoseconds. - Weight::from_parts(32_807_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `255` + // Estimated: `3720` + // Minimum execution time: 26_630_000 picoseconds. + Weight::from_parts(27_289_000, 0) + .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: PolkadotXcm XcmExecutionSuspended (r:0 w:1) - /// Proof Skipped: PolkadotXcm XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `PolkadotXcm::XcmExecutionSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn force_suspension() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_960_000 picoseconds. - Weight::from_parts(3_094_000, 0) + // Minimum execution time: 1_821_000 picoseconds. + Weight::from_parts(1_946_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm SupportedVersion (r:4 w:2) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `10985` - // Minimum execution time: 14_877_000 picoseconds. - Weight::from_parts(15_296_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `89` + // Estimated: `13454` + // Minimum execution time: 16_586_000 picoseconds. + Weight::from_parts(16_977_000, 0) + .saturating_add(Weight::from_parts(0, 13454)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifiers (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `10989` - // Minimum execution time: 14_835_000 picoseconds. - Weight::from_parts(15_115_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `93` + // Estimated: `13458` + // Minimum execution time: 16_923_000 picoseconds. + Weight::from_parts(17_415_000, 0) + .saturating_add(Weight::from_parts(0, 13458)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:5 w:0) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 15_368_000 picoseconds. - Weight::from_parts(15_596_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15946` + // Minimum execution time: 18_596_000 picoseconds. + Weight::from_parts(18_823_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(6)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 28_025_000 picoseconds. - Weight::from_parts(28_524_000, 0) + // Minimum execution time: 23_817_000 picoseconds. + Weight::from_parts(24_520_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:3 w:0) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_166_000 picoseconds. - Weight::from_parts(8_314_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11026` + // Minimum execution time: 11_042_000 picoseconds. + Weight::from_parts(11_578_000, 0) + .saturating_add(Weight::from_parts(0, 11026)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10996` - // Minimum execution time: 14_871_000 picoseconds. - Weight::from_parts(15_374_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `100` + // Estimated: `13465` + // Minimum execution time: 17_306_000 picoseconds. + Weight::from_parts(17_817_000, 0) + .saturating_add(Weight::from_parts(0, 13465)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `11002` - // Minimum execution time: 33_611_000 picoseconds. - Weight::from_parts(34_008_000, 0) - .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `106` + // Estimated: `13471` + // Minimum execution time: 32_141_000 picoseconds. + Weight::from_parts(32_954_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -319,11 +311,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn new_query() -> Weight { // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `1588` - // Minimum execution time: 5_496_000 picoseconds. - Weight::from_parts(5_652_000, 0) - .saturating_add(Weight::from_parts(0, 1588)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 3_410_000 picoseconds. + Weight::from_parts(3_556_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -331,11 +323,23 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn take_response() -> Weight { // Proof Size summary in bytes: - // Measured: `7740` - // Estimated: `11205` - // Minimum execution time: 26_140_000 picoseconds. - Weight::from_parts(26_824_000, 0) - .saturating_add(Weight::from_parts(0, 11205)) + // Measured: `7669` + // Estimated: `11134` + // Minimum execution time: 25_021_000 picoseconds. + Weight::from_parts(25_240_000, 0) + .saturating_add(Weight::from_parts(0, 11134)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 33_801_000 picoseconds. + Weight::from_parts(34_655_000, 0) + .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } 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 c7408b3fa84baed1bd03f8a7bb00077f98698be3..534d6519086205e9159f5064bbbcee2369c6f2b6 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -27,24 +27,23 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, HashedDescription, - IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, + HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -97,8 +96,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -150,13 +148,6 @@ impl Contains for ParentOrParentsPlurality { } } -pub struct ParentOrSiblings; -impl Contains for ParentOrSiblings { - fn contains(location: &Location) -> bool { - matches!(location.unpack(), (1, []) | (1, [Parachain(_)])) - } -} - /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly /// account for proof size weights. /// @@ -216,13 +207,13 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. AllowExplicitUnpaidExecutionFrom, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, @@ -244,7 +235,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; + type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // People chain does not recognize a reserve location for any asset. Users must teleport ROC // where allowed (e.g. with the Relay Chain). diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index c4c76074d75b93b9532ce2efc34988ebae5a0cb2..8d8421332c13d40c46636f7be01143617a9035a5 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -13,9 +13,9 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } enumflags2 = { version = "0.7.7" } hex-literal = { version = "0.4.1" } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -152,6 +152,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/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index b24f6767a717fc0d0245fbeaae3273af60a5919a..dea079a4a98ae6c5ee16aafd0d07f9e2b9dd34d5 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -83,8 +83,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, @@ -97,7 +97,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 = ( @@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-westend"), impl_name: create_runtime_str!("people-westend"), authoring_version: 1, - spec_version: 1_006_001, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, @@ -178,6 +178,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 = ConstU32<16>; @@ -232,6 +233,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! { @@ -448,6 +450,7 @@ mod benches { [frame_system, SystemBench::] [pallet_balances, Balances] [pallet_identity, Identity] + [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] @@ -455,6 +458,7 @@ mod benches { // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus + [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_collator_selection, CollatorSelection] // XCM @@ -493,7 +497,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -684,6 +688,12 @@ impl_runtime_apis! { use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForParentDelivery, + >; + fn reachable_dest() -> Option { Some(Parent.into()) } @@ -692,7 +702,7 @@ impl_runtime_apis! { // Relay/native token can be teleported between People and Relay. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Parent.into()) }, Parent.into(), @@ -702,6 +712,13 @@ impl_runtime_apis! { fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { None } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::parent()), + fun: Fungible(ExistentialDeposit::get()), + } + } } use xcm::latest::prelude::*; 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 0000000000000000000000000000000000000000..7130a62ab6a9c95aaf4938eff3c8a7ca0ed96d40 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,121 @@ +// 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() -> 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 3396a8caea0599574da40135c74bc19f9cf52125..c4cea99ee5aa4bede0ceac4cece3614497bd7134 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs @@ -20,6 +20,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_collator_selection; pub mod pallet_identity; @@ -27,6 +28,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/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 0000000000000000000000000000000000000000..30e4524e586e24247f604e82c0ea974d43ff060c --- /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/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs index d3b60471b850e0fffbad01915aaf461be3d48ae0..c337289243b748d721b60421bccf3349044ef194 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs @@ -1,40 +1,41 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// 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. +// 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_xcm` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, 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-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("people-polkadot-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("people-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./artifacts/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=people-polkadot-dev -// --execution=wasm -// --wasm-execution=compiled -// --pallet=pallet_xcm -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-polkadot/src/weights/pallet_xcm.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=people-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,57 +48,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (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`) fn send() -> Weight { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_783_000 picoseconds. - Weight::from_parts(26_398_000, 0) + // Minimum execution time: 17_856_000 picoseconds. + Weight::from_parts(18_473_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: ParachainInfo ParachainId (r:1 w:0) - /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 25_511_000 picoseconds. - Weight::from_parts(26_120_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - fn reserve_transfer_assets() -> 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: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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) @@ -108,18 +80,38 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// 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`) + fn teleport_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `70` + // Estimated: `3535` + // Minimum execution time: 56_112_000 picoseconds. + Weight::from_parts(57_287_000, 0) + .saturating_add(Weight::from_parts(0, 3535)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn reserve_transfer_assets() -> 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: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `496` - // Estimated: `6208` - // Minimum execution time: 146_932_000 picoseconds. - Weight::from_parts(153_200_000, 0) - .saturating_add(Weight::from_parts(0, 6208)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) + // 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: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -128,189 +120,189 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: PolkadotXcm SupportedVersion (r:0 w:1) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_707_000 picoseconds. - Weight::from_parts(9_874_000, 0) + // Minimum execution time: 6_186_000 picoseconds. + Weight::from_parts(6_420_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm SafeXcmVersion (r:0 w:1) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn force_default_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_073_000 picoseconds. - Weight::from_parts(3_183_000, 0) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(1_999_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm VersionNotifiers (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm QueryCounter (r:1 w:1) - /// Proof Skipped: PolkadotXcm QueryCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm Queries (r:0 w:1) - /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 30_999_000 picoseconds. - Weight::from_parts(31_641_000, 0) + // Minimum execution time: 23_833_000 picoseconds. + Weight::from_parts(24_636_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: PolkadotXcm VersionNotifiers (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm Queries (r:0 w:1) - /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `3685` - // Minimum execution time: 33_036_000 picoseconds. - Weight::from_parts(33_596_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) + // Measured: `255` + // Estimated: `3720` + // Minimum execution time: 26_557_000 picoseconds. + Weight::from_parts(27_275_000, 0) + .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: PolkadotXcm XcmExecutionSuspended (r:0 w:1) - /// Proof Skipped: PolkadotXcm XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `PolkadotXcm::XcmExecutionSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn force_suspension() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_035_000 picoseconds. - Weight::from_parts(3_154_000, 0) + // Minimum execution time: 1_921_000 picoseconds. + Weight::from_parts(2_040_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: PolkadotXcm SupportedVersion (r:4 w:2) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `10985` - // Minimum execution time: 14_805_000 picoseconds. - Weight::from_parts(15_120_000, 0) - .saturating_add(Weight::from_parts(0, 10985)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `89` + // Estimated: `13454` + // Minimum execution time: 16_832_000 picoseconds. + Weight::from_parts(17_312_000, 0) + .saturating_add(Weight::from_parts(0, 13454)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifiers (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `10989` - // Minimum execution time: 14_572_000 picoseconds. - Weight::from_parts(14_909_000, 0) - .saturating_add(Weight::from_parts(0, 10989)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `93` + // Estimated: `13458` + // Minimum execution time: 16_687_000 picoseconds. + Weight::from_parts(17_123_000, 0) + .saturating_add(Weight::from_parts(0, 13458)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:5 w:0) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 15_341_000 picoseconds. - Weight::from_parts(15_708_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15946` + // Minimum execution time: 18_164_000 picoseconds. + Weight::from_parts(18_580_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(6)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 27_840_000 picoseconds. - Weight::from_parts(28_248_000, 0) + // Minimum execution time: 23_577_000 picoseconds. + Weight::from_parts(24_324_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:3 w:0) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `8551` - // Minimum execution time: 8_245_000 picoseconds. - Weight::from_parts(8_523_000, 0) - .saturating_add(Weight::from_parts(0, 8551)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `11026` + // Minimum execution time: 11_014_000 picoseconds. + Weight::from_parts(11_223_000, 0) + .saturating_add(Weight::from_parts(0, 11026)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10996` - // Minimum execution time: 14_780_000 picoseconds. - Weight::from_parts(15_173_000, 0) - .saturating_add(Weight::from_parts(0, 10996)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `100` + // Estimated: `13465` + // Minimum execution time: 16_887_000 picoseconds. + Weight::from_parts(17_361_000, 0) + .saturating_add(Weight::from_parts(0, 13465)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem HostConfiguration (r:1 w:0) - /// Proof Skipped: ParachainSystem HostConfiguration (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParachainSystem PendingUpwardMessages (r:1 w:1) - /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `11002` - // Minimum execution time: 33_422_000 picoseconds. - Weight::from_parts(34_076_000, 0) - .saturating_add(Weight::from_parts(0, 11002)) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `106` + // Estimated: `13471` + // Minimum execution time: 31_705_000 picoseconds. + Weight::from_parts(32_166_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -319,11 +311,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn new_query() -> Weight { // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `1588` - // Minimum execution time: 5_496_000 picoseconds. - Weight::from_parts(5_652_000, 0) - .saturating_add(Weight::from_parts(0, 1588)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 3_568_000 picoseconds. + Weight::from_parts(3_669_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -331,11 +323,23 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn take_response() -> Weight { // Proof Size summary in bytes: - // Measured: `7740` - // Estimated: `11205` - // Minimum execution time: 26_140_000 picoseconds. - Weight::from_parts(26_824_000, 0) - .saturating_add(Weight::from_parts(0, 11205)) + // Measured: `7669` + // Estimated: `11134` + // Minimum execution time: 24_823_000 picoseconds. + Weight::from_parts(25_344_000, 0) + .saturating_add(Weight::from_parts(0, 11134)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 34_516_000 picoseconds. + Weight::from_parts(35_478_000, 0) + .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } 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 baead5234191594906c9b416aade7e67b9bae081..6353a58135258f75ff7be591b538e89e12231652 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -27,24 +27,23 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, HashedDescription, - IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, + HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -97,8 +96,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting the native currency on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -150,13 +148,6 @@ impl Contains for ParentOrParentsPlurality { } } -pub struct ParentOrSiblings; -impl Contains for ParentOrSiblings { - fn contains(location: &Location) -> bool { - matches!(location.unpack(), (1, []) | (1, [Parachain(_)])) - } -} - pub struct FellowsPlurality; impl Contains for FellowsPlurality { fn contains(location: &Location) -> bool { @@ -223,14 +214,14 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent, its pluralities (i.e. governance bodies), and the Fellows plurality // get free execution. AllowExplicitUnpaidExecutionFrom<(ParentOrParentsPlurality, FellowsPlurality)>, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, @@ -252,7 +243,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = CurrencyTransactor; + type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // People does not recognize a reserve location for any asset. Users must teleport WND // where allowed (e.g. with the Relay Chain). diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index ba077ef887947f6f0f2b639f85c10fcb13a06fcb..023c997830238051f3521932d39e2a13fe095d19 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -258,8 +258,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::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, @@ -269,7 +269,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< @@ -300,7 +300,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 457394760d989db4dcd5ba335e1ff2dad46eaaba..fedac36e48d6452ef2b13e3dd88fa4f17a18516b 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -34,15 +34,19 @@ pub mod xcm_config; use codec::{Decode, Encode}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::AggregateMessageOrigin; -use frame_support::unsigned::TransactionValidityError; use scale_info::TypeInfo; 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, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf}, - transaction_validity::{TransactionSource, TransactionValidity}, + traits::{ + AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf, OriginOf, + TransactionExtension, TransactionExtensionBase, ValidateResult, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + }, ApplyExtrinsicResult, }; use sp_std::prelude::*; @@ -275,35 +279,37 @@ construct_runtime! { /// Simple implementation which fails any transaction which is signed. #[derive(Eq, PartialEq, Clone, Default, sp_core::RuntimeDebug, Encode, Decode, TypeInfo)] pub struct DisallowSigned; -impl sp_runtime::traits::SignedExtension for DisallowSigned { + +impl TransactionExtensionBase for DisallowSigned { const IDENTIFIER: &'static str = "DisallowSigned"; - type AccountId = AccountId; - type Call = RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); +} + +impl TransactionExtension for DisallowSigned { + type Val = (); type Pre = (); - fn additional_signed( + fn validate( &self, - ) -> sp_std::result::Result<(), sp_runtime::transaction_validity::TransactionValidityError> { - Ok(()) + _origin: OriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + _context: &mut C, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> ValidateResult { + Err(InvalidTransaction::BadProof.into()) } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) - } - fn validate( - &self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, + _val: Self::Val, + _origin: &OriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { - let i = sp_runtime::transaction_validity::InvalidTransaction::BadProof; - Err(sp_runtime::transaction_validity::TransactionValidityError::Invalid(i)) + _context: &C, + ) -> Result { + Err(InvalidTransaction::BadProof.into()) } } @@ -323,11 +329,11 @@ 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 = DisallowSigned; +/// The extension to the basic transaction logic. +pub type TxExtension = DisallowSigned; /// 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, @@ -357,7 +363,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index a61e05de13fa6dff6e54f583a00683d4a270e429..eda88beb7dabb41bd4075ec5ab6bf8ec2f42d3c8 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -17,6 +17,7 @@ frame-support = { path = "../../../../substrate/frame/support", default-features frame-system = { path = "../../../../substrate/frame/system", default-features = false } pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } pallet-session = { path = "../../../../substrate/frame/session", default-features = false } +pallet-timestamp = { path = "../../../../substrate/frame/timestamp", default-features = false } sp-consensus-aura = { path = "../../../../substrate/primitives/consensus/aura", default-features = false } sp-io = { path = "../../../../substrate/primitives/io", default-features = false } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } @@ -59,6 +60,7 @@ std = [ "pallet-balances/std", "pallet-collator-selection/std", "pallet-session/std", + "pallet-timestamp/std", "pallet-xcm/std", "parachain-info/std", "polkadot-parachain-primitives/std", diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index b4eb57fcb66f412cd697cfd4d6efd1f551ef7eb6..e62daa16a1256fa993a97d82d4f6df96f261018b 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -34,7 +34,7 @@ use polkadot_parachain_primitives::primitives::{ }; use sp_consensus_aura::{SlotDuration, AURA_ENGINE_ID}; use sp_core::{Encode, U256}; -use sp_runtime::{traits::Header, BuildStorage, Digest, DigestItem}; +use sp_runtime::{traits::Header, BuildStorage, Digest, DigestItem, SaturatedConversion}; use xcm::{ latest::{Asset, Location, XcmContext, XcmHash}, prelude::*, @@ -129,6 +129,7 @@ pub trait BasicParachainRuntime: + parachain_info::Config + pallet_collator_selection::Config + cumulus_pallet_parachain_system::Config + + pallet_timestamp::Config { } @@ -140,7 +141,8 @@ where + pallet_xcm::Config + parachain_info::Config + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config, + + cumulus_pallet_parachain_system::Config + + pallet_timestamp::Config, ValidatorIdOf: From>, { } @@ -259,8 +261,10 @@ pub struct RuntimeHelper( ); /// Utility function that advances the chain to the desired block number. /// If an author is provided, that author information is injected to all the blocks in the meantime. -impl - RuntimeHelper +impl< + Runtime: frame_system::Config + cumulus_pallet_parachain_system::Config + pallet_timestamp::Config, + AllPalletsWithoutSystem, + > RuntimeHelper where AccountIdOf: Into<<::RuntimeOrigin as OriginTrait>::AccountId>, @@ -296,6 +300,65 @@ where last_header.expect("run_to_block empty block range") } + pub fn run_to_block_with_finalize(n: u32) -> HeaderFor { + let mut last_header = None; + loop { + let block_number = frame_system::Pallet::::block_number(); + if block_number >= n.into() { + break + } + // Set the new block number and author + let header = frame_system::Pallet::::finalize(); + + let pre_digest = Digest { + logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, block_number.encode())], + }; + frame_system::Pallet::::reset_events(); + + let next_block_number = block_number + 1u32.into(); + frame_system::Pallet::::initialize( + &next_block_number, + &header.hash(), + &pre_digest, + ); + AllPalletsWithoutSystem::on_initialize(next_block_number); + + let parent_head = HeadData(header.encode()); + let sproof_builder = RelayStateSproofBuilder { + para_id: ::SelfParaId::get(), + included_para_head: parent_head.clone().into(), + ..Default::default() + }; + + let (relay_parent_storage_root, relay_chain_state) = + sproof_builder.into_state_root_and_proof(); + let inherent_data = ParachainInherentData { + validation_data: PersistedValidationData { + parent_head, + relay_parent_number: (block_number.saturated_into::() * 2 + 1).into(), + relay_parent_storage_root, + max_pov_size: 100_000_000, + }, + relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + + let _ = cumulus_pallet_parachain_system::Pallet::::set_validation_data( + Runtime::RuntimeOrigin::none(), + inherent_data, + ); + let _ = pallet_timestamp::Pallet::::set( + Runtime::RuntimeOrigin::none(), + 300_u32.into(), + ); + AllPalletsWithoutSystem::on_finalize(next_block_number); + let header = frame_system::Pallet::::finalize(); + last_header = Some(header); + } + last_header.expect("run_to_block empty block range") + } + pub fn root_origin() -> ::RuntimeOrigin { ::RuntimeOrigin::root() } diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs index f78bf9877ec2443a9ce3d754a533f3ee6a3cf14a..1c58df189b673af60bc3e4a9ae7391294287e2aa 100644 --- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs @@ -37,7 +37,8 @@ pub fn change_storage_constant_by_governance_works: From>, StorageConstant: Get, StorageConstantType: Encode + PartialEq + std::fmt::Debug, @@ -107,7 +108,8 @@ pub fn set_storage_keys_by_governance_works( + pallet_xcm::Config + parachain_info::Config + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config, + + cumulus_pallet_parachain_system::Config + + pallet_timestamp::Config, ValidatorIdOf: From>, { let mut runtime = ExtBuilder::::default() diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index dab687c527786366ff1901156c0aec58879ccaf4..5a8b15740e4b10df36609e2a90f9e60f85807041 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -20,7 +20,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } smallvec = "1.11.0" @@ -77,7 +77,6 @@ cumulus-primitives-utility = { path = "../../../../primitives/utility", default- pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } -testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } assets-common = { path = "../../assets/common", default-features = false } [features] @@ -133,7 +132,6 @@ std = [ "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", - "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", @@ -158,6 +156,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/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index bf8dcbc24c8d51d61c70ea6a56fa8865ea32c893..62065619e42f3cb686877cab5033359d97cd7101 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -114,8 +114,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, @@ -128,7 +128,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, @@ -419,6 +419,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = (); } parameter_types! { @@ -608,6 +609,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; @@ -620,6 +634,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 { @@ -668,6 +685,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::] @@ -699,7 +717,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -851,6 +869,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(); @@ -867,6 +886,7 @@ impl_runtime_apis! { 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; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 3fad47576fd6cc5a735e4f4be7546a1d8ce73872..84b8fd9bb0a361fb04ec8cf14fd76caf5b4fcf5b 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -43,14 +43,12 @@ use pallet_xcm::XcmPassthrough; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; use sp_runtime::traits::Zero; -use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; use xcm::latest::prelude::*; -#[allow(deprecated)] use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, - ConvertedConcreteId, CurrencyAdapter, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, + ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, + FungibleAdapter, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, @@ -78,8 +76,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting assets on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type CurrencyTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -136,7 +133,7 @@ pub type ForeignFungiblesTransactor = FungiblesAdapter< ForeignAssets, // Use this currency when it is a fungible asset matching the given location or name: ForeignAssetsConvertedConcreteId, - // Convert an XCM MultiLocation into a local account id: + // Convert an XCM Location into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, @@ -297,7 +294,13 @@ parameter_types! { 0, [xcm::v3::Junction::PalletInstance(50), xcm::v3::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into())] ); - pub EthereumLocation: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]); + + /// The Penpal runtime is utilized for testing with various environment setups. + /// This storage item provides the opportunity to customize testing scenarios + /// by configuring the trusted asset from the `SystemAssetHub`. + /// + /// By default, it is configured as a `SystemAssetHubLocation` and can be modified using `System::set_storage`. + pub storage CustomizableAssetFromSystemAssetHub: Location = SystemAssetHubLocation::get(); } /// Accepts asset with ID `AssetLocation` and is coming from `Origin` chain. @@ -312,11 +315,11 @@ impl, Origin: Get> ContainsPair, NativeAssetFrom, - AssetPrefixFrom, + AssetPrefixFrom, ); pub type TrustedTeleporters = (AssetFromChain,); @@ -328,7 +331,7 @@ impl xcm_executor::Config for XcmConfig { // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = Reserves; + type IsReserve = TrustedReserves; // no teleport trust established with other chains type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 42169e8949f553e1920508e92a059e5b76818099..2023d9abf5d4b4ca2be7d5dd0aa9368065833ae1 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -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 c43d79271de717cbe0273edfdc6a7ba10a96aa01..469f06a1aa6fe42c08532aab003afbace08af504 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -84,14 +84,12 @@ use xcm_executor::traits::JustTry; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, - EnsureXcmOrigin, FixedWeightBounds, IsConcrete, NativeAsset, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - UsingComponents, + EnsureXcmOrigin, FixedWeightBounds, FungibleAdapter, IsConcrete, NativeAsset, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, }; use xcm_executor::XcmExecutor; @@ -109,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("test-parachain"), impl_name: create_runtime_str!("test-parachain"), authoring_version: 1, - spec_version: 1_006_000, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -269,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 { @@ -350,8 +349,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting assets on this chain. -#[allow(deprecated)] -pub type CurrencyTransactor = CurrencyAdapter< +pub type CurrencyTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -647,8 +645,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, @@ -660,7 +658,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, @@ -692,7 +690,7 @@ impl_runtime_apis! { Executive::execute_block(block); } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index cc0bd47cc77337362926c712b26ab7f6ae3d407d..a92e8a4c12ae721dc7c6c06b3f705dcedb87e2d3 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -16,13 +16,13 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.74" -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" -log = "0.4.20" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" +log = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } # Local rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } @@ -38,7 +38,7 @@ coretime-rococo-runtime = { path = "../parachains/runtimes/coretime/coretime-roc coretime-westend-runtime = { path = "../parachains/runtimes/coretime/coretime-westend" } bridge-hub-westend-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-westend" } penpal-runtime = { path = "../parachains/runtimes/testing/penpal" } -jsonrpsee = { version = "0.20.3", features = ["server"] } +jsonrpsee = { version = "0.22", features = ["server"] } people-rococo-runtime = { path = "../parachains/runtimes/people/people-rococo" } people-westend-runtime = { path = "../parachains/runtimes/people/people-westend" } parachains-common = { path = "../parachains/common" } @@ -136,6 +136,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "glutton-westend-runtime/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "parachains-common/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", "people-rococo-runtime/runtime-benchmarks", diff --git a/cumulus/polkadot-parachain/chain-specs/coretime-rococo.json b/cumulus/polkadot-parachain/chain-specs/coretime-rococo.json new file mode 120000 index 0000000000000000000000000000000000000000..6e47a6ad08cc787e2a66f6426b1516769779e995 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/coretime-rococo.json @@ -0,0 +1 @@ +../../parachains/chain-specs/coretime-rococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/coretime-westend.json b/cumulus/polkadot-parachain/chain-specs/coretime-westend.json new file mode 120000 index 0000000000000000000000000000000000000000..80dd771db54fc6067f19fadd883dd2274fb21f9d --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/coretime-westend.json @@ -0,0 +1 @@ +../../parachains/chain-specs/coretime-westend.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 1db826ea7daf82e93c0099807bab7f44642084b3..15e8a1bf11a055e6c5b4950ad07d78cad72f81a8 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -25,7 +25,10 @@ use std::str::FromStr; #[derive(Debug, PartialEq)] pub enum BridgeHubRuntimeType { Kusama, + KusamaLocal, + Polkadot, + PolkadotLocal, Rococo, RococoLocal, @@ -44,7 +47,9 @@ impl FromStr for BridgeHubRuntimeType { fn from_str(value: &str) -> Result { match value { polkadot::BRIDGE_HUB_POLKADOT => Ok(BridgeHubRuntimeType::Polkadot), + polkadot::BRIDGE_HUB_POLKADOT_LOCAL => Ok(BridgeHubRuntimeType::PolkadotLocal), kusama::BRIDGE_HUB_KUSAMA => Ok(BridgeHubRuntimeType::Kusama), + kusama::BRIDGE_HUB_KUSAMA_LOCAL => Ok(BridgeHubRuntimeType::KusamaLocal), westend::BRIDGE_HUB_WESTEND => Ok(BridgeHubRuntimeType::Westend), westend::BRIDGE_HUB_WESTEND_LOCAL => Ok(BridgeHubRuntimeType::WestendLocal), westend::BRIDGE_HUB_WESTEND_DEVELOPMENT => Ok(BridgeHubRuntimeType::WestendDevelopment), @@ -103,6 +108,7 @@ impl BridgeHubRuntimeType { Some("Bob".to_string()), |_| (), ))), + other => Err(std::format!("No default config present for {:?}", other)), } } } @@ -242,6 +248,7 @@ pub mod rococo { /// Sub-module for Kusama setup pub mod kusama { pub(crate) const BRIDGE_HUB_KUSAMA: &str = "bridge-hub-kusama"; + pub(crate) const BRIDGE_HUB_KUSAMA_LOCAL: &str = "bridge-hub-kusama-local"; } /// Sub-module for Westend setup. @@ -358,4 +365,5 @@ pub mod westend { /// Sub-module for Polkadot setup pub mod polkadot { pub(crate) const BRIDGE_HUB_POLKADOT: &str = "bridge-hub-polkadot"; + pub(crate) const BRIDGE_HUB_POLKADOT_LOCAL: &str = "bridge-hub-polkadot-local"; } diff --git a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs index f7c362cbd457639e3409eb1f24d3358186914269..42d56fc80eb3eee2810da1a414a13e346d6f8d17 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs @@ -29,6 +29,8 @@ pub enum CoretimeRuntimeType { // Benchmarks RococoDevelopment, + // Live + Westend, // Local WestendLocal, // Benchmarks @@ -43,6 +45,7 @@ impl FromStr for CoretimeRuntimeType { rococo::CORETIME_ROCOCO => Ok(CoretimeRuntimeType::Rococo), rococo::CORETIME_ROCOCO_LOCAL => Ok(CoretimeRuntimeType::RococoLocal), rococo::CORETIME_ROCOCO_DEVELOPMENT => Ok(CoretimeRuntimeType::RococoDevelopment), + westend::CORETIME_WESTEND => Ok(CoretimeRuntimeType::Westend), westend::CORETIME_WESTEND_LOCAL => Ok(CoretimeRuntimeType::WestendLocal), westend::CORETIME_WESTEND_DEVELOPMENT => Ok(CoretimeRuntimeType::WestendDevelopment), _ => Err(format!("Value '{}' is not configured yet", value)), @@ -56,6 +59,7 @@ impl From for &str { CoretimeRuntimeType::Rococo => rococo::CORETIME_ROCOCO, CoretimeRuntimeType::RococoLocal => rococo::CORETIME_ROCOCO_LOCAL, CoretimeRuntimeType::RococoDevelopment => rococo::CORETIME_ROCOCO_DEVELOPMENT, + CoretimeRuntimeType::Westend => westend::CORETIME_WESTEND, CoretimeRuntimeType::WestendLocal => westend::CORETIME_WESTEND_LOCAL, CoretimeRuntimeType::WestendDevelopment => westend::CORETIME_WESTEND_DEVELOPMENT, } @@ -65,7 +69,7 @@ impl From for &str { impl From for ChainType { fn from(runtime_type: CoretimeRuntimeType) -> Self { match runtime_type { - CoretimeRuntimeType::Rococo => ChainType::Live, + CoretimeRuntimeType::Rococo | CoretimeRuntimeType::Westend => ChainType::Live, CoretimeRuntimeType::RococoLocal | CoretimeRuntimeType::WestendLocal => ChainType::Local, CoretimeRuntimeType::RococoDevelopment | CoretimeRuntimeType::WestendDevelopment => @@ -82,12 +86,15 @@ impl CoretimeRuntimeType { pub fn load_config(&self) -> Result, String> { match self { CoretimeRuntimeType::Rococo => Ok(Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../../../parachains/chain-specs/coretime-rococo.json")[..], + &include_bytes!("../../chain-specs/coretime-rococo.json")[..], )?)), CoretimeRuntimeType::RococoLocal => Ok(Box::new(rococo::local_config(*self, "rococo-local"))), CoretimeRuntimeType::RococoDevelopment => Ok(Box::new(rococo::local_config(*self, "rococo-dev"))), + CoretimeRuntimeType::Westend => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../../parachains/chain-specs/coretime-westend.json")[..], + )?)), CoretimeRuntimeType::WestendLocal => Ok(Box::new(westend::local_config(*self, "westend-local"))), CoretimeRuntimeType::WestendDevelopment => @@ -213,6 +220,7 @@ pub mod westend { use parachains_common::{AccountId, AuraId, Balance}; use sp_core::sr25519; + pub(crate) const CORETIME_WESTEND: &str = "coretime-westend"; pub(crate) const CORETIME_WESTEND_LOCAL: &str = "coretime-westend-local"; pub(crate) const CORETIME_WESTEND_DEVELOPMENT: &str = "coretime-westend-dev"; const CORETIME_WESTEND_ED: Balance = coretime_westend_runtime::ExistentialDeposit::get(); diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 19d067068f48f2b1573b4d6c9b2cfef60a1b9333..9ba7b7876b3ee06f0d61c626d4fa3c234e313ff9 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -23,6 +23,7 @@ use crate::{ }, service::{new_partial, Block}, }; +use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; @@ -398,7 +399,7 @@ macro_rules! construct_partials { Runtime::AssetHubPolkadot => { let $partials = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AssetHubPolkadotAuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AssetHubPolkadotAuraId>, )?; $code }, @@ -412,28 +413,21 @@ macro_rules! construct_partials { Runtime::People(_) => { let $partials = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AuraId>, )?; $code }, Runtime::GluttonWestend | Runtime::Glutton | Runtime::Shell | Runtime::Seedling => { let $partials = new_partial::( &$config, - crate::service::shell_build_import_queue, + crate::service::build_shell_import_queue, )?; $code }, - Runtime::ContractsRococo => { + Runtime::ContractsRococo | Runtime::Penpal(_) | Runtime::Default => { let $partials = new_partial::( &$config, - crate::service::contracts_rococo_build_import_queue, - )?; - $code - }, - Runtime::Penpal(_) | Runtime::Default => { - let $partials = new_partial::( - &$config, - crate::service::rococo_parachain_build_import_queue, + crate::service::build_aura_import_queue, )?; $code }, @@ -449,7 +443,7 @@ macro_rules! construct_async_run { runner.async_run(|$config| { let $components = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AssetHubPolkadotAuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AssetHubPolkadotAuraId>, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) @@ -466,7 +460,7 @@ macro_rules! construct_async_run { runner.async_run(|$config| { let $components = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AuraId>, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) @@ -479,30 +473,20 @@ macro_rules! construct_async_run { runner.async_run(|$config| { let $components = new_partial::( &$config, - crate::service::shell_build_import_queue, + crate::service::build_shell_import_queue, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) }) } - Runtime::ContractsRococo => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::contracts_rococo_build_import_queue, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, - Runtime::Penpal(_) | Runtime::Default => { + Runtime::ContractsRococo | Runtime::Penpal(_) | Runtime::Default => { runner.async_run(|$config| { let $components = new_partial::< RuntimeApi, _, >( &$config, - crate::service::rococo_parachain_build_import_queue, + crate::service::build_aura_import_queue, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) @@ -584,7 +568,7 @@ pub fn run() -> Result<()> { match cmd { BenchmarkCmd::Pallet(cmd) => if cfg!(feature = "runtime-benchmarks") { - runner.sync_run(|config| cmd.run::(config)) + runner.sync_run(|config| cmd.run::, ReclaimHostFunctions>(config)) } else { Err("Benchmarking wasn't enabled when building the node. \ You can enable it with `--features runtime-benchmarks`." @@ -714,25 +698,19 @@ pub fn run() -> Result<()> { .map_err(Into::into), CollectivesPolkadot => - crate::service::start_generic_aura_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), CollectivesWestend => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), Seedling | Shell => - crate::service::start_shell_node::( + crate::service::start_shell_node( config, polkadot_config, collator_options, @@ -755,36 +733,26 @@ pub fn run() -> Result<()> { .map_err(Into::into), BridgeHub(bridge_hub_runtime_type) => match bridge_hub_runtime_type { - chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot => - crate::service::start_generic_aura_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | + chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal => + crate::service::start_generic_aura_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), - chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama => - crate::service::start_generic_aura_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama | + chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaLocal => + crate::service::start_generic_aura_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), chain_spec::bridge_hubs::BridgeHubRuntimeType::Rococo | chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), } @@ -794,12 +762,10 @@ pub fn run() -> Result<()> { chain_spec::coretime::CoretimeRuntimeType::Rococo | chain_spec::coretime::CoretimeRuntimeType::RococoLocal | chain_spec::coretime::CoretimeRuntimeType::RococoDevelopment | + chain_spec::coretime::CoretimeRuntimeType::Westend | chain_spec::coretime::CoretimeRuntimeType::WestendLocal | chain_spec::coretime::CoretimeRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), } @@ -818,10 +784,7 @@ pub fn run() -> Result<()> { .map_err(Into::into), Glutton | GluttonWestend => - crate::service::start_basic_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_basic_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), @@ -833,10 +796,7 @@ pub fn run() -> Result<()> { chain_spec::people::PeopleRuntimeType::Westend | chain_spec::people::PeopleRuntimeType::WestendLocal | chain_spec::people::PeopleRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), } diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs index 76dd7347ccbc35127747e144af7c8705a15022e4..7778d1bf7d2dc0187fe6a0684023a9a4648be596 100644 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs @@ -39,7 +39,7 @@ sp_api::impl_runtime_apis! { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs index 0f01b85ebcf6fa63aabd9115c2ef553c18badea8..880f5d760c74559db87597bce158f8f5e62dbd82 100644 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs @@ -39,7 +39,7 @@ sp_api::impl_runtime_apis! { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index daeeadd5ecee6986b73c540415e8c67d83fc97dd..ddf595ca70c1d675aa66a94daf21036cc8a3295e 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -36,12 +36,13 @@ use cumulus_primitives_core::{ ParaId, }; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +use sc_rpc::DenyUnsafe; use sp_core::Pair; use jsonrpsee::RpcModule; -use crate::{fake_runtime_api::aura::RuntimeApi, rpc}; -pub use parachains_common::{AccountId, Balance, Block, Hash, Header, Nonce}; +use crate::{fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, rpc}; +pub use parachains_common::{AccountId, AuraId, Balance, Block, Hash, Header, Nonce}; use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; use futures::{lock::Mutex, prelude::*}; @@ -68,11 +69,15 @@ use substrate_prometheus_endpoint::Registry; use polkadot_primitives::CollatorPair; #[cfg(not(feature = "runtime-benchmarks"))] -type HostFunctions = sp_io::SubstrateHostFunctions; +type HostFunctions = + (sp_io::SubstrateHostFunctions, cumulus_client_service::storage_proof_size::HostFunctions); #[cfg(feature = "runtime-benchmarks")] -type HostFunctions = - (sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions); +type HostFunctions = ( + sp_io::SubstrateHostFunctions, + cumulus_client_service::storage_proof_size::HostFunctions, + frame_benchmarking::benchmarking::HostFunctions, +); type ParachainClient = TFullClient>; @@ -81,141 +86,6 @@ type ParachainBackend = TFullBackend; type ParachainBlockImport = TParachainBlockImport>, ParachainBackend>; -/// Native executor instance. -pub struct ShellRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for ShellRuntimeExecutor { - type ExtendHostFunctions = (); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - shell_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - shell_runtime::native_version() - } -} - -/// Native Asset Hub Westend (Westmint) executor instance. -pub struct AssetHubWestendExecutor; -impl sc_executor::NativeExecutionDispatch for AssetHubWestendExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - asset_hub_westend_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - asset_hub_westend_runtime::native_version() - } -} - -/// Native Westend Collectives executor instance. -pub struct CollectivesWestendRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for CollectivesWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - collectives_westend_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - collectives_westend_runtime::native_version() - } -} - -/// Native BridgeHubRococo executor instance. -pub struct BridgeHubRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for BridgeHubRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - bridge_hub_rococo_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - bridge_hub_rococo_runtime::native_version() - } -} - -/// Native `CoretimeRococo` executor instance. -pub struct CoretimeRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for CoretimeRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - coretime_rococo_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - coretime_rococo_runtime::native_version() - } -} - -/// Native `CoretimeWestend` executor instance. -pub struct CoretimeWestendRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for CoretimeWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - coretime_westend_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - coretime_westend_runtime::native_version() - } -} - -/// Native contracts executor instance. -pub struct ContractsRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for ContractsRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - contracts_rococo_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - contracts_rococo_runtime::native_version() - } -} - -/// Native Westend Glutton executor instance. -pub struct GluttonWestendRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for GluttonWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - glutton_westend_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - glutton_westend_runtime::native_version() - } -} - -/// Native `PeopleWestend` executor instance. -pub struct PeopleWestendRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for PeopleWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - people_westend_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - people_westend_runtime::native_version() - } -} - -/// Native `PeopleRococo` executor instance. -pub struct PeopleRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for PeopleRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - people_rococo_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - people_rococo_runtime::native_version() - } -} - /// Assembly of PartialComponents (enough to run chain ops subcommands) pub type Service = PartialComponents< ParachainClient, @@ -274,10 +144,11 @@ where .build(); let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts::( + sc_service::new_full_parts_record_import::( config, telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), executor, + true, )?; let client = Arc::new(client); @@ -318,12 +189,11 @@ where }) } -/// Start a shell node with the given parachain `Configuration` and relay chain `Configuration`. +/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. /// -/// This is the actual implementation that is abstract over the executor and the runtime api for -/// shell nodes. +/// This is the actual implementation that is abstract over the executor and the runtime api. #[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_shell_node_impl( +async fn start_node_impl( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, @@ -342,8 +212,15 @@ where + sp_api::ApiExt + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo, - RB: Fn(Arc>) -> Result, sc_service::Error> + + cumulus_primitives_core::CollectCollationInfo + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + frame_rpc_system::AccountNonceApi, + RB: Fn( + DenyUnsafe, + Arc>, + Arc, + Arc>>, + ) -> Result, sc_service::Error> + 'static, BIQ: FnOnce( Arc>, @@ -367,6 +244,7 @@ where CollatorPair, OverseerHandle, Arc>) + Send + Sync>, + Arc, ) -> Result<(), sc_service::Error>, { let parachain_config = prepare_node_config(parachain_config); @@ -378,7 +256,6 @@ where let backend = params.backend.clone(); let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( polkadot_config, ¶chain_config, @@ -410,8 +287,20 @@ where }) .await?; - let rpc_client = client.clone(); - let rpc_builder = Box::new(move |_, _| rpc_ext_builder(rpc_client.clone())); + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend_for_rpc = backend.clone(); + + Box::new(move |deny_unsafe, _| { + rpc_ext_builder( + deny_unsafe, + client.clone(), + backend_for_rpc.clone(), + transaction_pool.clone(), + ) + }) + }; sc_service::spawn_tasks(sc_service::SpawnTasksParams { rpc_builder, @@ -488,6 +377,7 @@ where collator_key.expect("Command line arguments do not allow this. qed"), overseer_handle, announce_block, + backend.clone(), )?; } @@ -496,679 +386,179 @@ where Ok((task_manager, client)) } -/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. -/// -/// This is the actual implementation that is abstract over the executor and the runtime api. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_node_impl( +/// Build the import queue for Aura-based runtimes. +pub fn build_aura_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> { + let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + + cumulus_client_consensus_aura::import_queue::< + sp_consensus_aura::sr25519::AuthorityPair, + _, + _, + _, + _, + _, + >(cumulus_client_consensus_aura::ImportQueueParams { + block_import, + client, + create_inherent_data_providers: move |_, _| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + }, + registry: config.prometheus_registry(), + spawner: &task_manager.spawn_essential_handle(), + telemetry, + }) + .map_err(Into::into) +} + +/// Start a rococo parachain node. +pub async fn start_rococo_parachain_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, - sybil_resistance_level: CollatorSybilResistance, para_id: ParaId, - _rpc_ext_builder: RB, - build_import_queue: BIQ, - start_consensus: SC, hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + build_parachain_rpc_extensions::, + build_aura_import_queue, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + +/// Build the import queue for the shell runtime. +pub fn build_shell_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + _: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> { + cumulus_client_consensus_relay_chain::import_queue( + client, + block_import, + |_, _| async { Ok(()) }, + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + ) + .map_err(Into::into) +} + +fn build_parachain_rpc_extensions( + deny_unsafe: sc_rpc::DenyUnsafe, + client: Arc>, + backend: Arc, + pool: Arc>>, +) -> Result, sc_service::Error> where RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + frame_rpc_system::AccountNonceApi, - RB: Fn(Arc>) -> Result, sc_service::Error>, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, - SC: FnOnce( - Arc>, - ParachainBlockImport, - Option<&Registry>, - Option, - &TaskManager, - Arc, - Arc>>, - Arc>, - KeystorePtr, - Duration, - ParaId, - CollatorPair, - OverseerHandle, - Arc>) + Send + Sync>, - Arc, - ) -> Result<(), sc_service::Error>, { - let parachain_config = prepare_node_config(parachain_config); + let deps = rpc::FullDeps { client, pool, deny_unsafe }; - let params = new_partial::(¶chain_config, build_import_queue)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + rpc::create_full(deps, backend).map_err(Into::into) +} - let client = params.client.clone(); - let backend = params.backend.clone(); +fn build_contracts_rpc_extensions( + deny_unsafe: sc_rpc::DenyUnsafe, + client: Arc>, + _backend: Arc, + pool: Arc>>, +) -> Result, sc_service::Error> { + let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( + crate::rpc::create_contracts_rococo(deps).map_err(Into::into) +} + +/// Start a polkadot-shell parachain node. +pub async fn start_shell_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), + collator_options, + CollatorSybilResistance::Unresistant, // free-for-all consensus + para_id, + |_, _, _, _| Ok(RpcModule::new(())), + build_shell_import_queue, + start_relay_chain_consensus, + hwbench, ) .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::new(¶chain_config.network); +} - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level, - }) - .await?; +enum BuildOnAccess { + Uninitialized(Option R + Send + Sync>>), + Initialized(R), +} - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); +impl BuildOnAccess { + fn get_mut(&mut self) -> &mut R { + loop { + match self { + Self::Uninitialized(f) => { + *self = Self::Initialized((f.take().unwrap())()); + }, + Self::Initialized(ref mut r) => return r, + } + } + } +} - let backend_for_rpc = backend.clone(); - Box::new(move |deny_unsafe, _| { - let deps = rpc::FullDeps { - client: client.clone(), - pool: transaction_pool.clone(), - deny_unsafe, - }; +/// Special [`ParachainConsensus`] implementation that waits for the upgrade from +/// shell to a parachain runtime that implements Aura. +struct WaitForAuraConsensus { + client: Arc, + aura_consensus: Arc>>>>, + relay_chain_consensus: Arc>>>, + _phantom: PhantomData, +} - rpc::create_full(deps, backend_for_rpc.clone()).map_err(Into::into) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); +impl Clone for WaitForAuraConsensus { + fn clone(&self) -> Self { + Self { + client: self.client.clone(), + aura_consensus: self.aura_consensus.clone(), + relay_chain_consensus: self.relay_chain_consensus.clone(), + _phantom: PhantomData, } } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service: sync_service.clone(), - })?; - - if validator { - start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - sync_service.clone(), - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } - - start_network.start_network(); - - Ok((task_manager, client)) } -/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. -/// -/// This is the actual implementation that is abstract over the executor and the runtime api. -/// -/// This node is basic in the sense that it doesn't support functionality like transaction -/// payment. Intended to replace start_shell_node in use for glutton, shell, and seedling. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_basic_lookahead_node_impl( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - sybil_resistance_level: CollatorSybilResistance, - para_id: ParaId, - rpc_ext_builder: RB, - build_import_queue: BIQ, - start_consensus: SC, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +#[async_trait::async_trait] +impl ParachainConsensus for WaitForAuraConsensus where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + frame_rpc_system::AccountNonceApi, - RB: Fn(Arc>) -> Result, sc_service::Error> - + 'static, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, - SC: FnOnce( - Arc>, - ParachainBlockImport, - Option<&Registry>, - Option, - &TaskManager, - Arc, - Arc>>, - Arc>, - KeystorePtr, - Duration, - ParaId, - CollatorPair, - OverseerHandle, - Arc>) + Send + Sync>, - Arc, - ) -> Result<(), sc_service::Error>, -{ - let parachain_config = prepare_node_config(parachain_config); - - let params = new_partial::(¶chain_config, build_import_queue)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( - polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level, - }) - .await?; - - let rpc_client = client.clone(); - let rpc_builder = Box::new(move |_, _| rpc_ext_builder(rpc_client.clone())); - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service: sync_service.clone(), - })?; - - if validator { - start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - sync_service.clone(), - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } - - start_network.start_network(); - - Ok((task_manager, client)) -} - -/// Build the import queue for the rococo parachain runtime. -pub fn rococo_parachain_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; - - cumulus_client_consensus_aura::import_queue::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - >(cumulus_client_consensus_aura::ImportQueueParams { - block_import, - client, - create_inherent_data_providers: move |_, _| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - }, - registry: config.prometheus_registry(), - spawner: &task_manager.spawn_essential_handle(), - telemetry, - }) - .map_err(Into::into) -} - -/// Start a rococo parachain node. -pub async fn start_rococo_parachain_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - rococo_parachain_build_import_queue, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - backend| { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - let proposer = Proposer::new(proposer_factory); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend.clone(), - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; - - let fut = aura::run::< - Block, - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - _, - _, - _, - _, - >(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - }, - hwbench, - ) - .await -} - -/// Build the import queue for the shell runtime. -pub fn shell_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - _: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder, -{ - cumulus_client_consensus_relay_chain::import_queue( - client, - block_import, - |_, _| async { Ok(()) }, - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - ) - .map_err(Into::into) -} - -/// Start a polkadot-shell parachain node. -pub async fn start_shell_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo, -{ - start_shell_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Unresistant, // free-for-all consensus - para_id, - |_| Ok(RpcModule::new(())), - shell_build_import_queue, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - _sync_oracle, - _keystore, - _relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block| { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry, - ); - - let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( - cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { - para_id, - proposer_factory, - block_import, - relay_chain_interface: relay_chain_interface.clone(), - create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let relay_chain_interface = relay_chain_interface.clone(); - async move { - let parachain_inherent = - cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( - relay_parent, - &relay_chain_interface, - &validation_data, - para_id, - ).await; - let parachain_inherent = parachain_inherent.ok_or_else(|| { - Box::::from( - "Failed to create parachain inherent", - ) - })?; - Ok(parachain_inherent) - } - }, - }, - ); - - let spawner = task_manager.spawn_handle(); - - // Required for free-for-all consensus - #[allow(deprecated)] - old_consensus::start_collator_sync(old_consensus::StartCollatorParams { - para_id, - block_status: client.clone(), - announce_block, - overseer_handle, - spawner, - key: collator_key, - parachain_consensus: free_for_all, - runtime_api: client.clone(), - }); - - Ok(()) - }, - hwbench, - ) - .await -} - -enum BuildOnAccess { - Uninitialized(Option R + Send + Sync>>), - Initialized(R), -} - -impl BuildOnAccess { - fn get_mut(&mut self) -> &mut R { - loop { - match self { - Self::Uninitialized(f) => { - *self = Self::Initialized((f.take().unwrap())()); - }, - Self::Initialized(ref mut r) => return r, - } - } - } -} - -/// Special [`ParachainConsensus`] implementation that waits for the upgrade from -/// shell to a parachain runtime that implements Aura. -struct WaitForAuraConsensus { - client: Arc, - aura_consensus: Arc>>>>, - relay_chain_consensus: Arc>>>, - _phantom: PhantomData, -} - -impl Clone for WaitForAuraConsensus { - fn clone(&self) -> Self { - Self { - client: self.client.clone(), - aura_consensus: self.aura_consensus.clone(), - relay_chain_consensus: self.relay_chain_consensus.clone(), - _phantom: PhantomData, - } - } -} - -#[async_trait::async_trait] -impl ParachainConsensus for WaitForAuraConsensus -where - Client: sp_api::ProvideRuntimeApi + Send + Sync, - Client::Api: AuraApi, - AuraId: Send + Codec + Sync, + Client: sp_api::ProvideRuntimeApi + Send + Sync, + Client::Api: AuraApi, + AuraId: Send + Codec + Sync, { async fn produce_candidate( &mut self, @@ -1180,470 +570,64 @@ where .client .runtime_api() .has_api::>(parent.hash()) - .unwrap_or(false) - { - self.aura_consensus - .lock() - .await - .get_mut() - .produce_candidate(parent, relay_parent, validation_data) - .await - } else { - self.relay_chain_consensus - .lock() - .await - .produce_candidate(parent, relay_parent, validation_data) - .await - } - } -} - -struct Verifier { - client: Arc, - aura_verifier: BuildOnAccess>>, - relay_chain_verifier: Box>, - _phantom: PhantomData, -} - -#[async_trait::async_trait] -impl VerifierT for Verifier -where - Client: sp_api::ProvideRuntimeApi + Send + Sync, - Client::Api: AuraApi, - AuraId: Send + Sync + Codec, -{ - async fn verify( - &mut self, - block_import: BlockImportParams, - ) -> Result, String> { - if self - .client - .runtime_api() - .has_api::>(*block_import.header.parent_hash()) - .unwrap_or(false) - { - self.aura_verifier.get_mut().verify(block_import).await - } else { - self.relay_chain_verifier.verify(block_import).await - } - } -} - -/// Build the import queue for Aura-based runtimes. -pub fn aura_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry_handle: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + sp_consensus_aura::AuraApi::Pair as Pair>::Public>, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - let client2 = client.clone(); - - let aura_verifier = move || { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client2).unwrap(); - - Box::new(cumulus_client_consensus_aura::build_verifier::< - ::Pair, - _, - _, - _, - >(cumulus_client_consensus_aura::BuildVerifierParams { - client: client2.clone(), - create_inherent_data_providers: move |_, _| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - }, - telemetry: telemetry_handle, - })) as Box<_> - }; - - let relay_chain_verifier = - Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })) as Box<_>; - - let verifier = Verifier { - client, - relay_chain_verifier, - aura_verifier: BuildOnAccess::Uninitialized(Some(Box::new(aura_verifier))), - _phantom: PhantomData, - }; - - let registry = config.prometheus_registry(); - let spawner = task_manager.spawn_essential_handle(); - - Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) -} - -/// Start an aura powered parachain node. Some system chains use this. -pub async fn start_generic_aura_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - _backend| { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - let proposer = Proposer::new(proposer_factory); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = BasicAuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client, - relay_client: relay_chain_interface, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(500), - collation_request_receiver: None, - }; - - let fut = - basic_aura::run::::Pair, _, _, _, _, _, _, _>(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - }, - hwbench, - ) - .await -} - -/// Uses the lookahead collator to support async backing. -/// -/// Start an aura powered parachain node. Some system chains use this. -pub async fn start_generic_aura_lookahead_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - backend| { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - let proposer = Proposer::new(proposer_factory); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; - - let fut = - aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - }, - hwbench, - ) - .await -} - -/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub -/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and -/// needs to sync and upgrade before it can run `AuraApi` functions. -pub async fn start_asset_hub_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - _backend| { - let relay_chain_interface2 = relay_chain_interface.clone(); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let spawner = task_manager.spawn_handle(); - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - spawner, - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let collation_future = Box::pin(async move { - // Start collating with the `shell` runtime while waiting for an upgrade to an Aura - // compatible runtime. - let mut request_stream = cumulus_client_collator::relay_chain_driven::init( - collator_key.clone(), - para_id, - overseer_handle.clone(), - ) - .await; - while let Some(request) = request_stream.next().await { - let pvd = request.persisted_validation_data().clone(); - let last_head_hash = - match ::Header::decode(&mut &pvd.parent_head.0[..]) { - Ok(header) => header.hash(), - Err(e) => { - log::error!("Could not decode the head data: {e}"); - request.complete(None); - continue - }, - }; - - // Check if we have upgraded to an Aura compatible runtime and transition if - // necessary. - if client - .runtime_api() - .has_api::>(last_head_hash) - .unwrap_or(false) - { - // Respond to this request before transitioning to Aura. - request.complete(None); - break - } - } - - // Move to Aura consensus. - let slot_duration = match cumulus_client_consensus_aura::slot_duration(&*client) { - Ok(d) => d, - Err(e) => { - log::error!("Could not get Aura slot duration: {e}"); - return - }, - }; - - let proposer = Proposer::new(proposer_factory); - - let params = BasicAuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client, - relay_client: relay_chain_interface2, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(500), - collation_request_receiver: Some(request_stream), - }; - - basic_aura::run::::Pair, _, _, _, _, _, _, _>(params) - .await - }); + .unwrap_or(false) + { + self.aura_consensus + .lock() + .await + .get_mut() + .produce_candidate(parent, relay_parent, validation_data) + .await + } else { + self.relay_chain_consensus + .lock() + .await + .produce_candidate(parent, relay_parent, validation_data) + .await + } + } +} - let spawner = task_manager.spawn_essential_handle(); - spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); +struct Verifier { + client: Arc, + aura_verifier: BuildOnAccess>>, + relay_chain_verifier: Box>, + _phantom: PhantomData, +} - Ok(()) - }, - hwbench, - ) - .await +#[async_trait::async_trait] +impl VerifierT for Verifier +where + Client: sp_api::ProvideRuntimeApi + Send + Sync, + Client::Api: AuraApi, + AuraId: Send + Sync + Codec, +{ + async fn verify( + &mut self, + block_import: BlockImportParams, + ) -> Result, String> { + if self + .client + .runtime_api() + .has_api::>(*block_import.header.parent_hash()) + .unwrap_or(false) + { + self.aura_verifier.get_mut().verify(block_import).await + } else { + self.relay_chain_verifier.verify(block_import).await + } + } } -/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub -/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and -/// needs to sync and upgrade before it can run `AuraApi` functions. -/// -/// Uses the lookahead collator to support async backing. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -pub async fn start_asset_hub_lookahead_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +/// Build the import queue for parachain runtimes that started with relay chain consensus and +/// switched to aura. +pub fn build_relay_to_aura_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> where RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue @@ -1652,171 +636,74 @@ where + sp_api::ApiExt + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, + + sp_consensus_aura::AuraApi::Pair as Pair>::Public>, <::Pair as Pair>::Signature: TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - backend| { - let relay_chain_interface2 = relay_chain_interface.clone(); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let spawner = task_manager.spawn_handle(); - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - spawner, - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let collation_future = Box::pin(async move { - // Start collating with the `shell` runtime while waiting for an upgrade to an Aura - // compatible runtime. - let mut request_stream = cumulus_client_collator::relay_chain_driven::init( - collator_key.clone(), - para_id, - overseer_handle.clone(), - ) - .await; - while let Some(request) = request_stream.next().await { - let pvd = request.persisted_validation_data().clone(); - let last_head_hash = - match ::Header::decode(&mut &pvd.parent_head.0[..]) { - Ok(header) => header.hash(), - Err(e) => { - log::error!("Could not decode the head data: {e}"); - request.complete(None); - continue - }, - }; + let verifier_client = client.clone(); - // Check if we have upgraded to an Aura compatible runtime and transition if - // necessary. - if client - .runtime_api() - .has_api::>(last_head_hash) - .unwrap_or(false) - { - // Respond to this request before transitioning to Aura. - request.complete(None); - break - } + let aura_verifier = move || { + Box::new(cumulus_client_consensus_aura::build_verifier::< + ::Pair, + _, + _, + _, + >(cumulus_client_consensus_aura::BuildVerifierParams { + client: verifier_client.clone(), + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = verifier_client.clone(); + async move { + let slot_duration = cumulus_client_consensus_aura::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) } + }, + telemetry: telemetry_handle, + })) as Box<_> + }; - // Move to Aura consensus. - let slot_duration = match cumulus_client_consensus_aura::slot_duration(&*client) { - Ok(d) => d, - Err(e) => { - log::error!("Could not get Aura slot duration: {e}"); - return - }, - }; - - let proposer = Proposer::new(proposer_factory); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface2, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: true, /* we need to always re-initialize for asset-hub moving - * to aura */ - }; + let relay_chain_verifier = + Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })) as Box<_>; - aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params) - .await - }); + let verifier = Verifier { + client, + relay_chain_verifier, + aura_verifier: BuildOnAccess::Uninitialized(Some(Box::new(aura_verifier))), + _phantom: PhantomData, + }; - let spawner = task_manager.spawn_essential_handle(); - spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); + let registry = config.prometheus_registry(); + let spawner = task_manager.spawn_essential_handle(); - Ok(()) - }, - hwbench, - ) - .await + Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) } -/// Start an aura powered parachain node which uses the lookahead collator to support async backing. -/// This node is basic in the sense that its runtime api doesn't include common contents such as -/// transaction payment. Used for aura glutton. -pub async fn start_basic_lookahead_node( +/// Start an aura powered parachain node. Some system chains use this. +pub async fn start_generic_aura_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_basic_lookahead_node_impl::( +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( parachain_config, polkadot_config, collator_options, CollatorSybilResistance::Resistant, // Aura para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, |client, block_import, prometheus_registry, @@ -1831,7 +718,7 @@ where collator_key, overseer_handle, announce_block, - backend| { + _backend| { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( @@ -1850,15 +737,11 @@ where client.clone(), ); - let params = AuraParams { + let params = BasicAuraParams { create_inherent_data_providers: move |_, ()| async move { Ok(()) }, block_import, - para_client: client.clone(), - para_backend: backend.clone(), + para_client: client, relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, sync_oracle, keystore, collator_key, @@ -1868,12 +751,13 @@ where relay_chain_slot_duration, proposer, collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, + // Very limited proposal time. + authoring_duration: Duration::from_millis(500), + collation_request_receiver: None, }; let fut = - aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); + basic_aura::run::::Pair, _, _, _, _, _, _, _>(params); task_manager.spawn_essential_handle().spawn("aura", None, fut); Ok(()) @@ -1883,16 +767,38 @@ where .await } -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_contracts_rococo_node_impl( +/// Uses the lookahead collator to support async backing. +/// +/// Start an aura powered parachain node. Some system chains use this. +pub async fn start_generic_aura_lookahead_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + +/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub +/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and +/// needs to sync and upgrade before it can run `AuraApi` functions. +pub async fn start_asset_hub_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, - sybil_resistance_level: CollatorSybilResistance, para_id: ParaId, - _rpc_ext_builder: RB, - build_import_queue: BIQ, - start_consensus: SC, hwbench: Option, ) -> sc_service::error::Result<(TaskManager, Arc>)> where @@ -1904,228 +810,169 @@ where + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder + cumulus_primitives_core::CollectCollationInfo + + sp_consensus_aura::AuraApi::Pair as Pair>::Public> + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, - RB: Fn(Arc>) -> Result, sc_service::Error>, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, - SC: FnOnce( - Arc>, - ParachainBlockImport, - Option<&Registry>, - Option, - &TaskManager, - Arc, - Arc>>, - Arc>, - KeystorePtr, - Duration, - ParaId, - CollatorPair, - OverseerHandle, - Arc>) + Send + Sync>, - Arc, - ) -> Result<(), sc_service::Error>, + + frame_rpc_system::AccountNonceApi, + <::Pair as Pair>::Signature: + TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, { - let parachain_config = prepare_node_config(parachain_config); - - let params = new_partial::(¶chain_config, build_import_queue)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - let mut task_manager = params.task_manager; - - let (relay_chain_interface, collator_key) = build_relay_chain_interface( + start_node_impl::( + parachain_config, polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level, - }) - .await?; - - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - - Box::new(move |deny_unsafe, _| { - let deps = crate::rpc::FullDeps { - client: client.clone(), - pool: transaction_pool.clone(), - deny_unsafe, - }; - - crate::rpc::create_contracts_rococo(deps).map_err(Into::into) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), + collator_options, + CollatorSybilResistance::Resistant, // Aura para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service: sync_service.clone(), - })?; + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, + |client, + block_import, + prometheus_registry, + telemetry, + task_manager, + relay_chain_interface, + transaction_pool, + sync_oracle, + keystore, + relay_chain_slot_duration, + para_id, + collator_key, + overseer_handle, + announce_block, + _backend| { + let relay_chain_interface2 = relay_chain_interface.clone(); - if validator { - start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - sync_service.clone(), - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); - start_network.start_network(); + let spawner = task_manager.spawn_handle(); - Ok((task_manager, client)) -} + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + spawner, + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); -#[allow(clippy::type_complexity)] -pub fn contracts_rococo_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + let collation_future = Box::pin(async move { + // Start collating with the `shell` runtime while waiting for an upgrade to an Aura + // compatible runtime. + let mut request_stream = cumulus_client_collator::relay_chain_driven::init( + collator_key.clone(), + para_id, + overseer_handle.clone(), + ) + .await; + while let Some(request) = request_stream.next().await { + let pvd = request.persisted_validation_data().clone(); + let last_head_hash = + match ::Header::decode(&mut &pvd.parent_head.0[..]) { + Ok(header) => header.hash(), + Err(e) => { + log::error!("Could not decode the head data: {e}"); + request.complete(None); + continue + }, + }; - cumulus_client_consensus_aura::import_queue::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - >(cumulus_client_consensus_aura::ImportQueueParams { - block_import, - client, - create_inherent_data_providers: move |_, _| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + // Check if we have upgraded to an Aura compatible runtime and transition if + // necessary. + if client + .runtime_api() + .has_api::>(last_head_hash) + .unwrap_or(false) + { + // Respond to this request before transitioning to Aura. + request.complete(None); + break + } + } - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, + // Move to Aura consensus. + let slot_duration = match cumulus_client_consensus_aura::slot_duration(&*client) { + Ok(d) => d, + Err(e) => { + log::error!("Could not get Aura slot duration: {e}"); + return + }, + }; + + let proposer = Proposer::new(proposer_factory); + + let params = BasicAuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client, + relay_client: relay_chain_interface2, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, slot_duration, - ); + relay_chain_slot_duration, + proposer, + collator_service, + // Very limited proposal time. + authoring_duration: Duration::from_millis(500), + collation_request_receiver: Some(request_stream), + }; - Ok((slot, timestamp)) + basic_aura::run::::Pair, _, _, _, _, _, _, _>(params) + .await + }); + + let spawner = task_manager.spawn_essential_handle(); + spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); + + Ok(()) }, - registry: config.prometheus_registry(), - spawner: &task_manager.spawn_essential_handle(), - telemetry, - }) - .map_err(Into::into) + hwbench, + ) + .await } -/// Start a parachain node. -pub async fn start_contracts_rococo_node( +/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub +/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and +/// needs to sync and upgrade before it can run `AuraApi` functions. +/// +/// Uses the lookahead collator to support async backing. +#[sc_tracing::logging::prefix_logs_with("Parachain")] +pub async fn start_asset_hub_lookahead_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_contracts_rococo_node_impl::( +) -> sc_service::error::Result<(TaskManager, Arc>)> +where + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt + + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo + + sp_consensus_aura::AuraApi::Pair as Pair>::Public> + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + frame_rpc_system::AccountNonceApi + + cumulus_primitives_aura::AuraUnincludedSegmentApi, + <::Pair as Pair>::Signature: + TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, +{ + start_node_impl::( parachain_config, polkadot_config, collator_options, CollatorSybilResistance::Resistant, // Aura para_id, - |_| Ok(RpcModule::new(())), - contracts_rococo_build_import_queue, + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, |client, block_import, prometheus_registry, @@ -2141,61 +988,90 @@ pub async fn start_contracts_rococo_node( overseer_handle, announce_block, backend| { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + let relay_chain_interface2 = relay_chain_interface.clone(); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let spawner = task_manager.spawn_handle(); let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), + spawner, client.clone(), transaction_pool, prometheus_registry, telemetry.clone(), ); - let proposer = Proposer::new(proposer_factory); - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); + let collation_future = Box::pin(async move { + // Start collating with the `shell` runtime while waiting for an upgrade to an Aura + // compatible runtime. + let mut request_stream = cumulus_client_collator::relay_chain_driven::init( + collator_key.clone(), + para_id, + overseer_handle.clone(), + ) + .await; + while let Some(request) = request_stream.next().await { + let pvd = request.persisted_validation_data().clone(); + let last_head_hash = + match ::Header::decode(&mut &pvd.parent_head.0[..]) { + Ok(header) => header.hash(), + Err(e) => { + log::error!("Could not decode the head data: {e}"); + request.complete(None); + continue + }, + }; - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend.clone(), - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; + // Check if we have upgraded to an Aura compatible runtime and transition if + // necessary. + if client + .runtime_api() + .has_api::>(last_head_hash) + .unwrap_or(false) + { + // Respond to this request before transitioning to Aura. + request.complete(None); + break + } + } - let fut = aura::run::< - Block, - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - _, - _, - _, - _, - >(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); + // Move to Aura consensus. + let proposer = Proposer::new(proposer_factory); + + let params = AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend, + relay_client: relay_chain_interface2, + code_hash_provider: move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer, + collator_service, + authoring_duration: Duration::from_millis(1500), + reinitialize: true, /* we need to always re-initialize for asset-hub moving + * to aura */ + }; + + aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params) + .await + }); + + let spawner = task_manager.spawn_essential_handle(); + spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); Ok(()) }, @@ -2204,6 +1080,184 @@ pub async fn start_contracts_rococo_node( .await } +/// Start relay-chain consensus that is free for all. Everyone can submit a block, the relay-chain +/// decides what is backed and included. +fn start_relay_chain_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + _sync_oracle: Arc>, + _keystore: KeystorePtr, + _relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + _backend: Arc, +) -> Result<(), sc_service::Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry, + ); + + let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( + cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { + para_id, + proposer_factory, + block_import, + relay_chain_interface: relay_chain_interface.clone(), + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = + cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( + relay_parent, + &relay_chain_interface, + &validation_data, + para_id, + ).await; + let parachain_inherent = parachain_inherent.ok_or_else(|| { + Box::::from( + "Failed to create parachain inherent", + ) + })?; + Ok(parachain_inherent) + } + }, + }, + ); + + let spawner = task_manager.spawn_handle(); + + // Required for free-for-all consensus + #[allow(deprecated)] + old_consensus::start_collator_sync(old_consensus::StartCollatorParams { + para_id, + block_status: client.clone(), + announce_block, + overseer_handle, + spawner, + key: collator_key, + parachain_consensus: free_for_all, + runtime_api: client.clone(), + }); + + Ok(()) +} + +/// Start consensus using the lookahead aura collator. +fn start_lookahead_aura_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + sync_oracle: Arc>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc, +) -> Result<(), sc_service::Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let params = AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend, + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer: Proposer::new(proposer_factory), + collator_service, + authoring_duration: Duration::from_millis(1500), + reinitialize: false, + }; + + let fut = aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); + task_manager.spawn_essential_handle().spawn("aura", None, fut); + + Ok(()) +} + +/// Start an aura powered parachain node which uses the lookahead collator to support async backing. +/// This node is basic in the sense that its runtime api doesn't include common contents such as +/// transaction payment. Used for aura glutton. +pub async fn start_basic_lookahead_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + |_, _, _, _| Ok(RpcModule::new(())), + build_relay_to_aura_import_queue::<_, AuraId>, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + +/// Start a parachain node for Rococo Contracts. +pub async fn start_contracts_rococo_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + build_contracts_rpc_extensions, + build_aura_import_queue, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + /// Checks that the hardware meets the requirements and print a warning otherwise. fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { // Polkadot para-chains should generally use these requirements to ensure that the relay-chain diff --git a/cumulus/primitives/proof-size-hostfunction/src/lib.rs b/cumulus/primitives/proof-size-hostfunction/src/lib.rs index 6da6235e585a343887f87931e375b21bec48c20d..8ebc58ea450d4aea023f2a3af218bbd9eb3546e9 100644 --- a/cumulus/primitives/proof-size-hostfunction/src/lib.rs +++ b/cumulus/primitives/proof-size-hostfunction/src/lib.rs @@ -18,6 +18,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "std")] use sp_externalities::ExternalitiesExt; use sp_runtime_interface::runtime_interface; @@ -35,7 +36,8 @@ pub const PROOF_RECORDING_DISABLED: u64 = u64::MAX; pub trait StorageProofSize { /// Returns the current storage proof size. fn storage_proof_size(&mut self) -> u64 { - self.extension::().map_or(u64::MAX, |e| e.storage_proof_size()) + self.extension::() + .map_or(PROOF_RECORDING_DISABLED, |e| e.storage_proof_size()) } } diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9e8f60783d4dd1e4779e93af3f932b4034a1937a --- /dev/null +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "cumulus-primitives-storage-weight-reclaim" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +description = "Utilities to reclaim storage weight." +license = "Apache-2.0" + +[lints] +workspace = true + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { workspace = true } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } + +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } + +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } + +cumulus-primitives-core = { path = "../../primitives/core", default-features = false } +cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction", default-features = false } +docify = "0.2.7" + +[dev-dependencies] +sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +cumulus-test-runtime = { path = "../../test/runtime" } + +[features] +default = ["std"] +runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +std = [ + "codec/std", + "cumulus-primitives-core/std", + "cumulus-primitives-proof-size-hostfunction/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "sp-trie/std", +] diff --git a/cumulus/primitives/storage-weight-reclaim/src/benchmarking.rs b/cumulus/primitives/storage-weight-reclaim/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..2980d08271a2c8a50c338c84162fe4fe38a55c2e --- /dev/null +++ b/cumulus/primitives/storage-weight-reclaim/src/benchmarking.rs @@ -0,0 +1,70 @@ +// 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. + +//! Benchmarking setup for cumulus-primitives-storage-weight-reclaim + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use frame_benchmarking::{account, v2::*, BenchmarkError}; +use frame_support::pallet_prelude::DispatchClass; +use frame_system::{BlockWeight, RawOrigin}; +use sp_runtime::traits::{DispatchTransaction, Get}; +use sp_std::{ + marker::{Send, Sync}, + prelude::*, +}; + +/// Pallet we're benchmarking here. +pub struct Pallet(frame_system::Pallet); + +#[benchmarks(where + T: Send + Sync, + T::RuntimeCall: Dispatchable +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn storage_weight_reclaim() -> Result<(), BenchmarkError> { + let caller = account("caller", 0, 0); + BlockWeight::::mutate(|current_weight| { + current_weight.set(Weight::from_parts(0, 1000), DispatchClass::Normal); + }); + let base_extrinsic = ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; + let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(0, 200)), + pays_fee: Default::default(), + }; + let len = 0_usize; + let ext = StorageWeightReclaim::::new(); + + #[block] + { + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(post_info)) + .unwrap() + .unwrap(); + } + + assert_eq!(BlockWeight::::get().total().proof_size(), 700 + base_extrinsic.proof_size()); + + Ok(()) + } +} diff --git a/cumulus/primitives/storage-weight-reclaim/src/lib.rs b/cumulus/primitives/storage-weight-reclaim/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..4bb40176b78c012ccb37c1bc0f068ff35c63731c --- /dev/null +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -0,0 +1,207 @@ +// 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. + +//! Mechanism to reclaim PoV proof size weight after an extrinsic has been applied. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use cumulus_primitives_core::Weight; +use cumulus_primitives_proof_size_hostfunction::{ + storage_proof_size::storage_proof_size, PROOF_RECORDING_DISABLED, +}; +use frame_support::{ + dispatch::{DispatchInfo, PostDispatchInfo}, + weights::WeightMeter, +}; +use frame_system::Config; +use scale_info::TypeInfo; +use sp_runtime::{ + impl_tx_ext_default, + traits::{ + DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension, + TransactionExtensionBase, + }, + transaction_validity::TransactionValidityError, + DispatchResult, +}; +use sp_std::marker::PhantomData; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +const LOG_TARGET: &'static str = "runtime::storage_reclaim"; + +/// `StorageWeightReclaimer` is a mechanism for manually reclaiming storage weight. +/// +/// It internally keeps track of the proof size and storage weight at initialization time. At +/// reclaim it computes the real consumed storage weight and refunds excess weight. +/// +/// # Example +#[doc = docify::embed!("src/tests.rs", simple_reclaimer_example)] +pub struct StorageWeightReclaimer { + previous_remaining_proof_size: u64, + previous_reported_proof_size: Option, +} + +impl StorageWeightReclaimer { + /// Creates a new `StorageWeightReclaimer` instance and initializes it with the storage + /// size provided by `weight_meter` and reported proof size from the node. + #[must_use = "Must call `reclaim_with_meter` to reclaim the weight"] + pub fn new(weight_meter: &WeightMeter) -> StorageWeightReclaimer { + let previous_remaining_proof_size = weight_meter.remaining().proof_size(); + let previous_reported_proof_size = get_proof_size(); + Self { previous_remaining_proof_size, previous_reported_proof_size } + } + + /// Check the consumed storage weight and calculate the consumed excess weight. + fn reclaim(&mut self, remaining_weight: Weight) -> Option { + let current_remaining_weight = remaining_weight.proof_size(); + let current_storage_proof_size = get_proof_size()?; + let previous_storage_proof_size = self.previous_reported_proof_size?; + let used_weight = + self.previous_remaining_proof_size.saturating_sub(current_remaining_weight); + let reported_used_size = + current_storage_proof_size.saturating_sub(previous_storage_proof_size); + let reclaimable = used_weight.saturating_sub(reported_used_size); + log::trace!( + target: LOG_TARGET, + "Found reclaimable storage weight. benchmarked: {used_weight}, consumed: {reported_used_size}" + ); + + self.previous_remaining_proof_size = current_remaining_weight.saturating_add(reclaimable); + self.previous_reported_proof_size = Some(current_storage_proof_size); + Some(Weight::from_parts(0, reclaimable)) + } + + /// Check the consumed storage weight and add the reclaimed + /// weight budget back to `weight_meter`. + pub fn reclaim_with_meter(&mut self, weight_meter: &mut WeightMeter) -> Option { + let reclaimed = self.reclaim(weight_meter.remaining())?; + weight_meter.reclaim_proof_size(reclaimed.proof_size()); + Some(reclaimed) + } +} + +/// Returns the current storage proof size from the host side. +/// +/// Returns `None` if proof recording is disabled on the host. +pub fn get_proof_size() -> Option { + let proof_size = storage_proof_size(); + (proof_size != PROOF_RECORDING_DISABLED).then_some(proof_size) +} + +/// Storage weight reclaim mechanism. +/// +/// This extension checks the size of the node-side storage proof +/// before and after executing a given extrinsic. The difference between +/// benchmarked and spent weight can be reclaimed. +#[derive(Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct StorageWeightReclaim(PhantomData); + +impl StorageWeightReclaim { + /// Create a new `StorageWeightReclaim` instance. + pub fn new() -> Self { + Self(Default::default()) + } +} + +impl core::fmt::Debug for StorageWeightReclaim { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let _ = write!(f, "StorageWeightReclaim"); + Ok(()) + } +} + +impl TransactionExtensionBase for StorageWeightReclaim { + const IDENTIFIER: &'static str = "StorageWeightReclaim"; + type Implicit = (); +} + +impl TransactionExtension + for StorageWeightReclaim +where + T::RuntimeCall: Dispatchable, +{ + type Val = (); + type Pre = Option; + + fn prepare( + self, + _val: Self::Val, + _origin: &T::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + _context: &Context, + ) -> Result { + Ok(get_proof_size()) + } + + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + _context: &Context, + ) -> Result<(), TransactionValidityError> { + let Some(pre_dispatch_proof_size) = pre else { + return Ok(()); + }; + + let Some(post_dispatch_proof_size) = get_proof_size() else { + log::debug!( + target: LOG_TARGET, + "Proof recording enabled during pre-dispatch, now disabled. This should not happen." + ); + return Ok(()) + }; + let benchmarked_weight = info.weight.proof_size(); + let consumed_weight = post_dispatch_proof_size.saturating_sub(pre_dispatch_proof_size); + + // 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 storage_size_diff = + benchmarked_weight.saturating_sub(unspent).abs_diff(consumed_weight as u64); + + // This value will be reclaimed by [`frame_system::CheckWeight`], so we need to calculate + // that in. + frame_system::BlockWeight::::mutate(|current| { + if consumed_weight > benchmarked_weight { + log::error!( + target: LOG_TARGET, + "Benchmarked storage weight smaller than consumed storage weight. benchmarked: {benchmarked_weight} consumed: {consumed_weight} unspent: {unspent}" + ); + current.accrue(Weight::from_parts(0, storage_size_diff), info.class) + } else { + log::trace!( + target: LOG_TARGET, + "Reclaiming storage weight. benchmarked: {benchmarked_weight}, consumed: {consumed_weight} unspent: {unspent}" + ); + current.reduce(Weight::from_parts(0, storage_size_diff), info.class) + } + }); + Ok(()) + } + + impl_tx_ext_default!(T::RuntimeCall; Context; 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 0000000000000000000000000000000000000000..631827cf442622ab2e4f18ee05ac3cac440e8077 --- /dev/null +++ b/cumulus/primitives/storage-weight-reclaim/src/tests.rs @@ -0,0 +1,484 @@ +// 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 frame_support::{ + assert_ok, + dispatch::DispatchClass, + weights::{Weight, WeightMeter}, +}; +use frame_system::{BlockWeight, CheckWeight}; +use sp_runtime::{traits::DispatchTransaction, AccountId32, BuildStorage}; +use sp_std::marker::PhantomData; +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 = 0; + +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); + }); +} + +#[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(); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); + // We expect a refund of 400 + assert_ok!(StorageWeightReclaim::::post_dispatch( + pre, + &info, + &post_info, + LEN, + &Ok(()), + &() + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 600); + }) +} + +#[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(); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, None); + + assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); + assert_ok!(StorageWeightReclaim::::post_dispatch( + pre, + &info, + &post_info, + LEN, + &Ok(()), + &() + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1000); + }) +} + +#[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(); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // We expect no refund + assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); + assert_ok!(StorageWeightReclaim::::post_dispatch( + pre, + &info, + &post_info, + LEN, + &Ok(()), + &() + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1100); + }) +} + +#[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(); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); + assert_ok!(StorageWeightReclaim::::post_dispatch( + pre, + &info, + &post_info, + LEN, + &Ok(()), + &() + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 0); + }); +} + +#[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(); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(300)); + + assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); + assert_ok!(StorageWeightReclaim::::post_dispatch( + pre, + &info, + &post_info, + LEN, + &Ok(()), + &() + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 800); + }); +} + +#[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(), + }; + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .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((), &info, &post_info, 0, &Ok(()), &())); + assert_ok!(StorageWeightReclaim::::post_dispatch( + pre, + &info, + &post_info, + LEN, + &Ok(()), + &() + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 900); + }) +} + +#[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(), + }; + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .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((), &info, &post_info, 0, &Ok(()), &())); + assert_ok!(StorageWeightReclaim::::post_dispatch( + pre, + &info, + &post_info, + LEN, + &Ok(()), + &() + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1150); + }) +} + +#[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(), + }; + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + assert_ok!(StorageWeightReclaim::::post_dispatch( + 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((), &info, &post_info, 0, &Ok(()), &())); + + assert_eq!(BlockWeight::::get().total().proof_size(), 900); + }) +} + +#[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(), + }; + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + assert_ok!(StorageWeightReclaim::::post_dispatch( + 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((), &info, &post_info, 0, &Ok(()), &())); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1150); + }) +} + +#[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!(BlockWeight::::get().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/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 27e9fbe3c7eb1157c4dbd2f631d4d63c4088e570..1e2c300b9ba257d2c8fb998689ae45847099dd63 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } @@ -26,7 +26,6 @@ polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", d xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } -pallet-xcm-benchmarks = { path = "../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false } # Cumulus cumulus-primitives-core = { path = "../core", default-features = false } @@ -39,7 +38,6 @@ std = [ "frame-support/std", "log/std", "pallet-asset-conversion/std", - "pallet-xcm-benchmarks/std", "polkadot-runtime-common/std", "polkadot-runtime-parachains/std", "sp-io/std", @@ -54,7 +52,6 @@ runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", "frame-support/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", - "pallet-xcm-benchmarks/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index 0d8921227429c5c1e0f62a4f3c3f93db4ad73bcb..abc391bdcb8ed6ac3682c761e6a0a8d2d0e7f14b 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -760,7 +760,7 @@ mod test_trader { } } -/// Implementation of `pallet_xcm_benchmarks::EnsureDelivery` which helps to ensure delivery to the +/// Implementation of `xcm_builder::EnsureDelivery` which helps to ensure delivery to the /// parent relay chain. Deposits existential deposit for origin (if needed). /// Deposits estimated fee to the origin account (if needed). /// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if neeeded). @@ -774,17 +774,22 @@ impl< XcmConfig: xcm_executor::Config, ExistentialDeposit: Get>, PriceForDelivery: PriceForMessageDelivery, - > pallet_xcm_benchmarks::EnsureDelivery + > xcm_builder::EnsureDelivery for ToParentDeliveryHelper { fn ensure_successful_delivery( origin_ref: &Location, - _dest: &Location, + dest: &Location, fee_reason: xcm_executor::traits::FeeReason, ) -> (Option, Option) { use xcm::latest::{MAX_INSTRUCTIONS_TO_DECODE, MAX_ITEMS_IN_ASSETS}; use xcm_executor::{traits::FeeManager, FeesMode}; + // check if the destination is relay/parent + if dest.ne(&Location::parent()) { + return (None, None); + } + let mut fees_mode = None; if !XcmConfig::FeeManager::is_waived(Some(origin_ref), fee_reason) { // if not waived, we need to set up accounts for paying and receiving fees diff --git a/cumulus/scripts/create_coretime_westend_spec.sh b/cumulus/scripts/create_coretime_westend_spec.sh index 90996f4a74f47f9783a29ff2ce358920be810641..516dc06ac6660c0c1f9d565d88a9ae7d132ade9e 100755 --- a/cumulus/scripts/create_coretime_westend_spec.sh +++ b/cumulus/scripts/create_coretime_westend_spec.sh @@ -39,13 +39,7 @@ cat chain-spec-plain.json | jq --rawfile code rt-hex.txt '.genesis.runtimeGenesi | jq '.chainType = "Live"' \ | jq '.bootNodes = [ "/dns/westend-coretime-collator-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP93Dzk8T7GWxyWw9jhLcz8Pksokk3R9vL2eEH337bNkT", - "/dns/westend-coretime-collator-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH", - "/dns/westend-coretime-collator-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWAys2hVpF7AN8hYGnu1T6XYFRGKeBFqD8q5LUcvWXRLg8", - "/dns/westend-coretime-collator-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWSGgmiRryoi7A3qAmeYWgmVeGQkk66PrhDjJ6ZPP555as", - "/dns/westend-coretime-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWP93Dzk8T7GWxyWw9jhLcz8Pksokk3R9vL2eEH337bNkT", - "/dns/westend-coretime-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH", - "/dns/westend-coretime-connect-2.polkadot.io/tcp/443/wss/p2p/12D3KooWAys2hVpF7AN8hYGnu1T6XYFRGKeBFqD8q5LUcvWXRLg8", - "/dns/westend-coretime-connect-3.polkadot.io/tcp/443/wss/p2p/12D3KooWSGgmiRryoi7A3qAmeYWgmVeGQkk66PrhDjJ6ZPP555as", + "/dns/westend-coretime-collator-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH" ]' \ | jq '.relay_chain = "westend"' \ | jq --argjson para_id $para_id '.para_id = $para_id' \ @@ -53,37 +47,21 @@ cat chain-spec-plain.json | jq --rawfile code rt-hex.txt '.genesis.runtimeGenesi | jq '.genesis.runtimeGenesis.patch.balances.balances = []' \ | jq '.genesis.runtimeGenesis.patch.collatorSelection.invulnerables = [ "5GKXTtB7RG3mLJ2kT4AkDXoxvKCFDVUdwyRmeMEbX3gBwcGi", - "5DknBCD1h49nc8eqnm6XtHz3bMQm5hfMuGYcLenRfCmpnBJG", - "5D52g9Mt9jQnZn6hwYhv649QYqGwhjygxkpb6rm3FYzYHEs3", - "5Egx2B41PYj8uvuhkNJeucA54h6Xmi7ZH9wqrZLwj3CuvQKA" + "5DknBCD1h49nc8eqnm6XtHz3bMQm5hfMuGYcLenRfCmpnBJG" ]' \ | jq '.genesis.runtimeGenesis.patch.session.keys = [ [ "5GKXTtB7RG3mLJ2kT4AkDXoxvKCFDVUdwyRmeMEbX3gBwcGi", "5GKXTtB7RG3mLJ2kT4AkDXoxvKCFDVUdwyRmeMEbX3gBwcGi", { - "aura": "0xbc3ea120d2991b75447b0b53cd8623970a0f6d98fa2701036c74d94e6b79252c" + "aura": "5GKXTtB7RG3mLJ2kT4AkDXoxvKCFDVUdwyRmeMEbX3gBwcGi" } ], [ "5DknBCD1h49nc8eqnm6XtHz3bMQm5hfMuGYcLenRfCmpnBJG", "5DknBCD1h49nc8eqnm6XtHz3bMQm5hfMuGYcLenRfCmpnBJG", { - "aura": "0x4acc970c28713ec93bf925352d3023418fdf89933227e1e2fdae8481103dfe28" - } - ], - [ - "5D52g9Mt9jQnZn6hwYhv649QYqGwhjygxkpb6rm3FYzYHEs3", - "5D52g9Mt9jQnZn6hwYhv649QYqGwhjygxkpb6rm3FYzYHEs3", - { - "aura": "0x2c7b95155708c10616b6f1a77a84f3d92c9a0272609ed24dbb7e6bdb81b53e76" - } - ], - [ - "5Egx2B41PYj8uvuhkNJeucA54h6Xmi7ZH9wqrZLwj3CuvQKA", - "5Egx2B41PYj8uvuhkNJeucA54h6Xmi7ZH9wqrZLwj3CuvQKA", - { - "aura": "0x741cfb39ec61bc76824ccec62d61670a80a890e0e21d58817f84040d3ec54474" + "aura": "5DknBCD1h49nc8eqnm6XtHz3bMQm5hfMuGYcLenRfCmpnBJG" } ] ]' \ diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 7190172101cb509f7dd7c19ad25dc6d4d54036e7..9dfa6ecb3513e42a4d85615a3c844ab98e451ad9 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -41,13 +41,16 @@ cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } +cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-weight-reclaim" } [features] runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", + "cumulus-primitives-storage-weight-reclaim/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 df63f683de6b4312a953bbbf9f03862eac7ce451..9239ff0f23eeb062d1eaefbe2341720e38178f07 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -19,7 +19,7 @@ mod block_builder; use codec::{Decode, Encode}; use runtime::{ - Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedExtra, SignedPayload, + Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedPayload, TxExtension, UncheckedExtrinsic, VERSION, }; use sc_executor::HeapAllocStrategy; @@ -125,7 +125,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 @@ -143,7 +143,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(), @@ -151,14 +151,16 @@ pub fn generate_extrinsic_with_pair( frame_system::CheckNonce::::from(nonce), 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(), - ((), VERSION.spec_version, genesis_block, current_block_hash, (), (), ()), + tx_ext.clone(), + ((), VERSION.spec_version, genesis_block, current_block_hash, (), (), (), ()), ); let signature = raw_payload.using_encoded(|e| origin.sign(e)); @@ -166,7 +168,7 @@ pub fn generate_extrinsic_with_pair( function, origin.public().into(), Signature::Sr25519(signature), - extra, + tx_ext, ) } @@ -203,13 +205,16 @@ pub fn validate_block( let mut ext_ext = ext.ext(); let heap_pages = HeapAllocStrategy::Static { extra_pages: 1024 }; - let executor = WasmExecutor::::builder() - .with_execution_method(WasmExecutionMethod::default()) - .with_max_runtime_instances(1) - .with_runtime_cache_size(2) - .with_onchain_heap_alloc_strategy(heap_pages) - .with_offchain_heap_alloc_strategy(heap_pages) - .build(); + let executor = WasmExecutor::<( + sp_io::SubstrateHostFunctions, + cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions, + )>::builder() + .with_execution_method(WasmExecutionMethod::default()) + .with_max_runtime_instances(1) + .with_runtime_cache_size(2) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .build(); executor .uncached_call( diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 5902a62512bed772318145ccdb954ff2dfef4c92..449a8b819bc074e0c891d99d6fa2f42480f56ce6 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -39,6 +39,7 @@ sp-version = { path = "../../../substrate/primitives/version", default-features # Cumulus cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-weight-reclaim", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } @@ -49,6 +50,7 @@ std = [ "codec/std", "cumulus-pallet-parachain-system/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "frame-executive/std", "frame-support/std", "frame-system-rpc-runtime-api/std", diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 6068f895c83bf6adba5e2d7fa68b3aa2b8821204..154948a24b48111c882fa76008007c7e7fdb861a 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -246,6 +246,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 { @@ -322,8 +323,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, @@ -331,10 +332,11 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// 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, @@ -345,7 +347,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; @@ -376,7 +378,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index c17cdf35419a22b932b164d0e3a71cce2525ff61..39e8aeba433ab52f2bfb151ca78a73e8d30c4185 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -14,13 +14,13 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.74" -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.5.1", features = ["async_tokio"] } -jsonrpsee = { version = "0.20.3", features = ["server"] } +jsonrpsee = { version = "0.22", features = ["server"] } rand = "0.8.5" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } tokio = { version = "1.32.0", features = ["macros"] } tracing = "0.1.37" url = "2.4.0" @@ -81,6 +81,7 @@ cumulus-relay-chain-minimal-node = { path = "../../client/relay-chain-minimal-no cumulus-client-pov-recovery = { path = "../../client/pov-recovery" } cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } +cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-weight-reclaim" } pallet-timestamp = { path = "../../../substrate/frame/timestamp" } [dev-dependencies] @@ -103,10 +104,12 @@ substrate-test-utils = { path = "../../../substrate/test-utils" } runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-primitives-core/runtime-benchmarks", + "cumulus-primitives-storage-weight-reclaim/runtime-benchmarks", "cumulus-test-client/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-im-online/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/src/bench_utils.rs b/cumulus/test/service/src/bench_utils.rs index 4ace894b392aa2393741572249ed35f0a7101845..15128b23787987f22d2da6f409e2a7d6702c0095 100644 --- a/cumulus/test/service/src/bench_utils.rs +++ b/cumulus/test/service/src/bench_utils.rs @@ -69,7 +69,7 @@ pub fn extrinsic_set_time(client: &TestClient) -> OpaqueExtrinsic { let timestamp = best_number as u64 * cumulus_test_runtime::MinimumPeriod::get(); cumulus_test_runtime::UncheckedExtrinsic { - signature: None, + preamble: sp_runtime::generic::Preamble::Bare, function: cumulus_test_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: timestamp, }), @@ -102,7 +102,7 @@ pub fn extrinsic_set_validation_data( }; cumulus_test_runtime::UncheckedExtrinsic { - signature: None, + preamble: sp_runtime::generic::Preamble::Bare, function: cumulus_test_runtime::RuntimeCall::ParachainSystem( cumulus_pallet_parachain_system::Call::set_validation_data { data }, ), diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index aa2c4af97dfddd83e447bbf92f3b133daa30ce75..f05dc5f180f5a9ec526117fd980042ca7420e949 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -67,7 +67,7 @@ use sc_network::{ use sc_service::{ config::{ BlocksPruning, DatabaseSource, KeystoreConfig, MultiaddrWithPeerId, NetworkConfiguration, - OffchainWorkerConfig, PruningMode, WasmExecutionMethod, + OffchainWorkerConfig, PruningMode, RpcBatchRequestConfig, WasmExecutionMethod, }, BasePath, ChainSpec as ChainSpecService, Configuration, Error as ServiceError, PartialComponents, Role, RpcHandlers, TFullBackend, TFullClient, TaskManager, @@ -112,7 +112,7 @@ pub type AnnounceBlockFn = Arc>) + Send + Sync>; pub struct RuntimeExecutor; impl sc_executor::NativeExecutionDispatch for RuntimeExecutor { - type ExtendHostFunctions = (); + type ExtendHostFunctions = cumulus_client_service::storage_proof_size::HostFunctions; fn dispatch(method: &str, data: &[u8]) -> Option> { cumulus_test_runtime::api::dispatch(method, data) @@ -801,6 +801,8 @@ pub fn node_config( rpc_max_subs_per_conn: Default::default(), rpc_port: 9945, rpc_message_buffer_capacity: Default::default(), + rpc_batch_config: RpcBatchRequestConfig::Unlimited, + rpc_rate_limit: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, @@ -881,7 +883,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(), @@ -892,18 +894,20 @@ pub fn construct_extrinsic( frame_system::CheckNonce::::from(nonce), 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(), - ((), runtime::VERSION.spec_version, genesis_block, current_block_hash, (), (), ()), + 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(), runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) } diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index fb37fd01765e1623b1e412262948e1baae14f8d0..6b45770a8e3df47cb083dba5a8a0eeed1759e338 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } paste = "1.0.14" -log = { version = "0.4.20", default-features = false } +log = { workspace = true } lazy_static = "1.4.0" impl-trait-for-tuples = "0.2.2" diff --git a/cumulus/zombienet/tests/0002-pov_recovery.toml b/cumulus/zombienet/tests/0002-pov_recovery.toml index fe42fd4b2f6681154e89d5e7274618a8f307dfab..15a61eba2a0342bce55f805473d2c3ba9b51c7f8 100644 --- a/cumulus/zombienet/tests/0002-pov_recovery.toml +++ b/cumulus/zombienet/tests/0002-pov_recovery.toml @@ -4,7 +4,7 @@ default_command = "polkadot" chain = "rococo-local" -[relaychain.genesis.runtimeGenesis.patch.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] # set parameters such that collators only connect to 1 validator as a backing group max_validators_per_core = 1 group_rotation_frequency = 100 # 10 mins diff --git a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..4bfb73acda05880ef49570594d0769d1e5e4b147 --- /dev/null +++ b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile @@ -0,0 +1,58 @@ +# 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:v2023-11-07-rococo-westend-initial-relayer + +# metadata +ARG VCS_REF +ARG BUILD_DATE +ARG IMAGE_NAME + +# we need `substrate-relay` binary, built elsewhere +FROM ${SUBSTRATE_RELAY_IMAGE} as relay-builder + +# the base image is the zombienet image - we are planning to run zombienet tests using native +# provider here +FROM ${ZOMBIENET_IMAGE} + +LABEL io.parity.image.authors="devops-team@parity.io" \ + io.parity.image.vendor="Parity Technologies" \ + io.parity.image.title="${IMAGE_NAME}" \ + io.parity.image.description="Bridges Zombienet tests." \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile" \ + io.parity.image.revision="${VCS_REF}" \ + io.parity.image.created="${BUILD_DATE}" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/bridges/testing" + +# show backtraces +ENV RUST_BACKTRACE 1 +USER root + +# for native provider to work (TODO: fix in zn docker?) +RUN apt-get update && apt-get install -y procps sudo +RUN yarn global add @polkadot/api-cli + +# add polkadot binary to the docker image +COPY ./artifacts/polkadot /usr/local/bin/ +COPY ./artifacts/polkadot-execute-worker /usr/local/bin/ +COPY ./artifacts/polkadot-prepare-worker /usr/local/bin/ +# add polkadot-parachain binary to the docker image +COPY ./artifacts/polkadot-parachain /usr/local/bin +# copy substrate-relay to the docker image +COPY --from=relay-builder /home/user/substrate-relay /usr/local/bin/ +# we need bridges zombienet runner and tests +RUN mkdir -p /home/nonroot/bridges-polkadot-sdk +COPY ./artifacts/bridges-polkadot-sdk /home/nonroot/bridges-polkadot-sdk +# also prepare `generate_hex_encoded_call` for running +RUN set -eux; \ + cd /home/nonroot/bridges-polkadot-sdk/bridges/testing/framework/utils/generate_hex_encoded_call; \ + npm install + +# check if executable works in this container +USER nonroot +RUN /usr/local/bin/polkadot --version +RUN /usr/local/bin/polkadot-parachain --version +RUN /usr/local/bin/substrate-relay --version + +# https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:{PORT}#/explorer +EXPOSE 9942 9910 8943 9945 9010 8945 diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 6d681d78f367abff313c63adb1559ea6aa06dbc7..e73be2779a99426203e209da846f938c0f73cceb 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -18,10 +18,16 @@ Rococo. To easily refer to a release, it shall be named by its date in the form ## Crate -We try to follow [SemVer 2.0.0](https://semver.org/) as best as possible for versioning our crates. SemVer requires a -piece of software to first declare a public API. The public API of the Polkadot SDK is hereby declared as the sum of all -crates' public APIs. +We try to follow [SemVer 2.0.0](https://semver.org/) as best as possible for versioning our crates. The definitions of +`major`, `minor` and `patch` version for Rust crates are slightly altered from their standard for pre `1.0.0` versions. +Quoting [rust-lang.org](https://doc.rust-lang.org/cargo/reference/semver.html): +>Initial development releases starting with “0.y.z” can treat changes in “y” as a major release, and “z” as a minor +release. “0.0.z” releases are always major changes. This is because Cargo uses the convention that only changes in the +left-most non-zero component are considered incompatible. + +SemVer requires a piece of software to first declare a public API. The public API of the Polkadot SDK +is hereby declared as the sum of all crates' public APIs. Inductively, the public API of our library crates is declared as all public items that are neither: - Inside a `__private` module diff --git a/docs/mermaid/IA.mmd b/docs/mermaid/IA.mmd index 93d3e92814cf1307fa7c0ea9f290ed21edae58fb..4eb50bcf96a8932de3fa90748fcfeb3ca7f02a5f 100644 --- a/docs/mermaid/IA.mmd +++ b/docs/mermaid/IA.mmd @@ -3,7 +3,7 @@ flowchart devhub --> polkadot_sdk devhub --> reference_docs - devhub --> tutorial + devhub --> guides polkadot_sdk --> substrate polkadot_sdk --> frame diff --git a/docs/mermaid/outer_runtime_types.mmd b/docs/mermaid/outer_runtime_types.mmd new file mode 100644 index 0000000000000000000000000000000000000000..c909df16af1ffbb697e3d363634fa218005a9c32 --- /dev/null +++ b/docs/mermaid/outer_runtime_types.mmd @@ -0,0 +1,3 @@ +flowchart LR + RuntimeCall --"TryInto"--> PalletCall + PalletCall --"Into"--> RuntimeCall diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index c998a601486aa1ef15c2481180eb9db41a3af29b..8b498d407c02574a645420ea3d221b49177d7411 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -17,12 +17,16 @@ workspace = true # Needed for all FRAME-based code parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } -frame = { path = "../../substrate/frame", features = ["experimental", "runtime"] } +frame = { path = "../../substrate/frame", features = [ + "experimental", + "runtime", +] } pallet-examples = { path = "../../substrate/frame/examples" } pallet-default-config-example = { path = "../../substrate/frame/examples/default-config" } +pallet-example-offchain-worker = { path = "../../substrate/frame/examples/offchain-worker" } # How we build docs in rust-docs -simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b" } +simple-mermaid = "0.1.1" docify = "0.2.7" # Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. @@ -30,8 +34,12 @@ node-cli = { package = "staging-node-cli", path = "../../substrate/bin/node/cli" kitchensink-runtime = { path = "../../substrate/bin/node/runtime" } chain-spec-builder = { package = "staging-chain-spec-builder", path = "../../substrate/bin/utils/chain-spec-builder" } subkey = { path = "../../substrate/bin/utils/subkey" } +frame-system = { path = "../../substrate/frame/system", default-features = false } +frame-support = { path = "../../substrate/frame/support", default-features = false } +frame-executive = { path = "../../substrate/frame/executive", default-features = false } +pallet-example-single-block-migrations = { path = "../../substrate/frame/examples/single-block-migrations" } -# Substrate +# Substrate Client sc-network = { path = "../../substrate/client/network" } sc-rpc-api = { path = "../../substrate/client/rpc-api" } sc-rpc = { path = "../../substrate/client/rpc" } @@ -43,6 +51,7 @@ sc-consensus-grandpa = { path = "../../substrate/client/consensus/grandpa" } sc-consensus-beefy = { path = "../../substrate/client/consensus/beefy" } sc-consensus-manual-seal = { path = "../../substrate/client/consensus/manual-seal" } sc-consensus-pow = { path = "../../substrate/client/consensus/pow" } + substrate-wasm-builder = { path = "../../substrate/utils/wasm-builder" } # Cumulus @@ -52,7 +61,19 @@ cumulus-pallet-parachain-system = { path = "../../cumulus/pallets/parachain-syst ] } parachain-info = { package = "staging-parachain-info", path = "../../cumulus/parachains/pallets/parachain-info" } pallet-aura = { path = "../../substrate/frame/aura", default-features = false } + +# Pallets and FRAME internals pallet-timestamp = { path = "../../substrate/frame/timestamp" } +pallet-balances = { path = "../../substrate/frame/balances" } +pallet-assets = { path = "../../substrate/frame/assets" } +pallet-transaction-payment = { path = "../../substrate/frame/transaction-payment" } +pallet-utility = { path = "../../substrate/frame/utility" } +pallet-multisig = { path = "../../substrate/frame/multisig" } +pallet-proxy = { path = "../../substrate/frame/proxy" } +pallet-authorship = { path = "../../substrate/frame/authorship" } +pallet-collective = { path = "../../substrate/frame/collective" } +pallet-democracy = { path = "../../substrate/frame/democracy" } +pallet-scheduler = { path = "../../substrate/frame/scheduler" } # Primitives sp-io = { path = "../../substrate/primitives/io" } @@ -60,10 +81,11 @@ sp-api = { path = "../../substrate/primitives/api" } sp-core = { path = "../../substrate/primitives/core" } sp-keyring = { path = "../../substrate/primitives/keyring" } sp-runtime = { path = "../../substrate/primitives/runtime" } +sp-offchain = { path = "../../substrate/primitives/offchain" } +sp-version = { path = "../../substrate/primitives/version" } -[dev-dependencies] -parity-scale-codec = "3.6.5" -scale-info = "2.9.0" +# XCM +xcm = { package = "staging-xcm", path = "../../polkadot/xcm" } [features] experimental = ["pallet-aura/experimental"] diff --git a/docs/sdk/headers/header.html b/docs/sdk/headers/header.html new file mode 100644 index 0000000000000000000000000000000000000000..e28458c4ccc791d9a72613ffb530b685828ea828 --- /dev/null +++ b/docs/sdk/headers/header.html @@ -0,0 +1,144 @@ + + + diff --git a/docs/sdk/headers/theme.css b/docs/sdk/headers/theme.css new file mode 100644 index 0000000000000000000000000000000000000000..a488e15c36b70ee76b14f429434daf0717bc0320 --- /dev/null +++ b/docs/sdk/headers/theme.css @@ -0,0 +1,17 @@ +:root { + --polkadot-pink: #E6007A; + --polkadot-green: #56F39A; + --polkadot-lime: #D3FF33; + --polkadot-cyan: #00B2FF; + --polkadot-purple: #552BBF; +} + +body.sdk-docs { + nav.sidebar>div.sidebar-crate>a>img { + width: 190px; + } + + nav.sidebar { + flex: 0 0 250px; + } +} diff --git a/docs/sdk/headers/toc.html b/docs/sdk/headers/toc.html deleted file mode 100644 index a4a074cb4f3153cb135da8608462d4ecf59144cb..0000000000000000000000000000000000000000 --- a/docs/sdk/headers/toc.html +++ /dev/null @@ -1,54 +0,0 @@ - - diff --git a/docs/sdk/src/guides/your_first_pallet/mod.rs b/docs/sdk/src/guides/your_first_pallet/mod.rs index 29cdda36ed15ba3fcf964494732fc8364defff45..6a26292482477a712f34b787b5c82b6cebab9947 100644 --- a/docs/sdk/src/guides/your_first_pallet/mod.rs +++ b/docs/sdk/src/guides/your_first_pallet/mod.rs @@ -128,8 +128,8 @@ //! //! Recall that within our pallet, (almost) all blocks of code are generic over ``. And, //! because `trait Config: frame_system::Config`, we can get access to all items in `Config` (or -//! `frame_system::Config`) using `T::NameOfItem`. This is all within the boundaries of how Rust -//! traits and generics work. If unfamiliar with this pattern, read +//! `frame_system::Config`) using `T::NameOfItem`. This is all within the boundaries of how +//! Rust traits and generics work. If unfamiliar with this pattern, read //! [`crate::reference_docs::trait_based_programming`] before going further. //! //! Crucially, a typical FRAME runtime contains a `struct Runtime`. The main role of this `struct` @@ -250,14 +250,16 @@ // of event is probably not the best. //! //! 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 an extra `#[frame::event/error]` attribute -//! attached. +//! fairly familiar syntax: normal Rust enums, with extra +//! [`#[frame::event]`](frame::pallet_macros::event) and +//! [`#[frame::error]`](frame::pallet_macros::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)] //! -//! One slightly custom part of this is the `#[pallet::generate_deposit(pub(super) fn -//! deposit_event)]` 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 two things: +//! One slightly custom part of this is the [`#[pallet::generate_deposit(pub(super) fn +//! deposit_event)]`](frame::pallet_macros::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 two +//! things: //! //! 1. Declare a type in its `Config` that refers to the overarching event type of the runtime. In //! short, by doing this, the pallet is expressing an important bound: `type RuntimeEvent: @@ -266,11 +268,12 @@ //! store it where needed. //! //! 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. +//! provides a default way of storing events, and this is what +//! [`pallet::generate_deposit`](frame::pallet_macros::generate_deposit) is doing. #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", config_v2)] //! //! > These `Runtime*` types are better explained in -//! > [`crate::reference_docs::frame_composite_enums`]. +//! > [`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)] @@ -280,12 +283,12 @@ #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", runtime_v2)] //! //! In this snippet, the actual `RuntimeEvent` type (right hand side of `type RuntimeEvent = -//! RuntimeEvent`) is generated by `construct_runtime`. An interesting way to inspect this type is -//! to see its definition in rust-docs: +//! RuntimeEvent`) is generated by +//! [`construct_runtime`](frame::runtime::prelude::construct_runtime). An interesting way to inspect +//! this type is to see its definition in rust-docs: //! [`crate::guides::your_first_pallet::pallet_v2::tests::runtime_v2::RuntimeEvent`]. //! //! -//! //! ## What Next? //! //! The following topics where used in this guide, but not covered in depth. It is suggested to @@ -293,7 +296,7 @@ //! //! - [`crate::reference_docs::safe_defensive_programming`]. //! - [`crate::reference_docs::frame_origin`]. -//! - [`crate::reference_docs::frame_composite_enums`]. +//! - [`crate::reference_docs::frame_runtime_types`]. //! - The pallet we wrote in this guide was using `dev_mode`, learn more in //! [`frame::pallet_macros::config`]. //! - Learn more about the individual pallet items/macros, such as event and errors and call, in diff --git a/docs/sdk/src/lib.rs b/docs/sdk/src/lib.rs index 075d9ddaffe5bd95bafa4ca1d06667c253d4a21b..e211476d2514419a3d0889ef426817342155c178 100644 --- a/docs/sdk/src/lib.rs +++ b/docs/sdk/src/lib.rs @@ -15,7 +15,7 @@ //! - Start by learning about the the [`polkadot_sdk`], its structure and context. //! - Then, head over 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 [`crate::reference_docs`]. +//! - Whilst reading the guides, you might find back-links to [`reference_docs`]. //! - Finally, is the parent website of this crate that contains the //! list of further tools related to the Polkadot SDK. //! @@ -25,6 +25,11 @@ #![doc = simple_mermaid::mermaid!("../../mermaid/IA.mmd")] #![warn(rustdoc::broken_intra_doc_links)] #![warn(rustdoc::private_intra_doc_links)] +#![doc(html_favicon_url = "https://polkadot.network/favicon-32x32.png")] +#![doc( + html_logo_url = "https://europe1.discourse-cdn.com/standard21/uploads/polkadot2/original/1X/eb57081e2bb7c39e5fcb1a98b443e423fa4448ae.svg" +)] +#![doc(issue_tracker_base_url = "https://github.com/paritytech/polkadot-sdk/issues")] /// Meta information about this crate, how it is built, what principles dictates its evolution and /// how one can contribute to it. diff --git a/docs/sdk/src/meta_contributing.rs b/docs/sdk/src/meta_contributing.rs index 7ecf8b0adfd3a2038bd32b6d6b830c71782cd1b2..fcdcea9934bb6b8cf7ee6ec090ebd0939888238c 100644 --- a/docs/sdk/src/meta_contributing.rs +++ b/docs/sdk/src/meta_contributing.rs @@ -101,7 +101,7 @@ //! * Before even getting started, what is with all of this ``? We link to //! [`crate::reference_docs::trait_based_programming`]. //! * First, the name. Why is this called `pallet::call`? This goes back to `enum Call`, which is -//! explained in [`crate::reference_docs::frame_composite_enums`]. Build on top of this! +//! explained in [`crate::reference_docs::frame_runtime_types`]. Build on top of this! //! * Then, what is `origin`? Just an account id? [`crate::reference_docs::frame_origin`]. //! * Then, what is `DispatchResult`? Why is this called *dispatch*? Probably something that can be //! explained in the documentation of [`frame::prelude::DispatchResult`]. @@ -138,7 +138,9 @@ //! injected, run: //! //! ```sh -//! SKIP_WASM_BUILD=1 RUSTDOCFLAGS="--html-in-header $(pwd)/docs/sdk/headers/toc.html" cargo doc -p polkadot-sdk-docs --no-deps --open +//! SKIP_WASM_BUILD=1 \ +//! RUSTDOCFLAGS="--html-in-header $(pwd)/docs/sdk/headers/header.html --extend-css $(pwd)/docs/sdk/headers/theme.css --default-theme=ayu" \ +//! cargo doc -p polkadot-sdk-docs --no-deps --open //! ``` //! //! If even faster build time for docs is needed, you can temporarily remove most of the diff --git a/docs/sdk/src/polkadot_sdk/frame_runtime.rs b/docs/sdk/src/polkadot_sdk/frame_runtime.rs index c9eba7d64bd46b51230c1b06a96c6b89ffddd73d..f178fc82bf4ba350ffe67b8a237319f8542d686b 100644 --- a/docs/sdk/src/polkadot_sdk/frame_runtime.rs +++ b/docs/sdk/src/polkadot_sdk/frame_runtime.rs @@ -87,93 +87,89 @@ //! * writing a runtime in pure Rust, as done in [this template](https://github.com/JoshOrndorff/frameless-node-template). //! * writing a runtime in AssemblyScript,as explored in [this project](https://github.com/LimeChain/subsembly). -#[cfg(test)] -mod tests { - use frame::prelude::*; +use frame::prelude::*; - /// A FRAME based pallet. This `mod` is the entry point for everything else. All - /// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an - /// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for - /// more. - #[docify::export] - #[frame::pallet(dev_mode)] - pub mod pallet { - use super::*; +/// A FRAME based pallet. This `mod` is the entry point for everything else. All +/// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an +/// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for +/// more. +#[docify::export] +#[frame::pallet(dev_mode)] +pub mod pallet { + use super::*; - /// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a - /// later point from the runtime that wishes to contain it. It allows the pallet to be - /// parameterized over both types and values. - #[pallet::config] - pub trait Config: frame_system::Config { - /// A type that is not known now, but the runtime that will contain this pallet will - /// know it later, therefore we define it here as an associated type. - type RuntimeEvent: IsType<::RuntimeEvent> - + From>; + /// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a + /// later point from the runtime that wishes to contain it. It allows the pallet to be + /// parameterized over both types and values. + #[pallet::config] + pub trait Config: frame_system::Config { + /// A type that is not known now, but the runtime that will contain this pallet will + /// know it later, therefore we define it here as an associated type. + type RuntimeEvent: IsType<::RuntimeEvent> + From>; - /// A parameterize-able value that we receive later via the `Get<_>` trait. - type ValueParameter: Get; + /// A parameterize-able value that we receive later via the `Get<_>` trait. + type ValueParameter: Get; - /// Similar to [`Config::ValueParameter`], but using `const`. Both are functionally - /// equal, but offer different tradeoffs. - const ANOTHER_VALUE_PARAMETER: u32; - } + /// Similar to [`Config::ValueParameter`], but using `const`. Both are functionally + /// equal, but offer different tradeoffs. + const ANOTHER_VALUE_PARAMETER: u32; + } - /// A mandatory struct in each pallet. All functions callable by external users (aka. - /// transactions) must be attached to this type (see [`frame::pallet_macros::call`]). For - /// convenience, internal (private) functions can also be attached to this type. - #[pallet::pallet] - pub struct Pallet(PhantomData); + /// A mandatory struct in each pallet. All functions callable by external users (aka. + /// transactions) must be attached to this type (see [`frame::pallet_macros::call`]). For + /// convenience, internal (private) functions can also be attached to this type. + #[pallet::pallet] + pub struct Pallet(PhantomData); - /// The events tha this pallet can emit. - #[pallet::event] - pub enum Event {} + /// The events tha this pallet can emit. + #[pallet::event] + pub enum Event {} - /// A storage item that this pallet contains. This will be part of the state root trie/root - /// of the blockchain. - #[pallet::storage] - pub type Value = StorageValue; + /// A storage item that this pallet contains. This will be part of the state root trie/root + /// of the blockchain. + #[pallet::storage] + pub type Value = StorageValue; - /// All *dispatchable* call functions (aka. transactions) are attached to `Pallet` in a - /// `impl` block. - #[pallet::call] - impl Pallet { - /// This will be callable by external users, and has two u32s as a parameter. - pub fn some_dispatchable( - _origin: OriginFor, - _param: u32, - _other_para: u32, - ) -> DispatchResult { - Ok(()) - } + /// All *dispatchable* call functions (aka. transactions) are attached to `Pallet` in a + /// `impl` block. + #[pallet::call] + impl Pallet { + /// This will be callable by external users, and has two u32s as a parameter. + pub fn some_dispatchable( + _origin: OriginFor, + _param: u32, + _other_para: u32, + ) -> DispatchResult { + Ok(()) } } +} - /// A simple runtime that contains the above pallet and `frame_system`, the mandatory pallet of - /// all runtimes. This runtime is for testing, but it shares a lot of similarities with a *real* - /// runtime. - #[docify::export] - pub mod runtime { - use super::pallet as pallet_example; - use frame::{prelude::*, testing_prelude::*}; - - // The major macro that amalgamates pallets into `enum Runtime` - construct_runtime!( - pub enum Runtime { - System: frame_system, - Example: pallet_example, - } - ); +/// A simple runtime that contains the above pallet and `frame_system`, the mandatory pallet of +/// all runtimes. This runtime is for testing, but it shares a lot of similarities with a *real* +/// runtime. +#[docify::export] +pub mod runtime { + use super::pallet as pallet_example; + use frame::{prelude::*, testing_prelude::*}; - // These `impl` blocks specify the parameters of each pallet's `trait Config`. - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] - impl frame_system::Config for Runtime { - type Block = MockBlock; + // The major macro that amalgamates pallets into `enum Runtime` + construct_runtime!( + pub enum Runtime { + System: frame_system, + Example: pallet_example, } + ); - impl pallet_example::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ValueParameter = ConstU32<42>; - const ANOTHER_VALUE_PARAMETER: u32 = 42; - } + // These `impl` blocks specify the parameters of each pallet's `trait Config`. + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_example::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValueParameter = ConstU32<42>; + const ANOTHER_VALUE_PARAMETER: u32 = 42; } } diff --git a/docs/sdk/src/polkadot_sdk/xcm.rs b/docs/sdk/src/polkadot_sdk/xcm.rs index fd4d7f62aa702f5808552936404995ad67efaed9..5dcdc9e1de076c4507cb64517360df73e6733dc7 100644 --- a/docs/sdk/src/polkadot_sdk/xcm.rs +++ b/docs/sdk/src/polkadot_sdk/xcm.rs @@ -1,5 +1,71 @@ //! # XCM //! -//! @KiChjang @franciscoaguirre -//! TODO: RFCs, xcm-spec, the future of the repo, minimal example perhaps, forward to where actual -//! docs are hosted. +//! XCM, or Cross-Consensus Messaging, is a **language** to communicate **intentions** between +//! **consensus systems**. +//! +//! ## Overview +//! +//! XCM is a standard, whose specification lives in the [xcm format repo](https://github.com/paritytech/xcm-format). +//! It's agnostic both in programming language and blockchain platform, which means it could be used +//! in Rust in Polkadot, or in Go or C++ in any other platform like Cosmos or Ethereum. +//! +//! It enables different consensus systems to communicate with each other in an expressive manner. +//! Consensus systems include blockchains, smart contracts, and any other state machine that +//! achieves consensus in some way. +//! +//! XCM is executed on a virtual machine called the XCVM. +//! Scripts can be written with the XCM language, which are often called XCMs, messages or XCM +//! programs. Each program is a series of instructions, which get executed one after the other by +//! the virtual machine. These instructions aim to encompass all major things users typically do in +//! consensus systems. There are instructions on asset transferring, teleporting, locking, among +//! others. New instructions are added and changes to the XCVM are made via the [RFC process](https://github.com/paritytech/xcm-format/blob/master/proposals/0032-process.md). +//! +//! ## In Polkadot SDK +//! +//! The Polkadot SDK allows for easily deploying sovereign blockchains from scratch, all very +//! customizable. Dealing with many heterogeneous blockchains can be cumbersome. +//! XCM allows all these blockchains to communicate with an agreed-upon language. +//! As long as an implementation of the XCVM is implemented, the same XCM program can be executed in +//! all blockchains and perform the same task. +//! +//! ## Implementation +//! +//! A ready-to-use Rust implementation lives in the [polkadot-sdk repo](https://github.com/paritytech/polkadot-sdk/tree/master/polkadot/xcm), +//! but will be moved to its own repo in the future. +//! +//! Its main components are: +//! - `src`: the definition of the basic types and instructions +//! - [`xcm-executor`](https://paritytech.github.io/polkadot-sdk/master/staging_xcm_executor/struct.XcmExecutor.html): +//! an implementation of the virtual machine to execute instructions +//! - `pallet-xcm`: A FRAME pallet for interacting with the executor +//! - `xcm-builder`: a collection of types to configure the executor +//! - `xcm-simulator`: a playground for trying out different XCM programs and executor +//! configurations +//! +//! ## Example +//! +//! To perform the very usual operation of transferring assets, the following XCM program can be +//! used: +#![doc = docify::embed!("src/polkadot_sdk/xcm.rs", example_transfer)] +//! +//! ## Get started +//! +//! To learn how it works and to get started, go to the [XCM docs](https://paritytech.github.io/xcm-docs/). + +#[cfg(test)] +mod tests { + use xcm::latest::prelude::*; + + #[docify::export] + #[test] + fn example_transfer() { + let _transfer_program = Xcm::<()>(vec![ + WithdrawAsset((Here, 100u128).into()), + BuyExecution { fees: (Here, 100u128).into(), weight_limit: Unlimited }, + DepositAsset { + assets: All.into(), + beneficiary: AccountId32 { id: [0u8; 32].into(), network: None }.into(), + }, + ]); + } +} diff --git a/docs/sdk/src/reference_docs/development_environment_advice.rs b/docs/sdk/src/reference_docs/development_environment_advice.rs index 4317695979367b32bfb673d2d368399c5ca35faa..21bbe78836c44b8afd70cab68e4b9b2f929fb4a0 100644 --- a/docs/sdk/src/reference_docs/development_environment_advice.rs +++ b/docs/sdk/src/reference_docs/development_environment_advice.rs @@ -111,3 +111,74 @@ //! If you have a powerful remote server available, you may consider using //! [cargo-remote](https://github.com/sgeisler/cargo-remote) to execute cargo commands on it, //! freeing up local resources for other tasks like `rust-analyzer`. +//! +//! When using `cargo-remote`, you can configure your editor to perform the the typical +//! "check-on-save" remotely as well. The configuration for VSCode is as follows: +//! +//! ```json +//! { +//! "rust-analyzer.cargo.buildScripts.overrideCommand": [ +//! "cargo", +//! "remote", +//! "--build-env", +//! "SKIP_WASM_BUILD=1", +//! "--", +//! "check", +//! "--message-format=json", +//! "--all-targets", +//! "--all-features", +//! "--target-dir=target/rust-analyzer" +//! ], +//! "rust-analyzer.check.overrideCommand": [ +//! "cargo", +//! "remote", +//! "--build-env", +//! "SKIP_WASM_BUILD=1", +//! "--", +//! "check", +//! "--workspace", +//! "--message-format=json", +//! "--all-targets", +//! "--all-features", +//! "--target-dir=target/rust-analyzer" +//! ], +//! } +//! ``` +//! +//! //! and the same in Lua for `neovim/nvim-lspconfig`: +//! +//! ```lua +//! ["rust-analyzer"] = { +//! cargo = { +//! buildScripts = { +//! overrideCommand = { +//! "cargo", +//! "remote", +//! "--build-env", +//! "SKIP_WASM_BUILD=1", +//! "--", +//! "check", +//! "--message-format=json", +//! "--all-targets", +//! "--all-features", +//! "--target-dir=target/rust-analyzer" +//! }, +//! }, +//! check = { +//! overrideCommand = { +//! "cargo", +//! "remote", +//! "--build-env", +//! "SKIP_WASM_BUILD=1", +//! "--", +//! "check", +//! "--workspace", +//! "--message-format=json", +//! "--all-targets", +//! "--all-features", +//! "--target-dir=target/rust-analyzer" +//! }, +//! }, +//! }, +//! }, +//! ``` diff --git a/docs/sdk/src/reference_docs/extrinsic_encoding.rs b/docs/sdk/src/reference_docs/extrinsic_encoding.rs index 9008f8f835f5d6cd1705c9dd4e4e4e78fd3aa2d9..be1af50003849f6500fe39d8bf2ad83c7b7dfbe2 100644 --- a/docs/sdk/src/reference_docs/extrinsic_encoding.rs +++ b/docs/sdk/src/reference_docs/extrinsic_encoding.rs @@ -56,7 +56,7 @@ //! version_and_signed, //! from_address, //! signature, -//! signed_extensions_extra, +//! transaction_extensions_extra, //! ) //! ``` //! @@ -90,31 +90,31 @@ //! 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 +//! ### transaction_extensions_extra //! //! 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]. +//! 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]. //! -//! When it comes to constructing an extrinsic, each signed extension has two things that we are -//! interested in here: +//! 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 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). +//! - 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 of +//! the _signed payload_ (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 +//! 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 @@ -127,7 +127,7 @@ //! runtimes, a call is represented as an enum of enums, where the outer enum represents the FRAME //! pallet being called, and the inner enum represents the call being made within that pallet, and //! any arguments to it. Read more about the call enum -//! [here][crate::reference_docs::frame_composite_enums]. +//! [here][crate::reference_docs::frame_runtime_types]. //! //! FRAME `Call` enums are automatically generated, and end up looking something like this: #![doc = docify::embed!("./src/reference_docs/extrinsic_encoding.rs", call_data)] @@ -163,8 +163,8 @@ //! ```text //! signed_payload = concat( //! call_data, -//! signed_extensions_extra, -//! signed_extensions_additional, +//! transaction_extensions_extra, +//! transaction_extensions_implicit, //! ) //! //! if length(signed_payload) > 256 { @@ -172,16 +172,16 @@ //! } //! ``` //! -//! 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::TransactionExtensionBase::Implicit] for each +//! transaction extension that the chain is using, in order. //! //! 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 [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload -//! for us, given `call_data` and a tuple of signed extensions. +//! for us, given `call_data` and a tuple of transaction extensions. //! //! # Example Encoding //! @@ -192,11 +192,12 @@ #[docify::export] pub mod call_data { use parity_scale_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 +208,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 parity_scale_codec::Encode; use sp_core::crypto::AccountId32; use sp_keyring::sr25519::Keyring; @@ -232,34 +243,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 +286,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_composite_enums.rs b/docs/sdk/src/reference_docs/frame_composite_enums.rs deleted file mode 100644 index 6051cd534467672b9831187ef5c8b814712f7d18..0000000000000000000000000000000000000000 --- a/docs/sdk/src/reference_docs/frame_composite_enums.rs +++ /dev/null @@ -1 +0,0 @@ -//! # FRAME Composite Enums diff --git a/docs/sdk/src/reference_docs/frame_offchain_workers.rs b/docs/sdk/src/reference_docs/frame_offchain_workers.rs new file mode 100644 index 0000000000000000000000000000000000000000..7999707e5ee018c4bb7634e7a506ff8fee8fa8ac --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_offchain_workers.rs @@ -0,0 +1,115 @@ +//! # Offchain Workers +//! +//! This reference document explains how offchain workers work in Substrate and FRAME. The main +//! focus is upon FRAME's implementation of this functionality. Nonetheless, offchain workers are a +//! Substrate-provided feature and can be used with possible alternatives to [`frame`] as well. +//! +//! Offchain workers are a commonly misunderstood topic, therefore we explain them bottom-up, +//! starting at the fundamentals and then describing the developer interface. +//! +//! ## Context +//! +//! Recall from [`crate::reference_docs::wasm_meta_protocol`] that the node and the runtime +//! communicate with one another via host functions and runtime APIs. Many of these interactions +//! contribute to the actual state transition of the blockchain. For example [`sp_api::Core`] is the +//! main runtime API that is called to execute new blocks. +//! +//! Offchain workers are in principle not different in any way: It is a runtime API exposed by the +//! wasm blob ([`sp_offchain::OffchainWorkerApi`]), and the node software calls into it when it +//! deems fit. But, crucially, this API call is different in that: +//! +//! 1. It can have no impact on the state ie. it is _OFF (the) CHAIN_. If any state is altered +//! during the execution of this API call, it is discarded. +//! 2. It has access to an extended set of host functions that allow the wasm blob to do more. For +//! example, call into HTTP requests. +//! +//! > The main way through which an offchain worker can interact with the state is by submitting an +//! > extrinsic to the chain. This is the ONLY way to alter the state from an offchain worker. +//! > [`pallet_example_offchain_worker`] provides an example of this. +//! +//! +//! Given the "Off Chain" nature of this API, it is important to remember that calling this API is +//! entirely optional. Some nodes might call into it, some might not, and it would have no impact on +//! the execution of your blockchain because no state is altered no matter the execution of the +//! offchain worker API. +//! +//! Substrate's CLI allows some degree of configuration about this, allowing node operators to +//! specify when they want to run the offchain worker API. See +//! [`sc_cli::RunCmd::offchain_worker_params`]. +//! +//! ## Nondeterministic Execution +//! +//! Needless to say, given the above description, the code in your offchain worker API can be +//! nondeterministic, as it is not part of the blockchain's STF, so it can be executed at unknown +//! times, by unknown nodes, and has no impact on the state. This is why an HTTP +//! ([`sp_runtime::offchain::http`]) API is readily provided to the offchain worker APIs. Because +//! there is no need for determinism in this context. +//! +//! > A common mistake here is for novice developers to see this HTTP API, and imagine that +//! > `polkadot-sdk` somehow magically solved the determinism in blockchains, and now a blockchain +//! > can make HTTP calls and it will all work. This is absolutely NOT the case. An HTTP call made +//! > by the offchain worker is non-deterministic by design. Blockchains can't and always won't be +//! > able to perform non-deterministic operations such as making HTTP calls to a foreign server. +//! +//! ## FRAME's API +//! +//! [`frame`] provides a simple API through which pallets can define offchain worker functions. This +//! is part of [`frame::traits::Hooks`], which is implemented as a part of +//! [`frame::pallet_macros::hooks`]. +//! +//! ``` +//! +//! #[frame::pallet] +//! pub mod pallet { +//! use frame::prelude::*; +//! +//! #[pallet::config] +//! pub trait Config: frame_system::Config {} +//! +//! #[pallet::pallet] +//! pub struct Pallet(_); +//! +//! #[pallet::hooks] +//! impl Hooks> for Pallet { +//! fn offchain_worker(block_number: BlockNumberFor) { +//! // ... +//! } +//! } +//! } +//! ``` +//! +//! Additionally, [`sp_runtime::offchain`] provides a set of utilities that can be used to moderate +//! the execution of offchain workers. +//! +//! ## Think Twice: Why Use Substrate's Offchain Workers? +//! +//! Consider the fact that in principle, an offchain worker code written using the above API is no +//! different than an equivalent written with an _actual offchain interaction library_, such as +//! [Polkadot-JS](https://polkadot.js.org/docs/), or any of the other ones listed [here](https://github.com/substrate-developer-hub/awesome-substrate?tab=readme-ov-file#client-libraries). +//! +//! They can both read from the state, and have no means of updating the state, other than the route +//! of submitting an extrinsic to the chain. Therefore, it is worth thinking twice before embedding +//! a logic as a part of Substrate's offchain worker API. Does it have to be there? can it not be a +//! simple, actual offchain application that lives outside of the chain's WASM blob? +//! +//! Some of the reasons why you might want to do the opposite, and actually embed an offchain worker +//! API into the WASM blob are: +//! +//! * Accessing the state is easier within the `offchain_worker` function, as it is already a part +//! of the runtime, and [`frame::pallet_macros::storage`] provides all the tools needed to read +//! the state. Other client libraries might provide varying degrees of capability here. +//! * It will be updated in synchrony with the runtime. A Substrate's offchain application is part +//! of the same WASM blob, and is therefore guaranteed to be up to date. +//! +//! For example, imagine you have modified a storage item to have a new type. This will possibly +//! require a [`crate::reference_docs::frame_runtime_upgrades_and_migrations`], and any offchain +//! code, such as a Polkadot-JS application, will have to be updated to reflect this change. Whereas +//! the WASM offchain worker code is guaranteed to already be updated, or else the runtime code will +//! not even compile. +//! +//! +//! ## Further References +//! +//! - +//! - +//! - [Offchain worker example](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/examples/offchain-worker) diff --git a/docs/sdk/src/reference_docs/frame_origin.rs b/docs/sdk/src/reference_docs/frame_origin.rs index a4078377cd77dad6b3aac78ba6acdddda14251a8..49533157b014d77b3766cbfc8c3353397e0e48bf 100644 --- a/docs/sdk/src/reference_docs/frame_origin.rs +++ b/docs/sdk/src/reference_docs/frame_origin.rs @@ -1,14 +1,260 @@ //! # FRAME Origin //! -//! Notes: -//! -//! - Def talk about account abstraction and how it is a solved issue in frame. See Gav's talk in -//! Protocol Berg 2023 -//! - system's raw origin, how it is amalgamated with other origins into one type -//! [`frame_composite_enums`] -//! - signed origin -//! - unsigned origin, link to [`fee_less_runtime`] -//! - Root origin, how no one can obtain it. -//! - Abstract origin: how FRAME allows you to express "origin is 2/3 of the this body or 1/2 of -//! that body or half of the token holders". -//! - `type CustomOrigin: EnsureOrigin<_>` in pallets. +//! Let's start by clarifying a common wrong assumption about Origin: +//! +//! **ORIGIN IS NOT AN ACCOUNT ID**. +//! +//! FRAME's origin abstractions allow you to convey meanings far beyond just an account-id being the +//! caller of an extrinsic. Nonetheless, an account-id having signed an extrinsic is one of the +//! meanings that an origin can convey. This is the commonly used [`frame_system::ensure_signed`], +//! where the return value happens to be an account-id. +//! +//! Instead, let's establish the following as the correct definition of an origin: +//! +//! > The origin type represents the privilege level of the caller of an extrinsic. +//! +//! That is, an extrinsic, through checking the origin, can *express what privilege level it wishes +//! to impose on the caller of the extrinsic*. One of those checks can be as simple as "*any account +//! that has signed a statement can pass*". +//! +//! But the origin system can also express more abstract and complicated privilege levels. For +//! example: +//! +//! * If the majority of token holders agreed upon this. This is more or less what the +//! [`pallet_democracy`] does under the hood ([reference](https://github.com/paritytech/polkadot-sdk/blob/edd95b3749754d2ed0c5738588e872c87be91624/substrate/frame/democracy/src/lib.rs#L1603-L1633)). +//! * If a specific ratio of an instance of [`pallet_collective`]/DAO agrees upon this. +//! * If another consensus system, for example a bridged network or a parachain, agrees upon this. +//! * If the majority of validator/authority set agrees upon this[^1]. +//! * If caller holds a particular NFT. +//! +//! and many more. +//! +//! ## Context +//! +//! First, let's look at where the `origin` type is encountered in a typical pallet. The `origin: +//! OriginFor` has to be the first argument of any given callable extrinsic in FRAME: +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", call_simple)] +//! +//! Typically, the code of an extrinsic starts with an origin check, such as +//! [`frame_system::ensure_signed`]. +//! +//! Note that [`OriginFor`](frame_system::pallet_prelude::OriginFor) is merely a shorthand for +//! [`frame_system::Config::RuntimeOrigin`]. Given the name prefix `Runtime`, we can learn that +//! `RuntimeOrigin` is similar to `RuntimeCall` and others, a runtime composite enum that is +//! amalgamated at the runtime level. Read [`crate::reference_docs::frame_runtime_types`] to +//! familiarize yourself with these types. +//! +//! To understand this better, we will next create a pallet with a custom origin, which will add a +//! new variant to `RuntimeOrigin`. +//! +//! ## Adding Custom Pallet Origin to the Runtime +//! +//! For example, given a pallet that defines the following custom origin: +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", custom_origin)] +//! +//! And a runtime with the following pallets: +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", runtime_exp)] +//! +//! The type [`crate::reference_docs::frame_origin::runtime_for_origin::RuntimeOrigin`] is expanded. +//! This `RuntimeOrigin` contains a variant for the [`frame_system::RawOrigin`] and the custom +//! origin of the pallet. +//! +//! > Notice how the [`frame_system::ensure_signed`] is nothing more than a `match` statement. If +//! > you want to know where the actual origin of an extrinsic is set (and the signature +//! > verification happens, if any), see +//! > [`sp_runtime::generic::CheckedExtrinsic#trait-implementations`], specifically +//! > [`sp_runtime::traits::Applyable`]'s implementation. +//! +//! ## Asserting on a Custom Internal Origin +//! +//! In order to assert on a custom origin that is defined within your pallet, we need a way to first +//! convert the `::RuntimeOrigin` into the local `enum Origin` of the +//! current pallet. This is a common process that is explained in +//! [`crate::reference_docs::frame_runtime_types# +//! adding-further-constraints-to-runtime-composite-enums`]. +//! +//! We use the same process here to express that `RuntimeOrigin` has a number of additional bounds, +//! as follows. +//! +//! 1. Defining a custom `RuntimeOrigin` with further bounds in the pallet. +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", custom_origin_bound)] +//! +//! 2. Using it in the pallet. +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", custom_origin_usage)] +//! +//! ## Asserting on a Custom External Origin +//! +//! Very often, a pallet wants to have a parameterized origin that is **NOT** defined within the +//! pallet. In other words, a pallet wants to delegate an origin check to something that is +//! specified later at the runtime level. Like many other parameterizations in FRAME, this implies +//! adding a new associated type to `trait Config`. +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", external_origin_def)] +//! +//! Then, within the pallet, we can simply use this "unknown" origin check type: +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", external_origin_usage)] +//! +//! Finally, at the runtime, any implementation of [`frame::traits::EnsureOrigin`] can be passed. +#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", external_origin_provide)] +//! +//! Indeed, some of these implementations of [`frame::traits::EnsureOrigin`] are similar to the ones +//! that we know about: [`frame::runtime::prelude::EnsureSigned`], +//! [`frame::runtime::prelude::EnsureSignedBy`], [`frame::runtime::prelude::EnsureRoot`], +//! [`frame::runtime::prelude::EnsureNone`], etc. But, there are also many more that are not known +//! to us, and are defined in other pallets. +//! +//! For example, [`pallet_collective`] defines [`pallet_collective::EnsureMember`] and +//! [`pallet_collective::EnsureProportionMoreThan`] and many more, which is exactly what we alluded +//! to earlier in this document. +//! +//! Make sure to check the full list of [implementors of +//! `EnsureOrigin`](frame::traits::EnsureOrigin#implementors) for more inspiration. +//! +//! ## Obtaining Abstract Origins +//! +//! So far we have learned that FRAME pallets can assert on custom and abstract origin types, +//! whether they are defined within the pallet or not. But how can we obtain these abstract origins? +//! +//! > All extrinsics that come from the outer world can generally only be obtained as either +//! > `signed` or `none` origin. +//! +//! Generally, these abstract origins are only obtained within the runtime, when a call is +//! dispatched within the runtime. +//! +//! ## Further References +//! +//! - [Gavin Wood's speech about FRAME features at Protocol Berg 2023.](https://youtu.be/j7b8Upipmeg?si=83_XUgYuJxMwWX4g&t=195) +//! - [A related StackExchange question.](https://substrate.stackexchange.com/questions/10992/how-do-you-find-the-public-key-for-the-medium-spender-track-origin) +//! +//! [^1]: Inherents are essentially unsigned extrinsics that need an [`frame_system::ensure_none`] +//! origin check, and through the virtue of being an inherent, are agreed upon by all validators. + +use frame::prelude::*; + +#[frame::pallet(dev_mode)] +pub mod pallet_for_origin { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export(call_simple)] + #[pallet::call] + impl Pallet { + pub fn do_something(_origin: OriginFor) -> DispatchResult { + // ^^^^^^^^^^^^^^^^^^^^^ + todo!(); + } + } +} + +#[frame::pallet(dev_mode)] +pub mod pallet_with_custom_origin { + use super::*; + + #[docify::export(custom_origin_bound)] + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeOrigin: From<::RuntimeOrigin> + + Into::RuntimeOrigin>>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export(custom_origin)] + /// A dummy custom origin. + #[pallet::origin] + #[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] + pub enum Origin { + /// If all holders of a particular NFT have agreed upon this. + AllNftHolders, + /// If all validators have agreed upon this. + ValidatorSet, + } + + #[docify::export(custom_origin_usage)] + #[pallet::call] + impl Pallet { + pub fn only_validators(origin: OriginFor) -> DispatchResult { + // first, we convert from `::RuntimeOrigin` to `::RuntimeOrigin` + let local_runtime_origin = <::RuntimeOrigin as From< + ::RuntimeOrigin, + >>::from(origin); + // then we convert to `origin`, if possible + let local_origin = + local_runtime_origin.into().map_err(|_| "invalid origin type provided")?; + ensure!(matches!(local_origin, Origin::ValidatorSet), "Not authorized"); + todo!(); + } + } +} + +pub mod runtime_for_origin { + use super::pallet_with_custom_origin; + use frame::{runtime::prelude::*, testing_prelude::*}; + + #[docify::export(runtime_exp)] + construct_runtime!( + pub struct Runtime { + System: frame_system, + PalletWithCustomOrigin: pallet_with_custom_origin, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_with_custom_origin::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + } +} + +#[frame::pallet(dev_mode)] +pub mod pallet_with_external_origin { + use super::*; + #[docify::export(external_origin_def)] + #[pallet::config] + pub trait Config: frame_system::Config { + type ExternalOrigin: EnsureOrigin; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export(external_origin_usage)] + #[pallet::call] + impl Pallet { + pub fn externally_checked_ext(origin: OriginFor) -> DispatchResult { + let _ = T::ExternalOrigin::ensure_origin(origin)?; + todo!(); + } + } +} + +pub mod runtime_for_external_origin { + use super::*; + use frame::{runtime::prelude::*, testing_prelude::*}; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + PalletWithExternalOrigin: pallet_with_external_origin, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + #[docify::export(external_origin_provide)] + impl pallet_with_external_origin::Config for Runtime { + type ExternalOrigin = EnsureSigned<::AccountId>; + } +} diff --git a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs new file mode 100644 index 0000000000000000000000000000000000000000..942717ecfb2a12e44d45173c1631f77907f9dbaa --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs @@ -0,0 +1,296 @@ +//! # FRAME Pallet Coupling +//! +//! This reference document explains how FRAME pallets can be combined to interact together. +//! +//! It is suggested to re-read [`crate::polkadot_sdk::frame_runtime`], notably the information +//! around [`frame::pallet_macros::config`]. Recall that: +//! +//! > Configuration trait of a pallet: It allows a pallet to receive types at a later +//! > point from the runtime that wishes to contain it. It allows the pallet to be parameterized +//! > over both types and values. +//! +//! ## Context, Background +//! +//! FRAME pallets, as per described in [`crate::polkadot_sdk::frame_runtime`] are: +//! +//! > A pallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be +//! linked to other pallets. +//! +//! That is to say: +//! +//! * *encapsulated*: Ideally, a FRAME pallet contains encapsulated logic which has clear +//! boundaries. It is generally a bad idea to build a single monolithic pallet that does multiple +//! things, such as handling currencies, identities and staking all at the same time. +//! * *linked to other pallets*: But, adhering extensively to the above also hinders the ability to +//! write useful applications. Pallets often need to work with each other, communicate and use +//! each other's functionalities. +//! +//! The broad principle that allows pallets to be linked together is the same way through which a +//! pallet uses its `Config` trait to receive types and values from the runtime that contains it. +//! +//! There are generally two ways to achieve this: +//! +//! 1. Tight coupling pallets +//! 2. Loose coupling pallets +//! +//! To explain the difference between the two, consider two pallets, `A` and `B`. In both cases, `A` +//! wants to use some functionality exposed by `B`. +//! +//! When tightly coupling pallets, `A` can only exist in a runtime if `B` is also present in the +//! same runtime. That is, `A` is expressing that can only work if `B` is present. +//! +//! This translates to the following Rust code: +//! +//! ``` +//! trait Pallet_B_Config {} +//! trait Pallet_A_Config: Pallet_B_Config {} +//! ``` +//! +//! Contrary, when pallets are loosely coupled, `A` expresses that some functionality, expressed via +//! a trait `F`, needs to be fulfilled. This trait is then implemented by `B`, and the two pallets +//! are linked together at the runtime level. This means that `A` only relies on the implementation +//! of `F`, which may be `B`, or another implementation of `F`. +//! +//! This translates to the following Rust code: +//! +//! ``` +//! trait F {} +//! trait Pallet_A_Config { +//! type F: F; +//! } +//! // Pallet_B will implement and fulfill `F`. +//! ``` +//! +//! ## Example +//! +//! Consider the following example, in which `pallet-foo` needs another pallet to provide the block +//! author to it, and `pallet-author` which has access to this information. +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_foo)] +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_author)] +//! +//! ### Tight Coupling Pallets +//! +//! To tightly couple `pallet-foo` and `pallet-author`, we use Rust's supertrait system. When a +//! pallet makes its own `trait Config` be bounded by another pallet's `trait Config`, it is +//! expressing two things: +//! +//! 1. that it can only exist in a runtime if the other pallet is also present. +//! 2. that it can use the other pallet's functionality. +//! +//! `pallet-foo`'s `Config` would then look like: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", tight_config)] +//! +//! And `pallet-foo` can use the method exposed by `pallet_author::Pallet` directly: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", tight_usage)] +//! +//! +//! ### Loosely Coupling Pallets +//! +//! If `pallet-foo` wants to *not* rely on `pallet-author` directly, it can leverage its +//! `Config`'s associated types. First, we need a trait to express the functionality that +//! `pallet-foo` wants to obtain: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", AuthorProvider)] +//! +//! > We sometimes refer to such traits that help two pallets interact as "glue traits". +//! +//! Next, `pallet-foo` states that it needs this trait to be provided to it, at the runtime level, +//! via an associated type: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", loose_config)] +//! +//! Then, `pallet-foo` can use this trait to obtain the block author, without knowing where it comes +//! from: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", loose_usage)] +//! +//! Then, if `pallet-author` implements this glue-trait: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_author_provider)] +//! +//! And upon the creation of the runtime, the two pallets are linked together as such: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", runtime_author_provider)] +//! +//! Crucially, when using loose coupling, we gain the flexibility of providing different +//! implementations of `AuthorProvider`, such that different users of a `pallet-foo` can use +//! different ones, without any code change being needed. For example, in the code snippets of this +//! module, you can fund [`OtherAuthorProvider`] which is an alternative implementation of +//! [`AuthorProvider`]. +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", other_author_provider)] +//! +//! A common pattern in polkadot-sdk is to provide an implementation of such glu traits for the unit +//! type as a "default/test behavior". +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", unit_author_provider)] +//! +//! ## Frame System +//! +//! With the above information in context, we can conclude that **`frame_system` is a special pallet +//! that is tightly coupled with every other pallet**. This is because it provides the fundamental +//! system functionality that every pallet needs, such as some types like +//! [`frame::prelude::frame_system::Config::AccountId`], +//! [`frame::prelude::frame_system::Config::Hash`], and some functionality such as block number, +//! etc. +//! +//! ## Recap +//! +//! To recap, consider the following rules of thumb: +//! +//! * In all cases, try and break down big pallets apart with clear boundaries of responsibility. In +//! general, it is easier to argue about multiple pallet if they only communicate together via a +//! known trait, rather than having access to all of each others public items, such as storage and +//! dispatchables. +//! * If a group of pallets are meant to work together, and but are not foreseen to be generalized, +//! or used by others, consider tightly coupling pallets, *if it simplifies the development*. +//! * If a pallet needs a functionality provided by another pallet, but multiple implementations can +//! be foreseen, consider loosely coupling pallets. +//! +//! For example, all pallets in `polkadot-sdk` that needed to work with currencies could have been +//! tightly coupled with [`pallet_balances`]. But, `polkadot-sdk` also provides [`pallet_assets`] +//! (and more implementations by the community), therefore all pallets use traits to loosely couple +//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_currency`]. +//! +//! ## Further References +//! +//! - +//! - +//! +//! [`AuthorProvider`]: crate::reference_docs::frame_pallet_coupling::AuthorProvider +//! [`OtherAuthorProvider`]: crate::reference_docs::frame_pallet_coupling::OtherAuthorProvider + +#![allow(unused)] + +use frame::prelude::*; + +#[docify::export] +#[frame::pallet] +pub mod pallet_foo { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + impl Pallet { + fn do_stuff_with_author() { + // needs block author here + } + } +} + +#[docify::export] +#[frame::pallet] +pub mod pallet_author { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + impl Pallet { + pub fn author() -> T::AccountId { + todo!("somehow has access to the block author and can return it here") + } + } +} + +#[frame::pallet] +pub mod pallet_foo_tight { + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export(tight_config)] + /// This pallet can only live in a runtime that has both `frame_system` and `pallet_author`. + #[pallet::config] + pub trait Config: frame_system::Config + pallet_author::Config {} + + #[docify::export(tight_usage)] + impl Pallet { + // anywhere in `pallet-foo`, we can call into `pallet-author` directly, namely because + // `T: pallet_author::Config` + fn do_stuff_with_author() { + let _ = pallet_author::Pallet::::author(); + } + } +} + +#[docify::export] +/// Abstraction over "something that can provide the block author". +pub trait AuthorProvider { + fn author() -> AccountId; +} + +#[frame::pallet] +pub mod pallet_foo_loose { + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export(loose_config)] + #[pallet::config] + pub trait Config: frame_system::Config { + /// This pallet relies on the existence of something that implements [`AuthorProvider`], + /// which may or may not be `pallet-author`. + type AuthorProvider: AuthorProvider; + } + + #[docify::export(loose_usage)] + impl Pallet { + fn do_stuff_with_author() { + let _ = T::AuthorProvider::author(); + } + } +} + +#[docify::export(pallet_author_provider)] +impl AuthorProvider for pallet_author::Pallet { + fn author() -> T::AccountId { + pallet_author::Pallet::::author() + } +} + +pub struct OtherAuthorProvider; + +#[docify::export(other_author_provider)] +impl AuthorProvider for OtherAuthorProvider { + fn author() -> AccountId { + todo!("somehow get the block author here") + } +} + +#[docify::export(unit_author_provider)] +impl AuthorProvider for () { + fn author() -> AccountId { + todo!("somehow get the block author here") + } +} + +pub mod runtime { + use super::*; + use cumulus_pallet_aura_ext::pallet; + use frame::{runtime::prelude::*, testing_prelude::*}; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + PalletFoo: pallet_foo_loose, + PalletAuthor: pallet_author, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_author::Config for Runtime {} + + #[docify::export(runtime_author_provider)] + impl pallet_foo_loose::Config for Runtime { + type AuthorProvider = pallet_author::Pallet; + // which is also equivalent to + // type AuthorProvider = PalletAuthor; + } +} diff --git a/docs/sdk/src/reference_docs/frame_runtime_migration.rs b/docs/sdk/src/reference_docs/frame_runtime_migration.rs deleted file mode 100644 index 0616ccbb6f57971823c7347a60574ef0c0bef2ab..0000000000000000000000000000000000000000 --- a/docs/sdk/src/reference_docs/frame_runtime_migration.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! # Runtime Runtime Upgrade and Testing -//! -//! -//! Notes: -//! -//! - Flow of things, when does `on_runtime_upgrade` get called. Link to to `Hooks` and its diagram -//! as source of truth. -//! - Data migration and when it is needed. -//! - Look into the pba-lecture. diff --git a/docs/sdk/src/reference_docs/frame_runtime_types.rs b/docs/sdk/src/reference_docs/frame_runtime_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..883892729d1c1fab97f58a69bc44546d0cee5dae --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_runtime_types.rs @@ -0,0 +1,306 @@ +//! # FRAME Runtime Types +//! +//! This reference document briefly explores the idea around types generated at the runtime level by +//! the FRAME macros. +//! +//! > As of now, many of these important types are generated within the internals of +//! > [`construct_runtime`], and there is no easy way for you to visually know they exist. +//! > [#polkadot-sdk#1378](https://github.com/paritytech/polkadot-sdk/pull/1378) is meant to +//! > significantly improve this. Exploring the rust-docs of a runtime, such as [`runtime`] which is +//! > defined in this module is as of now the best way to learn about these types. +//! +//! ## Composite Enums +//! +//! Many types within a FRAME runtime follow the following structure: +//! +//! * Each individual pallet defines a type, for example `Foo`. +//! * At the runtime level, these types are amalgamated into a single type, for example +//! `RuntimeFoo`. +//! +//! As the names suggest, all composite enums in a FRAME runtime start their name with `Runtime`. +//! For example, `RuntimeCall` is a representation of the most high level `Call`-able type in the +//! runtime. +//! +//! Composite enums are generally convertible to their individual parts as such: +#![doc = simple_mermaid::mermaid!("../../../mermaid/outer_runtime_types.mmd")] +//! +//! In that one can always convert from the inner type into the outer type, but not vice versa. This +//! is usually expressed by implementing `From`, `TryFrom`, `From>` and similar traits. +//! +//! ### Example +//! +//! We provide the following two pallets: [`pallet_foo`] and [`pallet_bar`]. Each define a +//! dispatchable, and `Foo` also defines a custom origin. Lastly, `Bar` defines an additional +//! `GenesisConfig`. +#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pallet_foo)] +#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pallet_bar)] +//! +//! Let's explore how each of these affect the [`RuntimeCall`], [`RuntimeOrigin`] and +//! [`RuntimeGenesisConfig`] generated in [`runtime`] by respectively. +//! +//! As observed, [`RuntimeCall`] has 3 variants, one for each pallet and one for `frame_system`. If +//! you explore further, you will soon realize that each variant is merely a pointer to the `Call` +//! type in each pallet, for example [`pallet_foo::Call`]. +//! +//! [`RuntimeOrigin`]'s [`OriginCaller`] has two variants, one for system, and one for `pallet_foo` +//! which utilized [`frame::pallet_macros::origin`]. +//! +//! Finally, [`RuntimeGenesisConfig`] is composed of `frame_system` and a variant for `pallet_bar`'s +//! [`pallet_bar::GenesisConfig`]. +//! +//! You can find other composite enums by scanning [`runtime`] for other types who's name starts +//! with `Runtime`. Some of the more noteworthy ones are: +//! +//! - [`RuntimeEvent`] +//! - [`RuntimeError`] +//! - [`RuntimeHoldReason`] +//! +//! ### Adding Further Constraints to Runtime Composite Enums +//! +//! This section explores a common scenario where a pallet has access to one of these runtime +//! composite enums, but it wishes to further specify it by adding more trait bounds to it. +//! +//! Let's take the example of `RuntimeCall`. This is an associated type in +//! [`frame_system::Config::RuntimeCall`], and all pallets have access to this type, because they +//! have access to [`frame_system::Config`]. Finally, this type is meant to be set to outer call of +//! the entire runtime. +//! +//! But, let's not forget that this is information that *we know*, and the Rust compiler does not. +//! All that the rust compiler knows about this type is *ONLY* what the trait bounds of +//! [`frame_system::Config::RuntimeCall`] are specifying: +#![doc = docify::embed!("../../substrate/frame/system/src/lib.rs", system_runtime_call)] +//! +//! So, when at a given pallet, one accesses `::RuntimeCall`, the type is +//! extremely opaque from the perspective of the Rust compiler. +//! +//! How can a pallet access the `RuntimeCall` type with further constraints? For example, each +//! pallet has its own `enum Call`, and knows that its local `Call` is a part of `RuntimeCall`, +//! therefore there should be a `impl From> for RuntimeCall`. +//! +//! The only way to express this using Rust's associated types is for the pallet to **define its own +//! associated type `RuntimeCall`, and further specify what it thinks `RuntimeCall` should be**. +//! +//! In this case, we will want to assert the existence of [`frame::traits::IsSubType`], which is +//! very similar to [`TryFrom`]. +#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", custom_runtime_call)] +//! +//! And indeed, at the runtime level, this associated type would be the same `RuntimeCall` that is +//! passed to `frame_system`. +#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pallet_with_specific_runtime_call_impl)] +//! +//! > In other words, the degree of specificity that [`frame_system::Config::RuntimeCall`] has is +//! > not enough for the pallet to work with. Therefore, the pallet has to define its own associated +//! > type representing `RuntimeCall`. +//! +//! Another way to look at this is: +//! +//! `pallet_with_specific_runtime_call::Config::RuntimeCall` and `frame_system::Config::RuntimeCall` +//! are two different representations of the same concrete type that is only known when the runtime +//! is being constructed. +//! +//! Now, within this pallet, this new `RuntimeCall` can be used, and it can use its new trait +//! bounds, such as being [`frame::traits::IsSubType`]: +#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", custom_runtime_call_usages)] +//! +//! ### Asserting Equality of Multiple Runtime Composite Enums +//! +//! Recall that in the above example, `::RuntimeCall` and `::RuntimeCall` are expected to be equal types, but at the compile-time we +//! have to represent them with two different associated types with different bounds. Would it not +//! be cool if we had a test to make sure they actually resolve to the same concrete type once the +//! runtime is constructed? The following snippet exactly does that: +#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", assert_equality)] +//! +//! We leave it to the reader to further explore what [`frame::traits::Hooks::integrity_test`] is, +//! and what [`core::any::TypeId`] is. Another way to assert this is using +//! [`frame::traits::IsType`]. +//! +//! ## Type Aliases +//! +//! A number of type aliases are generated by the `construct_runtime` which are also noteworthy: +//! +//! * [`runtime::PalletFoo`] is an alias to [`pallet_foo::Pallet`]. Same for `PalletBar`, and +//! `System` +//! * [`runtime::AllPalletsWithSystem`] is an alias for a tuple of all of the above. This type is +//! important to FRAME internals such as `executive`, as it implements traits such as +//! [`frame::traits::Hooks`]. +//! +//! ## Further Details +//! +//! * [`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::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). +//! +//! +//! [`construct_runtime`]: frame::runtime::prelude::construct_runtime +//! [`runtime::PalletFoo`]: crate::reference_docs::frame_runtime_types::runtime::PalletFoo +//! [`runtime::AllPalletsWithSystem`]: crate::reference_docs::frame_runtime_types::runtime::AllPalletsWithSystem +//! [`runtime`]: crate::reference_docs::frame_runtime_types::runtime +//! [`pallet_foo`]: crate::reference_docs::frame_runtime_types::pallet_foo +//! [`pallet_foo::Call`]: crate::reference_docs::frame_runtime_types::pallet_foo::Call +//! [`pallet_foo::Pallet`]: crate::reference_docs::frame_runtime_types::pallet_foo::Pallet +//! [`pallet_bar`]: crate::reference_docs::frame_runtime_types::pallet_bar +//! [`pallet_bar::GenesisConfig`]: crate::reference_docs::frame_runtime_types::pallet_bar::GenesisConfig +//! [`RuntimeEvent`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeEvent +//! [`RuntimeGenesisConfig`]: +//! crate::reference_docs::frame_runtime_types::runtime::RuntimeGenesisConfig +//! [`RuntimeOrigin`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeOrigin +//! [`OriginCaller`]: crate::reference_docs::frame_runtime_types::runtime::OriginCaller +//! [`RuntimeError`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeError +//! [`RuntimeCall`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeCall +//! [`RuntimeHoldReason`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeHoldReason + +use frame::prelude::*; + +#[docify::export] +#[frame::pallet(dev_mode)] +pub mod pallet_foo { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::origin] + #[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] + pub enum Origin { + A, + B, + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + pub fn foo(_origin: OriginFor) -> DispatchResult { + todo!(); + } + + pub fn other(_origin: OriginFor) -> DispatchResult { + todo!(); + } + } +} + +#[docify::export] +#[frame::pallet(dev_mode)] +pub mod pallet_bar { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::genesis_config] + #[derive(DefaultNoBound)] + pub struct GenesisConfig { + pub initial_account: Option, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) {} + } + + #[pallet::call] + impl Pallet { + pub fn bar(_origin: OriginFor) -> DispatchResult { + todo!(); + } + } +} + +pub mod runtime { + use super::{pallet_bar, pallet_foo}; + use frame::{runtime::prelude::*, testing_prelude::*}; + + #[docify::export(runtime_exp)] + construct_runtime!( + pub struct Runtime { + System: frame_system, + PalletFoo: pallet_foo, + PalletBar: pallet_bar, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_foo::Config for Runtime {} + impl pallet_bar::Config for Runtime {} +} + +#[frame::pallet(dev_mode)] +pub mod pallet_with_specific_runtime_call { + use super::*; + use frame::traits::IsSubType; + + #[docify::export(custom_runtime_call)] + /// A pallet that wants to further narrow down what `RuntimeCall` is. + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeCall: IsSubType>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + // note that this pallet needs some `call` to have a `enum Call`. + #[pallet::call] + impl Pallet { + pub fn foo(_origin: OriginFor) -> DispatchResult { + todo!(); + } + } + + #[docify::export(custom_runtime_call_usages)] + impl Pallet { + fn _do_something_useful_with_runtime_call(call: ::RuntimeCall) { + // check if the runtime call given is of this pallet's variant. + let _maybe_my_call: Option<&Call> = call.is_sub_type(); + todo!(); + } + } + + #[docify::export(assert_equality)] + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + use core::any::TypeId; + assert_eq!( + TypeId::of::<::RuntimeCall>(), + TypeId::of::<::RuntimeCall>() + ); + } + } +} + +pub mod runtime_with_specific_runtime_call { + use super::pallet_with_specific_runtime_call; + use frame::{runtime::prelude::*, testing_prelude::*}; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + PalletWithSpecificRuntimeCall: pallet_with_specific_runtime_call, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + #[docify::export(pallet_with_specific_runtime_call_impl)] + impl pallet_with_specific_runtime_call::Config for Runtime { + // an implementation of `IsSubType` is provided by `construct_runtime`. + type RuntimeCall = RuntimeCall; + } +} diff --git a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs new file mode 100644 index 0000000000000000000000000000000000000000..7d870b432218e9e9a06c25f4f19e1f07ca72c6c6 --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs @@ -0,0 +1,138 @@ +//! # Runtime Upgrades +//! +//! At their core, blockchain logic consists of +//! +//! 1. on-chain state and +//! 2. a state transition function +//! +//! In Substrate-based blockchains, state transition functions are referred to as +//! [runtimes](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/blockchain_state_machines/index.html). +//! +//! Traditionally, before Substrate, upgrading state transition functions required node +//! operators to download new software and restart their nodes in a process called +//! [forking](https://en.wikipedia.org/wiki/Fork_(blockchain)). +//! +//! Substrate-based blockchains do not require forking, and instead upgrade runtimes +//! in a process called "Runtime Upgrades". +//! +//! Forkless runtime upgrades are a defining feature of the Substrate framework. Updating the +//! runtime logic without forking the code base enables your blockchain to seemlessly evolve +//! over time in a deterministic, rules-based manner. It also removes ambiguity for node operators +//! and other participants in the network about what is the canonical runtime. +//! +//! This capability is possible due to the runtime of a blockchain existing in on-chain storage. +//! +//! ## Performing a Runtime Upgrade +//! +//! To upgrade a runtime, an [`Origin`](frame_system::RawOrigin) with the necesarry permissions +//! (usually via governance) changes the `:code` storage. Usually, this is performed via a call to +//! [`set_code`] (or [`set_code_without_checks`]) with the desired new runtime blob, scheduled +//! using [`pallet_scheduler`]. +//! +//! Prior to building the new runtime, don't forget to update the +//! [`RuntimeVersion`](sp_version::RuntimeVersion). +//! +//! # Migrations +//! +//! It is often desirable to define logic to execute immediately after runtime upgrades (see +//! [this diagram](frame::traits::Hooks)). +//! +//! Self-contained pieces of logic that execute after a runtime upgrade are called "Migrations". +//! +//! The typical use case of a migration is to 'migrate' pallet storage from one layout to another, +//! for example when the encoding of a storage item is changed. However, they can also execute +//! arbitary logic such as: +//! +//! - Calling arbitrary pallet methods +//! - Mutating arbitrary on-chain state +//! - Cleaning up some old storage items that are no longer needed +//! +//! ## Single Block Migrations +//! +//! - Execute immediately and entirely at the beginning of the block following +//! a runtime upgrade. +//! - Are suitable for migrations which are guaranteed to not exceed the block weight. +//! - Are simply implementations of [`OnRuntimeUpgrade`]. +//! +//! To learn best practices for writing single block pallet storage migrations, see the +//! [Single Block Migration Example Pallet](pallet_example_single_block_migrations). +//! +//! ### Scheduling the Single Block Migrations to Run Next Runtime Upgrade +//! +//! Schedule migrations to run next runtime upgrade passing them as a generic parameter to your +//! [`Executive`](frame_executive) pallet: +//! +//! ```ignore +//! /// Tuple of migrations (structs that implement `OnRuntimeUpgrade`) +//! type Migrations = ( +//! pallet_example_storage_migration::migrations::v1::versioned::MigrateV0ToV1, +//! MyCustomMigration, +//! // ...more migrations here +//! ); +//! pub type Executive = frame_executive::Executive< +//! Runtime, +//! Block, +//! frame_system::ChainContext, +//! Runtime, +//! AllPalletsWithSystem, +//! Migrations, // <-- pass your migrations to Executive here +//! >; +//! ``` +//! +//! ### Ensuring Single Block Migration Safety +//! +//! "My migration unit tests pass, so it should be safe to deploy right?" +//! +//! No! Unit tests execute the migration in a very simple test environment, and cannot account +//! for the complexities of a real runtime or real on-chain state. +//! +//! Prior to deploying migrations, it is critical to perform additional checks to ensure that when +//! run in our real runtime they will not brick the chain due to: +//! - Panicing +//! - Touching too many storage keys and resulting in an excessively large PoV +//! - Taking too long to execute +//! +//! [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli) has a sub-command +//! [`on-runtime-upgrade`](https://paritytech.github.io/try-runtime-cli/try_runtime_core/commands/enum.Action.html#variant.OnRuntimeUpgrade) +//! which is designed to help with exactly this. +//! +//! Developers MUST run this command before deploying migrations to ensure they will not +//! inadvertently result in a bricked chain. +//! +//! It is recommended to run as part of your CI pipeline. See the +//! [polkadot-sdk check-runtime-migration job](https://github.com/paritytech/polkadot-sdk/blob/4a293bc5a25be637c06ce950a34490706597615b/.gitlab/pipeline/check.yml#L103-L124) +//! for an example of how to configure this. +//! +//! ### Note on the Manipulability of PoV Size and Execution Time +//! +//! While [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli) can help ensure with +//! very high certainty that a migration will succeed given **existing** on-chain state, it cannot +//! prevent a malicious actor from manipulating state in a way that will cause the migration to take +//! longer or produce a PoV much larger than previously measured. +//! +//! Therefore, it is important to write migrations in such a way that the execution time or PoV size +//! it adds to the block cannot be easily manipulated. e.g., do not iterate over storage that can +//! quickly or cheaply be bloated. +//! +//! If writing your migration in such a way is not possible, a multi block migration should be used +//! instead. +//! +//! ### Other useful tools +//! +//! [`Chopsticks`](https://github.com/AcalaNetwork/chopsticks) is another tool in the Substrate +//! ecosystem which developers may find useful to use in addition to `try-runtime-cli` when testing +//! their single block migrations. +//! +//! ## Multi Block Migrations +//! +//! Safely and easily execute long-running migrations across multiple blocks. +//! +//! Suitable for migrations which could use arbitrary amounts of block weight. +//! +//! TODO: Link to multi block migration example/s once PR is merged (). +//! +//! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion +//! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade +//! [`StorageVersion`]: frame_support::traits::StorageVersion +//! [`set_code`]: frame_system::Call::set_code +//! [`set_code_without_checks`]: frame_system::Call::set_code_without_checks diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index c16122ee4287b17614f5d61acc9f26df0429c2cd..f4b52208e2fd6c37248b01352fc17cbd41792a02 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -39,20 +39,20 @@ 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. +/// Learn about the transaction extensions that form a part of extrinsics. // TODO: @jsdw https://github.com/paritytech/polkadot-sdk-docs/issues/42 -pub mod signed_extensions; +pub mod transaction_extensions; -/// Learn about *"Origin"* A topic in FRAME that enables complex account abstractions to be built. -// TODO: @shawntabrizi https://github.com/paritytech/polkadot-sdk-docs/issues/43 +/// Learn about *Origins*, a topic in FRAME that enables complex account abstractions to be built. pub mod frame_origin; /// Learn about how to write safe and defensive code in your FRAME runtime. // TODO: @CrackTheCode016 https://github.com/paritytech/polkadot-sdk-docs/issues/44 pub mod safe_defensive_programming; -/// Learn about composite enums in FRAME-based runtimes, such as "RuntimeEvent" and "RuntimeCall". -pub mod frame_composite_enums; +/// Learn about composite enums and other runtime level types, such as "RuntimeEvent" and +/// "RuntimeCall". +pub mod frame_runtime_types; /// Learn about how to make a pallet/runtime that is fee-less and instead uses another mechanism to /// control usage and sybil attacks. @@ -92,11 +92,18 @@ pub mod cli; // TODO: @JoshOrndorff @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/54 pub mod consensus_swapping; -/// Learn about all the advance ways to test your coordinate a rutnime upgrade and data migration. -// TODO: @liamaharon https://github.com/paritytech/polkadot-sdk-docs/issues/55 -pub mod frame_runtime_migration; +/// Learn about Runtime Upgrades and best practices for writing Migrations. +pub mod frame_runtime_upgrades_and_migrations; /// Learn about light nodes, how they function, and how Substrate-based chains come /// light-node-first out of the box. // TODO: @jsdw @josepot https://github.com/paritytech/polkadot-sdk-docs/issues/68 pub mod light_nodes; + +/// Learn about the offchain workers, how they function, and how to use them, as provided by the +/// [`frame`] APIs. +pub mod frame_offchain_workers; + +/// Learn about the different ways through which multiple [`frame`] pallets can be combined to work +/// together. +pub mod frame_pallet_coupling; diff --git a/docs/sdk/src/reference_docs/signed_extensions.rs b/docs/sdk/src/reference_docs/signed_extensions.rs deleted file mode 100644 index 28b1426536bcdf371865db74a104a27d51869c86..0000000000000000000000000000000000000000 --- a/docs/sdk/src/reference_docs/signed_extensions.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! 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. -//! -//! # Example -//! -//! 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 parity_scale_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(()) - } - } -} 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 0000000000000000000000000000000000000000..4f96d665d9bd2745de7b9911bd06cb059c62e9b4 --- /dev/null +++ b/docs/sdk/src/reference_docs/transaction_extensions.rs @@ -0,0 +1,57 @@ +//! 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. +//! +//! # Example +//! +//! 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 parity_scale_codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_runtime::{ + impl_tx_ext_default, + traits::{Dispatchable, TransactionExtension, TransactionExtensionBase}, + 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 TransactionExtensionBase for AddToPayload { + const IDENTIFIER: &'static str = "AddToPayload"; + type Implicit = (); + } + + impl TransactionExtension for AddToPayload { + type Pre = (); + type Val = (); + + impl_tx_ext_default!(Call; (); 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 TransactionExtensionBase for AddToSignaturePayload { + const IDENTIFIER: &'static str = "AddToSignaturePayload"; + type Implicit = u32; + + fn implicit(&self) -> Result { + Ok(1234) + } + } + + impl TransactionExtension for AddToSignaturePayload { + type Pre = (); + type Val = (); + + impl_tx_ext_default!(Call; (); validate prepare); + } +} diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 3186e31f39e80f28e792842b3809e524fdac2d03..b9232f95981bf66427ffc67cc98282efb8cf330b 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -19,9 +19,9 @@ crate-type = ["cdylib", "rlib"] [dependencies] cfg-if = "1.0" -clap = { version = "4.4.18", features = ["derive"], optional = true } -log = "0.4.17" -thiserror = "1.0.48" +clap = { version = "4.5.1", features = ["derive"], optional = true } +log = { workspace = true, default-features = true } +thiserror = { workspace = true } futures = "0.3.21" pyro = { package = "pyroscope", version = "0.5.3", optional = true } pyroscope_pprofrs = { version = "0.2", optional = true } @@ -42,6 +42,7 @@ sc-tracing = { path = "../../substrate/client/tracing", optional = true } sc-sysinfo = { path = "../../substrate/client/sysinfo" } sc-executor = { path = "../../substrate/client/executor" } sc-storage-monitor = { path = "../../substrate/client/storage-monitor" } +sp-runtime = { path = "../../substrate/primitives/runtime" } [build-dependencies] substrate-build-script-utils = { path = "../../substrate/utils/build-script-utils" } @@ -63,9 +64,14 @@ runtime-benchmarks = [ "polkadot-node-metrics/runtime-benchmarks", "sc-service?/runtime-benchmarks", "service/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] full-node = ["service/full-node"] -try-runtime = ["service/try-runtime", "try-runtime-cli/try-runtime"] +try-runtime = [ + "service/try-runtime", + "sp-runtime/try-runtime", + "try-runtime-cli/try-runtime", +] fast-runtime = ["service/fast-runtime"] pyroscope = ["pyro", "pyroscope_pprofrs"] diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index 30f35ebcb6ffa95f0f2384821e168353d95df94b..e1bc2309a942a8255dd5c99a0db0725aa3b1b37d 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -52,7 +52,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone CLI /// (). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, /// Key management CLI utilities diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 7319f28a2e2aa0a952b9f5d4d956fc9fc2321923..f71891ecde34c0caea9f0b0372f2eb7a1d648e7a 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -451,7 +451,7 @@ pub fn run() -> Result<()> { if cfg!(feature = "runtime-benchmarks") { runner.sync_run(|config| { - cmd.run::(config) + cmd.run::, ()>(config) .map_err(|e| Error::SubstrateCli(e)) }) } else { diff --git a/polkadot/doc/testing.md b/polkadot/doc/testing.md deleted file mode 100644 index 76703b1b4398a0cac8423183a5d2febfabab0e6c..0000000000000000000000000000000000000000 --- a/polkadot/doc/testing.md +++ /dev/null @@ -1,302 +0,0 @@ -# Testing - -Testing is an essential tool to assure correctness. This document describes how we test the Polkadot code, whether -locally, at scale, and/or automatically in CI. - -## Scopes - -The testing strategy for Polkadot is 4-fold: - -### Unit testing (1) - -Boring, small scale correctness tests of individual functions. It is usually -enough to run `cargo test` in the crate you are testing. - -For full coverage you may have to pass some additional features. For example: - -```sh -cargo test --features ci-only-tests -``` - -### Integration tests - -There are the following variants of integration tests: - -#### Subsystem tests (2) - -One particular subsystem (subsystem under test) interacts with a mocked overseer that is made to assert incoming and -outgoing messages of the subsystem under test. See e.g. the `statement-distribution` tests. - -#### Behavior tests (3) - -Launching small scale networks, with multiple adversarial nodes. This should include tests around the thresholds in -order to evaluate the error handling once certain assumed invariants fail. - -Currently, we commonly use **zombienet** to run mini test-networks, whether locally or in CI. To run on your machine: - -- First, make sure you have [zombienet][zombienet] installed. - -- Now, all the required binaries must be installed in your $PATH. You must run the following from the `polkadot/` -directory in order to test your changes. (Not `zombienet setup`, or you will get the released binaries without your -local changes!) - -```sh -cargo install --path . --locked -``` - -- You will also need to install whatever binaries are required for your specific tests. For example, to install -`undying-collator`, from `polkadot/`, run: - -```sh -cargo install --path ./parachain/test-parachains/undying/collator --locked -``` - -- Finally, run the zombienet test from the `polkadot` directory: - -```sh -RUST_LOG=parachain::pvf=trace zombienet --provider=native spawn zombienet_tests/functional/0001-parachains-pvf.toml -``` - -- You can pick a validator node like `alice` from the output and view its logs -(`tail -f `) or metrics. Make sure there is nothing funny in the logs -(try `grep WARN `). - -#### Testing at scale (4) - -Launching many nodes with configurable network speed and node features in a cluster of nodes. At this scale the -[Simnet][simnet] comes into play which launches a full cluster of nodes. The scale is handled by spawning a kubernetes -cluster and the meta description is covered by [Gurke][Gurke]. Asserts are made using Grafana rules, based on the -existing prometheus metrics. This can be extended by adding an additional service translating `jaeger` spans into -addition prometheus avoiding additional Polkadot source changes. - -_Behavior tests_ and _testing at scale_ have naturally soft boundary. The most significant difference is the presence of -a real network and the number of nodes, since a single host often not capable to run multiple nodes at once. - -## Observing Logs - -To verify expected behavior it's often useful to observe logs. To avoid too many -logs at once, you can run one test at a time: - -1. Add `sp_tracing::try_init_simple();` to the beginning of a test -2. Specify `RUST_LOG=::=trace` before the cargo command. - -For example: - -```sh -RUST_LOG=parachain::pvf=trace cargo test execute_can_run_serially -``` - -For more info on how our logs work, check [the docs][logs]. - -## Coverage - -Coverage gives a _hint_ of the actually covered source lines by tests and test applications. - -The state of the art is currently tarpaulin which unfortunately yields a lot of false negatives. Lines that -are in fact covered, marked as uncovered due to a mere linebreak in a statement can cause these artifacts. This leads to -lower coverage percentages than there actually is. - -Since late 2020 rust has gained [MIR based coverage tooling]( -https://blog.rust-lang.org/inside-rust/2020/11/12/source-based-code-coverage.html). - -```sh -# setup -rustup component add llvm-tools-preview -cargo install grcov miniserve - -export CARGO_INCREMENTAL=0 -# wasm is not happy with the instrumentation -export SKIP_BUILD_WASM=true -export BUILD_DUMMY_WASM_BINARY=true -# the actully collected coverage data -export LLVM_PROFILE_FILE="llvmcoveragedata-%p-%m.profraw" -# build wasm without instrumentation -export WASM_TARGET_DIRECTORY=/tmp/wasm -cargo +nightly build -# required rust flags -export RUSTFLAGS="-Zinstrument-coverage" -# assure target dir is clean -rm -r target/{debug,tests} -# run tests to get coverage data -cargo +nightly test --all - -# create the *html* report out of all the test binaries -# mostly useful for local inspection -grcov . --binary-path ./target/debug -s . -t html --branch --ignore-not-existing -o ./coverage/ -miniserve -r ./coverage - -# create a *codecov* compatible report -grcov . --binary-path ./target/debug/ -s . -t lcov --branch --ignore-not-existing --ignore "/*" -o lcov.info -``` - -The test coverage in `lcov` can the be published to . - -```sh -bash <(curl -s https://codecov.io/bash) -f lcov.info -``` - -or just printed as part of the PR using a github action i.e. -[`jest-lcov-reporter`](https://github.com/marketplace/actions/jest-lcov-reporter). - -For full examples on how to use [`grcov` /w Polkadot specifics see the github -repo](https://github.com/mozilla/grcov#coverallscodecov-output). - -## Fuzzing - -Fuzzing is an approach to verify correctness against arbitrary or partially structured inputs. - -Currently implemented fuzzing targets: - -- `erasure-coding` - -The tooling of choice here is `honggfuzz-rs` as it allows _fastest_ coverage according to "some paper" which is a -positive feature when run as part of PRs. - -Fuzzing is generally not applicable for data secured by cryptographic hashes or signatures. Either the input has to be -specifically crafted, such that the discarded input percentage stays in an acceptable range. System level fuzzing is -hence simply not feasible due to the amount of state that is required. - -Other candidates to implement fuzzing are: - -- `rpc` -- ... - -## Performance metrics - -There are various ways of performance metrics. - -- timing with `criterion` -- cache hits/misses w/ `iai` harness or `criterion-perf` -- `coz` a performance based compiler - -Most of them are standard tools to aid in the creation of statistical tests regarding change in time of certain unit -tests. - -`coz` is meant for runtime. In our case, the system is far too large to yield a sufficient number of measurements in -finite time. An alternative approach could be to record incoming package streams per subsystem and store dumps of them, -which in return could be replayed repeatedly at an accelerated speed, with which enough metrics could be obtained to -yield information on which areas would improve the metrics. This unfortunately will not yield much information, since -most if not all of the subsystem code is linear based on the input to generate one or multiple output messages, it is -unlikely to get any useful metrics without mocking a sufficiently large part of the other subsystem which overlaps with -[#Integration tests] which is unfortunately not repeatable as of now. As such the effort gain seems low and this is not -pursued at the current time. - -## Writing small scope integration tests with preconfigured workers - -Requirements: - -- spawn nodes with preconfigured behaviors -- allow multiple types of configuration to be specified -- allow extendability via external crates -- ... - ---- - -## Implementation of different behavior strain nodes - -### Goals - -The main goals are is to allow creating a test node which exhibits a certain behavior by utilizing a subset of _wrapped_ -or _replaced_ subsystems easily. The runtime must not matter at all for these tests and should be simplistic. The -execution must be fast, this mostly means to assure a close to zero network latency as well as shorting the block time -and epoch times down to a few `100ms` and a few dozend blocks per epoch. - -### Approach - -#### MVP - -A simple small scale builder pattern would suffice for stage one implementation of allowing to replace individual -subsystems. An alternative would be to harness the existing `AllSubsystems` type and replace the subsystems as needed. - -#### Full `proc-macro` implementation - -`Overseer` is a common pattern. It could be extracted as `proc` macro and generative `proc-macro`. This would replace -the `AllSubsystems` type as well as implicitly create the `AllMessages` enum as `AllSubsystemsGen` does today. - -The implementation is yet to be completed, see the [implementation PR](https://github.com/paritytech/polkadot/pull/2962) -for details. - -##### Declare an overseer implementation - -```rust -struct BehaveMaleficient; - -impl OverseerGen for BehaveMaleficient { - fn generate<'a, Spawner, RuntimeClient>( - &self, - args: OverseerGenArgs<'a, Spawner, RuntimeClient>, - ) -> Result<(Overseer>, OverseerHandler), Error> - where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, - Spawner: 'static + overseer::gen::Spawner + Clone + Unpin, - { - let spawner = args.spawner.clone(); - let leaves = args.leaves.clone(); - let runtime_client = args.runtime_client.clone(); - let registry = args.registry.clone(); - let candidate_validation_config = args.candidate_validation_config.clone(); - // modify the subsystem(s) as needed: - let all_subsystems = create_default_subsystems(args)?. - // or spawn an entirely new set - - replace_candidate_validation( - // create the filtered subsystem - FilteredSubsystem::new( - CandidateValidationSubsystem::with_config( - candidate_validation_config, - Metrics::register(registry)?, - ), - // an implementation of - Skippy::default(), - ), - ); - - Overseer::new(leaves, all_subsystems, registry, runtime_client, spawner) - .map_err(|e| e.into()) - - // A builder pattern will simplify this further - // WIP https://github.com/paritytech/polkadot/pull/2962 - } -} - -fn main() -> eyre::Result<()> { - color_eyre::install()?; - let cli = Cli::from_args(); - assert_matches::assert_matches!(cli.subcommand, None); - polkadot_cli::run_node(cli, BehaveMaleficient)?; - Ok(()) -} -``` - -[`variant-a`](../node/malus/src/variant-a.rs) is a fully working example. - -#### Simnet - -Spawn a kubernetes cluster based on a meta description using [Gurke] with the [Simnet] scripts. - -Coordinated attacks of multiple nodes or subsystems must be made possible via a side-channel, that is out of scope for -this document. - -The individual node configurations are done as targets with a particular builder configuration. - -#### Behavior tests w/o Simnet - -Commonly this will require multiple nodes, and most machines are limited to running two or three nodes concurrently. -Hence, this is not the common case and is just an implementation _idea_. - -```rust -behavior_testcase!{ -"TestRuntime" => -"Alice": , -"Bob": , -"Charles": Default, -"David": "Charles", -"Eve": "Bob", -} -``` - -[zombienet]: https://github.com/paritytech/zombienet -[Gurke]: https://github.com/paritytech/gurke -[simnet]: https://github.com/paritytech/simnet_scripts -[logs]: https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/node/gum/src/lib.rs diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index 8705c14c3a4d026aa6dda5cc5232e9fdf10baf82..677f15c4b9a1446c7828c78f92933f7811733ee8 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -16,7 +16,7 @@ novelpoly = { package = "reed-solomon-novelpoly", version = "2.0.0" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "std"] } sp-core = { path = "../../substrate/primitives/core" } sp-trie = { path = "../../substrate/primitives/trie" } -thiserror = "1.0.48" +thiserror = { workspace = true } [dev-dependencies] criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index 8c6644ad6da59f51c2eb0ebb583fed0cd211d821..8df0c2b1edae47cad98881e7243eb1dc68449e9e 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -19,7 +19,7 @@ polkadot-node-subsystem-util = { path = "../subsystem-util" } polkadot-primitives = { path = "../../primitives" } sp-core = { path = "../../../substrate/primitives/core" } sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } -thiserror = "1.0.48" +thiserror = { workspace = true } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } [dev-dependencies] diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 5ab823f489454e8cc8f3b7fa3fd32119484277fa..2a5b6198b9a827788696bdf5e1eeeb5829a9da6d 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -20,7 +20,7 @@ merlin = "3.0" schnorrkel = "0.11.4" kvdb = "0.13.0" derive_more = "0.99.17" -thiserror = "1.0.48" +thiserror = { workspace = true } itertools = "0.10.5" polkadot-node-subsystem = { path = "../../subsystem" } @@ -35,7 +35,7 @@ sp-consensus = { path = "../../../../substrate/primitives/consensus/common", def sp-consensus-slots = { path = "../../../../substrate/primitives/consensus/slots", default-features = false } sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto", default-features = false, features = ["full_crypto"] } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -# should match schnorrkel +# rand_core should match schnorrkel rand_core = "0.6.2" rand_chacha = { version = "0.3.1" } rand = "0.8.5" @@ -51,5 +51,5 @@ polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } assert_matches = "1.4.0" kvdb-memorydb = "0.13.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } -log = "0.4.17" +log = { workspace = true, default-features = true } env_logger = "0.9.0" diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 456ae319787b07740bb0817dcfbe260500eb9dd8..8cc16a6e1ec199776003204e8d9c870fb0f62114 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -1253,13 +1253,20 @@ async fn handle_actions( Action::BecomeActive => { *mode = Mode::Active; - let messages = distribution_messages_for_activation( + let (messages, next_actions) = distribution_messages_for_activation( + ctx, overlayed_db, state, delayed_approvals_timers, - )?; + session_info_provider, + ) + .await?; ctx.send_messages(messages.into_iter()).await; + let next_actions: Vec = + next_actions.into_iter().map(|v| v.clone()).chain(actions_iter).collect(); + + actions_iter = next_actions.into_iter(); }, Action::Conclude => { conclude = true; @@ -1313,15 +1320,19 @@ fn get_assignment_core_indices( } } -fn distribution_messages_for_activation( +#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] +async fn distribution_messages_for_activation( + ctx: &mut Context, db: &OverlayedBackend<'_, impl Backend>, state: &State, delayed_approvals_timers: &mut DelayedApprovalTimer, -) -> SubsystemResult> { + session_info_provider: &mut RuntimeInfo, +) -> SubsystemResult<(Vec, Vec)> { let all_blocks: Vec = db.load_all_blocks()?; let mut approval_meta = Vec::with_capacity(all_blocks.len()); let mut messages = Vec::new(); + let mut actions = Vec::new(); messages.push(ApprovalDistributionMessage::NewBlocks(Vec::new())); // dummy value. @@ -1396,16 +1407,60 @@ fn distribution_messages_for_activation( &claimed_core_indices, &block_entry, ) { - Ok(bitfield) => messages.push( - ApprovalDistributionMessage::DistributeAssignment( - IndirectAssignmentCertV2 { - block_hash, - validator: assignment.validator_index(), - cert: assignment.cert().clone(), - }, - bitfield, - ), - ), + Ok(bitfield) => { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?candidate_entry.candidate_receipt().hash(), + ?block_hash, + "Discovered, triggered assignment, not approved yet", + ); + + let indirect_cert = IndirectAssignmentCertV2 { + block_hash, + validator: assignment.validator_index(), + cert: assignment.cert().clone(), + }; + messages.push( + ApprovalDistributionMessage::DistributeAssignment( + indirect_cert.clone(), + bitfield.clone(), + ), + ); + + if !block_entry + .candidate_is_pending_signature(*candidate_hash) + { + let ExtendedSessionInfo { ref executor_params, .. } = + match get_extended_session_info( + session_info_provider, + ctx.sender(), + block_entry.block_hash(), + block_entry.session(), + ) + .await + { + Some(i) => i, + None => continue, + }; + + actions.push(Action::LaunchApproval { + claimed_candidate_indices: bitfield, + candidate_hash: candidate_entry + .candidate_receipt() + .hash(), + indirect_cert, + assignment_tranche: assignment.tranche(), + relay_block_hash: block_hash, + session: block_entry.session(), + executor_params: executor_params.clone(), + candidate: candidate_entry + .candidate_receipt() + .clone(), + backing_group: approval_entry.backing_group(), + distribute_assignment: false, + }); + } + }, Err(err) => { // Should never happen. If we fail here it means the // assignment is null (no cores claimed). @@ -1496,7 +1551,7 @@ fn distribution_messages_for_activation( } messages[0] = ApprovalDistributionMessage::NewBlocks(approval_meta); - Ok(messages) + Ok((messages, actions)) } // Handle an incoming signal from the overseer. Returns true if execution should conclude. diff --git a/polkadot/node/core/approval-voting/src/persisted_entries.rs b/polkadot/node/core/approval-voting/src/persisted_entries.rs index ef47bdb2213a153dc7223c1018ba8ec9b341a5aa..b924a1b52ccf49a242adecfd534b498004ec3d87 100644 --- a/polkadot/node/core/approval-voting/src/persisted_entries.rs +++ b/polkadot/node/core/approval-voting/src/persisted_entries.rs @@ -588,6 +588,13 @@ impl BlockEntry { !self.candidates_pending_signature.is_empty() } + /// Returns true if candidate hash is in the queue for a signature. + pub fn candidate_is_pending_signature(&self, candidate_hash: CandidateHash) -> bool { + self.candidates_pending_signature + .values() + .any(|context| context.candidate_hash == candidate_hash) + } + /// Candidate hashes for candidates pending signatures fn candidate_hashes_pending_signature(&self) -> Vec { self.candidates_pending_signature diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 9220e84a2554a48c14468567e87e74319ce94151..c9053232a4c8752f03134047dbc64b020377740a 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -78,6 +78,7 @@ struct TestSyncOracle { struct TestSyncOracleHandle { done_syncing_receiver: oneshot::Receiver<()>, + is_major_syncing: Arc, } impl TestSyncOracleHandle { @@ -108,8 +109,9 @@ impl SyncOracle for TestSyncOracle { fn make_sync_oracle(val: bool) -> (Box, TestSyncOracleHandle) { let (tx, rx) = oneshot::channel(); let flag = Arc::new(AtomicBool::new(val)); - let oracle = TestSyncOracle { flag, done_syncing_sender: Arc::new(Mutex::new(Some(tx))) }; - let handle = TestSyncOracleHandle { done_syncing_receiver: rx }; + let oracle = + TestSyncOracle { flag: flag.clone(), done_syncing_sender: Arc::new(Mutex::new(Some(tx))) }; + let handle = TestSyncOracleHandle { done_syncing_receiver: rx, is_major_syncing: flag }; (Box::new(oracle), handle) } @@ -465,6 +467,7 @@ struct HarnessConfigBuilder { clock: Option, backend: Option, assignment_criteria: Option>, + major_syncing: bool, } impl HarnessConfigBuilder { @@ -476,9 +479,19 @@ impl HarnessConfigBuilder { self } + pub fn major_syncing(&mut self, value: bool) -> &mut Self { + self.major_syncing = value; + self + } + + pub fn backend(&mut self, store: TestStore) -> &mut Self { + self.backend = Some(store); + self + } + pub fn build(&mut self) -> HarnessConfig { let (sync_oracle, sync_oracle_handle) = - self.sync_oracle.take().unwrap_or_else(|| make_sync_oracle(false)); + self.sync_oracle.take().unwrap_or_else(|| make_sync_oracle(self.major_syncing)); let assignment_criteria = self .assignment_criteria @@ -736,11 +749,13 @@ struct BlockConfig { slot: Slot, candidates: Option>, session_info: Option, + end_syncing: bool, } struct ChainBuilder { blocks_by_hash: HashMap, blocks_at_height: BTreeMap>, + is_major_syncing: Arc, } impl ChainBuilder { @@ -748,16 +763,28 @@ impl ChainBuilder { const GENESIS_PARENT_HASH: Hash = Hash::repeat_byte(0x00); pub fn new() -> Self { - let mut builder = - Self { blocks_by_hash: HashMap::new(), blocks_at_height: BTreeMap::new() }; + let mut builder = Self { + blocks_by_hash: HashMap::new(), + blocks_at_height: BTreeMap::new(), + is_major_syncing: Arc::new(AtomicBool::new(false)), + }; builder.add_block_inner( Self::GENESIS_HASH, Self::GENESIS_PARENT_HASH, 0, - BlockConfig { slot: Slot::from(0), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(0), + candidates: None, + session_info: None, + end_syncing: false, + }, ); builder } + pub fn major_syncing(&mut self, major_syncing: Arc) -> &mut Self { + self.is_major_syncing = major_syncing; + self + } pub fn add_block( &mut self, @@ -808,8 +835,16 @@ impl ChainBuilder { } ancestry.reverse(); - import_block(overseer, ancestry.as_ref(), *number, block_config, false, i > 0) - .await; + import_block( + overseer, + ancestry.as_ref(), + *number, + block_config, + false, + i > 0, + self.is_major_syncing.clone(), + ) + .await; let _: Option<()> = future::pending().timeout(Duration::from_millis(100)).await; } } @@ -863,6 +898,7 @@ async fn import_block( config: &BlockConfig, gap: bool, fork: bool, + major_syncing: Arc, ) { let (new_head, new_header) = &hashes[hashes.len() - 1]; let candidates = config.candidates.clone().unwrap_or(vec![( @@ -891,6 +927,12 @@ async fn import_block( h_tx.send(Ok(Some(new_header.clone()))).unwrap(); } ); + + let is_major_syncing = major_syncing.load(Ordering::SeqCst); + if config.end_syncing { + major_syncing.store(false, Ordering::SeqCst); + } + if !fork { let mut _ancestry_step = 0; if gap { @@ -931,7 +973,7 @@ async fn import_block( } } - if number > 0 { + if number > 0 && !is_major_syncing { assert_matches!( overseer_recv(overseer).await, AllMessages::RuntimeApi( @@ -944,7 +986,6 @@ async fn import_block( c_tx.send(Ok(inclusion_events)).unwrap(); } ); - assert_matches!( overseer_recv(overseer).await, AllMessages::RuntimeApi( @@ -984,14 +1025,14 @@ async fn import_block( ); } - if number == 0 { + if number == 0 && !is_major_syncing { assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NewBlocks(v)) => { assert_eq!(v.len(), 0usize); } ); - } else { + } else if number > 0 && !is_major_syncing { if !fork { // SessionInfo won't be called for forks - it's already cached assert_matches!( @@ -1031,20 +1072,23 @@ async fn import_block( ); } - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalDistribution( - ApprovalDistributionMessage::NewBlocks(mut approval_vec) - ) => { - assert_eq!(approval_vec.len(), 1); - let metadata = approval_vec.pop().unwrap(); - let hash = &hashes[number as usize]; - let parent_hash = &hashes[(number - 1) as usize]; - assert_eq!(metadata.hash, hash.0.clone()); - assert_eq!(metadata.parent_hash, parent_hash.0.clone()); - assert_eq!(metadata.slot, config.slot); - } - ); + if !is_major_syncing { + assert_matches!( + overseer_recv(overseer).await, + + AllMessages::ApprovalDistribution( + ApprovalDistributionMessage::NewBlocks(mut approval_vec) + ) => { + assert_eq!(approval_vec.len(), 1); + let metadata = approval_vec.pop().unwrap(); + let hash = &hashes[number as usize]; + let parent_hash = &hashes[(number - 1) as usize]; + assert_eq!(metadata.hash, hash.0.clone()); + assert_eq!(metadata.parent_hash, parent_hash.0.clone()); + assert_eq!(metadata.slot, config.slot); + } + ); + } } } @@ -1072,7 +1116,7 @@ fn subsystem_rejects_bad_assignment_ok_criteria() { block_hash, head, 1, - BlockConfig { slot, candidates: None, session_info: None }, + BlockConfig { slot, candidates: None, session_info: None, end_syncing: false }, ); builder.build(&mut virtual_overseer).await; @@ -1135,7 +1179,7 @@ fn subsystem_rejects_bad_assignment_err_criteria() { block_hash, head, 1, - BlockConfig { slot, candidates: None, session_info: None }, + BlockConfig { slot, candidates: None, session_info: None, end_syncing: false }, ); builder.build(&mut virtual_overseer).await; @@ -1240,6 +1284,7 @@ fn subsystem_rejects_approval_if_no_candidate_entry() { slot, candidates: Some(vec![(candidate_descriptor, CoreIndex(1), GroupIndex(1))]), session_info: None, + end_syncing: false, }, ); builder.build(&mut virtual_overseer).await; @@ -1345,7 +1390,12 @@ fn subsystem_rejects_approval_before_assignment() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(1), + candidates: None, + session_info: None, + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -1398,7 +1448,12 @@ fn subsystem_rejects_assignment_in_future() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(0), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(0), + candidates: None, + session_info: None, + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -1472,6 +1527,7 @@ fn subsystem_accepts_duplicate_assignment() { (candidate_receipt2, CoreIndex(1), GroupIndex(1)), ]), session_info: None, + end_syncing: false, }, ) .build(&mut virtual_overseer) @@ -1537,7 +1593,12 @@ fn subsystem_rejects_assignment_with_unknown_candidate() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(1), + candidates: None, + session_info: None, + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -1582,7 +1643,12 @@ fn subsystem_rejects_oversized_bitfields() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(1), + candidates: None, + session_info: None, + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -1650,7 +1716,12 @@ fn subsystem_accepts_and_imports_approval_after_assignment() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(1), + candidates: None, + session_info: None, + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -1741,6 +1812,7 @@ fn subsystem_second_approval_import_only_schedules_wakeups() { slot: Slot::from(0), candidates: None, session_info: Some(session_info), + end_syncing: false, }, ) .build(&mut virtual_overseer) @@ -1824,7 +1896,12 @@ fn subsystem_assignment_import_updates_candidate_entry_and_schedules_wakeup() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(1), + candidates: None, + session_info: None, + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -1873,7 +1950,12 @@ fn subsystem_process_wakeup_schedules_wakeup() { block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot: Slot::from(1), candidates: None, session_info: None }, + BlockConfig { + slot: Slot::from(1), + candidates: None, + session_info: None, + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -1925,7 +2007,7 @@ fn linear_import_act_on_leaf() { hash, head, i, - BlockConfig { slot, candidates: None, session_info: None }, + BlockConfig { slot, candidates: None, session_info: None, end_syncing: false }, ); head = hash; } @@ -1983,7 +2065,7 @@ fn forkful_import_at_same_height_act_on_leaf() { hash, head, i, - BlockConfig { slot, candidates: None, session_info: None }, + BlockConfig { slot, candidates: None, session_info: None, end_syncing: false }, ); head = hash; } @@ -1997,7 +2079,7 @@ fn forkful_import_at_same_height_act_on_leaf() { hash, head, session, - BlockConfig { slot, candidates: None, session_info: None }, + BlockConfig { slot, candidates: None, session_info: None, end_syncing: false }, ); } builder.build(&mut virtual_overseer).await; @@ -2168,6 +2250,7 @@ fn import_checked_approval_updates_entries_and_schedules() { slot, candidates: Some(vec![(candidate_descriptor, CoreIndex(0), GroupIndex(0))]), session_info: Some(session_info), + end_syncing: false, }, ); builder.build(&mut virtual_overseer).await; @@ -2323,6 +2406,7 @@ fn subsystem_import_checked_approval_sets_one_block_bit_at_a_time() { (candidate_receipt2, CoreIndex(1), GroupIndex(1)), ]), session_info: Some(session_info), + end_syncing: false, }, ) .build(&mut virtual_overseer) @@ -2445,6 +2529,7 @@ fn approved_ancestor_test( slot: Slot::from(i as u64), candidates: Some(vec![(candidate_receipt, CoreIndex(0), GroupIndex(0))]), session_info: None, + end_syncing: false, }, ); } @@ -2623,13 +2708,19 @@ fn subsystem_validate_approvals_cache() { slot, candidates: candidates.clone(), session_info: Some(session_info.clone()), + end_syncing: false, }, ) .add_block( fork_block_hash, ChainBuilder::GENESIS_HASH, 1, - BlockConfig { slot, candidates, session_info: Some(session_info) }, + BlockConfig { + slot, + candidates, + session_info: Some(session_info), + end_syncing: false, + }, ) .build(&mut virtual_overseer) .await; @@ -2740,6 +2831,7 @@ fn subsystem_doesnt_distribute_duplicate_compact_assignments() { (candidate_receipt2.clone(), CoreIndex(1), GroupIndex(1)), ]), session_info: None, + end_syncing: false, }, ) .build(&mut virtual_overseer) @@ -2997,6 +3089,7 @@ where slot, candidates: Some(vec![(candidate_receipt, CoreIndex(0), GroupIndex(2))]), session_info: Some(session_info), + end_syncing: false, }, ) .build(&mut virtual_overseer) @@ -3314,6 +3407,7 @@ fn pre_covers_dont_stall_approval() { slot, candidates: Some(vec![(candidate_descriptor, CoreIndex(0), GroupIndex(0))]), session_info: Some(session_info), + end_syncing: false, }, ); builder.build(&mut virtual_overseer).await; @@ -3491,6 +3585,7 @@ fn waits_until_approving_assignments_are_old_enough() { slot, candidates: Some(vec![(candidate_descriptor, CoreIndex(0), GroupIndex(0))]), session_info: Some(session_info), + end_syncing: false, }, ); builder.build(&mut virtual_overseer).await; @@ -3705,6 +3800,7 @@ fn test_approval_is_sent_on_max_approval_coalesce_count() { slot, candidates: candidates.clone(), session_info: Some(session_info.clone()), + end_syncing: false, }, ) .build(&mut virtual_overseer) @@ -3943,8 +4039,7 @@ fn test_approval_is_sent_on_max_approval_coalesce_wait() { let store = config.backend(); test_harness(config, |test_harness| async move { - let TestHarness { mut virtual_overseer, clock, sync_oracle_handle: _sync_oracle_handle } = - test_harness; + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle: _ } = test_harness; assert_matches!( overseer_recv(&mut virtual_overseer).await, @@ -4006,6 +4101,7 @@ fn test_approval_is_sent_on_max_approval_coalesce_wait() { slot, candidates: candidates.clone(), session_info: Some(session_info.clone()), + end_syncing: false, }, ) .build(&mut virtual_overseer) @@ -4040,3 +4136,569 @@ fn test_approval_is_sent_on_max_approval_coalesce_wait() { virtual_overseer }); } + +// Builds a chain with a fork where both relay blocks include the same candidate. +async fn build_chain_with_two_blocks_with_one_candidate_each( + block_hash1: Hash, + block_hash2: Hash, + slot: Slot, + sync_oracle_handle: TestSyncOracleHandle, + candidate_receipt: CandidateReceipt, +) -> (ChainBuilder, SessionInfo) { + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + ]; + let session_info = SessionInfo { + validator_groups: IndexedVec::>::from(vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3), ValidatorIndex(4)], + ]), + ..session_info(&validators) + }; + + let candidates = Some(vec![(candidate_receipt.clone(), CoreIndex(0), GroupIndex(0))]); + let mut chain_builder = ChainBuilder::new(); + + chain_builder + .major_syncing(sync_oracle_handle.is_major_syncing.clone()) + .add_block( + block_hash1, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot, + candidates: candidates.clone(), + session_info: Some(session_info.clone()), + end_syncing: false, + }, + ) + .add_block( + block_hash2, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot, + candidates, + session_info: Some(session_info.clone()), + end_syncing: true, + }, + ); + (chain_builder, session_info) +} + +async fn setup_overseer_with_two_blocks_each_with_one_assignment_triggered( + virtual_overseer: &mut VirtualOverseer, + store: TestStore, + clock: &Box, + sync_oracle_handle: TestSyncOracleHandle, +) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + let fork_block_hash = Hash::repeat_byte(0x02); + let candidate_commitments = CandidateCommitments::default(); + let mut candidate_receipt = dummy_candidate_receipt(block_hash); + candidate_receipt.commitments_hash = candidate_commitments.hash(); + let candidate_hash = candidate_receipt.hash(); + let slot = Slot::from(1); + let (chain_builder, _session_info) = build_chain_with_two_blocks_with_one_candidate_each( + block_hash, + fork_block_hash, + slot, + sync_oracle_handle, + candidate_receipt, + ) + .await; + chain_builder.build(virtual_overseer).await; + + assert!(!clock.inner.lock().current_wakeup_is(1)); + clock.inner.lock().wakeup_all(1); + + assert!(clock.inner.lock().current_wakeup_is(slot_to_tick(slot))); + clock.inner.lock().wakeup_all(slot_to_tick(slot)); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + clock.inner.lock().wakeup_all(slot_to_tick(slot + 2)); + + assert_eq!(clock.inner.lock().wakeups.len(), 0); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + let candidate_entry = store.load_candidate_entry(&candidate_hash).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); +} + +// Tests that for candidates that we did not approve yet, for which we triggered the assignment and +// the approval work we restart the work to approve it. +#[test] +fn subsystem_relaunches_approval_work_on_restart() { + let assignment_criteria = Box::new(MockAssignmentCriteria( + || { + let mut assignments = HashMap::new(); + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + .into(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(1), CoreIndex(2)] + .try_into() + .unwrap(), + }), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + assignments + }, + |_| Ok(0), + )); + let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); + let store = config.backend(); + let store_clone = config.backend(); + + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle } = test_harness; + + setup_overseer_with_two_blocks_each_with_one_assignment_triggered( + &mut virtual_overseer, + store, + &clock, + sync_oracle_handle, + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _ + )) => { + } + ); + + // Bail early after the assignment has been distributed but before we answer with the mocked + // approval from CandidateValidation. + virtual_overseer + }); + + // Restart a new approval voting subsystem with the same database and major syncing true untill + // the last leaf. + let config = HarnessConfigBuilder::default().backend(store_clone).major_syncing(true).build(); + + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle } = test_harness; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + let fork_block_hash = Hash::repeat_byte(0x02); + let candidate_commitments = CandidateCommitments::default(); + let mut candidate_receipt = dummy_candidate_receipt(block_hash); + candidate_receipt.commitments_hash = candidate_commitments.hash(); + let slot = Slot::from(1); + clock.inner.lock().set_tick(slot_to_tick(slot + 2)); + let (chain_builder, session_info) = build_chain_with_two_blocks_with_one_candidate_each( + block_hash, + fork_block_hash, + slot, + sync_oracle_handle, + candidate_receipt, + ) + .await; + + chain_builder.build(&mut virtual_overseer).await; + + futures_timer::Delay::new(Duration::from_millis(2000)).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionInfo(_, si_tx), + ) + ) => { + si_tx.send(Ok(Some(session_info.clone()))).unwrap(); + } + ); + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(_, si_tx), + ) + ) => { + // Make sure all SessionExecutorParams calls are not made for the leaf (but for its relay parent) + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + + // On major syncing ending Approval voting should send all the necessary messages for a + // candidate to be approved. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NewBlocks( + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + // Guarantees the approval work has been relaunched. + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { + exec_kind, + response_sender, + .. + }) if exec_kind == PvfExecKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) + .unwrap(); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 1, + })); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 1, + })); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) + ); + + // Assert that there are no more messages being sent by the subsystem + assert!(overseer_recv(&mut virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + + virtual_overseer + }); +} + +// Test that cached approvals, which are candidates that we approved but we didn't issue +// the signature yet because we want to coalesce it with more candidate are sent after restart. +#[test] +fn subsystem_sends_pending_approvals_on_approval_restart() { + let assignment_criteria = Box::new(MockAssignmentCriteria( + || { + let mut assignments = HashMap::new(); + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + .into(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(1), CoreIndex(2)] + .try_into() + .unwrap(), + }), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + assignments + }, + |_| Ok(0), + )); + let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); + let store = config.backend(); + let store_clone = config.backend(); + + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle } = test_harness; + + setup_overseer_with_two_blocks_each_with_one_assignment_triggered( + &mut virtual_overseer, + store, + &clock, + sync_oracle_handle, + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _ + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { + exec_kind, + response_sender, + .. + }) if exec_kind == PvfExecKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) + .unwrap(); + } + ); + + // Configure a big coalesce number, so that the signature is cached instead of being sent to + // approval-distribution. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 6, + })); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 6, + })); + } + ); + + // Assert that there are no more messages being sent by the subsystem + assert!(overseer_recv(&mut virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + + virtual_overseer + }); + + let config = HarnessConfigBuilder::default().backend(store_clone).major_syncing(true).build(); + // On restart signatures should be sent to approval-distribution without relaunching the + // approval work. + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle } = test_harness; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + let fork_block_hash = Hash::repeat_byte(0x02); + let candidate_commitments = CandidateCommitments::default(); + let mut candidate_receipt = dummy_candidate_receipt(block_hash); + candidate_receipt.commitments_hash = candidate_commitments.hash(); + let slot = Slot::from(1); + + clock.inner.lock().set_tick(slot_to_tick(slot + 2)); + let (chain_builder, session_info) = build_chain_with_two_blocks_with_one_candidate_each( + block_hash, + fork_block_hash, + slot, + sync_oracle_handle, + candidate_receipt, + ) + .await; + chain_builder.build(&mut virtual_overseer).await; + + futures_timer::Delay::new(Duration::from_millis(2000)).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NewBlocks( + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 1, + })); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionInfo(_, si_tx), + ) + ) => { + si_tx.send(Ok(Some(session_info.clone()))).unwrap(); + } + ); + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(_, si_tx), + ) + ) => { + // Make sure all SessionExecutorParams calls are not made for the leaf (but for its relay parent) + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 1, + })); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) + ); + + // Assert that there are no more messages being sent by the subsystem + assert!(overseer_recv(&mut virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + + virtual_overseer + }); +} diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 68769fb8cc8a66b94d52251d1e203555e900f43f..05212da7479848830a8fb70ee4c38d449e9a6a7e 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -13,7 +13,7 @@ workspace = true futures = "0.3.21" futures-timer = "3.0.2" kvdb = "0.13.0" -thiserror = "1.0.48" +thiserror = { workspace = true } gum = { package = "tracing-gum", path = "../../gum" } bitvec = "1.0.0" @@ -28,7 +28,7 @@ sp-consensus = { path = "../../../../substrate/primitives/consensus/common", def polkadot-node-jaeger = { path = "../../jaeger" } [dev-dependencies] -log = "0.4.17" +log = { workspace = true, default-features = true } env_logger = "0.9.0" assert_matches = "1.4.0" kvdb-memorydb = "0.13.0" diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index 1c69fc441b3284d1790e03f6896b67e71f32aae3..d0c1f9aa4832dfe629e1fb20d3082f27c260a7d5 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -20,8 +20,9 @@ erasure-coding = { package = "polkadot-erasure-coding", path = "../../../erasure statement-table = { package = "polkadot-statement-table", path = "../../../statement-table" } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } gum = { package = "tracing-gum", path = "../../gum" } -thiserror = "1.0.48" +thiserror = { workspace = true } fatality = "0.0.6" +schnellru = "0.2.1" [dev-dependencies] sp-core = { path = "../../../../substrate/primitives/core" } @@ -31,5 +32,6 @@ sc-keystore = { path = "../../../../substrate/client/keystore" } sp-tracing = { path = "../../../../substrate/primitives/tracing" } futures = { version = "0.3.21", features = ["thread-pool"] } assert_matches = "1.4.0" +rstest = "0.18.2" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } diff --git a/polkadot/node/core/backing/src/error.rs b/polkadot/node/core/backing/src/error.rs index 1b00a62510b7c634b3135a56ca6412c0948ef6a0..64955a393962076bd7b202dd31a7d69d46a4d1b9 100644 --- a/polkadot/node/core/backing/src/error.rs +++ b/polkadot/node/core/backing/src/error.rs @@ -48,6 +48,9 @@ pub enum Error { #[error("Candidate is not found")] CandidateNotFound, + #[error("CoreIndex cannot be determined for a candidate")] + CoreIndexUnavailable, + #[error("Signature is invalid")] InvalidSignature, diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 98bbd6232add4d893293fc948c0a99bba8d46bf3..69bf2e956a0f6bb7f3b9f4a19446e5e7d2c125bb 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -77,6 +77,7 @@ use futures::{ stream::FuturesOrdered, FutureExt, SinkExt, StreamExt, TryFutureExt, }; +use schnellru::{ByLength, LruMap}; use error::{Error, FatalResult}; use polkadot_node_primitives::{ @@ -104,10 +105,12 @@ use polkadot_node_subsystem_util::{ Validator, }; use polkadot_primitives::{ + vstaging::{node_features::FeatureIndex, NodeFeatures}, BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, - CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, Hash, Id as ParaId, - PersistedValidationData, PvfExecKind, SigningContext, ValidationCode, ValidatorId, - ValidatorIndex, ValidatorSignature, ValidityAttestation, + CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, GroupIndex, GroupRotationInfo, + Hash, Id as ParaId, IndexedVec, PersistedValidationData, PvfExecKind, SessionIndex, + SigningContext, ValidationCode, ValidatorId, ValidatorIndex, ValidatorSignature, + ValidityAttestation, }; use sp_keystore::KeystorePtr; use statement_table::{ @@ -118,7 +121,7 @@ use statement_table::{ }, Config as TableConfig, Context as TableContextTrait, Table, }; -use util::vstaging::get_disabled_validators_with_fallback; +use util::{runtime::request_node_features, vstaging::get_disabled_validators_with_fallback}; mod error; @@ -209,7 +212,9 @@ struct PerRelayParentState { /// The hash of the relay parent on top of which this job is doing it's work. parent: Hash, /// The `ParaId` assigned to the local validator at this relay parent. - assignment: Option, + assigned_para: Option, + /// 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. backed: HashSet, /// The table of candidates and statements under this relay-parent. @@ -224,6 +229,15 @@ struct PerRelayParentState { fallbacks: HashMap, /// The minimum backing votes threshold. minimum_backing_votes: u32, + /// If true, we're appending extra bits in the BackedCandidate validator indices bitfield, + /// which represent the assigned core index. True if ElasticScalingMVP is enabled. + inject_core_index: bool, + /// The core states for all cores. + cores: Vec, + /// The validator index -> group mapping at this relay parent. + validator_to_group: Arc>>, + /// The associated group rotation information. + group_rotation_info: GroupRotationInfo, } struct PerCandidateState { @@ -275,6 +289,9 @@ struct State { /// 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 cloneable sender which is dispatched to background candidate validation tasks to inform /// the main task of the result. background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, @@ -292,6 +309,7 @@ impl State { per_leaf: HashMap::default(), per_relay_parent: HashMap::default(), per_candidate: HashMap::new(), + validator_to_group_cache: LruMap::new(ByLength::new(2)), background_validation_tx, keystore, } @@ -379,10 +397,10 @@ struct AttestingData { backing: Vec, } -#[derive(Default)] +#[derive(Default, Debug)] struct TableContext { validator: Option, - groups: HashMap>, + groups: HashMap>, validators: Vec, disabled_validators: Vec, } @@ -404,7 +422,7 @@ impl TableContext { impl TableContextTrait for TableContext { type AuthorityId = ValidatorIndex; type Digest = CandidateHash; - type GroupId = ParaId; + type GroupId = CoreIndex; type Signature = ValidatorSignature; type Candidate = CommittedCandidateReceipt; @@ -412,15 +430,11 @@ impl TableContextTrait for TableContext { candidate.hash() } - fn candidate_group(candidate: &CommittedCandidateReceipt) -> ParaId { - candidate.descriptor().para_id + fn is_member_of(&self, authority: &ValidatorIndex, core: &CoreIndex) -> bool { + self.groups.get(core).map_or(false, |g| g.iter().any(|a| a == authority)) } - fn is_member_of(&self, authority: &ValidatorIndex, group: &ParaId) -> bool { - self.groups.get(group).map_or(false, |g| g.iter().any(|a| a == authority)) - } - - fn get_group_size(&self, group: &ParaId) -> Option { + fn get_group_size(&self, group: &CoreIndex) -> Option { self.groups.get(group).map(|g| g.len()) } } @@ -442,19 +456,20 @@ fn primitive_statement_to_table(s: &SignedFullStatementWithPVD) -> TableSignedSt fn table_attested_to_backed( attested: TableAttestedCandidate< - ParaId, + CoreIndex, CommittedCandidateReceipt, ValidatorIndex, ValidatorSignature, >, table_context: &TableContext, + inject_core_index: bool, ) -> Option { - let TableAttestedCandidate { candidate, validity_votes, group_id: para_id } = attested; + let TableAttestedCandidate { candidate, validity_votes, group_id: core_index } = attested; let (ids, validity_votes): (Vec<_>, Vec) = validity_votes.into_iter().map(|(id, vote)| (id, vote.into())).unzip(); - let group = table_context.groups.get(¶_id)?; + let group = table_context.groups.get(&core_index)?; let mut validator_indices = BitVec::with_capacity(group.len()); @@ -479,14 +494,15 @@ fn table_attested_to_backed( } vote_positions.sort_by_key(|(_orig, pos_in_group)| *pos_in_group); - Some(BackedCandidate { + Some(BackedCandidate::new( candidate, - validity_votes: vote_positions + vote_positions .into_iter() .map(|(pos_in_votes, _pos_in_group)| validity_votes[pos_in_votes].clone()) .collect(), validator_indices, - }) + inject_core_index.then_some(core_index), + )) } async fn store_available_data( @@ -971,7 +987,14 @@ async fn handle_active_leaves_update( // construct a `PerRelayParent` from the runtime API // and insert it. - let per = construct_per_relay_parent_state(ctx, maybe_new, &state.keystore, mode).await?; + let per = construct_per_relay_parent_state( + ctx, + maybe_new, + &state.keystore, + &mut state.validator_to_group_cache, + mode, + ) + .await?; if let Some(per) = per { state.per_relay_parent.insert(maybe_new, per); @@ -981,31 +1004,112 @@ async fn handle_active_leaves_update( Ok(()) } +macro_rules! try_runtime_api { + ($x: expr) => { + match $x { + Ok(x) => x, + Err(err) => { + // Only bubble up fatal errors. + error::log_error(Err(Into::::into(err).into()))?; + + // We can't do candidate validation work if we don't have the + // requisite runtime API data. But these errors should not take + // down the node. + return Ok(None) + }, + } + }; +} + +fn core_index_from_statement( + validator_to_group: &IndexedVec>, + group_rotation_info: &GroupRotationInfo, + cores: &[CoreState], + statement: &SignedFullStatementWithPVD, +) -> Option { + let compact_statement = statement.as_unchecked(); + let candidate_hash = CandidateHash(*compact_statement.unchecked_payload().candidate_hash()); + + let n_cores = cores.len(); + + gum::trace!( + target:LOG_TARGET, + ?group_rotation_info, + ?statement, + ?validator_to_group, + n_cores = ?cores.len(), + ?candidate_hash, + "Extracting core index from statement" + ); + + let statement_validator_index = statement.validator_index(); + let Some(Some(group_index)) = validator_to_group.get(statement_validator_index) else { + gum::debug!( + target: LOG_TARGET, + ?group_rotation_info, + ?statement, + ?validator_to_group, + n_cores = ?cores.len() , + ?candidate_hash, + "Invalid validator index: {:?}", + statement_validator_index + ); + return None + }; + + // First check if the statement para id matches the core assignment. + let core_index = group_rotation_info.core_for_group(*group_index, n_cores); + + if core_index.0 as usize > n_cores { + gum::warn!(target: LOG_TARGET, ?candidate_hash, ?core_index, n_cores, "Invalid CoreIndex"); + return None + } + + if let StatementWithPVD::Seconded(candidate, _pvd) = statement.payload() { + let candidate_para_id = candidate.descriptor.para_id; + let assigned_para_id = match &cores[core_index.0 as usize] { + CoreState::Free => { + gum::debug!(target: LOG_TARGET, ?candidate_hash, "Invalid CoreIndex, core is not assigned to any para_id"); + return None + }, + CoreState::Occupied(occupied) => + if let Some(next) = &occupied.next_up_on_available { + next.para_id + } else { + return None + }, + CoreState::Scheduled(scheduled) => scheduled.para_id, + }; + + if assigned_para_id != candidate_para_id { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + ?core_index, + ?assigned_para_id, + ?candidate_para_id, + "Invalid CoreIndex, core is assigned to a different para_id" + ); + return None + } + return Some(core_index) + } else { + return Some(core_index) + } +} + /// Load the data necessary to do backing work on top of a relay-parent. #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] 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, ) -> Result, Error> { - macro_rules! try_runtime_api { - ($x: expr) => { - match $x { - Ok(x) => x, - Err(err) => { - // Only bubble up fatal errors. - error::log_error(Err(Into::::into(err).into()))?; - - // We can't do candidate validation work if we don't have the - // requisite runtime API data. But these errors should not take - // down the node. - return Ok(None) - }, - } - }; - } - let parent = relay_parent; let (session_index, validators, groups, cores) = futures::try_join!( @@ -1020,6 +1124,16 @@ async fn construct_per_relay_parent_state( .map_err(Error::JoinMultiple)?; let session_index = try_runtime_api!(session_index); + + let inject_core_index = request_node_features(parent, session_index, ctx.sender()) + .await? + .unwrap_or(NodeFeatures::EMPTY) + .get(FeatureIndex::ElasticScalingMVP as usize) + .map(|b| *b) + .unwrap_or(false); + + 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); @@ -1055,18 +1169,24 @@ async fn construct_per_relay_parent_state( }, }; - let mut groups = HashMap::new(); let n_cores = cores.len(); - let mut assignment = None; - for (idx, core) in cores.into_iter().enumerate() { + let mut groups = HashMap::>::new(); + let mut assigned_core = None; + let mut assigned_para = None; + + for (idx, core) in cores.iter().enumerate() { let core_para_id = match core { CoreState::Scheduled(scheduled) => scheduled.para_id, CoreState::Occupied(occupied) => if mode.is_enabled() { // Async backing makes it legal to build on top of // occupied core. - occupied.candidate_descriptor.para_id + if let Some(next) = &occupied.next_up_on_available { + next.para_id + } else { + continue + } } else { continue }, @@ -1077,11 +1197,27 @@ async fn construct_per_relay_parent_state( let group_index = group_rotation_info.group_for_core(core_index, n_cores); if let Some(g) = validator_groups.get(group_index.0 as usize) { if validator.as_ref().map_or(false, |v| g.contains(&v.index())) { - assignment = Some(core_para_id); + assigned_para = Some(core_para_id); + assigned_core = Some(core_index); } - groups.insert(core_para_id, g.clone()); + groups.insert(core_index, g.clone()); } } + 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 table_context = TableContext { validator, groups, validators, disabled_validators }; let table_config = TableConfig { @@ -1094,7 +1230,8 @@ async fn construct_per_relay_parent_state( Ok(Some(PerRelayParentState { prospective_parachains_mode: mode, parent, - assignment, + assigned_core, + assigned_para, backed: HashSet::new(), table: Table::new(table_config), table_context, @@ -1102,6 +1239,10 @@ async fn construct_per_relay_parent_state( awaiting_validation: HashSet::new(), fallbacks: HashMap::new(), minimum_backing_votes, + inject_core_index, + cores, + validator_to_group: validator_to_group.clone(), + group_rotation_info, })) } @@ -1519,15 +1660,16 @@ async fn import_statement( per_candidate: &mut HashMap, statement: &SignedFullStatementWithPVD, ) -> Result, Error> { + let candidate_hash = statement.payload().candidate_hash(); + gum::debug!( target: LOG_TARGET, statement = ?statement.payload().to_compact(), validator_index = statement.validator_index().0, + ?candidate_hash, "Importing statement", ); - let candidate_hash = statement.payload().candidate_hash(); - // If this is a new candidate (statement is 'seconded' and candidate is unknown), // we need to create an entry in the `PerCandidateState` map. // @@ -1593,7 +1735,15 @@ async fn import_statement( let stmt = primitive_statement_to_table(statement); - Ok(rp_state.table.import_statement(&rp_state.table_context, stmt)) + let core = core_index_from_statement( + &rp_state.validator_to_group, + &rp_state.group_rotation_info, + &rp_state.cores, + statement, + ) + .ok_or(Error::CoreIndexUnavailable)?; + + Ok(rp_state.table.import_statement(&rp_state.table_context, core, stmt)) } /// Handles a summary received from [`import_statement`] and dispatches `Backed` notifications and @@ -1615,8 +1765,12 @@ async fn post_import_statement_actions( // `HashSet::insert` returns true if the thing wasn't in there already. if rp_state.backed.insert(candidate_hash) { - if let Some(backed) = table_attested_to_backed(attested, &rp_state.table_context) { - let para_id = backed.candidate.descriptor.para_id; + if let Some(backed) = table_attested_to_backed( + attested, + &rp_state.table_context, + rp_state.inject_core_index, + ) { + let para_id = backed.candidate().descriptor.para_id; gum::debug!( target: LOG_TARGET, candidate_hash = ?candidate_hash, @@ -1637,7 +1791,7 @@ async fn post_import_statement_actions( // notify collator protocol. ctx.send_message(CollatorProtocolMessage::Backed { para_id, - para_head: backed.candidate.descriptor.para_head, + para_head: backed.candidate().descriptor.para_head, }) .await; // Notify statement distribution of backed candidate. @@ -1654,8 +1808,14 @@ async fn post_import_statement_actions( ); ctx.send_unbounded_message(message); } + } else { + gum::debug!(target: LOG_TARGET, ?candidate_hash, "Cannot get BackedCandidate"); } + } else { + gum::debug!(target: LOG_TARGET, ?candidate_hash, "Candidate already known"); } + } else { + gum::debug!(target: LOG_TARGET, "No attested candidate"); } issue_new_misbehaviors(ctx, rp_state.parent, &mut rp_state.table); @@ -1722,18 +1882,20 @@ async fn background_validate_and_make_available( if rp_state.awaiting_validation.insert(candidate_hash) { // spawn background task. let bg = async move { - if let Err(e) = validate_and_make_available(params).await { - if let Error::BackgroundValidationMpsc(error) = e { + if let Err(error) = validate_and_make_available(params).await { + if let Error::BackgroundValidationMpsc(error) = error { gum::debug!( target: LOG_TARGET, + ?candidate_hash, ?error, "Mpsc background validation mpsc died during validation- leaf no longer active?" ); } else { gum::error!( target: LOG_TARGET, - "Failed to validate and make available: {:?}", - e + ?candidate_hash, + ?error, + "Failed to validate and make available", ); } } @@ -1859,9 +2021,10 @@ async fn maybe_validate_and_import( let candidate_hash = summary.candidate; - if Some(summary.group_id) != rp_state.assignment { + if Some(summary.group_id) != rp_state.assigned_core { return Ok(()) } + let attesting = match statement.payload() { StatementWithPVD::Seconded(receipt, _) => { let attesting = AttestingData { @@ -2004,10 +2167,11 @@ async fn handle_second_message( } // Sanity check that candidate is from our assignment. - if Some(candidate.descriptor().para_id) != rp_state.assignment { + if Some(candidate.descriptor().para_id) != rp_state.assigned_para { gum::debug!( target: LOG_TARGET, - our_assignment = ?rp_state.assignment, + our_assignment_core = ?rp_state.assigned_core, + our_assignment_para = ?rp_state.assigned_para, collation = ?candidate.descriptor().para_id, "Subsystem asked to second for para outside of our assignment", ); @@ -2015,6 +2179,14 @@ async fn handle_second_message( return Ok(()) } + gum::debug!( + target: LOG_TARGET, + our_assignment_core = ?rp_state.assigned_core, + our_assignment_para = ?rp_state.assigned_para, + collation = ?candidate.descriptor().para_id, + "Current assignments vs collation", + ); + // If the message is a `CandidateBackingMessage::Second`, sign and dispatch a // Seconded statement only if we have not signed a Valid statement for the requested candidate. // @@ -2087,7 +2259,13 @@ fn handle_get_backed_candidates_message( &rp_state.table_context, rp_state.minimum_backing_votes, ) - .and_then(|attested| table_attested_to_backed(attested, &rp_state.table_context)) + .and_then(|attested| { + table_attested_to_backed( + attested, + &rp_state.table_context, + rp_state.inject_core_index, + ) + }) }) .collect(); diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 1957f4e19c54bd9845e5bb5bd03383985d9c9636..e3cc5727435a3fef3532a9de342cd194ecd4fe3a 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -33,9 +33,10 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, PvfExecKind, - ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, + vstaging::node_features, CandidateDescriptor, GroupRotationInfo, HeadData, + PersistedValidationData, PvfExecKind, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, }; +use rstest::rstest; use sp_application_crypto::AppCrypto; use sp_keyring::Sr25519Keyring; use sp_keystore::Keystore; @@ -65,19 +66,21 @@ fn dummy_pvd() -> PersistedValidationData { } } -struct TestState { +pub(crate) struct TestState { chain_ids: Vec, keystore: KeystorePtr, validators: Vec, validator_public: Vec, validation_data: PersistedValidationData, validator_groups: (Vec>, GroupRotationInfo), + validator_to_group: IndexedVec>, availability_cores: Vec, head_data: HashMap, signing_context: SigningContext, relay_parent: Hash, minimum_backing_votes: u32, disabled_validators: Vec, + node_features: NodeFeatures, } impl TestState { @@ -114,6 +117,11 @@ impl Default for TestState { .into_iter() .map(|g| g.into_iter().map(ValidatorIndex).collect()) .collect(); + let validator_to_group: IndexedVec<_, _> = + vec![Some(0), Some(1), Some(0), Some(0), None, Some(0)] + .into_iter() + .map(|x| x.map(|x| GroupIndex(x))) + .collect(); let group_rotation_info = GroupRotationInfo { session_start_block: 0, group_rotation_frequency: 100, now: 1 }; @@ -143,6 +151,7 @@ impl Default for TestState { validators, validator_public, validator_groups: (validator_groups, group_rotation_info), + validator_to_group, availability_cores, head_data, validation_data, @@ -150,6 +159,7 @@ impl Default for TestState { relay_parent, minimum_backing_votes: LEGACY_MIN_BACKING_VOTES, disabled_validators: Vec::new(), + node_features: Default::default(), } } } @@ -285,6 +295,16 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS } ); + // 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)) + ) => { + 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, @@ -477,9 +497,20 @@ fn backing_second_works() { } // Test that the candidate reaches quorum successfully. -#[test] -fn backing_works() { - let test_state = TestState::default(); +#[rstest] +#[case(true)] +#[case(false)] +fn backing_works(#[case] elastic_scaling_mvp: bool) { + let mut test_state = TestState::default(); + if elastic_scaling_mvp { + test_state + .node_features + .resize((node_features::FeatureIndex::ElasticScalingMVP as u8 + 1) as usize, false); + test_state + .node_features + .set(node_features::FeatureIndex::ElasticScalingMVP as u8 as usize, true); + } + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { test_startup(&mut virtual_overseer, &test_state).await; @@ -630,6 +661,31 @@ fn backing_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + let (tx, rx) = oneshot::channel(); + let msg = CandidateBackingMessage::GetBackedCandidates( + vec![(candidate_a_hash, test_state.relay_parent)], + tx, + ); + + virtual_overseer.send(FromOrchestra::Communication { msg }).await; + + let candidates = rx.await.unwrap(); + assert_eq!(1, candidates.len()); + assert_eq!(candidates[0].validity_votes().len(), 3); + + let (validator_indices, maybe_core_index) = + candidates[0].validator_indices_and_core_index(elastic_scaling_mvp); + if elastic_scaling_mvp { + assert_eq!(maybe_core_index.unwrap(), CoreIndex(0)); + } else { + assert!(maybe_core_index.is_none()); + } + + assert_eq!( + validator_indices, + bitvec::bitvec![u8, bitvec::order::Lsb0; 1, 1, 0, 1].as_bitslice() + ); + virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( ActiveLeavesUpdate::stop_work(test_state.relay_parent), @@ -639,6 +695,107 @@ fn backing_works() { }); } +#[test] +fn extract_core_index_from_statement_works() { + let test_state = TestState::default(); + + 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 mut candidate = TestCandidateBuilder { + para_id: test_state.chain_ids[0], + relay_parent: test_state.relay_parent, + pov_hash, + 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() + } + .build(); + + let public2 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[2].to_seed()), + ) + .expect("Insert key into keystore"); + + let signed_statement_1 = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate.clone(), pvd_a.clone()), + &test_state.signing_context, + ValidatorIndex(2), + &public2.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let public1 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[1].to_seed()), + ) + .expect("Insert key into keystore"); + + let signed_statement_2 = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate.clone(), pvd_a.clone()), + &test_state.signing_context, + ValidatorIndex(1), + &public1.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + candidate.descriptor.para_id = test_state.chain_ids[1]; + + let signed_statement_3 = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate, pvd_a.clone()), + &test_state.signing_context, + ValidatorIndex(1), + &public1.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let core_index_1 = core_index_from_statement( + &test_state.validator_to_group, + &test_state.validator_groups.1, + &test_state.availability_cores, + &signed_statement_1, + ) + .unwrap(); + + assert_eq!(core_index_1, CoreIndex(0)); + + let core_index_2 = core_index_from_statement( + &test_state.validator_to_group, + &test_state.validator_groups.1, + &test_state.availability_cores, + &signed_statement_2, + ); + + // Must be none, para_id in descriptor is different than para assigned to core + assert_eq!(core_index_2, None); + + let core_index_3 = core_index_from_statement( + &test_state.validator_to_group, + &test_state.validator_groups.1, + &test_state.availability_cores, + &signed_statement_3, + ) + .unwrap(); + + assert_eq!(core_index_3, CoreIndex(1)); +} + #[test] fn backing_works_while_validation_ongoing() { let test_state = TestState::default(); @@ -801,20 +958,20 @@ fn backing_works_while_validation_ongoing() { let candidates = rx.await.unwrap(); assert_eq!(1, candidates.len()); - assert_eq!(candidates[0].validity_votes.len(), 3); + assert_eq!(candidates[0].validity_votes().len(), 3); assert!(candidates[0] - .validity_votes + .validity_votes() .contains(&ValidityAttestation::Implicit(signed_a.signature().clone()))); assert!(candidates[0] - .validity_votes + .validity_votes() .contains(&ValidityAttestation::Explicit(signed_b.signature().clone()))); assert!(candidates[0] - .validity_votes + .validity_votes() .contains(&ValidityAttestation::Explicit(signed_c.signature().clone()))); assert_eq!( - candidates[0].validator_indices, - bitvec::bitvec![u8, bitvec::order::Lsb0; 1, 0, 1, 1], + candidates[0].validator_indices_and_core_index(false), + (bitvec::bitvec![u8, bitvec::order::Lsb0; 1, 0, 1, 1].as_bitslice(), None) ); virtual_overseer @@ -1422,7 +1579,7 @@ fn backing_works_after_failed_validation() { fn candidate_backing_reorders_votes() { use sp_core::Encode; - let para_id = ParaId::from(10); + let core_idx = CoreIndex(10); let validators = vec![ Sr25519Keyring::Alice, Sr25519Keyring::Bob, @@ -1436,7 +1593,7 @@ fn candidate_backing_reorders_votes() { let validator_groups = { let mut validator_groups = HashMap::new(); validator_groups - .insert(para_id, vec![0, 1, 2, 3, 4, 5].into_iter().map(ValidatorIndex).collect()); + .insert(core_idx, vec![0, 1, 2, 3, 4, 5].into_iter().map(ValidatorIndex).collect()); validator_groups }; @@ -1466,10 +1623,10 @@ fn candidate_backing_reorders_votes() { (ValidatorIndex(3), fake_attestation(3)), (ValidatorIndex(1), fake_attestation(1)), ], - group_id: para_id, + group_id: core_idx, }; - let backed = table_attested_to_backed(attested, &table_context).unwrap(); + let backed = table_attested_to_backed(attested, &table_context, false).unwrap(); let expected_bitvec = { let mut validator_indices = BitVec::::with_capacity(6); @@ -1486,8 +1643,11 @@ fn candidate_backing_reorders_votes() { let expected_attestations = vec![fake_attestation(1).into(), fake_attestation(3).into(), fake_attestation(5).into()]; - assert_eq!(backed.validator_indices, expected_bitvec); - assert_eq!(backed.validity_votes, expected_attestations); + assert_eq!( + backed.validator_indices_and_core_index(false), + (expected_bitvec.as_bitslice(), None) + ); + assert_eq!(backed.validity_votes(), expected_attestations); } // Test whether we retry on failed PoV fetching. diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 578f21bef66515e49042d7a11692de67b9642d41..94310d2aa164650db84b78ddf361a9f465ac207d 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -185,6 +185,16 @@ async fn activate_leaf( } ); + // 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, @@ -305,10 +315,11 @@ async fn assert_hypothetical_frontier_requests( ) => { let idx = match expected_requests.iter().position(|r| r.0 == request) { Some(idx) => idx, - None => panic!( + None => + panic!( "unexpected hypothetical frontier request, no match found for {:?}", request - ), + ), }; let resp = std::mem::take(&mut expected_requests[idx].1); tx.send(resp).unwrap(); @@ -1268,6 +1279,7 @@ fn concurrent_dependent_candidates() { 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 @@ -1388,7 +1400,19 @@ fn concurrent_dependent_candidates() { 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( + _parent, + RuntimeApiRequest::AvailabilityCores(tx), + )) => { + tx.send(Ok(test_state.availability_cores.clone())).unwrap(); + }, _ => panic!("unexpected message received from overseer: {:?}", msg), } } @@ -1419,7 +1443,6 @@ fn seconding_sanity_check_occupy_same_depth() { 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 }; @@ -1555,13 +1578,14 @@ fn occupied_core_assignment() { 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 = ::test_helpers::dummy_candidate_descriptor(Hash::zero()); - candidate_descriptor.para_id = para_id; + candidate_descriptor.para_id = previous_para_id; test_state.availability_cores[0] = CoreState::Occupied(OccupiedCore { group_responsible: Default::default(), - next_up_on_available: None, + 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, diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index f42e8f8d22ba3d92e799bcd5aebe1cbeedca83de..6ecfffd7249b9213cc4ffb86f84a38e1cdb9babf 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -17,7 +17,7 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } wasm-timer = "0.2.5" -thiserror = "1.0.48" +thiserror = { workspace = true } [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index bf6e09fd1b69b702206eb52090cb4a12812c00c0..8237137fdca015ace87248d062431230a2ad47d4 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -695,6 +695,8 @@ async fn validate_candidate_exhaustive( ))), Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(err))), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::RuntimeConstruction(err))) => + Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(err))), Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath(err))) => Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(format!( @@ -780,40 +782,50 @@ trait ValidationBackend { return validation_result } + macro_rules! break_if_no_retries_left { + ($counter:ident) => { + if $counter > 0 { + $counter -= 1; + } else { + break + } + }; + } + // Allow limited retries for each kind of error. let mut num_death_retries_left = 1; let mut num_job_error_retries_left = 1; let mut num_internal_retries_left = 1; + let mut num_runtime_construction_retries_left = 1; loop { // Stop retrying if we exceeded the timeout. if total_time_start.elapsed() + retry_delay > exec_timeout { break } - + let mut retry_immediately = false; match validation_result { Err(ValidationError::PossiblyInvalid( PossiblyInvalidError::AmbiguousWorkerDeath | PossiblyInvalidError::AmbiguousJobDeath(_), - )) => - if num_death_retries_left > 0 { - num_death_retries_left -= 1; - } else { - break - }, + )) => break_if_no_retries_left!(num_death_retries_left), Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(_))) => - if num_job_error_retries_left > 0 { - num_job_error_retries_left -= 1; - } else { - break - }, + break_if_no_retries_left!(num_job_error_retries_left), Err(ValidationError::Internal(_)) => - if num_internal_retries_left > 0 { - num_internal_retries_left -= 1; - } else { - break - }, + break_if_no_retries_left!(num_internal_retries_left), + + Err(ValidationError::PossiblyInvalid( + PossiblyInvalidError::RuntimeConstruction(_), + )) => { + break_if_no_retries_left!(num_runtime_construction_retries_left); + self.precheck_pvf(pvf.clone()).await?; + // In this case the error is deterministic + // And a retry forces the ValidationBackend + // to re-prepare the artifact so + // there is no need to wait before the retry + retry_immediately = true; + }, Ok(_) | Err(ValidationError::Invalid(_) | ValidationError::Preparation(_)) => break, } @@ -821,8 +833,11 @@ trait ValidationBackend { // If we got a possibly transient error, retry once after a brief delay, on the // assumption that the conditions that caused this error may have resolved on their own. { - // Wait a brief delay before retrying. - futures_timer::Delay::new(retry_delay).await; + // In case of many transient errors it is necessary to wait a little bit + // for the error to be probably resolved + if !retry_immediately { + futures_timer::Delay::new(retry_delay).await; + } let new_timeout = exec_timeout.saturating_sub(total_time_start.elapsed()); diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 27c2df85235e86d86860496923c3f89ce5fb0199..96fd42785cdd84ee463146f095b06ea01cc7b491 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -18,7 +18,7 @@ polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } kvdb = "0.13.0" -thiserror = "1.0.48" +thiserror = { workspace = true } parity-scale-codec = "3.6.1" [dev-dependencies] diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 8a414a35f39cb9e1f3246e1afb83a5ea7a93cff1..1fff0a77170669753fa3fd8d852f936446fe7264 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.1" kvdb = "0.13.0" -thiserror = "1.0.48" +thiserror = { workspace = true } schnellru = "0.2.1" fatality = "0.0.6" diff --git a/polkadot/node/core/dispute-coordinator/src/import.rs b/polkadot/node/core/dispute-coordinator/src/import.rs index 278561d5d00c1b9f4ec5d4e87287f76bebe8fb70..d3a4625f0d24b2ff0fc3bcc914d629e604909193 100644 --- a/polkadot/node/core/dispute-coordinator/src/import.rs +++ b/polkadot/node/core/dispute-coordinator/src/import.rs @@ -52,7 +52,8 @@ pub struct CandidateEnvironment<'a> { executor_params: &'a ExecutorParams, /// Validator indices controlled by this node. controlled_indices: HashSet, - /// Indices of disabled validators at the `relay_parent`. + /// Indices of on-chain disabled validators at the `relay_parent` combined + /// with the off-chain state. disabled_indices: HashSet, } @@ -67,16 +68,15 @@ impl<'a> CandidateEnvironment<'a> { runtime_info: &'a mut RuntimeInfo, session_index: SessionIndex, relay_parent: Hash, + disabled_offchain: impl IntoIterator, ) -> Option> { - let disabled_indices = runtime_info + let disabled_onchain = runtime_info .get_disabled_validators(ctx.sender(), relay_parent) .await .unwrap_or_else(|err| { gum::info!(target: LOG_TARGET, ?err, "Failed to get disabled validators"); Vec::new() - }) - .into_iter() - .collect(); + }); let (session, executor_params) = match runtime_info .get_session_info_by_index(ctx.sender(), relay_parent, session_index) @@ -87,6 +87,24 @@ impl<'a> CandidateEnvironment<'a> { Err(_) => return None, }; + let n_validators = session.validators.len(); + let byzantine_threshold = polkadot_primitives::byzantine_threshold(n_validators); + // combine on-chain with off-chain disabled validators + // process disabled validators in the following order: + // - on-chain disabled validators + // - prioritized order of off-chain disabled validators + // deduplicate the list and take at most `byzantine_threshold` validators + let disabled_indices = { + let mut d: HashSet = HashSet::new(); + for v in disabled_onchain.into_iter().chain(disabled_offchain.into_iter()) { + if d.len() == byzantine_threshold { + break + } + d.insert(v); + } + d + }; + let controlled_indices = find_controlled_validator_indices(keystore, &session.validators); Some(Self { session_index, session, executor_params, controlled_indices, disabled_indices }) } @@ -116,7 +134,7 @@ impl<'a> CandidateEnvironment<'a> { &self.controlled_indices } - /// Indices of disabled validators at the `relay_parent`. + /// Indices of off-chain and on-chain disabled validators. pub fn disabled_indices(&'a self) -> &'a HashSet { &self.disabled_indices } @@ -237,13 +255,19 @@ impl CandidateVoteState { let supermajority_threshold = polkadot_primitives::supermajority_threshold(n_validators); - // We have a dispute, if we have votes on both sides: - let is_disputed = !votes.invalid.is_empty() && !votes.valid.raw().is_empty(); + // We have a dispute, if we have votes on both sides, with at least one invalid vote + // from non-disabled validator or with votes on both sides and confirmed. + let has_non_disabled_invalid_votes = + votes.invalid.keys().any(|i| !env.disabled_indices().contains(i)); + let byzantine_threshold = polkadot_primitives::byzantine_threshold(n_validators); + let votes_on_both_sides = !votes.valid.raw().is_empty() && !votes.invalid.is_empty(); + let is_confirmed = + votes_on_both_sides && (votes.voted_indices().len() > byzantine_threshold); + let is_disputed = + is_confirmed || (has_non_disabled_invalid_votes && !votes.valid.raw().is_empty()); let (dispute_status, byzantine_threshold_against) = if is_disputed { let mut status = DisputeStatus::active(); - let byzantine_threshold = polkadot_primitives::byzantine_threshold(n_validators); - let is_confirmed = votes.voted_indices().len() > byzantine_threshold; if is_confirmed { status = status.confirm(); }; diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index a1bcc1f01707c434a7d58eaa801dfb762b573007..5f86da87f21ca060cfe14de536b39e652d12b7b1 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -17,7 +17,7 @@ //! Dispute coordinator subsystem in initialized state (after first active leaf is received). use std::{ - collections::{BTreeMap, HashSet, VecDeque}, + collections::{BTreeMap, VecDeque}, sync::Arc, }; @@ -99,7 +99,7 @@ pub(crate) struct Initialized { /// This is the highest `SessionIndex` seen via `ActiveLeavesUpdate`. It doesn't matter if it /// was cached successfully or not. It is used to detect ancient disputes. highest_session_seen: SessionIndex, - /// Will be set to `true` if an error occured during the last caching attempt + /// Will be set to `true` if an error occurred during the last caching attempt gaps_in_cache: bool, spam_slots: SpamSlots, participation: Participation, @@ -970,6 +970,7 @@ impl Initialized { &mut self.runtime_info, session, relay_parent, + self.offchain_disabled_validators.iter(session), ) .await { @@ -1099,36 +1100,14 @@ impl Initialized { let new_state = import_result.new_state(); - let byzantine_threshold = polkadot_primitives::byzantine_threshold(n_validators); - // combine on-chain with off-chain disabled validators - // process disabled validators in the following order: - // - on-chain disabled validators - // - prioritized order of off-chain disabled validators - // deduplicate the list and take at most `byzantine_threshold` validators - let disabled_validators = { - let mut d: HashSet = HashSet::new(); - for v in env - .disabled_indices() - .iter() - .cloned() - .chain(self.offchain_disabled_validators.iter(session)) - { - if d.len() == byzantine_threshold { - break - } - d.insert(v); - } - d - }; - let is_included = self.scraper.is_candidate_included(&candidate_hash); let is_backed = self.scraper.is_candidate_backed(&candidate_hash); let own_vote_missing = new_state.own_vote_missing(); let is_disputed = new_state.is_disputed(); let is_confirmed = new_state.is_confirmed(); - let potential_spam = is_potential_spam(&self.scraper, &new_state, &candidate_hash, |v| { - disabled_validators.contains(v) - }); + let is_disabled = |v: &ValidatorIndex| env.disabled_indices().contains(v); + let potential_spam = + is_potential_spam(&self.scraper, &new_state, &candidate_hash, is_disabled); let allow_participation = !potential_spam; gum::trace!( @@ -1139,7 +1118,7 @@ impl Initialized { ?candidate_hash, confirmed = ?new_state.is_confirmed(), has_invalid_voters = ?!import_result.new_invalid_voters().is_empty(), - n_disabled_validators = ?disabled_validators.len(), + n_disabled_validators = ?env.disabled_indices().len(), "Is spam?" ); @@ -1439,6 +1418,7 @@ impl Initialized { &mut self.runtime_info, session, 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 c3038fc0953c6bcc7cdc979f259f7e9bf80f3039..4b511e7430af655303a7bb6e5ca0e86d0f8e8c7b 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -341,6 +341,8 @@ impl DisputeCoordinatorSubsystem { runtime_info, highest_session, leaf_hash, + // on startup we don't have any off-chain disabled state + std::iter::empty(), ) .await { @@ -370,10 +372,9 @@ impl DisputeCoordinatorSubsystem { }, }; let vote_state = CandidateVoteState::new(votes, &env, now); - let onchain_disabled = env.disabled_indices(); - let potential_spam = is_potential_spam(&scraper, &vote_state, candidate_hash, |v| { - onchain_disabled.contains(v) - }); + let is_disabled = |v: &ValidatorIndex| env.disabled_indices().contains(v); + let potential_spam = + is_potential_spam(&scraper, &vote_state, candidate_hash, is_disabled); let is_included = scraper.is_candidate_included(&vote_state.votes().candidate_receipt.hash()); diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index af384256c4f71e2f78e4ac0baff2558b9ba27f46..0360e357bee4ca70fe9a6ab3a9454d611ddc93fd 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -2645,14 +2645,23 @@ fn participation_with_onchain_disabling_unconfirmed() { .await; handle_disabled_validators_queries(&mut virtual_overseer, vec![disabled_index]).await; - handle_approval_vote_request(&mut virtual_overseer, &candidate_hash, HashMap::new()) - .await; - assert_eq!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport)); // we should not participate due to disabled indices on chain assert!(virtual_overseer.recv().timeout(TEST_TIMEOUT).await.is_none()); + { + // make sure the dispute is not active + let (tx, rx) = oneshot::channel(); + virtual_overseer + .send(FromOrchestra::Communication { + msg: DisputeCoordinatorMessage::ActiveDisputes(tx), + }) + .await; + + assert_eq!(rx.await.unwrap().len(), 0); + } + // Scenario 2: unconfirmed dispute with non-disabled validator against. // Expectation: even if the dispute is unconfirmed, we should participate // once we receive an invalid vote from a non-disabled validator. @@ -2679,6 +2688,9 @@ fn participation_with_onchain_disabling_unconfirmed() { }) .await; + handle_approval_vote_request(&mut virtual_overseer, &candidate_hash, HashMap::new()) + .await; + assert_eq!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport)); participation_with_distribution( @@ -2710,7 +2722,7 @@ fn participation_with_onchain_disabling_unconfirmed() { .await; let (_, _, votes) = rx.await.unwrap().get(0).unwrap().clone(); - assert_eq!(votes.valid.raw().len(), 2); // 3+1 => we have participated + assert_eq!(votes.valid.raw().len(), 2); // 1+1 => we have participated assert_eq!(votes.invalid.len(), 2); } @@ -2832,6 +2844,7 @@ fn participation_with_onchain_disabling_confirmed() { #[test] fn participation_with_offchain_disabling() { + sp_tracing::init_for_tests(); test_harness(|mut test_state, mut virtual_overseer| { Box::pin(async move { let session = 1; @@ -2968,17 +2981,23 @@ fn participation_with_offchain_disabling() { // let's disable validators 3, 4 on chain, but this should not affect this import let disabled_validators = vec![ValidatorIndex(3), ValidatorIndex(4)]; handle_disabled_validators_queries(&mut virtual_overseer, disabled_validators).await; - handle_approval_vote_request( - &mut virtual_overseer, - &another_candidate_hash, - HashMap::new(), - ) - .await; assert_eq!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport)); // we should not participate since due to offchain disabling assert!(virtual_overseer.recv().timeout(TEST_TIMEOUT).await.is_none()); + { + // make sure the new dispute is not active + let (tx, rx) = oneshot::channel(); + virtual_overseer + .send(FromOrchestra::Communication { + msg: DisputeCoordinatorMessage::ActiveDisputes(tx), + }) + .await; + + assert_eq!(rx.await.unwrap().len(), 1); + } + // now import enough votes for dispute confirmation // even though all of these votes are from (on chain) disabled validators let mut statements = Vec::new(); @@ -3007,6 +3026,12 @@ fn participation_with_offchain_disabling() { }) .await; + handle_approval_vote_request( + &mut virtual_overseer, + &another_candidate_hash, + HashMap::new(), + ) + .await; assert_eq!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport)); participation_with_distribution( diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 3b2fa634102dd0537408a041443b301ffe073c08..24da4dc1e316f8469704ab57e4742dbc07197992 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -13,7 +13,7 @@ workspace = true futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } -thiserror = "1.0.48" +thiserror = { workspace = true } async-trait = "0.1.74" polkadot-node-subsystem = { path = "../../subsystem" } polkadot-overseer = { path = "../../overseer" } diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 5f0b2c0fdc96beb8c90a3e207307d4c9d5a2619b..f66a66e859ec0a139e31068f78225597d577d1a9 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -13,7 +13,7 @@ workspace = true futures = "0.3.19" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.4" -thiserror = "1.0.48" +thiserror = { workspace = true } fatality = "0.0.6" bitvec = "1" @@ -23,6 +23,7 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } [dev-dependencies] +rstest = "0.18.2" assert_matches = "1" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } polkadot-node-subsystem-types = { path = "../../subsystem-types" } diff --git a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs b/polkadot/node/core/prospective-parachains/src/fragment_tree.rs index 04ee42a9de062bbd183f92c360703eb12c25f1aa..8061dc82d8358ae9e7c741e3f785634601eb5d03 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_tree.rs @@ -96,6 +96,7 @@ use std::{ use super::LOG_TARGET; use bitvec::prelude::*; +use polkadot_node_subsystem::messages::Ancestors; use polkadot_node_subsystem_util::inclusion_emulator::{ ConstraintModifications, Constraints, Fragment, ProspectiveCandidate, RelayChainBlockInfo, }; @@ -756,45 +757,46 @@ impl FragmentTree { depths.iter_ones().collect() } - /// Select `count` candidates after the given `required_path` which pass + /// Select `count` candidates after the given `ancestors` which pass /// the predicate and have not already been backed on chain. /// - /// Does an exhaustive search into the tree starting after `required_path`. - /// If there are multiple possibilities of size `count`, this will select the first one. - /// If there is no chain of size `count` that matches the criteria, this will return the largest - /// chain it could find with the criteria. - /// If there are no candidates meeting those criteria, returns an empty `Vec`. - /// Cycles are accepted, see module docs for the `Cycles` section. + /// Does an exhaustive search into the tree after traversing the ancestors path. + /// If the ancestors draw out a path that can be traversed in multiple ways, no + /// candidates will be returned. + /// If the ancestors do not draw out a full path (the path contains holes), candidates will be + /// suggested that may fill these holes. + /// If the ancestors don't draw out a valid path, no candidates will be returned. If there are + /// multiple possibilities of the same size, this will select the first one. If there is no + /// chain of size `count` that matches the criteria, this will return the largest chain it could + /// find with the criteria. If there are no candidates meeting those criteria, returns an empty + /// `Vec`. + /// Cycles are accepted, but this code expects that the runtime will deduplicate + /// identical candidates when occupying the cores (when proposing to back A->B->A, only A will + /// be backed on chain). /// - /// The intention of the `required_path` is to allow queries on the basis of + /// The intention of the `ancestors` is to allow queries on the basis of /// one or more candidates which were previously pending availability becoming - /// available and opening up more room on the core. - pub(crate) fn select_children( + /// available or candidates timing out. + pub(crate) fn find_backable_chain( &self, - required_path: &[CandidateHash], + ancestors: Ancestors, count: u32, pred: impl Fn(&CandidateHash) -> bool, ) -> Vec { - let base_node = { - // traverse the required path. - let mut node = NodePointer::Root; - for required_step in required_path { - if let Some(next_node) = self.node_candidate_child(node, &required_step) { - node = next_node; - } else { - return vec![] - }; - } - - node - }; - - // TODO: taking the first best selection might introduce bias - // or become gameable. - // - // For plausibly unique parachains, this shouldn't matter much. - // figure out alternative selection criteria? - self.select_children_inner(base_node, count, count, &pred, &mut vec![]) + if count == 0 { + return vec![] + } + // First, we need to order the ancestors. + // The node returned is the one from which we can start finding new backable candidates. + let Some(base_node) = self.find_ancestor_path(ancestors) else { return vec![] }; + + self.find_backable_chain_inner( + base_node, + count, + count, + &pred, + &mut Vec::with_capacity(count as usize), + ) } // Try finding a candidate chain starting from `base_node` of length `expected_count`. @@ -805,7 +807,7 @@ impl FragmentTree { // Cycles are accepted, but this doesn't allow for infinite execution time, because the maximum // depth we'll reach is `expected_count`. // - // Worst case performance is `O(num_forks ^ expected_count)`. + // Worst case performance is `O(num_forks ^ expected_count)`, the same as populating the tree. // Although an exponential function, this is actually a constant that can only be altered via // sudo/governance, because: // 1. `num_forks` at a given level is at most `max_candidate_depth * max_validators_per_core` @@ -817,7 +819,7 @@ impl FragmentTree { // scaling scenario). For non-elastic-scaling, this is just 1. In practice, this should be a // small number (1-3), capped by the total number of available cores (a constant alterable // only via governance/sudo). - fn select_children_inner( + fn find_backable_chain_inner( &self, base_node: NodePointer, expected_count: u32, @@ -857,7 +859,7 @@ impl FragmentTree { for (child_ptr, child_hash) in children { accumulator.push(child_hash); - let result = self.select_children_inner( + let result = self.find_backable_chain_inner( child_ptr, expected_count, remaining_count - 1, @@ -869,6 +871,9 @@ impl FragmentTree { // Short-circuit the search if we've found the right length. Otherwise, we'll // search for a max. + // Taking the first best selection doesn't introduce bias or become gameable, + // because `find_ancestor_path` uses a `HashSet` to track the ancestors, which + // makes the order in which ancestors are visited non-deterministic. if result.len() == expected_count as usize { return result } else if best_result.len() < result.len() { @@ -879,6 +884,93 @@ impl FragmentTree { best_result } + // Orders the ancestors into a viable path from root to the last one. + // Returns a pointer to the last node in the path. + // We assume that the ancestors form a chain (that the + // av-cores do not back parachain forks), None is returned otherwise. + // If we cannot use all ancestors, stop at the first found hole in the chain. This usually + // translates to a timed out candidate. + fn find_ancestor_path(&self, mut ancestors: Ancestors) -> Option { + // The number of elements in the path we've processed so far. + let mut depth = 0; + let mut last_node = NodePointer::Root; + let mut next_node: Option = Some(NodePointer::Root); + + while let Some(node) = next_node { + if depth > self.scope.max_depth { + return None; + } + + last_node = node; + + next_node = match node { + NodePointer::Root => { + let children = self + .nodes + .iter() + .enumerate() + .take_while(|n| n.1.parent == NodePointer::Root) + .map(|(index, node)| (NodePointer::Storage(index), node.candidate_hash)) + .collect::>(); + + self.find_valid_child(&mut ancestors, children.iter()).ok()? + }, + NodePointer::Storage(ptr) => { + let children = self.nodes.get(ptr).and_then(|n| Some(n.children.iter())); + if let Some(children) = children { + self.find_valid_child(&mut ancestors, children).ok()? + } else { + None + } + }, + }; + + depth += 1; + } + + Some(last_node) + } + + // Find a node from the given iterator which is present in the ancestors + // collection. If there are multiple such nodes, return an error and log a warning. We don't + // accept forks in a parachain to be backed. The supplied ancestors should all form a chain. + // If there is no such node, return None. + fn find_valid_child<'a>( + &self, + ancestors: &'a mut Ancestors, + nodes: impl Iterator + 'a, + ) -> Result, ()> { + let mut possible_children = + nodes.filter_map(|(node_ptr, hash)| match ancestors.remove(&hash) { + true => Some(node_ptr), + false => None, + }); + + // We don't accept forks in a parachain to be backed. The supplied ancestors + // should all form a chain. + let next = possible_children.next(); + if let Some(second_child) = possible_children.next() { + if let (Some(NodePointer::Storage(first_child)), NodePointer::Storage(second_child)) = + (next, second_child) + { + gum::error!( + target: LOG_TARGET, + para_id = ?self.scope.para, + relay_parent = ?self.scope.relay_parent, + "Trying to find new backable candidates for a parachain for which we've backed a fork.\ + This is a bug and the runtime should not have allowed it.\n\ + Backed candidates with the same parent: {}, {}", + self.nodes[*first_child].candidate_hash, + self.nodes[*second_child].candidate_hash, + ); + } + + Err(()) + } else { + Ok(next.copied()) + } + } + fn populate_from_bases(&mut self, storage: &CandidateStorage, initial_bases: Vec) { // Populate the tree breadth-first. let mut last_sweep_start = None; @@ -1061,8 +1153,18 @@ mod tests { use polkadot_node_subsystem_util::inclusion_emulator::InboundHrmpLimitations; use polkadot_primitives::{BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData}; use polkadot_primitives_test_helpers as test_helpers; + use rstest::rstest; use std::iter; + impl NodePointer { + fn unwrap_idx(self) -> usize { + match self { + NodePointer::Root => panic!("Unexpected root"), + NodePointer::Storage(index) => index, + } + } + } + fn make_constraints( min_relay_parent_number: BlockNumber, valid_watermarks: Vec, @@ -1546,6 +1648,373 @@ mod tests { assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); } + #[test] + fn test_find_ancestor_path_and_find_backable_chain_empty_tree() { + let para_id = ParaId::from(5u32); + let relay_parent = Hash::repeat_byte(1); + let required_parent: HeadData = vec![0xff].into(); + let max_depth = 10; + + // Empty tree + let storage = CandidateStorage::new(); + let base_constraints = make_constraints(0, vec![0], required_parent.clone()); + + let relay_parent_info = + RelayChainBlockInfo { number: 0, hash: relay_parent, storage_root: Hash::zero() }; + + let scope = Scope::with_ancestors( + para_id, + relay_parent_info, + base_constraints, + vec![], + max_depth, + vec![], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + assert_eq!(tree.candidates().collect::>().len(), 0); + assert_eq!(tree.nodes.len(), 0); + + assert_eq!(tree.find_ancestor_path(Ancestors::new()).unwrap(), NodePointer::Root); + assert_eq!(tree.find_backable_chain(Ancestors::new(), 2, |_| true), vec![]); + // Invalid candidate. + let ancestors: Ancestors = [CandidateHash::default()].into_iter().collect(); + assert_eq!(tree.find_ancestor_path(ancestors.clone()), Some(NodePointer::Root)); + assert_eq!(tree.find_backable_chain(ancestors, 2, |_| true), vec![]); + } + + #[rstest] + #[case(true, 13)] + #[case(false, 8)] + // The tree with no cycles looks like: + // Make a tree that looks like this (note that there's no cycle): + // +-(root)-+ + // | | + // +----0---+ 7 + // | | + // 1----+ 5 + // | | + // | | + // 2 6 + // | + // 3 + // | + // 4 + // + // The tree with cycles is the same as the first but has a cycle from 4 back to the state + // produced by 0 (It's bounded by the max_depth + 1). + // +-(root)-+ + // | | + // +----0---+ 7 + // | | + // 1----+ 5 + // | | + // | | + // 2 6 + // | + // 3 + // | + // 4---+ + // | | + // 1 5 + // | + // 2 + // | + // 3 + fn test_find_ancestor_path_and_find_backable_chain( + #[case] has_cycle: bool, + #[case] expected_node_count: usize, + ) { + let para_id = ParaId::from(5u32); + let relay_parent = Hash::repeat_byte(1); + let required_parent: HeadData = vec![0xff].into(); + let max_depth = 7; + let relay_parent_number = 0; + let relay_parent_storage_root = Hash::repeat_byte(69); + + let mut candidates = vec![]; + + // Candidate 0 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + required_parent.clone(), + vec![0].into(), + 0, + )); + // Candidate 1 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + vec![0].into(), + vec![1].into(), + 0, + )); + // Candidate 2 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + vec![1].into(), + vec![2].into(), + 0, + )); + // Candidate 3 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + vec![2].into(), + vec![3].into(), + 0, + )); + // Candidate 4 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + vec![3].into(), + vec![4].into(), + 0, + )); + // Candidate 5 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + vec![0].into(), + vec![5].into(), + 0, + )); + // Candidate 6 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + vec![1].into(), + vec![6].into(), + 0, + )); + // Candidate 7 + candidates.push(make_committed_candidate( + para_id, + relay_parent, + 0, + required_parent.clone(), + vec![7].into(), + 0, + )); + + if has_cycle { + candidates[4] = make_committed_candidate( + para_id, + relay_parent, + 0, + vec![3].into(), + vec![0].into(), // put the cycle here back to the output state of 0. + 0, + ); + } + + let base_constraints = make_constraints(0, vec![0], required_parent.clone()); + let mut storage = CandidateStorage::new(); + + let relay_parent_info = RelayChainBlockInfo { + number: relay_parent_number, + hash: relay_parent, + storage_root: relay_parent_storage_root, + }; + + for (pvd, candidate) in candidates.iter() { + storage.add_candidate(candidate.clone(), pvd.clone()).unwrap(); + } + let candidates = + candidates.into_iter().map(|(_pvd, candidate)| candidate).collect::>(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_info, + base_constraints, + vec![], + max_depth, + vec![], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + assert_eq!(tree.candidates().collect::>().len(), candidates.len()); + assert_eq!(tree.nodes.len(), expected_node_count); + + // Do some common tests on both trees. + { + // No ancestors supplied. + assert_eq!(tree.find_ancestor_path(Ancestors::new()).unwrap(), NodePointer::Root); + assert_eq!( + tree.find_backable_chain(Ancestors::new(), 4, |_| true), + [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + // Ancestor which is not part of the tree. Will be ignored. + let ancestors: Ancestors = [CandidateHash::default()].into_iter().collect(); + assert_eq!(tree.find_ancestor_path(ancestors.clone()).unwrap(), NodePointer::Root); + assert_eq!( + tree.find_backable_chain(ancestors, 4, |_| true), + [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + // A chain fork. + let ancestors: Ancestors = + [(candidates[0].hash()), (candidates[7].hash())].into_iter().collect(); + assert_eq!(tree.find_ancestor_path(ancestors.clone()), None); + assert_eq!(tree.find_backable_chain(ancestors, 1, |_| true), vec![]); + + // Ancestors which are part of the tree but don't form a path. Will be ignored. + let ancestors: Ancestors = + [candidates[1].hash(), candidates[2].hash()].into_iter().collect(); + assert_eq!(tree.find_ancestor_path(ancestors.clone()).unwrap(), NodePointer::Root); + assert_eq!( + tree.find_backable_chain(ancestors, 4, |_| true), + [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // Valid ancestors. + let ancestors: Ancestors = [candidates[7].hash()].into_iter().collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + let candidate = &tree.nodes[res.unwrap_idx()]; + assert_eq!(candidate.candidate_hash, candidates[7].hash()); + assert_eq!(tree.find_backable_chain(ancestors, 1, |_| true), vec![]); + + let ancestors: Ancestors = + [candidates[2].hash(), candidates[0].hash(), candidates[1].hash()] + .into_iter() + .collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + let candidate = &tree.nodes[res.unwrap_idx()]; + assert_eq!(candidate.candidate_hash, candidates[2].hash()); + assert_eq!( + tree.find_backable_chain(ancestors.clone(), 2, |_| true), + [3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // Valid ancestors with candidates which have been omitted due to timeouts + let ancestors: Ancestors = + [candidates[0].hash(), candidates[2].hash()].into_iter().collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + let candidate = &tree.nodes[res.unwrap_idx()]; + assert_eq!(candidate.candidate_hash, candidates[0].hash()); + assert_eq!( + tree.find_backable_chain(ancestors, 3, |_| true), + [1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + let ancestors: Ancestors = + [candidates[0].hash(), candidates[1].hash(), candidates[3].hash()] + .into_iter() + .collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + let candidate = &tree.nodes[res.unwrap_idx()]; + assert_eq!(candidate.candidate_hash, candidates[1].hash()); + if has_cycle { + assert_eq!( + tree.find_backable_chain(ancestors, 2, |_| true), + [2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + } else { + assert_eq!( + tree.find_backable_chain(ancestors, 4, |_| true), + [2, 3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + } + + let ancestors: Ancestors = + [candidates[1].hash(), candidates[2].hash()].into_iter().collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + assert_eq!(res, NodePointer::Root); + assert_eq!( + tree.find_backable_chain(ancestors, 4, |_| true), + [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // Requested count is 0. + assert_eq!(tree.find_backable_chain(Ancestors::new(), 0, |_| true), vec![]); + + let ancestors: Ancestors = + [candidates[2].hash(), candidates[0].hash(), candidates[1].hash()] + .into_iter() + .collect(); + assert_eq!(tree.find_backable_chain(ancestors, 0, |_| true), vec![]); + + let ancestors: Ancestors = + [candidates[2].hash(), candidates[0].hash()].into_iter().collect(); + assert_eq!(tree.find_backable_chain(ancestors, 0, |_| true), vec![]); + } + + // Now do some tests only on the tree with cycles + if has_cycle { + // Exceeds the maximum tree depth. 0-1-2-3-4-1-2-3-4, when the tree stops at + // 0-1-2-3-4-1-2-3. + let ancestors: Ancestors = [ + candidates[0].hash(), + candidates[1].hash(), + candidates[2].hash(), + candidates[3].hash(), + candidates[4].hash(), + ] + .into_iter() + .collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + let candidate = &tree.nodes[res.unwrap_idx()]; + assert_eq!(candidate.candidate_hash, candidates[4].hash()); + assert_eq!( + tree.find_backable_chain(ancestors, 4, |_| true), + [1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // 0-1-2. + let ancestors: Ancestors = + [candidates[0].hash(), candidates[1].hash(), candidates[2].hash()] + .into_iter() + .collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + let candidate = &tree.nodes[res.unwrap_idx()]; + assert_eq!(candidate.candidate_hash, candidates[2].hash()); + assert_eq!( + tree.find_backable_chain(ancestors.clone(), 1, |_| true), + [3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + assert_eq!( + tree.find_backable_chain(ancestors, 5, |_| true), + [3, 4, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // 0-1 + let ancestors: Ancestors = + [candidates[0].hash(), candidates[1].hash()].into_iter().collect(); + let res = tree.find_ancestor_path(ancestors.clone()).unwrap(); + let candidate = &tree.nodes[res.unwrap_idx()]; + assert_eq!(candidate.candidate_hash, candidates[1].hash()); + assert_eq!( + tree.find_backable_chain(ancestors, 6, |_| true), + [2, 3, 4, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>(), + ); + + // For 0-1-2-3-4-5, there's more than 1 way of finding this path in + // the tree. `None` should be returned. The runtime should not have accepted this. + let ancestors: Ancestors = [ + candidates[0].hash(), + candidates[1].hash(), + candidates[2].hash(), + candidates[3].hash(), + candidates[4].hash(), + candidates[5].hash(), + ] + .into_iter() + .collect(); + let res = tree.find_ancestor_path(ancestors.clone()); + assert_eq!(res, None); + assert_eq!(tree.find_backable_chain(ancestors, 1, |_| true), vec![]); + } + } + #[test] fn graceful_cycle_of_0() { let mut storage = CandidateStorage::new(); @@ -1602,13 +2071,17 @@ mod tests { for count in 1..10 { assert_eq!( - tree.select_children(&[], count, |_| true), + tree.find_backable_chain(Ancestors::new(), count, |_| true), iter::repeat(candidate_a_hash) .take(std::cmp::min(count as usize, max_depth + 1)) .collect::>() ); assert_eq!( - tree.select_children(&[candidate_a_hash], count - 1, |_| true), + tree.find_backable_chain( + [candidate_a_hash].into_iter().collect(), + count - 1, + |_| true + ), iter::repeat(candidate_a_hash) .take(std::cmp::min(count as usize - 1, max_depth)) .collect::>() @@ -1682,22 +2155,22 @@ mod tests { assert_eq!(tree.nodes[3].candidate_hash, candidate_b_hash); assert_eq!(tree.nodes[4].candidate_hash, candidate_a_hash); - assert_eq!(tree.select_children(&[], 1, |_| true), vec![candidate_a_hash],); + assert_eq!(tree.find_backable_chain(Ancestors::new(), 1, |_| true), vec![candidate_a_hash],); assert_eq!( - tree.select_children(&[], 2, |_| true), + tree.find_backable_chain(Ancestors::new(), 2, |_| true), vec![candidate_a_hash, candidate_b_hash], ); assert_eq!( - tree.select_children(&[], 3, |_| true), + tree.find_backable_chain(Ancestors::new(), 3, |_| true), vec![candidate_a_hash, candidate_b_hash, candidate_a_hash], ); assert_eq!( - tree.select_children(&[candidate_a_hash], 2, |_| true), + tree.find_backable_chain([candidate_a_hash].into_iter().collect(), 2, |_| true), vec![candidate_b_hash, candidate_a_hash], ); assert_eq!( - tree.select_children(&[], 6, |_| true), + tree.find_backable_chain(Ancestors::new(), 6, |_| true), vec![ candidate_a_hash, candidate_b_hash, @@ -1706,10 +2179,17 @@ mod tests { candidate_a_hash ], ); - assert_eq!( - tree.select_children(&[candidate_a_hash, candidate_b_hash], 6, |_| true), - vec![candidate_a_hash, candidate_b_hash, candidate_a_hash,], - ); + + for count in 3..7 { + assert_eq!( + tree.find_backable_chain( + [candidate_a_hash, candidate_b_hash].into_iter().collect(), + count, + |_| true + ), + vec![candidate_a_hash, candidate_b_hash, candidate_a_hash], + ); + } } #[test] diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index 6e6915b92728ce745969581f5b700788f5156bc8..2b14e09b4fb4f56f5f7c6ffd738e4167804f44ad 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -35,7 +35,7 @@ use futures::{channel::oneshot, prelude::*}; use polkadot_node_subsystem::{ messages::{ - ChainApiMessage, FragmentTreeMembership, HypotheticalCandidate, + Ancestors, ChainApiMessage, FragmentTreeMembership, HypotheticalCandidate, HypotheticalFrontierRequest, IntroduceCandidateRequest, ProspectiveParachainsMessage, ProspectiveValidationDataRequest, RuntimeApiMessage, RuntimeApiRequest, }, @@ -150,16 +150,9 @@ async fn run_iteration( relay_parent, para, count, - required_path, + ancestors, tx, - ) => answer_get_backable_candidates( - &view, - relay_parent, - para, - count, - required_path, - tx, - ), + ) => answer_get_backable_candidates(&view, relay_parent, para, count, ancestors, tx), ProspectiveParachainsMessage::GetHypotheticalFrontier(request, tx) => answer_hypothetical_frontier_request(&view, request, tx), ProspectiveParachainsMessage::GetTreeMembership(para, candidate, tx) => @@ -298,7 +291,7 @@ async fn handle_active_leaves_update( ) .expect("ancestors are provided in reverse order and correctly; qed"); - gum::debug!( + gum::trace!( target: LOG_TARGET, relay_parent = ?hash, min_relay_parent = scope.earliest_relay_parent().number, @@ -565,7 +558,7 @@ fn answer_get_backable_candidates( relay_parent: Hash, para: ParaId, count: u32, - required_path: Vec, + ancestors: Ancestors, tx: oneshot::Sender>, ) { let data = match view.active_leaves.get(&relay_parent) { @@ -614,7 +607,7 @@ fn answer_get_backable_candidates( }; let backable_candidates: Vec<_> = tree - .select_children(&required_path, count, |candidate| storage.is_backed(candidate)) + .find_backable_chain(ancestors.clone(), count, |candidate| storage.is_backed(candidate)) .into_iter() .filter_map(|child_hash| { storage.relay_parent_by_candidate_hash(&child_hash).map_or_else( @@ -635,7 +628,7 @@ fn answer_get_backable_candidates( if backable_candidates.is_empty() { gum::trace!( target: LOG_TARGET, - ?required_path, + ?ancestors, para_id = ?para, %relay_parent, "Could not find any backable candidate", diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index 732736b101de0ce525c7753af4b60cca7534522b..0beddbf1416a7ec94cb84a6893e9c20cbeaf28ce 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -407,7 +407,7 @@ async fn get_backable_candidates( virtual_overseer: &mut VirtualOverseer, leaf: &TestLeaf, para_id: ParaId, - required_path: Vec, + ancestors: Ancestors, count: u32, expected_result: Vec<(CandidateHash, Hash)>, ) { @@ -415,11 +415,7 @@ async fn get_backable_candidates( virtual_overseer .send(overseer::FromOrchestra::Communication { msg: ProspectiveParachainsMessage::GetBackableCandidates( - leaf.hash, - para_id, - count, - required_path, - tx, + leaf.hash, para_id, count, ancestors, tx, ), }) .await; @@ -903,7 +899,7 @@ fn check_backable_query_single_candidate() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), 1, vec![], ) @@ -912,12 +908,20 @@ fn check_backable_query_single_candidate() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), + 0, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::new(), 0, vec![], ) .await; - get_backable_candidates(&mut virtual_overseer, &leaf_a, 1.into(), vec![], 0, vec![]).await; // Second candidates. second_candidate(&mut virtual_overseer, candidate_a.clone()).await; @@ -928,7 +932,7 @@ fn check_backable_query_single_candidate() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), 1, vec![], ) @@ -939,12 +943,20 @@ fn check_backable_query_single_candidate() { back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; // Should not get any backable candidates for the other para. - get_backable_candidates(&mut virtual_overseer, &leaf_a, 2.into(), vec![], 1, vec![]).await; get_backable_candidates( &mut virtual_overseer, &leaf_a, 2.into(), - vec![candidate_hash_a], + Ancestors::new(), + 1, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + vec![candidate_hash_a].into_iter().collect(), 1, vec![], ) @@ -955,7 +967,7 @@ fn check_backable_query_single_candidate() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![], + Ancestors::new(), 1, vec![(candidate_hash_a, leaf_a.hash)], ) @@ -964,20 +976,20 @@ fn check_backable_query_single_candidate() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), 1, vec![(candidate_hash_b, leaf_a.hash)], ) .await; - // Should not get anything at the wrong path. + // Wrong path get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_b], + vec![candidate_hash_b].into_iter().collect(), 1, - vec![], + vec![(candidate_hash_a, leaf_a.hash)], ) .await; @@ -1075,15 +1087,29 @@ fn check_backable_query_multiple_candidates() { make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_i, 10); // Should not get any backable candidates for the other para. - get_backable_candidates(&mut virtual_overseer, &leaf_a, 2.into(), vec![], 1, vec![]) - .await; - get_backable_candidates(&mut virtual_overseer, &leaf_a, 2.into(), vec![], 5, vec![]) - .await; get_backable_candidates( &mut virtual_overseer, &leaf_a, 2.into(), - vec![candidate_hash_a], + Ancestors::new(), + 1, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + Ancestors::new(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + vec![candidate_hash_a].into_iter().collect(), 1, vec![], ) @@ -1097,7 +1123,7 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![], + Ancestors::new(), 1, vec![(candidate_hash_a, leaf_a.hash)], ) @@ -1106,7 +1132,7 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![], + Ancestors::new(), 4, vec![ (candidate_hash_a, leaf_a.hash), @@ -1124,7 +1150,7 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), 1, vec![(candidate_hash_b, leaf_a.hash)], ) @@ -1133,16 +1159,7 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a], - 2, - vec![(candidate_hash_b, leaf_a.hash), (candidate_hash_d, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), 3, vec![ (candidate_hash_b, leaf_a.hash), @@ -1159,7 +1176,7 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), count, vec![ (candidate_hash_c, leaf_a.hash), @@ -1172,26 +1189,30 @@ fn check_backable_query_multiple_candidates() { } } - // required path of 2 + // required path of 2 and higher { get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a, candidate_hash_b], + vec![candidate_hash_a, candidate_hash_i, candidate_hash_h, candidate_hash_c] + .into_iter() + .collect(), 1, - vec![(candidate_hash_d, leaf_a.hash)], + vec![(candidate_hash_j, leaf_a.hash)], ) .await; + get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a, candidate_hash_c], + vec![candidate_hash_a, candidate_hash_b].into_iter().collect(), 1, - vec![(candidate_hash_h, leaf_a.hash)], + vec![(candidate_hash_d, leaf_a.hash)], ) .await; + // If the requested count exceeds the largest chain, return the longest // chain we can get. for count in 4..10 { @@ -1199,7 +1220,7 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a, candidate_hash_c], + vec![candidate_hash_a, candidate_hash_c].into_iter().collect(), count, vec![ (candidate_hash_h, leaf_a.hash), @@ -1213,317 +1234,127 @@ fn check_backable_query_multiple_candidates() { // No more candidates in any chain. { - let required_paths = vec![ - vec![candidate_hash_a, candidate_hash_b, candidate_hash_e], - vec![ - candidate_hash_a, - candidate_hash_c, - candidate_hash_h, - candidate_hash_i, - candidate_hash_j, - ], - ]; - for path in required_paths { - for count in 1..4 { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - path.clone(), - count, - vec![], - ) - .await; - } + for count in 1..4 { + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a, candidate_hash_b, candidate_hash_e] + .into_iter() + .collect(), + count, + vec![], + ) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![ + candidate_hash_a, + candidate_hash_c, + candidate_hash_h, + candidate_hash_i, + candidate_hash_j, + ] + .into_iter() + .collect(), + count, + vec![], + ) + .await; } } - // Should not get anything at the wrong path. + // Wrong paths. get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_b], + vec![candidate_hash_b].into_iter().collect(), 1, - vec![], + vec![(candidate_hash_a, leaf_a.hash)], ) .await; get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_b, candidate_hash_a], + vec![candidate_hash_b, candidate_hash_f].into_iter().collect(), 3, - vec![], + vec![ + (candidate_hash_a, leaf_a.hash), + (candidate_hash_b, leaf_a.hash), + (candidate_hash_d, leaf_a.hash), + ], ) .await; get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a, candidate_hash_b, candidate_hash_c], - 3, - vec![], + vec![candidate_hash_a, candidate_hash_h].into_iter().collect(), + 4, + vec![ + (candidate_hash_c, leaf_a.hash), + (candidate_hash_h, leaf_a.hash), + (candidate_hash_i, leaf_a.hash), + (candidate_hash_j, leaf_a.hash), + ], ) .await; - - virtual_overseer - }); - - assert_eq!(view.active_leaves.len(), 1); - assert_eq!(view.candidate_storage.len(), 2); - // 10 candidates and 7 parents on para 1. - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (7, 10)); - assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); - } - - // A tree with multiple roots. - // Parachain 1 looks like this: - // (imaginary root) - // | | - // +----B---+ A - // | | | | - // | | | C - // D E F | - // | H - // G | - // I - // | - // J - { - let test_state = TestState::default(); - let view = test_harness(|mut virtual_overseer| async move { - // Leaf A - let leaf_a = TestLeaf { - number: 100, - hash: Hash::from_low_u64_be(130), - para_data: vec![ - (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), - (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), - ], - }; - - // Activate leaves. - activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; - - // Candidate B - let (candidate_b, pvd_b) = make_candidate( - leaf_a.hash, - leaf_a.number, + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, 1.into(), - HeadData(vec![1, 2, 3]), - HeadData(vec![2]), - test_state.validation_code_hash, - ); - let candidate_hash_b = candidate_b.hash(); - introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; - second_candidate(&mut virtual_overseer, candidate_b.clone()).await; - back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; + vec![candidate_hash_e, candidate_hash_h].into_iter().collect(), + 2, + vec![(candidate_hash_a, leaf_a.hash), (candidate_hash_b, leaf_a.hash)], + ) + .await; - // Candidate A - let (candidate_a, pvd_a) = make_candidate( - leaf_a.hash, - leaf_a.number, + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, 1.into(), - HeadData(vec![1, 2, 3]), - HeadData(vec![1]), - test_state.validation_code_hash, - ); - let candidate_hash_a = candidate_a.hash(); - introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; - second_candidate(&mut virtual_overseer, candidate_a.clone()).await; - back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; - - let (candidate_c, candidate_hash_c) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_a, 3); - let (_candidate_d, candidate_hash_d) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_b, 4); - let (_candidate_e, candidate_hash_e) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_b, 5); - let (candidate_f, candidate_hash_f) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_b, 6); - let (_candidate_g, candidate_hash_g) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_f, 7); - let (candidate_h, candidate_hash_h) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_c, 8); - let (candidate_i, candidate_hash_i) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_h, 9); - let (_candidate_j, candidate_hash_j) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_i, 10); + vec![candidate_hash_a, candidate_hash_c, candidate_hash_d].into_iter().collect(), + 2, + vec![(candidate_hash_h, leaf_a.hash), (candidate_hash_i, leaf_a.hash)], + ) + .await; - // Should not get any backable candidates for the other para. - get_backable_candidates(&mut virtual_overseer, &leaf_a, 2.into(), vec![], 1, vec![]) - .await; - get_backable_candidates(&mut virtual_overseer, &leaf_a, 2.into(), vec![], 5, vec![]) - .await; + // Parachain fork. get_backable_candidates( &mut virtual_overseer, &leaf_a, - 2.into(), - vec![candidate_hash_a], + 1.into(), + vec![candidate_hash_a, candidate_hash_b, candidate_hash_c].into_iter().collect(), 1, vec![], ) .await; - // Test various scenarios with various counts. - - // empty required_path - { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![], - 1, - vec![(candidate_hash_b, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![], - 2, - vec![(candidate_hash_b, leaf_a.hash), (candidate_hash_d, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![], - 4, - vec![ - (candidate_hash_a, leaf_a.hash), - (candidate_hash_c, leaf_a.hash), - (candidate_hash_h, leaf_a.hash), - (candidate_hash_i, leaf_a.hash), - ], - ) - .await; - } - - // required path of 1 - { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a], - 1, - vec![(candidate_hash_c, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_b], - 1, - vec![(candidate_hash_d, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a], - 2, - vec![(candidate_hash_c, leaf_a.hash), (candidate_hash_h, leaf_a.hash)], - ) - .await; - - // If the requested count exceeds the largest chain, return the longest - // chain we can get. - for count in 2..10 { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_b], - count, - vec![(candidate_hash_f, leaf_a.hash), (candidate_hash_g, leaf_a.hash)], - ) - .await; - } - } - - // required path of 2 - { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_b, candidate_hash_f], - 1, - vec![(candidate_hash_g, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a, candidate_hash_c], - 1, - vec![(candidate_hash_h, leaf_a.hash)], - ) - .await; - // If the requested count exceeds the largest chain, return the longest - // chain we can get. - for count in 4..10 { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a, candidate_hash_c], - count, - vec![ - (candidate_hash_h, leaf_a.hash), - (candidate_hash_i, leaf_a.hash), - (candidate_hash_j, leaf_a.hash), - ], - ) - .await; - } - } - - // No more candidates in any chain. - { - let required_paths = vec![ - vec![candidate_hash_b, candidate_hash_f, candidate_hash_g], - vec![candidate_hash_b, candidate_hash_e], - vec![candidate_hash_b, candidate_hash_d], - vec![ - candidate_hash_a, - candidate_hash_c, - candidate_hash_h, - candidate_hash_i, - candidate_hash_j, - ], - ]; - for path in required_paths { - for count in 1..4 { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - path.clone(), - count, - vec![], - ) - .await; - } - } - } + // Non-existent candidate. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a, CandidateHash(Hash::from_low_u64_be(100))] + .into_iter() + .collect(), + 2, + vec![(candidate_hash_b, leaf_a.hash), (candidate_hash_d, leaf_a.hash)], + ) + .await; - // Should not get anything at the wrong path. + // Requested count is zero. get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_d], - 1, + Ancestors::new(), + 0, vec![], ) .await; @@ -1531,8 +1362,8 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_b, candidate_hash_a], - 3, + vec![candidate_hash_a].into_iter().collect(), + 0, vec![], ) .await; @@ -1540,8 +1371,8 @@ fn check_backable_query_multiple_candidates() { &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a, candidate_hash_c, candidate_hash_d], - 3, + vec![candidate_hash_a, candidate_hash_b].into_iter().collect(), + 0, vec![], ) .await; @@ -1853,8 +1684,8 @@ fn check_pvd_query() { assert_eq!(view.candidate_storage.len(), 2); } -// Test simultaneously activating and deactivating leaves, and simultaneously deactivating multiple -// leaves. +// Test simultaneously activating and deactivating leaves, and simultaneously deactivating +// multiple leaves. #[test] fn correctly_updates_leaves() { let test_state = TestState::default(); @@ -2048,7 +1879,7 @@ fn persists_pending_availability_candidate() { &mut virtual_overseer, &leaf_b, para_id, - vec![candidate_hash_a], + vec![candidate_hash_a].into_iter().collect(), 1, vec![(candidate_hash_b, leaf_b_hash)], ) @@ -2113,7 +1944,7 @@ fn backwards_compatible() { &mut virtual_overseer, &leaf_a, para_id, - vec![], + Ancestors::new(), 1, vec![(candidate_hash_a, candidate_relay_parent)], ) @@ -2135,7 +1966,15 @@ fn backwards_compatible() { ) .await; - get_backable_candidates(&mut virtual_overseer, &leaf_b, para_id, vec![], 1, vec![]).await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + para_id, + Ancestors::new(), + 1, + vec![], + ) + .await; virtual_overseer }); @@ -2162,13 +2001,13 @@ fn uses_ancestry_only_within_session() { .await; assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) - ) if parent == hash => { - tx.send(Ok(AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: ancestry_len })).unwrap(); - } - ); + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) + ) if parent == hash => { + tx.send(Ok(AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: ancestry_len + })).unwrap(); } + ); assert_matches!( virtual_overseer.recv().await, diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 175980e90a057f136de25ad7091bcaef497f0a5f..2a09e2b5b2cc83a0596c6f0ae153e66f8f6a1e66 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -13,16 +13,18 @@ workspace = true bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } -thiserror = "1.0.48" +thiserror = { workspace = true } polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } futures-timer = "3.0.2" fatality = "0.0.6" +schnellru = "0.2.1" [dev-dependencies] sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } +rstest = "0.18.2" diff --git a/polkadot/node/core/provisioner/src/error.rs b/polkadot/node/core/provisioner/src/error.rs index 376d69f276fc892e92828bf994b29f847fae31d0..aae3234c3cc49d19bdaf20b87fa71cf3f3276bfe 100644 --- a/polkadot/node/core/provisioner/src/error.rs +++ b/polkadot/node/core/provisioner/src/error.rs @@ -44,14 +44,17 @@ pub enum Error { #[error("failed to get block number")] CanceledBlockNumber(#[source] oneshot::Canceled), + #[error("failed to get session index")] + CanceledSessionIndex(#[source] oneshot::Canceled), + #[error("failed to get backed candidates")] CanceledBackedCandidates(#[source] oneshot::Canceled), #[error("failed to get votes on dispute")] CanceledCandidateVotes(#[source] oneshot::Canceled), - #[error("failed to get backable candidate from prospective parachains")] - CanceledBackableCandidate(#[source] oneshot::Canceled), + #[error("failed to get backable candidates from prospective parachains")] + CanceledBackableCandidates(#[source] oneshot::Canceled), #[error(transparent)] ChainApi(#[from] ChainApiError), @@ -71,11 +74,6 @@ pub enum Error { #[error("failed to send return message with Inherents")] InherentDataReturnChannel, - #[error( - "backed candidate does not correspond to selected candidate; check logic in provisioner" - )] - BackedCandidateOrderingProblem, - #[fatal] #[error("Failed to spawn background task")] FailedToSpawnBackgroundTask, diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index 51f768d782e0bff3d54efd70523120658b73bba2..c9ed873d3c25ae1a0fbe590a51412839e8105634 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -24,26 +24,29 @@ use futures::{ channel::oneshot, future::BoxFuture, prelude::*, stream::FuturesUnordered, FutureExt, }; use futures_timer::Delay; +use schnellru::{ByLength, LruMap}; use polkadot_node_subsystem::{ jaeger, messages::{ - CandidateBackingMessage, ChainApiMessage, ProspectiveParachainsMessage, ProvisionableData, - ProvisionerInherentData, ProvisionerMessage, RuntimeApiRequest, + Ancestors, CandidateBackingMessage, ChainApiMessage, ProspectiveParachainsMessage, + ProvisionableData, ProvisionerInherentData, ProvisionerMessage, RuntimeApiRequest, }, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_util::{ has_required_runtime, request_availability_cores, request_persisted_validation_data, - runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, + request_session_index_for_child, + runtime::{prospective_parachains_mode, request_node_features, ProspectiveParachainsMode}, TimeoutExt, }; use polkadot_primitives::{ - BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, CoreState, Hash, Id as ParaId, - OccupiedCoreAssumption, SignedAvailabilityBitfield, ValidatorIndex, + vstaging::{node_features::FeatureIndex, NodeFeatures}, + BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, CoreState, Hash, + Id as ParaId, OccupiedCoreAssumption, SessionIndex, SignedAvailabilityBitfield, ValidatorIndex, }; -use std::collections::{BTreeMap, HashMap}; +use std::collections::{BTreeMap, HashMap, HashSet}; mod disputes; mod error; @@ -77,11 +80,18 @@ impl ProvisionerSubsystem { } } +/// Per-session info we need for the provisioner subsystem. +pub struct PerSession { + prospective_parachains_mode: ProspectiveParachainsMode, + elastic_scaling_mvp: bool, +} + /// A per-relay-parent state for the provisioning subsystem. pub struct PerRelayParent { leaf: ActivatedLeaf, backed_candidates: Vec, prospective_parachains_mode: ProspectiveParachainsMode, + elastic_scaling_mvp: bool, signed_bitfields: Vec, is_inherent_ready: bool, awaiting_inherent: Vec>, @@ -89,13 +99,14 @@ pub struct PerRelayParent { } impl PerRelayParent { - fn new(leaf: ActivatedLeaf, prospective_parachains_mode: ProspectiveParachainsMode) -> Self { + fn new(leaf: ActivatedLeaf, per_session: &PerSession) -> Self { let span = PerLeafSpan::new(leaf.span.clone(), "provisioner"); Self { leaf, backed_candidates: Vec::new(), - prospective_parachains_mode, + prospective_parachains_mode: per_session.prospective_parachains_mode, + elastic_scaling_mvp: per_session.elastic_scaling_mvp, signed_bitfields: Vec::new(), is_inherent_ready: false, awaiting_inherent: Vec::new(), @@ -124,10 +135,17 @@ impl ProvisionerSubsystem { async fn run(mut ctx: Context, metrics: Metrics) -> FatalResult<()> { let mut inherent_delays = InherentDelays::new(); let mut per_relay_parent = HashMap::new(); + let mut per_session = LruMap::new(ByLength::new(2)); loop { - let result = - run_iteration(&mut ctx, &mut per_relay_parent, &mut inherent_delays, &metrics).await; + let result = run_iteration( + &mut ctx, + &mut per_relay_parent, + &mut per_session, + &mut inherent_delays, + &metrics, + ) + .await; match result { Ok(()) => break, @@ -142,6 +160,7 @@ async fn run(mut ctx: Context, metrics: Metrics) -> FatalResult<()> { async fn run_iteration( ctx: &mut Context, per_relay_parent: &mut HashMap, + per_session: &mut LruMap, inherent_delays: &mut InherentDelays, metrics: &Metrics, ) -> Result<(), Error> { @@ -151,7 +170,7 @@ async fn run_iteration( // Map the error to ensure that the subsystem exits when the overseer is gone. match from_overseer.map_err(Error::OverseerExited)? { FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => - handle_active_leaves_update(ctx.sender(), update, per_relay_parent, inherent_delays).await?, + handle_active_leaves_update(ctx.sender(), update, per_relay_parent, per_session, inherent_delays).await?, FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {}, FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), FromOrchestra::Communication { msg } => { @@ -183,6 +202,7 @@ async fn handle_active_leaves_update( sender: &mut impl overseer::ProvisionerSenderTrait, update: ActiveLeavesUpdate, per_relay_parent: &mut HashMap, + per_session: &mut LruMap, inherent_delays: &mut InherentDelays, ) -> Result<(), Error> { gum::trace!(target: LOG_TARGET, "Handle ActiveLeavesUpdate"); @@ -191,10 +211,31 @@ async fn handle_active_leaves_update( } if let Some(leaf) = update.activated { + let session_index = request_session_index_for_child(leaf.hash, sender) + .await + .await + .map_err(Error::CanceledSessionIndex)??; + if per_session.get(&session_index).is_none() { + let prospective_parachains_mode = + prospective_parachains_mode(sender, leaf.hash).await?; + let elastic_scaling_mvp = request_node_features(leaf.hash, session_index, sender) + .await? + .unwrap_or(NodeFeatures::EMPTY) + .get(FeatureIndex::ElasticScalingMVP as usize) + .map(|b| *b) + .unwrap_or(false); + + per_session.insert( + session_index, + PerSession { prospective_parachains_mode, elastic_scaling_mvp }, + ); + } + + let session_info = per_session.get(&session_index).expect("Just inserted"); + gum::trace!(target: LOG_TARGET, leaf_hash=?leaf.hash, "Adding delay"); - let prospective_parachains_mode = prospective_parachains_mode(sender, leaf.hash).await?; let delay_fut = Delay::new(PRE_PROPOSE_TIMEOUT).map(move |_| leaf.hash).boxed(); - per_relay_parent.insert(leaf.hash, PerRelayParent::new(leaf, prospective_parachains_mode)); + per_relay_parent.insert(leaf.hash, PerRelayParent::new(leaf, session_info)); inherent_delays.push(delay_fut); } @@ -253,6 +294,7 @@ async fn send_inherent_data_bg( let signed_bitfields = per_relay_parent.signed_bitfields.clone(); let backed_candidates = per_relay_parent.backed_candidates.clone(); let mode = per_relay_parent.prospective_parachains_mode; + let elastic_scaling_mvp = per_relay_parent.elastic_scaling_mvp; let span = per_relay_parent.span.child("req-inherent-data"); let mut sender = ctx.sender().clone(); @@ -272,6 +314,7 @@ async fn send_inherent_data_bg( &signed_bitfields, &backed_candidates, mode, + elastic_scaling_mvp, return_senders, &mut sender, &metrics, @@ -383,6 +426,7 @@ async fn send_inherent_data( bitfields: &[SignedAvailabilityBitfield], candidates: &[CandidateReceipt], prospective_parachains_mode: ProspectiveParachainsMode, + elastic_scaling_mvp: bool, return_senders: Vec>, from_job: &mut impl overseer::ProvisionerSenderTrait, metrics: &Metrics, @@ -434,6 +478,7 @@ async fn send_inherent_data( &bitfields, candidates, prospective_parachains_mode, + elastic_scaling_mvp, leaf.hash, from_job, ) @@ -558,6 +603,8 @@ async fn select_candidate_hashes_from_tracked( let mut selected_candidates = Vec::with_capacity(candidates.len().min(availability_cores.len())); + let mut selected_parachains = + HashSet::with_capacity(candidates.len().min(availability_cores.len())); gum::debug!( target: LOG_TARGET, @@ -591,6 +638,12 @@ async fn select_candidate_hashes_from_tracked( CoreState::Free => continue, }; + if selected_parachains.contains(&scheduled_core.para_id) { + // We already picked a candidate for this parachain. Elastic scaling only works with + // prospective parachains mode. + continue + } + let validation_data = match request_persisted_validation_data( relay_parent, scheduled_core.para_id, @@ -624,6 +677,7 @@ async fn select_candidate_hashes_from_tracked( "Selected candidate receipt", ); + selected_parachains.insert(candidate.descriptor.para_id); selected_candidates.push((candidate_hash, candidate.descriptor.relay_parent)); } } @@ -637,63 +691,93 @@ async fn select_candidate_hashes_from_tracked( /// Should be called when prospective parachains are enabled. async fn request_backable_candidates( availability_cores: &[CoreState], + elastic_scaling_mvp: bool, bitfields: &[SignedAvailabilityBitfield], relay_parent: Hash, sender: &mut impl overseer::ProvisionerSenderTrait, ) -> Result, Error> { let block_number = get_block_number_under_construction(relay_parent, sender).await?; - let mut selected_candidates = Vec::with_capacity(availability_cores.len()); + // Record how many cores are scheduled for each paraid. Use a BTreeMap because + // we'll need to iterate through them. + let mut scheduled_cores: BTreeMap = BTreeMap::new(); + // The on-chain ancestors of a para present in availability-cores. + let mut ancestors: HashMap = + HashMap::with_capacity(availability_cores.len()); for (core_idx, core) in availability_cores.iter().enumerate() { - let (para_id, required_path) = match core { + let core_idx = CoreIndex(core_idx as u32); + match core { CoreState::Scheduled(scheduled_core) => { - // The core is free, pick the first eligible candidate from - // the fragment tree. - (scheduled_core.para_id, Vec::new()) + *scheduled_cores.entry(scheduled_core.para_id).or_insert(0) += 1; }, CoreState::Occupied(occupied_core) => { - if bitfields_indicate_availability(core_idx, bitfields, &occupied_core.availability) - { + let is_available = bitfields_indicate_availability( + core_idx.0 as usize, + bitfields, + &occupied_core.availability, + ); + + if is_available { + ancestors + .entry(occupied_core.para_id()) + .or_default() + .insert(occupied_core.candidate_hash); + if let Some(ref scheduled_core) = occupied_core.next_up_on_available { - // The candidate occupying the core is available, choose its - // child in the fragment tree. - // - // TODO: doesn't work for on-demand parachains. We lean hard on the - // assumption that cores are fixed to specific parachains within a session. - // https://github.com/paritytech/polkadot/issues/5492 - (scheduled_core.para_id, vec![occupied_core.candidate_hash]) - } else { - continue - } - } else { - if occupied_core.time_out_at != block_number { - continue + // Request a new backable candidate for the newly scheduled para id. + *scheduled_cores.entry(scheduled_core.para_id).or_insert(0) += 1; } + } else if occupied_core.time_out_at <= block_number { + // Timed out before being available. + if let Some(ref scheduled_core) = occupied_core.next_up_on_time_out { // Candidate's availability timed out, practically same as scheduled. - (scheduled_core.para_id, Vec::new()) - } else { - continue + *scheduled_cores.entry(scheduled_core.para_id).or_insert(0) += 1; } + } else { + // Not timed out and not available. + ancestors + .entry(occupied_core.para_id()) + .or_default() + .insert(occupied_core.candidate_hash); } }, CoreState::Free => continue, }; + } - let response = get_backable_candidate(relay_parent, para_id, required_path, sender).await?; + let mut selected_candidates: Vec<(CandidateHash, Hash)> = + Vec::with_capacity(availability_cores.len()); - match response { - Some((hash, relay_parent)) => selected_candidates.push((hash, relay_parent)), - None => { - gum::debug!( - target: LOG_TARGET, - leaf_hash = ?relay_parent, - core = core_idx, - "No backable candidate returned by prospective parachains", - ); - }, + for (para_id, core_count) in scheduled_cores { + let para_ancestors = ancestors.remove(¶_id).unwrap_or_default(); + + // If elastic scaling MVP is disabled, only allow one candidate per parachain. + if !elastic_scaling_mvp && core_count > 1 { + continue } + + let response = get_backable_candidates( + relay_parent, + para_id, + para_ancestors, + core_count as u32, + sender, + ) + .await?; + + if response.is_empty() { + gum::debug!( + target: LOG_TARGET, + leaf_hash = ?relay_parent, + ?para_id, + "No backable candidate returned by prospective parachains", + ); + continue + } + + selected_candidates.extend(response.into_iter().take(core_count)); } Ok(selected_candidates) @@ -706,6 +790,7 @@ async fn select_candidates( bitfields: &[SignedAvailabilityBitfield], candidates: &[CandidateReceipt], prospective_parachains_mode: ProspectiveParachainsMode, + elastic_scaling_mvp: bool, relay_parent: Hash, sender: &mut impl overseer::ProvisionerSenderTrait, ) -> Result, Error> { @@ -715,7 +800,14 @@ async fn select_candidates( let selected_candidates = match prospective_parachains_mode { ProspectiveParachainsMode::Enabled { .. } => - request_backable_candidates(availability_cores, bitfields, relay_parent, sender).await?, + request_backable_candidates( + availability_cores, + elastic_scaling_mvp, + bitfields, + relay_parent, + sender, + ) + .await?, ProspectiveParachainsMode::Disabled => select_candidate_hashes_from_tracked( availability_cores, @@ -726,6 +818,7 @@ async fn select_candidates( ) .await?, }; + gum::debug!(target: LOG_TARGET, ?selected_candidates, "Got backable candidates"); // now get the backed candidates corresponding to these candidate receipts let (tx, rx) = oneshot::channel(); @@ -737,28 +830,10 @@ async fn select_candidates( gum::trace!(target: LOG_TARGET, leaf_hash=?relay_parent, "Got {} backed candidates", candidates.len()); - // `selected_candidates` is generated in ascending order by core index, and - // `GetBackedCandidates` _should_ preserve that property, but let's just make sure. - // - // We can't easily map from `BackedCandidate` to `core_idx`, but we know that every selected - // candidate maps to either 0 or 1 backed candidate, and the hashes correspond. Therefore, by - // checking them in order, we can ensure that the backed candidates are also in order. - let mut backed_idx = 0; - for selected in selected_candidates { - if selected.0 == - candidates.get(backed_idx).ok_or(Error::BackedCandidateOrderingProblem)?.hash() - { - backed_idx += 1; - } - } - if candidates.len() != backed_idx { - Err(Error::BackedCandidateOrderingProblem)?; - } - // keep only one candidate with validation code. let mut with_validation_code = false; candidates.retain(|c| { - if c.candidate.commitments.new_validation_code.is_some() { + if c.candidate().commitments.new_validation_code.is_some() { if with_validation_code { return false } @@ -796,28 +871,27 @@ async fn get_block_number_under_construction( } } -/// Requests backable candidate from Prospective Parachains based on -/// the given path in the fragment tree. -async fn get_backable_candidate( +/// Requests backable candidates from Prospective Parachains based on +/// the given ancestors in the fragment tree. The ancestors may not be ordered. +async fn get_backable_candidates( relay_parent: Hash, para_id: ParaId, - required_path: Vec, + ancestors: Ancestors, + count: u32, sender: &mut impl overseer::ProvisionerSenderTrait, -) -> Result, Error> { +) -> Result, Error> { let (tx, rx) = oneshot::channel(); sender .send_message(ProspectiveParachainsMessage::GetBackableCandidates( relay_parent, para_id, - 1, // core count hardcoded to 1, until elastic scaling is implemented and enabled. - required_path, + count, + ancestors, tx, )) .await; - rx.await - .map_err(Error::CanceledBackableCandidate) - .map(|res| res.get(0).copied()) + rx.await.map_err(Error::CanceledBackableCandidates) } /// The availability bitfield for a given core is the transpose diff --git a/polkadot/node/core/provisioner/src/tests.rs b/polkadot/node/core/provisioner/src/tests.rs index b26df8ddb910465fc9920d462fd9266935112175..bdb4f85f4009bdfff879cefcb8928899c5b85c81 100644 --- a/polkadot/node/core/provisioner/src/tests.rs +++ b/polkadot/node/core/provisioner/src/tests.rs @@ -22,6 +22,9 @@ use polkadot_primitives::{OccupiedCore, ScheduledCore}; 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(); + CoreState::Occupied(OccupiedCore { group_responsible: para_id.into(), next_up_on_available: None, @@ -29,7 +32,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: dummy_candidate_descriptor(dummy_hash()), + candidate_descriptor, candidate_hash: Default::default(), }) } @@ -254,10 +257,56 @@ mod select_candidates { use polkadot_primitives::{ BlockNumber, CandidateCommitments, CommittedCandidateReceipt, PersistedValidationData, }; + use rstest::rstest; const BLOCK_UNDER_PRODUCTION: BlockNumber = 128; - // For test purposes, we always return this set of availability cores: + 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; + CandidateReceipt { + descriptor: descriptor_template, + commitments_hash: CandidateCommitments::default().hash(), + } + } + + fn make_candidates( + core_count: usize, + expected_backed_indices: Vec, + ) -> (Vec, Vec) { + let candidate_template = dummy_candidate_template(); + let candidates: Vec<_> = std::iter::repeat(candidate_template) + .take(core_count) + .enumerate() + .map(|(idx, mut candidate)| { + candidate.descriptor.para_id = idx.into(); + candidate + }) + .collect(); + + let expected_backed = expected_backed_indices + .iter() + .map(|&idx| candidates[idx].clone()) + .map(|c| { + BackedCandidate::new( + CommittedCandidateReceipt { + descriptor: c.descriptor.clone(), + commitments: Default::default(), + }, + Vec::new(), + default_bitvec(MOCK_GROUP_SIZE), + None, + ) + }) + .collect(); + let candidate_hashes = candidates.into_iter().map(|c| c.hash()).collect(); + + (candidate_hashes, expected_backed) + } + + // For testing only one core assigned to a parachain, we return this set of availability cores: // // [ // 0: Free, @@ -273,7 +322,7 @@ mod select_candidates { // 10: Occupied(both next_up set, not available, timeout), // 11: Occupied(next_up_on_available and available, but different successor para_id) // ] - fn mock_availability_cores() -> Vec { + fn mock_availability_cores_one_per_para() -> Vec { use std::ops::Not; use CoreState::{Free, Scheduled}; @@ -292,6 +341,7 @@ mod select_candidates { build_occupied_core(4, |core| { core.next_up_on_available = Some(scheduled_core(4)); core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(41)); }), // 5: Occupied(next_up_on_time_out set but not timeout), build_occupied_core(5, |core| { @@ -307,12 +357,14 @@ mod select_candidates { build_occupied_core(7, |core| { core.next_up_on_time_out = Some(scheduled_core(7)); core.time_out_at = BLOCK_UNDER_PRODUCTION; + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(71)); }), // 8: Occupied(both next_up set, available), build_occupied_core(8, |core| { core.next_up_on_available = Some(scheduled_core(8)); core.next_up_on_time_out = Some(scheduled_core(8)); core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(81)); }), // 9: Occupied(both next_up set, not available, no timeout), build_occupied_core(9, |core| { @@ -324,6 +376,7 @@ mod select_candidates { core.next_up_on_available = Some(scheduled_core(10)); core.next_up_on_time_out = Some(scheduled_core(10)); core.time_out_at = BLOCK_UNDER_PRODUCTION; + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(101)); }), // 11: Occupied(next_up_on_available and available, but different successor para_id) build_occupied_core(11, |core| { @@ -333,20 +386,189 @@ mod select_candidates { ] } + // For test purposes with multiple possible cores assigned to a para, we always return this set + // of availability cores: + fn mock_availability_cores_multiple_per_para() -> Vec { + use std::ops::Not; + use CoreState::{Free, Scheduled}; + + vec![ + // 0: Free, + Free, + // 1: Scheduled(default), + Scheduled(scheduled_core(1)), + // 2: Occupied(no next_up set), + occupied_core(2), + // 3: Occupied(next_up_on_available set but not available), + build_occupied_core(3, |core| { + core.next_up_on_available = Some(scheduled_core(3)); + }), + // 4: Occupied(next_up_on_available set and available), + build_occupied_core(4, |core| { + core.next_up_on_available = Some(scheduled_core(4)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(41)); + }), + // 5: Occupied(next_up_on_time_out set but not timeout), + build_occupied_core(5, |core| { + core.next_up_on_time_out = Some(scheduled_core(5)); + }), + // 6: Occupied(next_up_on_time_out set and timeout but available), + build_occupied_core(6, |core| { + core.next_up_on_time_out = Some(scheduled_core(6)); + core.time_out_at = BLOCK_UNDER_PRODUCTION; + core.availability = core.availability.clone().not(); + }), + // 7: Occupied(next_up_on_time_out set and timeout and not available), + build_occupied_core(7, |core| { + core.next_up_on_time_out = Some(scheduled_core(7)); + core.time_out_at = BLOCK_UNDER_PRODUCTION; + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(71)); + }), + // 8: Occupied(both next_up set, available), + build_occupied_core(8, |core| { + core.next_up_on_available = Some(scheduled_core(8)); + core.next_up_on_time_out = Some(scheduled_core(8)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(81)); + }), + // 9: Occupied(both next_up set, not available, no timeout), + build_occupied_core(9, |core| { + core.next_up_on_available = Some(scheduled_core(9)); + core.next_up_on_time_out = Some(scheduled_core(9)); + }), + // 10: Occupied(both next_up set, not available, timeout), + build_occupied_core(10, |core| { + core.next_up_on_available = Some(scheduled_core(10)); + core.next_up_on_time_out = Some(scheduled_core(10)); + core.time_out_at = BLOCK_UNDER_PRODUCTION; + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(101)); + }), + // 11: Occupied(next_up_on_available and available, but different successor para_id) + build_occupied_core(11, |core| { + core.next_up_on_available = Some(scheduled_core(12)); + core.availability = core.availability.clone().not(); + }), + // 12-14: Occupied(next_up_on_available and available, same para_id). + build_occupied_core(12, |core| { + core.next_up_on_available = Some(scheduled_core(12)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(121)); + }), + build_occupied_core(12, |core| { + core.next_up_on_available = Some(scheduled_core(12)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(122)); + }), + build_occupied_core(12, |core| { + core.next_up_on_available = Some(scheduled_core(12)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(123)); + }), + // 15: Scheduled on same para_id as 12-14. + Scheduled(scheduled_core(12)), + // 16: Occupied(13, no next_up set, not available) + build_occupied_core(13, |core| { + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(131)); + }), + // 17: Occupied(13, no next_up set, available) + build_occupied_core(13, |core| { + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(132)); + }), + // 18: Occupied(13, next_up_on_available set to 13 but not available) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(13)); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(133)); + }), + // 19: Occupied(13, next_up_on_available set to 13 and available) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(13)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(134)); + }), + // 20: Occupied(13, next_up_on_time_out set to 13 but not timeout) + build_occupied_core(13, |core| { + core.next_up_on_time_out = Some(scheduled_core(13)); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(135)); + }), + // 21: Occupied(13, next_up_on_available set to 14 and available) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(14)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(136)); + }), + // 22: Occupied(13, next_up_on_available set to 14 but not available) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(14)); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(137)); + }), + // 23: Occupied(13, both next_up set to 14, available) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(14)); + core.next_up_on_time_out = Some(scheduled_core(14)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(138)); + }), + // 24: Occupied(13, both next_up set to 14, not available, timeout) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(14)); + core.next_up_on_time_out = Some(scheduled_core(14)); + core.time_out_at = BLOCK_UNDER_PRODUCTION; + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(1399)); + }), + // 25: Occupied(13, next_up_on_available and available, but successor para_id 15) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(15)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(139)); + }), + // 26: Occupied(15, next_up_on_available and available, but successor para_id 13) + build_occupied_core(15, |core| { + core.next_up_on_available = Some(scheduled_core(13)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(151)); + }), + // 27: Occupied(15, both next_up, both available and timed out) + build_occupied_core(15, |core| { + core.next_up_on_available = Some(scheduled_core(15)); + core.availability = core.availability.clone().not(); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(152)); + core.time_out_at = BLOCK_UNDER_PRODUCTION; + }), + // 28: Occupied(13, both next_up set to 13, not available) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(13)); + core.next_up_on_time_out = Some(scheduled_core(13)); + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(1398)); + }), + // 29: Occupied(13, both next_up set to 13, not available, timeout) + build_occupied_core(13, |core| { + core.next_up_on_available = Some(scheduled_core(13)); + core.next_up_on_time_out = Some(scheduled_core(13)); + core.time_out_at = BLOCK_UNDER_PRODUCTION; + core.candidate_hash = CandidateHash(Hash::from_low_u64_be(1397)); + }), + ] + } + async fn mock_overseer( mut receiver: mpsc::UnboundedReceiver, - expected: Vec, + mock_availability_cores: Vec, + mut expected: Vec, + mut expected_ancestors: HashMap, Ancestors>, prospective_parachains_mode: ProspectiveParachainsMode, ) { use ChainApiMessage::BlockNumber; use RuntimeApiMessage::Request; + let mut backed_iter = expected.clone().into_iter(); + + expected.sort_by_key(|c| c.candidate().descriptor.para_id); let mut candidates_iter = expected .iter() .map(|candidate| (candidate.hash(), candidate.descriptor().relay_parent)); - let mut backed_iter = expected.clone().into_iter(); - while let Some(from_job) = receiver.next().await { match from_job { AllMessages::ChainApi(BlockNumber(_relay_parent, tx)) => @@ -356,7 +578,7 @@ mod select_candidates { PersistedValidationDataReq(_para_id, _assumption, tx), )) => tx.send(Ok(Some(Default::default()))).unwrap(), AllMessages::RuntimeApi(Request(_parent_hash, AvailabilityCores(tx))) => - tx.send(Ok(mock_availability_cores())).unwrap(), + tx.send(Ok(mock_availability_cores.clone())).unwrap(), AllMessages::CandidateBacking(CandidateBackingMessage::GetBackedCandidates( hashes, sender, @@ -373,35 +595,71 @@ mod select_candidates { let _ = sender.send(response); }, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::GetBackableCandidates(_, _, count, _, tx), - ) => { - assert_eq!(count, 1); - - match prospective_parachains_mode { - ProspectiveParachainsMode::Enabled { .. } => { - let _ = - tx.send(candidates_iter.next().map_or_else(Vec::new, |c| vec![c])); - }, - ProspectiveParachainsMode::Disabled => - panic!("unexpected prospective parachains request"), - } + ProspectiveParachainsMessage::GetBackableCandidates( + _, + _para_id, + count, + actual_ancestors, + tx, + ), + ) => match prospective_parachains_mode { + ProspectiveParachainsMode::Enabled { .. } => { + assert!(count > 0); + let candidates = + (&mut candidates_iter).take(count as usize).collect::>(); + assert_eq!(candidates.len(), count as usize); + + if !expected_ancestors.is_empty() { + if let Some(expected_required_ancestors) = expected_ancestors.remove( + &(candidates + .clone() + .into_iter() + .take(actual_ancestors.len()) + .map(|(c_hash, _)| c_hash) + .collect::>()), + ) { + assert_eq!(expected_required_ancestors, actual_ancestors); + } else { + assert_eq!(actual_ancestors.len(), 0); + } + } + + let _ = tx.send(candidates); + }, + ProspectiveParachainsMode::Disabled => + panic!("unexpected prospective parachains request"), }, _ => panic!("Unexpected message: {:?}", from_job), } } + + if let ProspectiveParachainsMode::Enabled { .. } = prospective_parachains_mode { + assert_eq!(candidates_iter.next(), None); + } + assert_eq!(expected_ancestors.len(), 0); } - #[test] - fn can_succeed() { + #[rstest] + #[case(ProspectiveParachainsMode::Disabled)] + #[case(ProspectiveParachainsMode::Enabled {max_candidate_depth: 0, allowed_ancestry_len: 0})] + fn can_succeed(#[case] prospective_parachains_mode: ProspectiveParachainsMode) { test_harness( - |r| mock_overseer(r, Vec::new(), ProspectiveParachainsMode::Disabled), + |r| { + mock_overseer( + r, + Vec::new(), + Vec::new(), + HashMap::new(), + prospective_parachains_mode, + ) + }, |mut tx: TestSubsystemSender| async move { - let prospective_parachains_mode = ProspectiveParachainsMode::Disabled; select_candidates( &[], &[], &[], prospective_parachains_mode, + false, Default::default(), &mut tx, ) @@ -411,22 +669,22 @@ mod select_candidates { ) } - // this tests that only the appropriate candidates get selected. - // To accomplish this, we supply a candidate list containing one candidate per possible core; - // the candidate selection algorithm must filter them to the appropriate set - #[test] - fn selects_correct_candidates() { - let mock_cores = mock_availability_cores(); - - let empty_hash = PersistedValidationData::::default().hash(); - - let mut descriptor_template = dummy_candidate_descriptor(dummy_hash()); - descriptor_template.persisted_validation_data_hash = empty_hash; - let candidate_template = CandidateReceipt { - descriptor: descriptor_template, - commitments_hash: CandidateCommitments::default().hash(), - }; - + // Test candidate selection when prospective parachains mode is disabled. + // This tests that only the appropriate candidates get selected when prospective parachains mode + // is disabled. To accomplish this, we supply a candidate list containing one candidate per + // possible core; the candidate selection algorithm must filter them to the appropriate set + #[rstest] + // why those particular indices? see the comments on mock_availability_cores_*() functions. + #[case(mock_availability_cores_one_per_para(), vec![1, 4, 7, 8, 10], true)] + #[case(mock_availability_cores_one_per_para(), vec![1, 4, 7, 8, 10], false)] + #[case(mock_availability_cores_multiple_per_para(), vec![1, 4, 7, 8, 10, 12, 13, 14, 15], true)] + #[case(mock_availability_cores_multiple_per_para(), vec![1, 4, 7, 8, 10, 12, 13, 14, 15], false)] + fn test_in_subsystem_selection( + #[case] mock_cores: Vec, + #[case] expected_candidates: Vec, + #[case] elastic_scaling_mvp: bool, + ) { + let candidate_template = dummy_candidate_template(); let candidates: Vec<_> = std::iter::repeat(candidate_template) .take(mock_cores.len()) .enumerate() @@ -453,31 +711,43 @@ mod select_candidates { }) .collect(); - // why those particular indices? see the comments on mock_availability_cores() let expected_candidates: Vec<_> = - [1, 4, 7, 8, 10].iter().map(|&idx| candidates[idx].clone()).collect(); + expected_candidates.into_iter().map(|idx| candidates[idx].clone()).collect(); let prospective_parachains_mode = ProspectiveParachainsMode::Disabled; let expected_backed = expected_candidates .iter() - .map(|c| BackedCandidate { - candidate: CommittedCandidateReceipt { - descriptor: c.descriptor.clone(), - commitments: Default::default(), - }, - validity_votes: Vec::new(), - validator_indices: default_bitvec(MOCK_GROUP_SIZE), + .map(|c| { + BackedCandidate::new( + CommittedCandidateReceipt { + descriptor: c.descriptor().clone(), + commitments: Default::default(), + }, + Vec::new(), + default_bitvec(MOCK_GROUP_SIZE), + None, + ) }) .collect(); + let mock_cores_clone = mock_cores.clone(); test_harness( - |r| mock_overseer(r, expected_backed, prospective_parachains_mode), + |r| { + mock_overseer( + r, + mock_cores_clone, + expected_backed, + HashMap::new(), + prospective_parachains_mode, + ) + }, |mut tx: TestSubsystemSender| async move { - let result = select_candidates( + let result: Vec = select_candidates( &mock_cores, &[], &candidates, prospective_parachains_mode, + elastic_scaling_mvp, Default::default(), &mut tx, ) @@ -486,7 +756,7 @@ mod select_candidates { result.into_iter().for_each(|c| { assert!( - expected_candidates.iter().any(|c2| c.candidate.corresponds_to(c2)), + expected_candidates.iter().any(|c2| c.candidate().corresponds_to(c2)), "Failed to find candidate: {:?}", c, ) @@ -495,20 +765,24 @@ mod select_candidates { ) } - #[test] - fn selects_max_one_code_upgrade() { - let mock_cores = mock_availability_cores(); + #[rstest] + #[case(ProspectiveParachainsMode::Disabled)] + #[case(ProspectiveParachainsMode::Enabled {max_candidate_depth: 0, allowed_ancestry_len: 0})] + fn selects_max_one_code_upgrade( + #[case] prospective_parachains_mode: ProspectiveParachainsMode, + ) { + let mock_cores = mock_availability_cores_one_per_para(); let empty_hash = PersistedValidationData::::default().hash(); // why those particular indices? see the comments on mock_availability_cores() - // the first candidate with code is included out of [1, 4, 7, 8, 10]. - let cores = [1, 4, 7, 8, 10]; + // the first candidate with code is included out of [1, 4, 7, 8, 10, 12]. + let cores = [1, 4, 7, 8, 10, 12]; let cores_with_code = [1, 4, 8]; - let expected_cores = [1, 7, 10]; + let expected_cores = [1, 7, 10, 12]; - let committed_receipts: Vec<_> = (0..mock_cores.len()) + let committed_receipts: Vec<_> = (0..=mock_cores.len()) .map(|i| { let mut descriptor = dummy_candidate_descriptor(dummy_hash()); descriptor.para_id = i.into(); @@ -532,10 +806,13 @@ mod select_candidates { // Build possible outputs from select_candidates let backed_candidates: Vec<_> = committed_receipts .iter() - .map(|committed_receipt| BackedCandidate { - candidate: committed_receipt.clone(), - validity_votes: Vec::new(), - validator_indices: default_bitvec(MOCK_GROUP_SIZE), + .map(|committed_receipt| { + BackedCandidate::new( + committed_receipt.clone(), + Vec::new(), + default_bitvec(MOCK_GROUP_SIZE), + None, + ) }) .collect(); @@ -546,27 +823,36 @@ mod select_candidates { let expected_backed_filtered: Vec<_> = expected_cores.iter().map(|&idx| candidates[idx].clone()).collect(); - let prospective_parachains_mode = ProspectiveParachainsMode::Disabled; + let mock_cores_clone = mock_cores.clone(); test_harness( - |r| mock_overseer(r, expected_backed, prospective_parachains_mode), + |r| { + mock_overseer( + r, + mock_cores_clone, + expected_backed, + HashMap::new(), + prospective_parachains_mode, + ) + }, |mut tx: TestSubsystemSender| async move { let result = select_candidates( &mock_cores, &[], &candidates, prospective_parachains_mode, + false, Default::default(), &mut tx, ) .await .unwrap(); - assert_eq!(result.len(), 3); + assert_eq!(result.len(), 4); result.into_iter().for_each(|c| { assert!( - expected_backed_filtered.iter().any(|c2| c.candidate.corresponds_to(c2)), + expected_backed_filtered.iter().any(|c2| c.candidate().corresponds_to(c2)), "Failed to find candidate: {:?}", c, ) @@ -575,63 +861,214 @@ mod select_candidates { ) } - #[test] - fn request_from_prospective_parachains() { - let mock_cores = mock_availability_cores(); - let empty_hash = PersistedValidationData::::default().hash(); + #[rstest] + #[case(true)] + #[case(false)] + fn request_from_prospective_parachains_one_core_per_para(#[case] elastic_scaling_mvp: bool) { + let mock_cores = mock_availability_cores_one_per_para(); - let mut descriptor_template = dummy_candidate_descriptor(dummy_hash()); - descriptor_template.persisted_validation_data_hash = empty_hash; - let candidate_template = CandidateReceipt { - descriptor: descriptor_template, - commitments_hash: CandidateCommitments::default().hash(), - }; + // why those particular indices? see the comments on mock_availability_cores() + let expected_candidates: Vec<_> = vec![1, 4, 7, 8, 10, 12]; + let (candidates, expected_candidates) = + make_candidates(mock_cores.len() + 1, expected_candidates); - let candidates: Vec<_> = std::iter::repeat(candidate_template) - .take(mock_cores.len()) - .enumerate() - .map(|(idx, mut candidate)| { - candidate.descriptor.para_id = idx.into(); - candidate - }) - .collect(); + // Expect prospective parachains subsystem requests. + let prospective_parachains_mode = + ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; + + let mut required_ancestors: HashMap, Ancestors> = HashMap::new(); + required_ancestors.insert( + vec![candidates[4]], + vec![CandidateHash(Hash::from_low_u64_be(41))].into_iter().collect(), + ); + required_ancestors.insert( + vec![candidates[8]], + vec![CandidateHash(Hash::from_low_u64_be(81))].into_iter().collect(), + ); + + let mock_cores_clone = mock_cores.clone(); + let expected_candidates_clone = expected_candidates.clone(); + test_harness( + |r| { + mock_overseer( + r, + mock_cores_clone, + expected_candidates_clone, + required_ancestors, + prospective_parachains_mode, + ) + }, + |mut tx: TestSubsystemSender| async move { + let result = select_candidates( + &mock_cores, + &[], + &[], + prospective_parachains_mode, + elastic_scaling_mvp, + Default::default(), + &mut tx, + ) + .await + .unwrap(); + + assert_eq!(result.len(), expected_candidates.len()); + result.into_iter().for_each(|c| { + assert!( + expected_candidates + .iter() + .any(|c2| c.candidate().corresponds_to(&c2.receipt())), + "Failed to find candidate: {:?}", + c, + ) + }); + }, + ) + } + + #[test] + fn request_from_prospective_parachains_multiple_cores_per_para_elastic_scaling_mvp() { + let mock_cores = mock_availability_cores_multiple_per_para(); // why those particular indices? see the comments on mock_availability_cores() let expected_candidates: Vec<_> = - [1, 4, 7, 8, 10].iter().map(|&idx| candidates[idx].clone()).collect(); + vec![1, 4, 7, 8, 10, 12, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15]; // Expect prospective parachains subsystem requests. let prospective_parachains_mode = ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; - let expected_backed = expected_candidates - .iter() - .map(|c| BackedCandidate { - candidate: CommittedCandidateReceipt { - descriptor: c.descriptor.clone(), - commitments: Default::default(), - }, - validity_votes: Vec::new(), - validator_indices: default_bitvec(MOCK_GROUP_SIZE), - }) - .collect(); + let (candidates, expected_candidates) = + make_candidates(mock_cores.len(), expected_candidates); + + let mut required_ancestors: HashMap, Ancestors> = HashMap::new(); + required_ancestors.insert( + vec![candidates[4]], + vec![CandidateHash(Hash::from_low_u64_be(41))].into_iter().collect(), + ); + required_ancestors.insert( + vec![candidates[8]], + vec![CandidateHash(Hash::from_low_u64_be(81))].into_iter().collect(), + ); + required_ancestors.insert( + [12, 12, 12].iter().map(|&idx| candidates[idx]).collect::>(), + vec![ + CandidateHash(Hash::from_low_u64_be(121)), + CandidateHash(Hash::from_low_u64_be(122)), + CandidateHash(Hash::from_low_u64_be(123)), + ] + .into_iter() + .collect(), + ); + required_ancestors.insert( + [13, 13, 13].iter().map(|&idx| candidates[idx]).collect::>(), + (131..=139) + .map(|num| CandidateHash(Hash::from_low_u64_be(num))) + .chain(std::iter::once(CandidateHash(Hash::from_low_u64_be(1398)))) + .collect(), + ); + + required_ancestors.insert( + [15, 15].iter().map(|&idx| candidates[idx]).collect::>(), + vec![ + CandidateHash(Hash::from_low_u64_be(151)), + CandidateHash(Hash::from_low_u64_be(152)), + ] + .into_iter() + .collect(), + ); + + let mock_cores_clone = mock_cores.clone(); + let expected_candidates_clone = expected_candidates.clone(); + test_harness( + |r| { + mock_overseer( + r, + mock_cores_clone, + expected_candidates, + required_ancestors, + prospective_parachains_mode, + ) + }, + |mut tx: TestSubsystemSender| async move { + let result = select_candidates( + &mock_cores, + &[], + &[], + prospective_parachains_mode, + true, + Default::default(), + &mut tx, + ) + .await + .unwrap(); + assert_eq!(result.len(), expected_candidates_clone.len()); + result.into_iter().for_each(|c| { + assert!( + expected_candidates_clone + .iter() + .any(|c2| c.candidate().corresponds_to(&c2.receipt())), + "Failed to find candidate: {:?}", + c, + ) + }); + }, + ) + } + + #[test] + fn request_from_prospective_parachains_multiple_cores_per_para_elastic_scaling_mvp_disabled() { + let mock_cores = mock_availability_cores_multiple_per_para(); + + // why those particular indices? see the comments on mock_availability_cores() + let expected_candidates: Vec<_> = vec![1, 4, 7, 8, 10]; + // Expect prospective parachains subsystem requests. + let prospective_parachains_mode = + ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; + + let (candidates, expected_candidates) = + make_candidates(mock_cores.len(), expected_candidates); + + let mut required_ancestors: HashMap, Ancestors> = HashMap::new(); + required_ancestors.insert( + vec![candidates[4]], + vec![CandidateHash(Hash::from_low_u64_be(41))].into_iter().collect(), + ); + required_ancestors.insert( + vec![candidates[8]], + vec![CandidateHash(Hash::from_low_u64_be(81))].into_iter().collect(), + ); + + let mock_cores_clone = mock_cores.clone(); + let expected_candidates_clone = expected_candidates.clone(); test_harness( - |r| mock_overseer(r, expected_backed, prospective_parachains_mode), + |r| { + mock_overseer( + r, + mock_cores_clone, + expected_candidates, + required_ancestors, + prospective_parachains_mode, + ) + }, |mut tx: TestSubsystemSender| async move { let result = select_candidates( &mock_cores, &[], &[], prospective_parachains_mode, + false, Default::default(), &mut tx, ) .await .unwrap(); + assert_eq!(result.len(), expected_candidates_clone.len()); result.into_iter().for_each(|c| { assert!( - expected_candidates.iter().any(|c2| c.candidate.corresponds_to(c2)), + expected_candidates_clone + .iter() + .any(|c2| c.candidate().corresponds_to(&c2.receipt())), "Failed to find candidate: {:?}", c, ) @@ -642,18 +1079,11 @@ mod select_candidates { #[test] fn request_receipts_based_on_relay_parent() { - let mock_cores = mock_availability_cores(); - let empty_hash = PersistedValidationData::::default().hash(); - - let mut descriptor_template = dummy_candidate_descriptor(dummy_hash()); - descriptor_template.persisted_validation_data_hash = empty_hash; - let candidate_template = CandidateReceipt { - descriptor: descriptor_template, - commitments_hash: CandidateCommitments::default().hash(), - }; + let mock_cores = mock_availability_cores_one_per_para(); + let candidate_template = dummy_candidate_template(); let candidates: Vec<_> = std::iter::repeat(candidate_template) - .take(mock_cores.len()) + .take(mock_cores.len() + 1) .enumerate() .map(|(idx, mut candidate)| { candidate.descriptor.para_id = idx.into(); @@ -664,31 +1094,44 @@ mod select_candidates { // why those particular indices? see the comments on mock_availability_cores() let expected_candidates: Vec<_> = - [1, 4, 7, 8, 10].iter().map(|&idx| candidates[idx].clone()).collect(); + [1, 4, 7, 8, 10, 12].iter().map(|&idx| candidates[idx].clone()).collect(); // Expect prospective parachains subsystem requests. let prospective_parachains_mode = ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; let expected_backed = expected_candidates .iter() - .map(|c| BackedCandidate { - candidate: CommittedCandidateReceipt { - descriptor: c.descriptor.clone(), - commitments: Default::default(), - }, - validity_votes: Vec::new(), - validator_indices: default_bitvec(MOCK_GROUP_SIZE), + .map(|c| { + BackedCandidate::new( + CommittedCandidateReceipt { + descriptor: c.descriptor().clone(), + commitments: Default::default(), + }, + Vec::new(), + default_bitvec(MOCK_GROUP_SIZE), + None, + ) }) .collect(); + let mock_cores_clone = mock_cores.clone(); test_harness( - |r| mock_overseer(r, expected_backed, prospective_parachains_mode), + |r| { + mock_overseer( + r, + mock_cores_clone, + expected_backed, + HashMap::new(), + prospective_parachains_mode, + ) + }, |mut tx: TestSubsystemSender| async move { let result = select_candidates( &mock_cores, &[], &[], prospective_parachains_mode, + false, Default::default(), &mut tx, ) @@ -697,7 +1140,7 @@ mod select_candidates { result.into_iter().for_each(|c| { assert!( - expected_candidates.iter().any(|c2| c.candidate.corresponds_to(c2)), + expected_candidates.iter().any(|c2| c.candidate().corresponds_to(c2)), "Failed to find candidate: {:?}", c, ) diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index 3f02c2fa74a8e09248a586187f342ff5db2e6146..f4f954e316c0b758a4cb1e94f80b729257349632 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] futures = "0.3.21" -thiserror = "1.0.48" +thiserror = { workspace = true } gum = { package = "tracing-gum", path = "../../gum" } polkadot-node-primitives = { path = "../../primitives" } diff --git a/polkadot/node/core/pvf-checker/src/lib.rs b/polkadot/node/core/pvf-checker/src/lib.rs index ae0fae6b4f9f7e2a4924effd4c3395d60b456f2f..c00ec0d952f158f8df21de87ee9d7460d68218bc 100644 --- a/polkadot/node/core/pvf-checker/src/lib.rs +++ b/polkadot/node/core/pvf-checker/src/lib.rs @@ -415,7 +415,7 @@ async fn check_signing_credentials( gum::warn!( target: LOG_TARGET, relay_parent = ?leaf, - "error occured during requesting validators: {:?}", + "error occurred during requesting validators: {:?}", e ); return None @@ -508,7 +508,7 @@ async fn sign_and_submit_pvf_check_statement( target: LOG_TARGET, ?relay_parent, ?validation_code_hash, - "error occured during submitting a vote: {:?}", + "error occurred during submitting a vote: {:?}", e, ); }, diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index d7ea573cfd2f3e772a3af04c0b840ce94ecdf93a..9ed64b88ffde857c6abe171a7d1cad7dd66dd509 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -23,7 +23,7 @@ pin-project = "1.0.9" rand = "0.8.5" slotmap = "1.0" tempfile = "3.3.0" -thiserror = "1.0.31" +thiserror = { workspace = true } tokio = { version = "1.24.2", features = ["fs", "process"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/core/pvf/README.md b/polkadot/node/core/pvf/README.md index 796e17c05faa47ceec455125ae29f7943ffa5740..5304b0720b2df614c005ff54eabb4d2c74b0bb4b 100644 --- a/polkadot/node/core/pvf/README.md +++ b/polkadot/node/core/pvf/README.md @@ -13,7 +13,7 @@ See also: Running `cargo test` in the `pvf/` directory will run unit and integration tests. -**Note:** some tests run only under Linux, amd64, and/or with the +**Note:** some tests run only under Linux, x86-64, and/or with the `ci-only-tests` feature enabled. See the general [Testing][testing] instructions for more information on @@ -34,8 +34,8 @@ RUST_LOG=parachain::pvf=trace zombienet --provider=native spawn zombienet_tests/ ## Testing on Linux Some of the PVF functionality, especially related to security, is Linux-only, -and some is amd64-only. If you touch anything security-related, make sure to -test on Linux amd64! If you're on a Mac, you can either run a VM or you can hire +and some is x86-64-only. If you touch anything security-related, make sure to +test on Linux x86-64! If you're on a Mac, you can either run a VM or you can hire a VPS and use the open-source tool [EternalTerminal][et] to connect to it.[^et] [^et]: Unlike ssh, ET preserves your session across disconnects, and unlike diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 583db0b29f45aeb1c04f1d393b856b96bb41b92e..56bad9792fa0b6accea6460025c64c18e8e1e5d8 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -15,7 +15,7 @@ cpu-time = "1.0.0" futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.152" -thiserror = "1.0.31" +thiserror = { workspace = true } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -35,6 +35,8 @@ sp-tracing = { path = "../../../../../substrate/primitives/tracing" } [target.'cfg(target_os = "linux")'.dependencies] landlock = "0.3.0" nix = { version = "0.27.1", features = ["sched"] } + +[target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] seccompiler = "0.4.0" [dev-dependencies] diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index f8faefc24e65aadb2c50d2375e30fc7d579d6d37..cf274044456f3ea2db6770fbd61b3319f6420996 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -16,6 +16,7 @@ use crate::prepare::{PrepareSuccess, PrepareWorkerSuccess}; use parity_scale_codec::{Decode, Encode}; +pub use sc_executor_common::error::Error as ExecuteError; /// Result of PVF preparation from a worker, with checksum of the compiled PVF and stats of the /// preparation if successful. diff --git a/polkadot/node/core/pvf/common/src/execute.rs b/polkadot/node/core/pvf/common/src/execute.rs index 6b3becf524d71fa2d4f4bf574e0a86d09a7a60d9..18c97b03cbcd6fccc03cb27cb9f9e3aba9c7cf2a 100644 --- a/polkadot/node/core/pvf/common/src/execute.rs +++ b/polkadot/node/core/pvf/common/src/execute.rs @@ -40,6 +40,9 @@ pub enum WorkerResponse { }, /// The candidate is invalid. InvalidCandidate(String), + /// Instantiation of the WASM module instance failed during an execution. + /// Possibly related to local issues or dirty node update. May be retried with re-preparation. + RuntimeConstruction(String), /// The job timed out. JobTimedOut, /// The job process has died. We must kill the worker just in case. @@ -68,6 +71,9 @@ pub enum JobResponse { /// The result of parachain validation. result_descriptor: ValidationResult, }, + /// A possibly transient runtime instantiation error happened during the execution; may be + /// retried with re-preparation + RuntimeConstruction(String), /// The candidate is invalid. InvalidCandidate(String), } @@ -81,6 +87,15 @@ impl JobResponse { Self::InvalidCandidate(format!("{}: {}", ctx, msg)) } } + + /// Creates a may retry response from a context `ctx` and a message `msg` (which can be empty). + pub fn runtime_construction(ctx: &'static str, msg: &str) -> Self { + if msg.is_empty() { + Self::RuntimeConstruction(ctx.to_string()) + } else { + Self::RuntimeConstruction(format!("{}: {}", ctx, msg)) + } + } } /// An unexpected error occurred in the execution job process. Because this comes from the job, diff --git a/polkadot/node/core/pvf/common/src/executor_interface.rs b/polkadot/node/core/pvf/common/src/executor_interface.rs index 4cd2f5c85eec53661fde7625bb50a1d195381beb..252e611db8a488cff776b5d7863c987318e7e013 100644 --- a/polkadot/node/core/pvf/common/src/executor_interface.rs +++ b/polkadot/node/core/pvf/common/src/executor_interface.rs @@ -16,6 +16,7 @@ //! Interface to the Substrate Executor +use crate::error::ExecuteError; use polkadot_primitives::{ executor_params::{DEFAULT_LOGICAL_STACK_MAX, DEFAULT_NATIVE_STACK_MAX}, ExecutorParam, ExecutorParams, @@ -23,7 +24,7 @@ use polkadot_primitives::{ use sc_executor_common::{ error::WasmError, runtime_blob::RuntimeBlob, - wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmModule as _}, + wasm_runtime::{HeapAllocStrategy, WasmModule as _}, }; use sc_executor_wasmtime::{Config, DeterministicStackLimit, Semantics, WasmtimeRuntime}; use sp_core::storage::{ChildInfo, TrackedStorageKey}; @@ -109,7 +110,7 @@ pub unsafe fn execute_artifact( compiled_artifact_blob: &[u8], executor_params: &ExecutorParams, params: &[u8], -) -> Result, String> { +) -> Result, ExecuteError> { let mut extensions = sp_externalities::Extensions::new(); extensions.register(sp_core::traits::ReadRuntimeVersionExt::new(ReadRuntimeVersion)); @@ -118,12 +119,11 @@ pub unsafe fn execute_artifact( match sc_executor::with_externalities_safe(&mut ext, || { let runtime = create_runtime_from_artifact_bytes(compiled_artifact_blob, executor_params)?; - runtime.new_instance()?.call(InvokeMethod::Export("validate_block"), params) + runtime.new_instance()?.call("validate_block", params) }) { Ok(Ok(ok)) => Ok(ok), Ok(Err(err)) | Err(err) => Err(err), } - .map_err(|err| format!("execute error: {:?}", err)) } /// Constructs the runtime for the given PVF, given the artifact bytes. diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index d891c06bf2ada3efedbdd9420119c61fb96f5791..15097dbd3af5c29d1fceabc8d04f6ee9a395ef30 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -86,3 +86,33 @@ pub fn framed_recv_blocking(r: &mut (impl Read + Unpin)) -> io::Result> r.read_exact(&mut buf)?; Ok(buf) } + +#[cfg(all(test, not(feature = "test-utils")))] +mod tests { + use super::*; + + #[test] + fn default_secure_status() { + let status = SecurityStatus::default(); + assert!( + !status.secure_validator_mode, + "secure_validator_mode is false for default security status" + ); + assert!( + !status.can_enable_landlock, + "can_enable_landlock is false for default security status" + ); + assert!( + !status.can_enable_seccomp, + "can_enable_seccomp is false for default security status" + ); + assert!( + !status.can_unshare_user_namespace_and_change_root, + "can_unshare_user_namespace_and_change_root is false for default security status" + ); + assert!( + !status.can_do_secure_clone, + "can_do_secure_clone is false for default security status" + ); + } +} diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 0cfa5a786946c7428ea8954515fe03807a90da32..bd7e76010a6dfedb339fd2fc1c17aa7f4007babe 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -16,7 +16,9 @@ //! Contains the logic for executing PVFs. Used by the polkadot-execute-worker binary. -pub use polkadot_node_core_pvf_common::executor_interface::execute_artifact; +pub use polkadot_node_core_pvf_common::{ + error::ExecuteError, executor_interface::execute_artifact, +}; // NOTE: Initializing logging in e.g. tests will not have an effect in the workers, as they are // separate spawned processes. Run with e.g. `RUST_LOG=parachain::pvf-execute-worker=trace`. @@ -237,7 +239,9 @@ fn validate_using_artifact( // [`executor_interface::prepare`]. execute_artifact(compiled_artifact_blob, executor_params, params) } { - Err(err) => return JobResponse::format_invalid("execute", &err), + Err(ExecuteError::RuntimeConstruction(wasmerr)) => + return JobResponse::runtime_construction("execute", &wasmerr.to_string()), + Err(err) => return JobResponse::format_invalid("execute", &err.to_string()), Ok(d) => d, }; @@ -550,6 +554,8 @@ fn handle_parent_process( Ok(WorkerResponse::Ok { result_descriptor, duration: cpu_tv }) }, Ok(JobResponse::InvalidCandidate(err)) => Ok(WorkerResponse::InvalidCandidate(err)), + Ok(JobResponse::RuntimeConstruction(err)) => + Ok(WorkerResponse::RuntimeConstruction(err)), Err(job_error) => { gum::warn!( target: LOG_TARGET, diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index 78dfe71adaddcd8d917a639591c102e08ebb7e4b..6288755526d497812027f7bf04e11e5a67ab799e 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -238,6 +238,14 @@ impl Artifacts { .is_none()); } + /// Remove artifact by its id. + pub fn remove(&mut self, artifact_id: ArtifactId) -> Option<(ArtifactId, PathBuf)> { + self.inner.remove(&artifact_id).and_then(|state| match state { + ArtifactState::Prepared { path, .. } => Some((artifact_id, path)), + _ => None, + }) + } + /// Remove artifacts older than the given TTL and return id and path of the removed ones. pub fn prune(&mut self, artifact_ttl: Duration) -> Vec<(ArtifactId, PathBuf)> { let now = SystemTime::now(); diff --git a/polkadot/node/core/pvf/src/error.rs b/polkadot/node/core/pvf/src/error.rs index 80d41d5c64be1a5cec31aee084a0f536ad0380bf..8dc96305eadb8f3ced1231889f5fa6c5ffaeac57 100644 --- a/polkadot/node/core/pvf/src/error.rs +++ b/polkadot/node/core/pvf/src/error.rs @@ -86,6 +86,10 @@ pub enum PossiblyInvalidError { /// vote invalid. #[error("possibly invalid: job error: {0}")] JobError(String), + /// Instantiation of the WASM module instance failed during an execution. + /// Possibly related to local issues or dirty node update. May be retried with re-preparation. + #[error("possibly invalid: runtime construction: {0}")] + RuntimeConstruction(String), } impl From for ValidationError { diff --git a/polkadot/node/core/pvf/src/execute/mod.rs b/polkadot/node/core/pvf/src/execute/mod.rs index c6d9cf90fa289601f89b0aad307483a002f89427..365e98196cae29dcb9c5085708cfaf7ee8b26238 100644 --- a/polkadot/node/core/pvf/src/execute/mod.rs +++ b/polkadot/node/core/pvf/src/execute/mod.rs @@ -23,4 +23,4 @@ mod queue; mod worker_interface; -pub use queue::{start, PendingExecutionRequest, ToQueue}; +pub use queue::{start, FromQueue, PendingExecutionRequest, ToQueue}; diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index aa91d11781fc625993484fa64ff8ebca4d65aeb2..bdc3c7327b06079eaaeebf737ffa7ca2c8c8270c 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -25,7 +25,7 @@ use crate::{ InvalidCandidate, PossiblyInvalidError, ValidationError, LOG_TARGET, }; use futures::{ - channel::mpsc, + channel::{mpsc, oneshot}, future::BoxFuture, stream::{FuturesUnordered, StreamExt as _}, Future, FutureExt, @@ -54,6 +54,12 @@ pub enum ToQueue { Enqueue { artifact: ArtifactPathId, pending_execution_request: PendingExecutionRequest }, } +/// A response from queue. +#[derive(Debug)] +pub enum FromQueue { + RemoveArtifact { artifact: ArtifactId, reply_to: oneshot::Sender<()> }, +} + /// An execution request that should execute the PVF (known in the context) and send the results /// to the given result sender. #[derive(Debug)] @@ -137,6 +143,8 @@ struct Queue { /// The receiver that receives messages to the pool. to_queue_rx: mpsc::Receiver, + /// The sender to send messages back to validation host. + from_queue_tx: mpsc::UnboundedSender, // Some variables related to the current session. program_path: PathBuf, @@ -161,6 +169,7 @@ impl Queue { node_version: Option, security_status: SecurityStatus, to_queue_rx: mpsc::Receiver, + from_queue_tx: mpsc::UnboundedSender, ) -> Self { Self { metrics, @@ -170,6 +179,7 @@ impl Queue { node_version, security_status, to_queue_rx, + from_queue_tx, queue: VecDeque::new(), mux: Mux::new(), workers: Workers { @@ -301,7 +311,7 @@ async fn handle_mux(queue: &mut Queue, event: QueueEvent) { handle_worker_spawned(queue, idle, handle, job); }, QueueEvent::StartWork(worker, outcome, artifact_id, result_tx) => { - handle_job_finish(queue, worker, outcome, artifact_id, result_tx); + handle_job_finish(queue, worker, outcome, artifact_id, result_tx).await; }, } } @@ -327,42 +337,69 @@ fn handle_worker_spawned( /// If there are pending jobs in the queue, schedules the next of them onto the just freed up /// worker. Otherwise, puts back into the available workers list. -fn handle_job_finish( +async fn handle_job_finish( queue: &mut Queue, worker: Worker, outcome: Outcome, artifact_id: ArtifactId, result_tx: ResultSender, ) { - let (idle_worker, result, duration) = match outcome { + let (idle_worker, result, duration, sync_channel) = match outcome { Outcome::Ok { result_descriptor, duration, idle_worker } => { // TODO: propagate the soft timeout - (Some(idle_worker), Ok(result_descriptor), Some(duration)) + (Some(idle_worker), Ok(result_descriptor), Some(duration), None) }, Outcome::InvalidCandidate { err, idle_worker } => ( Some(idle_worker), Err(ValidationError::Invalid(InvalidCandidate::WorkerReportedInvalid(err))), None, + None, ), - Outcome::InternalError { err } => (None, Err(ValidationError::Internal(err)), None), + Outcome::RuntimeConstruction { err, idle_worker } => { + // The task for artifact removal is executed concurrently with + // the message to the host on the execution result. + let (result_tx, result_rx) = oneshot::channel(); + queue + .from_queue_tx + .unbounded_send(FromQueue::RemoveArtifact { + artifact: artifact_id.clone(), + reply_to: result_tx, + }) + .expect("from execute queue receiver is listened by the host; qed"); + ( + Some(idle_worker), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::RuntimeConstruction( + err, + ))), + None, + Some(result_rx), + ) + }, + Outcome::InternalError { err } => (None, Err(ValidationError::Internal(err)), None, None), // Either the worker or the job timed out. Kill the worker in either case. Treated as // definitely-invalid, because if we timed out, there's no time left for a retry. Outcome::HardTimeout => - (None, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)), None), + (None, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)), None, None), // "Maybe invalid" errors (will retry). Outcome::WorkerIntfErr => ( None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), None, + None, ), Outcome::JobDied { err } => ( None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath(err))), None, + None, + ), + Outcome::JobError { err } => ( + None, + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err))), + None, + None, ), - Outcome::JobError { err } => - (None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err))), None), }; queue.metrics.execute_finished(); @@ -386,6 +423,12 @@ fn handle_job_finish( ); } + if let Some(sync_channel) = sync_channel { + // err means the sender is dropped (the artifact is already removed from the cache) + // so that's legitimate to ignore the result + let _ = sync_channel.await; + } + // First we send the result. It may fail due to the other end of the channel being dropped, // that's legitimate and we don't treat that as an error. let _ = result_tx.send(result); @@ -521,8 +564,10 @@ pub fn start( spawn_timeout: Duration, node_version: Option, security_status: SecurityStatus, -) -> (mpsc::Sender, impl Future) { +) -> (mpsc::Sender, mpsc::UnboundedReceiver, impl Future) { let (to_queue_tx, to_queue_rx) = mpsc::channel(20); + let (from_queue_tx, from_queue_rx) = mpsc::unbounded(); + let run = Queue::new( metrics, program_path, @@ -532,7 +577,8 @@ pub fn start( node_version, security_status, to_queue_rx, + from_queue_tx, ) .run(); - (to_queue_tx, run) + (to_queue_tx, from_queue_rx, run) } diff --git a/polkadot/node/core/pvf/src/execute/worker_interface.rs b/polkadot/node/core/pvf/src/execute/worker_interface.rs index 9f7738f00e699ab981d7fa4396fcd09d5e1a4abe..db81da118d7b5563ea7b4bec1b6c76bd3bf842e2 100644 --- a/polkadot/node/core/pvf/src/execute/worker_interface.rs +++ b/polkadot/node/core/pvf/src/execute/worker_interface.rs @@ -87,6 +87,10 @@ pub enum Outcome { /// a trap. Errors related to the preparation process are not expected to be encountered by the /// execution workers. InvalidCandidate { err: String, idle_worker: IdleWorker }, + /// The error is probably transient. It may be for example + /// because the artifact was prepared with a Wasmtime version different from the version + /// in the current execution environment. + RuntimeConstruction { err: String, idle_worker: IdleWorker }, /// The execution time exceeded the hard limit. The worker is terminated. HardTimeout, /// An I/O error happened during communication with the worker. This may mean that the worker @@ -193,6 +197,10 @@ pub async fn start_work( err, idle_worker: IdleWorker { stream, pid, worker_dir }, }, + WorkerResponse::RuntimeConstruction(err) => Outcome::RuntimeConstruction { + err, + idle_worker: IdleWorker { stream, pid, worker_dir }, + }, WorkerResponse::JobTimedOut => Outcome::HardTimeout, WorkerResponse::JobDied { err, job_pid: _ } => Outcome::JobDied { err }, WorkerResponse::JobError(err) => Outcome::JobError { err }, diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index e215f11b91d396a1b9e5fa5710d34acf28ca9cff..8ec46f4b08f193082f1fcf8f6a08cae2ef261765 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -24,7 +24,7 @@ use crate::{ artifacts::{ArtifactId, ArtifactPathId, ArtifactState, Artifacts}, execute::{self, PendingExecutionRequest}, metrics::Metrics, - prepare, security, Priority, SecurityStatus, ValidationError, LOG_TARGET, + prepare, Priority, SecurityStatus, ValidationError, LOG_TARGET, }; use always_assert::never; use futures::{ @@ -225,10 +225,32 @@ pub async fn start( // Run checks for supported security features once per host startup. If some checks fail, warn // if Secure Validator Mode is disabled and return an error otherwise. - let security_status = match security::check_security_status(&config).await { + #[cfg(target_os = "linux")] + let security_status = match crate::security::check_security_status(&config).await { Ok(ok) => ok, Err(err) => return Err(SubsystemError::Context(err)), }; + #[cfg(not(target_os = "linux"))] + let security_status = if config.secure_validator_mode { + gum::error!( + target: LOG_TARGET, + "{}{}{}", + crate::SECURE_MODE_ERROR, + crate::SECURE_LINUX_NOTE, + crate::IGNORE_SECURE_MODE_TIP + ); + return Err(SubsystemError::Context( + "could not enable Secure Validator Mode for non-Linux; check logs".into(), + )); + } else { + gum::warn!( + target: LOG_TARGET, + "{}{}", + crate::SECURE_MODE_WARNING, + crate::SECURE_LINUX_NOTE, + ); + SecurityStatus::default() + }; let (to_host_tx, to_host_rx) = mpsc::channel(HOST_MESSAGE_QUEUE_SIZE); @@ -252,7 +274,7 @@ pub async fn start( from_prepare_pool, ); - let (to_execute_queue_tx, run_execute_queue) = execute::start( + let (to_execute_queue_tx, from_execute_queue_rx, run_execute_queue) = execute::start( metrics, config.execute_worker_program_path.to_owned(), config.cache_path.clone(), @@ -274,6 +296,7 @@ pub async fn start( to_prepare_queue_tx, from_prepare_queue_rx, to_execute_queue_tx, + from_execute_queue_rx, to_sweeper_tx, awaiting_prepare: AwaitingPrepare::default(), }) @@ -320,6 +343,8 @@ struct Inner { from_prepare_queue_rx: mpsc::UnboundedReceiver, to_execute_queue_tx: mpsc::Sender, + from_execute_queue_rx: mpsc::UnboundedReceiver, + to_sweeper_tx: mpsc::Sender, awaiting_prepare: AwaitingPrepare, @@ -336,6 +361,7 @@ async fn run( to_host_rx, from_prepare_queue_rx, mut to_prepare_queue_tx, + from_execute_queue_rx, mut to_execute_queue_tx, mut to_sweeper_tx, mut awaiting_prepare, @@ -362,10 +388,21 @@ async fn run( let mut to_host_rx = to_host_rx.fuse(); let mut from_prepare_queue_rx = from_prepare_queue_rx.fuse(); + let mut from_execute_queue_rx = from_execute_queue_rx.fuse(); loop { // biased to make it behave deterministically for tests. futures::select_biased! { + from_execute_queue_rx = from_execute_queue_rx.next() => { + let from_queue = break_if_fatal!(from_execute_queue_rx.ok_or(Fatal)); + let execute::FromQueue::RemoveArtifact { artifact, reply_to } = from_queue; + break_if_fatal!(handle_artifact_removal( + &mut to_sweeper_tx, + &mut artifacts, + artifact, + reply_to, + ).await); + }, () = cleanup_pulse.select_next_some() => { // `select_next_some` because we don't expect this to fail, but if it does, we // still don't fail. The trade-off is that the compiled cache will start growing @@ -839,6 +876,37 @@ async fn handle_cleanup_pulse( Ok(()) } +async fn handle_artifact_removal( + sweeper_tx: &mut mpsc::Sender, + artifacts: &mut Artifacts, + artifact_id: ArtifactId, + reply_to: oneshot::Sender<()>, +) -> Result<(), Fatal> { + let (artifact_id, path) = if let Some(artifact) = artifacts.remove(artifact_id) { + artifact + } else { + // if we haven't found the artifact by its id, + // it has been probably removed + // anyway with the randomness of the artifact name + // it is safe to ignore + return Ok(()); + }; + reply_to + .send(()) + .expect("the execute queue waits for the artifact remove confirmation; qed"); + // Thanks to the randomness of the artifact name (see + // `artifacts::generate_artifact_path`) there is no issue with any name conflict on + // future repreparation. + // So we can confirm the artifact removal already + gum::debug!( + target: LOG_TARGET, + validation_code_hash = ?artifact_id.code_hash, + "PVF pruning: pruning artifact by request from the execute queue", + ); + sweeper_tx.send(path).await.map_err(|_| Fatal)?; + Ok(()) +} + /// A simple task which sole purpose is to delete files thrown at it. async fn sweeper_task(mut sweeper_rx: mpsc::Receiver) { loop { @@ -946,6 +1014,8 @@ pub(crate) mod tests { to_prepare_queue_rx: mpsc::Receiver, from_prepare_queue_tx: mpsc::UnboundedSender, to_execute_queue_rx: mpsc::Receiver, + #[allow(unused)] + from_execute_queue_tx: mpsc::UnboundedSender, to_sweeper_rx: mpsc::Receiver, run: BoxFuture<'static, ()>, @@ -957,6 +1027,7 @@ pub(crate) mod tests { let (to_prepare_queue_tx, to_prepare_queue_rx) = mpsc::channel(10); let (from_prepare_queue_tx, from_prepare_queue_rx) = mpsc::unbounded(); let (to_execute_queue_tx, to_execute_queue_rx) = mpsc::channel(10); + let (from_execute_queue_tx, from_execute_queue_rx) = mpsc::unbounded(); let (to_sweeper_tx, to_sweeper_rx) = mpsc::channel(10); let run = run(Inner { @@ -967,6 +1038,7 @@ pub(crate) mod tests { to_prepare_queue_tx, from_prepare_queue_rx, to_execute_queue_tx, + from_execute_queue_rx, to_sweeper_tx, awaiting_prepare: AwaitingPrepare::default(), }) @@ -977,6 +1049,7 @@ pub(crate) mod tests { to_prepare_queue_rx, from_prepare_queue_tx, to_execute_queue_rx, + from_execute_queue_tx, to_sweeper_rx, run, } diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 92263281eeab1c5f0cf96dad249db4c110c43114..462498fa8f6b108c6057b378d2a0b07face31ec9 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -97,6 +97,7 @@ mod host; mod metrics; mod prepare; mod priority; +#[cfg(target_os = "linux")] mod security; mod worker_interface; @@ -135,3 +136,22 @@ pub fn get_worker_version(worker_path: &Path) -> std::io::Result { .trim() .to_string()) } + +// Trying to run securely and some mandatory errors occurred. +pub(crate) const SECURE_MODE_ERROR: &'static str = + "🚨 Your system cannot securely run a validator. \ +\nRunning validation of malicious PVF code has a higher risk of compromising this machine."; +// Some errors occurred when running insecurely, or some optional errors occurred when running +// securely. +pub(crate) const SECURE_MODE_WARNING: &'static str = "🚨 Some security issues have been detected. \ +\nRunning validation of malicious PVF code has a higher risk of compromising this machine."; +// Message to be printed only when running securely and mandatory errors occurred. +pub(crate) const IGNORE_SECURE_MODE_TIP: &'static str = +"\nYou can ignore this error with the `--insecure-validator-i-know-what-i-do` \ +command line argument if you understand and accept the risks of running insecurely. \ +With this flag, security features are enabled on a best-effort basis, but not mandatory. \ +\nMore information: https://wiki.polkadot.network/docs/maintain-guides-secure-validator#secure-validator-mode"; +// Only Linux supports security features +#[cfg(not(target_os = "linux"))] +pub(crate) const SECURE_LINUX_NOTE: &'static str = "\nSecure mode is enabled only for Linux \ +\nand a full secure mode is enabled only for Linux x86-64."; diff --git a/polkadot/node/core/pvf/src/security.rs b/polkadot/node/core/pvf/src/security.rs index f62a232abf27a3745e0622094686d56b07e16cc1..733ef18bcadb497020db70f54db72d507a750c58 100644 --- a/polkadot/node/core/pvf/src/security.rs +++ b/polkadot/node/core/pvf/src/security.rs @@ -169,20 +169,6 @@ impl fmt::Display for SecureModeError { /// Print an error if Secure Validator Mode and some mandatory errors occurred, warn otherwise. fn print_secure_mode_error_or_warning(security_status: &FullSecurityStatus) { - // Trying to run securely and some mandatory errors occurred. - const SECURE_MODE_ERROR: &'static str = "🚨 Your system cannot securely run a validator. \ - \nRunning validation of malicious PVF code has a higher risk of compromising this machine."; - // Some errors occurred when running insecurely, or some optional errors occurred when running - // securely. - const SECURE_MODE_WARNING: &'static str = "🚨 Some security issues have been detected. \ - \nRunning validation of malicious PVF code has a higher risk of compromising this machine."; - // Message to be printed only when running securely and mandatory errors occurred. - const IGNORE_SECURE_MODE_TIP: &'static str = - "\nYou can ignore this error with the `--insecure-validator-i-know-what-i-do` \ - command line argument if you understand and accept the risks of running insecurely. \ - With this flag, security features are enabled on a best-effort basis, but not mandatory. \ - \nMore information: https://wiki.polkadot.network/docs/maintain-guides-secure-validator#secure-validator-mode"; - let all_errs_allowed = security_status.all_errs_allowed(); let errs_string = security_status.errs_string(); @@ -190,16 +176,16 @@ fn print_secure_mode_error_or_warning(security_status: &FullSecurityStatus) { gum::warn!( target: LOG_TARGET, "{}{}", - SECURE_MODE_WARNING, + crate::SECURE_MODE_WARNING, errs_string, ); } else { gum::error!( target: LOG_TARGET, "{}{}{}", - SECURE_MODE_ERROR, + crate::SECURE_MODE_ERROR, errs_string, - IGNORE_SECURE_MODE_TIP + crate::IGNORE_SECURE_MODE_TIP ); } } @@ -210,29 +196,25 @@ fn print_secure_mode_error_or_warning(security_status: &FullSecurityStatus) { /// to running the check in a worker, we try it... in a worker. The expected return status is 0 on /// success and -1 on failure. async fn check_can_unshare_user_namespace_and_change_root( - #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] prepare_worker_program_path: &Path, - #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] cache_path: &Path, + cache_path: &Path, ) -> SecureModeResult { - cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - let cache_dir_tempdir = tempfile::Builder::new() - .prefix("check-can-unshare-") - .tempdir_in(cache_path) - .map_err(|err| SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( - format!("could not create a temporary directory in {:?}: {}", cache_path, err) - ))?; - spawn_process_for_security_check( - prepare_worker_program_path, - "--check-can-unshare-user-namespace-and-change-root", - &[cache_dir_tempdir.path()], - ).await.map_err(|err| SecureModeError::CannotUnshareUserNamespaceAndChangeRoot(err)) - } else { - Err(SecureModeError::CannotUnshareUserNamespaceAndChangeRoot( - "only available on Linux".into() + let cache_dir_tempdir = tempfile::Builder::new() + .prefix("check-can-unshare-") + .tempdir_in(cache_path) + .map_err(|err| { + SecureModeError::CannotUnshareUserNamespaceAndChangeRoot(format!( + "could not create a temporary directory in {:?}: {}", + cache_path, err )) - } - } + })?; + spawn_process_for_security_check( + prepare_worker_program_path, + "--check-can-unshare-user-namespace-and-change-root", + &[cache_dir_tempdir.path()], + ) + .await + .map_err(|err| SecureModeError::CannotUnshareUserNamespaceAndChangeRoot(err)) } /// Check if landlock is supported and return an error if not. @@ -240,25 +222,15 @@ async fn check_can_unshare_user_namespace_and_change_root( /// We do this check by spawning a new process and trying to sandbox it. To get as close as possible /// to running the check in a worker, we try it... in a worker. The expected return status is 0 on /// success and -1 on failure. -async fn check_landlock( - #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] - prepare_worker_program_path: &Path, -) -> SecureModeResult { - cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - let abi = polkadot_node_core_pvf_common::worker::security::landlock::LANDLOCK_ABI as u8; - spawn_process_for_security_check( - prepare_worker_program_path, - "--check-can-enable-landlock", - std::iter::empty::<&str>(), - ).await.map_err(|err| SecureModeError::CannotEnableLandlock { err, abi }) - } else { - Err(SecureModeError::CannotEnableLandlock { - err: "only available on Linux".into(), - abi: 0, - }) - } - } +async fn check_landlock(prepare_worker_program_path: &Path) -> SecureModeResult { + let abi = polkadot_node_core_pvf_common::worker::security::landlock::LANDLOCK_ABI as u8; + spawn_process_for_security_check( + prepare_worker_program_path, + "--check-can-enable-landlock", + std::iter::empty::<&str>(), + ) + .await + .map_err(|err| SecureModeError::CannotEnableLandlock { err, abi }) } /// Check if seccomp is supported and return an error if not. @@ -266,39 +238,23 @@ async fn check_landlock( /// We do this check by spawning a new process and trying to sandbox it. To get as close as possible /// to running the check in a worker, we try it... in a worker. The expected return status is 0 on /// success and -1 on failure. -async fn check_seccomp( - #[cfg_attr(not(all(target_os = "linux", target_arch = "x86_64")), allow(unused_variables))] - prepare_worker_program_path: &Path, -) -> SecureModeResult { - cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - cfg_if::cfg_if! { - if #[cfg(target_arch = "x86_64")] { - spawn_process_for_security_check( - prepare_worker_program_path, - "--check-can-enable-seccomp", - std::iter::empty::<&str>(), - ).await.map_err(|err| SecureModeError::CannotEnableSeccomp(err)) - } else { - Err(SecureModeError::CannotEnableSeccomp( - "only supported on CPUs from the x86_64 family (usually Intel or AMD)".into() - )) - } - } - } else { - cfg_if::cfg_if! { - if #[cfg(target_arch = "x86_64")] { - Err(SecureModeError::CannotEnableSeccomp( - "only supported on Linux".into() - )) - } else { - Err(SecureModeError::CannotEnableSeccomp( - "only supported on Linux and on CPUs from the x86_64 family (usually Intel or AMD).".into() - )) - } - } - } - } + +#[cfg(target_arch = "x86_64")] +async fn check_seccomp(prepare_worker_program_path: &Path) -> SecureModeResult { + spawn_process_for_security_check( + prepare_worker_program_path, + "--check-can-enable-seccomp", + std::iter::empty::<&str>(), + ) + .await + .map_err(|err| SecureModeError::CannotEnableSeccomp(err)) +} + +#[cfg(not(target_arch = "x86_64"))] +async fn check_seccomp(_: &Path) -> SecureModeResult { + Err(SecureModeError::CannotEnableSeccomp( + "only supported on CPUs from the x86_64 family (usually Intel or AMD)".into(), + )) } /// Check if we can call `clone` with all sandboxing flags, and return an error if not. @@ -306,26 +262,16 @@ async fn check_seccomp( /// We do this check by spawning a new process and trying to sandbox it. To get as close as possible /// to running the check in a worker, we try it... in a worker. The expected return status is 0 on /// success and -1 on failure. -async fn check_can_do_secure_clone( - #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] - prepare_worker_program_path: &Path, -) -> SecureModeResult { - cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - spawn_process_for_security_check( - prepare_worker_program_path, - "--check-can-do-secure-clone", - std::iter::empty::<&str>(), - ).await.map_err(|err| SecureModeError::CannotDoSecureClone(err)) - } else { - Err(SecureModeError::CannotDoSecureClone( - "only available on Linux".into() - )) - } - } +async fn check_can_do_secure_clone(prepare_worker_program_path: &Path) -> SecureModeResult { + spawn_process_for_security_check( + prepare_worker_program_path, + "--check-can-do-secure-clone", + std::iter::empty::<&str>(), + ) + .await + .map_err(|err| SecureModeError::CannotDoSecureClone(err)) } -#[cfg(target_os = "linux")] async fn spawn_process_for_security_check( prepare_worker_program_path: &Path, check_arg: &'static str, diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index bcc10749e746d05479997e161329bbc6b4c468ff..cdfbcd8e57855121a7128a0ed616df4f8ecb0cbd 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -21,13 +21,14 @@ use parity_scale_codec::Encode as _; #[cfg(all(feature = "ci-only-tests", target_os = "linux"))] use polkadot_node_core_pvf::SecurityStatus; use polkadot_node_core_pvf::{ - start, testing::build_workers_and_get_paths, Config, InvalidCandidate, Metrics, PrepareError, - PrepareJobKind, PvfPrepData, ValidationError, ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, + start, testing::build_workers_and_get_paths, Config, InvalidCandidate, Metrics, + PossiblyInvalidError, PrepareError, PrepareJobKind, PvfPrepData, ValidationError, + ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; use polkadot_primitives::{ExecutorParam, ExecutorParams}; -use std::time::Duration; +use std::{io::Write, time::Duration}; use tokio::sync::Mutex; mod adder; @@ -352,10 +353,80 @@ async fn deleting_prepared_artifact_does_not_dispute() { ) .await; - match result { - Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)) => {}, - r => panic!("{:?}", r), + assert_matches!(result, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout))); +} + +// Test that corruption of a prepared artifact does not lead to a dispute when we try to execute it. +#[tokio::test] +async fn corrupted_prepared_artifact_does_not_dispute() { + let host = TestHost::new().await; + let cache_dir = host.cache_dir.path(); + + let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), Default::default()).await.unwrap(); + + // Manually corrupting the prepared artifact from disk. The in-memory artifacts table won't + // change. + let artifact_path = { + // Get the artifact path (asserting it exists). + let mut cache_dir: Vec<_> = std::fs::read_dir(cache_dir).unwrap().collect(); + // Should contain the artifact and the worker dir. + assert_eq!(cache_dir.len(), 2); + let mut artifact_path = cache_dir.pop().unwrap().unwrap(); + if artifact_path.path().is_dir() { + artifact_path = cache_dir.pop().unwrap().unwrap(); + } + + // Corrupt the artifact. + let mut f = std::fs::OpenOptions::new() + .write(true) + .truncate(true) + .open(artifact_path.path()) + .unwrap(); + f.write_all(b"corrupted wasm").unwrap(); + f.flush().unwrap(); + artifact_path + }; + + assert!(artifact_path.path().exists()); + + // Try to validate, artifact should get removed because of the corruption. + let result = host + .validate_candidate( + halt::wasm_binary_unwrap(), + ValidationParams { + block_data: BlockData(Vec::new()), + parent_head: Default::default(), + relay_parent_number: 1, + relay_parent_storage_root: Default::default(), + }, + Default::default(), + ) + .await; + + assert_matches!( + result, + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::RuntimeConstruction(_))) + ); + + // because of RuntimeConstruction we may retry + host.precheck_pvf(halt::wasm_binary_unwrap(), Default::default()).await.unwrap(); + + // The actual artifact removal is done concurrently + // with sending of the result of the execution + // it is not a problem for further re-preparation as + // artifact filenames are random + for _ in 1..5 { + if !artifact_path.path().exists() { + break; + } + tokio::time::sleep(Duration::from_secs(1)).await; } + + assert!( + !artifact_path.path().exists(), + "the corrupted artifact ({}) should be deleted by the host", + artifact_path.path().display() + ); } #[tokio::test] diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index 4bedfd827340bc60b0101f1c854f207705bc0b31..3ff1a35d0687b6c6dc2d0ae70c96caeefc727c8f 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -433,6 +433,7 @@ where .unwrap_or_else(|e| { gum::warn!( target: LOG_TARGET, + api = ?stringify!($api_name), "cannot query the runtime API version: {}", e, ); diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index 6fb38653e735428bad1f1da53c39fdc0863cbc6b..70126b4f43367ce11a1a23d462392b513ca1c028 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "2.0.48", features = ["extra-traits", "full"] } -quote = "1.0.28" +syn = { features = ["extra-traits", "full"], workspace = true } +quote = { workspace = true } proc-macro2 = "1.0.56" proc-macro-crate = "3.0.0" expander = "2.0.0" diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index 892292c714b11bba1114f7016706299065378de6..23ab8f8421084751fa61d48bd3aa2b346e5a75c1 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -17,7 +17,7 @@ polkadot-primitives = { path = "../../primitives" } polkadot-node-primitives = { path = "../primitives" } sc-network = { path = "../../../substrate/client/network" } sp-core = { path = "../../../substrate/primitives/core" } -thiserror = "1.0.48" +thiserror = { workspace = true } tokio = "1.24.2" -log = "0.4.17" +log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", default-features = false } diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 6a3dff726ed328aecf37e4985ed0d7ec3eb07674..ea25b9077f3a7000cef89a328016fd95b80b9035 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -43,7 +43,7 @@ assert_matches = "1.5" async-trait = "0.1.74" sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/node/malus/src/variants/back_garbage_candidate.rs b/polkadot/node/malus/src/variants/back_garbage_candidate.rs index 82475d291422582f5197613d4f347baaf203b929..b939a2151e2359828da74d317c9e2bc0af2c6e0c 100644 --- a/polkadot/node/malus/src/variants/back_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/back_garbage_candidate.rs @@ -20,14 +20,13 @@ use polkadot_cli::{ service::{ - AuthorityDiscoveryApi, AuxStore, BabeApi, Block, Error, ExtendedOverseerGenArgs, - HeaderBackend, Overseer, OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, - ParachainHost, ProvideRuntimeApi, + AuxStore, Error, ExtendedOverseerGenArgs, Overseer, OverseerConnector, OverseerGen, + OverseerGenArgs, OverseerHandle, }, validator_overseer_builder, Cli, }; use polkadot_node_subsystem::SpawnGlue; -use polkadot_node_subsystem_types::DefaultSubsystemClient; +use polkadot_node_subsystem_types::{ChainApiBackend, RuntimeApiSubsystemClient}; use sp_core::traits::SpawnNamed; use crate::{ @@ -63,13 +62,9 @@ impl OverseerGen for BackGarbageCandidates { connector: OverseerConnector, args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { let spawner = args.spawner.clone(); diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index 011fcc80e37331909434ccd2fa1bfa1e96f48f35..eb6988f81811687442a36ae3f8ec225de48dd9df 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -23,10 +23,6 @@ use crate::{ use polkadot_node_core_candidate_validation::find_validation_data; use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; -use polkadot_node_subsystem::{ - messages::{CandidateValidationMessage, ValidationFailed}, - overseer, -}; use polkadot_primitives::{ CandidateCommitments, CandidateDescriptor, CandidateReceipt, PersistedValidationData, diff --git a/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs b/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs index b3555ba2f5beb3e45285bc443dee9a4d029b070b..7a95bdaead26e204bd4cd8b386ae02b5e12297f9 100644 --- a/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs +++ b/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs @@ -34,14 +34,13 @@ use futures::channel::oneshot; use polkadot_cli::{ service::{ - AuthorityDiscoveryApi, AuxStore, BabeApi, Block, Error, ExtendedOverseerGenArgs, - HeaderBackend, Overseer, OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, - ParachainHost, ProvideRuntimeApi, + AuxStore, Error, ExtendedOverseerGenArgs, Overseer, OverseerConnector, OverseerGen, + OverseerGenArgs, OverseerHandle, }, validator_overseer_builder, Cli, }; -use polkadot_node_subsystem::{messages::ApprovalVotingMessage, SpawnGlue}; -use polkadot_node_subsystem_types::{DefaultSubsystemClient, OverseerSignal}; +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 sp_core::traits::SpawnNamed; @@ -237,13 +236,9 @@ impl OverseerGen for DisputeFinalizedCandidates { connector: OverseerConnector, args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { gum::info!( diff --git a/polkadot/node/malus/src/variants/dispute_valid_candidates.rs b/polkadot/node/malus/src/variants/dispute_valid_candidates.rs index b9812cbb5012a4ff97e3f1ed146538147efda03b..a50fdce16e4ec41d6b9bea4f0190616f756d9193 100644 --- a/polkadot/node/malus/src/variants/dispute_valid_candidates.rs +++ b/polkadot/node/malus/src/variants/dispute_valid_candidates.rs @@ -24,14 +24,13 @@ use polkadot_cli::{ service::{ - AuthorityDiscoveryApi, AuxStore, BabeApi, Block, Error, ExtendedOverseerGenArgs, - HeaderBackend, Overseer, OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, - ParachainHost, ProvideRuntimeApi, + AuxStore, Error, ExtendedOverseerGenArgs, Overseer, OverseerConnector, OverseerGen, + OverseerGenArgs, OverseerHandle, }, validator_overseer_builder, Cli, }; use polkadot_node_subsystem::SpawnGlue; -use polkadot_node_subsystem_types::DefaultSubsystemClient; +use polkadot_node_subsystem_types::{ChainApiBackend, RuntimeApiSubsystemClient}; use sp_core::traits::SpawnNamed; // Filter wrapping related types. @@ -80,13 +79,9 @@ impl OverseerGen for DisputeValidCandidates { connector: OverseerConnector, args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { let spawner = args.spawner.clone(); diff --git a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs index 22b44ddd1dc359620b199118bebf0bb83b69dada..739ed40db362a2ae330f14b7a24cc77c1ab76159 100644 --- a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs @@ -25,14 +25,13 @@ use futures::channel::oneshot; use polkadot_cli::{ service::{ - AuthorityDiscoveryApi, AuxStore, BabeApi, Block, Error, ExtendedOverseerGenArgs, - HeaderBackend, Overseer, OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, - ParachainHost, ProvideRuntimeApi, + AuxStore, Error, ExtendedOverseerGenArgs, Overseer, OverseerConnector, OverseerGen, + OverseerGenArgs, OverseerHandle, }, validator_overseer_builder, Cli, }; use polkadot_node_primitives::{AvailableData, BlockData, PoV}; -use polkadot_node_subsystem_types::DefaultSubsystemClient; +use polkadot_node_subsystem_types::{ChainApiBackend, RuntimeApiSubsystemClient}; use polkadot_primitives::{CandidateDescriptor, CandidateReceipt}; use polkadot_node_subsystem_util::request_validators; @@ -52,7 +51,7 @@ use crate::{ // Import extra types relevant to the particular // subsystem. -use polkadot_node_subsystem::{messages::CandidateBackingMessage, SpawnGlue}; +use polkadot_node_subsystem::SpawnGlue; use std::sync::Arc; @@ -296,13 +295,9 @@ impl OverseerGen for SuggestGarbageCandidates { connector: OverseerConnector, args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { gum::info!( diff --git a/polkadot/node/malus/src/variants/support_disabled.rs b/polkadot/node/malus/src/variants/support_disabled.rs index e25df56fd643cdde44b861973751b1cd23e25480..169c442db25b7426f44cdfbe2c4181233802a914 100644 --- a/polkadot/node/malus/src/variants/support_disabled.rs +++ b/polkadot/node/malus/src/variants/support_disabled.rs @@ -19,14 +19,13 @@ use polkadot_cli::{ service::{ - AuthorityDiscoveryApi, AuxStore, BabeApi, Block, Error, ExtendedOverseerGenArgs, - HeaderBackend, Overseer, OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, - ParachainHost, ProvideRuntimeApi, + AuxStore, Error, ExtendedOverseerGenArgs, Overseer, OverseerConnector, OverseerGen, + OverseerGenArgs, OverseerHandle, }, validator_overseer_builder, Cli, }; use polkadot_node_subsystem::SpawnGlue; -use polkadot_node_subsystem_types::DefaultSubsystemClient; +use polkadot_node_subsystem_types::{ChainApiBackend, RuntimeApiSubsystemClient}; use sp_core::traits::SpawnNamed; use crate::interceptor::*; @@ -50,13 +49,9 @@ impl OverseerGen for SupportDisabled { connector: OverseerConnector, args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { validator_overseer_builder( diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index 7d67c0a58d3b0a58904e8e1b00e0e13a1f48e710..c567278f70ea79740510aea4099170179f7e1f85 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -24,7 +24,7 @@ sc-tracing = { path = "../../../substrate/client/tracing" } codec = { package = "parity-scale-codec", version = "3.6.1" } primitives = { package = "polkadot-primitives", path = "../../primitives" } bs58 = { version = "0.5.0", features = ["alloc"] } -log = "0.4.17" +log = { workspace = true, default-features = true } [dev-dependencies] assert_cmd = "2.0.4" diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index a1fa803abc25fcbe587c4c574902ca8dbf63ad4b..2bc09c5f42acad52a8a96dab3916ed6314f27d56 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -38,4 +38,4 @@ schnorrkel = { version = "0.11.4", default-features = false } rand_core = "0.6.2" rand_chacha = "0.3.1" env_logger = "0.9.0" -log = "0.4.17" +log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index a1484429ed633a09974e230bcf5be118f7280e15..182d92cb163179eea85cafeb1c605763ac18cde1 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -21,7 +21,7 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-primitives = { path = "../../primitives" } sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } sp-keystore = { path = "../../../../substrate/primitives/keystore" } -thiserror = "1.0.48" +thiserror = { workspace = true } rand = "0.8.5" derive_more = "0.99.17" schnellru = "0.2.1" @@ -36,3 +36,14 @@ sc-network = { path = "../../../../substrate/client/network" } futures-timer = "3.0.2" assert_matches = "1.4.0" polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +polkadot-subsystem-bench = { path = "../../subsystem-bench" } + + +[[test]] +name = "availability-distribution-regression-bench" +path = "tests/availability-distribution-regression-bench.rs" +harness = false +required-features = ["subsystem-benchmarks"] + +[features] +subsystem-benchmarks = [] diff --git a/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs new file mode 100644 index 0000000000000000000000000000000000000000..7a490d5e47f74103634e2ed0266e5230a3842b8b --- /dev/null +++ b/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs @@ -0,0 +1,104 @@ +// 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 . + +//! availability-read regression tests +//! +//! Availability read benchmark based on Kusama parameters and scale. +//! +//! Subsystems involved: +//! - availability-distribution +//! - bitfield-distribution +//! - availability-store + +use polkadot_subsystem_bench::{ + availability::{benchmark_availability_write, prepare_test, TestDataAvailability, TestState}, + configuration::TestConfiguration, + usage::BenchmarkUsage, +}; + +const BENCH_COUNT: usize = 3; +const WARM_UP_COUNT: usize = 30; +const WARM_UP_PRECISION: f64 = 0.01; + +fn main() -> Result<(), String> { + let mut messages = vec![]; + let mut config = TestConfiguration::default(); + // A single node effort roughly n_cores * needed_approvals / n_validators = 60 * 30 / 300 + config.n_cores = 6; + config.num_blocks = 3; + config.generate_pov_sizes(); + + warm_up(config.clone())?; + let usage = benchmark(config.clone()); + + messages.extend(usage.check_network_usage(&[ + ("Received from peers", 4330.0, 0.05), + ("Sent to peers", 15900.0, 0.05), + ])); + messages.extend(usage.check_cpu_usage(&[ + ("availability-distribution", 0.025, 0.05), + ("bitfield-distribution", 0.085, 0.05), + ("availability-store", 0.180, 0.05), + ])); + + if messages.is_empty() { + Ok(()) + } else { + eprintln!("{}", messages.join("\n")); + Err("Regressions found".to_string()) + } +} + +fn warm_up(config: TestConfiguration) -> Result<(), String> { + println!("Warming up..."); + let mut prev_run: Option = None; + for _ in 0..WARM_UP_COUNT { + let curr = run(config.clone()); + if let Some(ref prev) = prev_run { + let av_distr_diff = + curr.cpu_usage_diff(prev, "availability-distribution").expect("Must exist"); + let bitf_distr_diff = + curr.cpu_usage_diff(prev, "bitfield-distribution").expect("Must exist"); + let av_store_diff = + curr.cpu_usage_diff(prev, "availability-store").expect("Must exist"); + if av_distr_diff < WARM_UP_PRECISION && + bitf_distr_diff < WARM_UP_PRECISION && + av_store_diff < WARM_UP_PRECISION + { + return Ok(()) + } + } + prev_run = Some(curr); + } + + Err("Can't warm up".to_string()) +} + +fn benchmark(config: TestConfiguration) -> BenchmarkUsage { + println!("Benchmarking..."); + let usages: Vec = (0..BENCH_COUNT).map(|_| run(config.clone())).collect(); + let usage = BenchmarkUsage::average(&usages); + println!("{}", usage); + usage +} + +fn run(config: TestConfiguration) -> BenchmarkUsage { + let mut state = TestState::new(&config); + let (mut env, _protocol_config) = + prepare_test(config.clone(), &mut state, TestDataAvailability::Write, false); + env.runtime() + .block_on(benchmark_availability_write("data_availability_write", &mut env, state)) +} diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 9f1d9052312f2cbbff8f32ffc22b7e1c234cfc3f..12b6ce7a05715480bc6ca79d67742bc089b5f67c 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -15,7 +15,7 @@ tokio = "1.24.2" schnellru = "0.2.1" rand = "0.8.5" fatality = "0.0.6" -thiserror = "1.0.48" +thiserror = { workspace = true } async-trait = "0.1.74" gum = { package = "tracing-gum", path = "../../gum" } @@ -32,7 +32,7 @@ sc-network = { path = "../../../../substrate/client/network" } assert_matches = "1.4.0" env_logger = "0.9.0" futures-timer = "3.0.2" -log = "0.4.17" +log = { workspace = true, default-features = true } sp-core = { path = "../../../../substrate/primitives/core" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } @@ -41,6 +41,13 @@ sc-network = { path = "../../../../substrate/client/network" } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +polkadot-subsystem-bench = { path = "../../subsystem-bench" } + +[[test]] +name = "availability-recovery-regression-bench" +path = "tests/availability-recovery-regression-bench.rs" +harness = false +required-features = ["subsystem-benchmarks"] [features] subsystem-benchmarks = [] diff --git a/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs new file mode 100644 index 0000000000000000000000000000000000000000..30cc4d47ecc13048cd4326625a2156d7bbc4ddc9 --- /dev/null +++ b/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs @@ -0,0 +1,94 @@ +// 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 . + +//! availability-write regression tests +//! +//! Availability write benchmark based on Kusama parameters and scale. +//! +//! Subsystems involved: +//! - availability-recovery + +use polkadot_subsystem_bench::{ + availability::{ + benchmark_availability_read, prepare_test, DataAvailabilityReadOptions, + TestDataAvailability, TestState, + }, + configuration::TestConfiguration, + usage::BenchmarkUsage, +}; + +const BENCH_COUNT: usize = 3; +const WARM_UP_COUNT: usize = 10; +const WARM_UP_PRECISION: f64 = 0.01; + +fn main() -> Result<(), String> { + let mut messages = vec![]; + + let options = DataAvailabilityReadOptions { fetch_from_backers: true }; + let mut config = TestConfiguration::default(); + config.num_blocks = 3; + config.generate_pov_sizes(); + + warm_up(config.clone(), options.clone())?; + let usage = benchmark(config.clone(), options.clone()); + + messages.extend(usage.check_network_usage(&[ + ("Received from peers", 102400.000, 0.05), + ("Sent to peers", 0.335, 0.05), + ])); + messages.extend(usage.check_cpu_usage(&[("availability-recovery", 3.850, 0.05)])); + + if messages.is_empty() { + Ok(()) + } else { + eprintln!("{}", messages.join("\n")); + Err("Regressions found".to_string()) + } +} + +fn warm_up(config: TestConfiguration, options: DataAvailabilityReadOptions) -> Result<(), String> { + println!("Warming up..."); + let mut prev_run: Option = None; + for _ in 0..WARM_UP_COUNT { + let curr = run(config.clone(), options.clone()); + if let Some(ref prev) = prev_run { + let diff = curr.cpu_usage_diff(prev, "availability-recovery").expect("Must exist"); + if diff < WARM_UP_PRECISION { + return Ok(()) + } + } + prev_run = Some(curr); + } + + Err("Can't warm up".to_string()) +} + +fn benchmark(config: TestConfiguration, options: DataAvailabilityReadOptions) -> BenchmarkUsage { + println!("Benchmarking..."); + let usages: Vec = + (0..BENCH_COUNT).map(|_| run(config.clone(), options.clone())).collect(); + let usage = BenchmarkUsage::average(&usages); + println!("{}", usage); + usage +} + +fn run(config: TestConfiguration, options: DataAvailabilityReadOptions) -> BenchmarkUsage { + let mut state = TestState::new(&config); + let (mut env, _protocol_config) = + prepare_test(config.clone(), &mut state, TestDataAvailability::Read(options), false); + env.runtime() + .block_on(benchmark_availability_read("data_availability_read", &mut env, state)) +} diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index 8a05bcbd493fd21c5c55bd1603319465f6003ae8..0ddb5f643b89d382855de92fe450a5807e6e21ac 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -29,7 +29,7 @@ sp-authority-discovery = { path = "../../../../substrate/primitives/authority-di sp-keystore = { path = "../../../../substrate/primitives/keystore" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } maplit = "1.0.2" -log = "0.4.17" +log = { workspace = true, default-features = true } env_logger = "0.9.0" assert_matches = "1.4.0" rand_chacha = "0.3.1" diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index 0cdd7bfbcb136bef97f856dc5fd3cb0a3cdf507e..2e889fc30eb90063f07c05e34e51d863a3d32f59 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -25,7 +25,7 @@ polkadot-overseer = { path = "../../overseer" } parking_lot = "0.12.1" bytes = "1" fatality = "0.0.6" -thiserror = "1" +thiserror = { workspace = true } [dev-dependencies] assert_matches = "1.4.0" diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index 9a9ce6fce6359a9e44e7820839952c5f9a8c11ba..f0f8be0f7bab240a928be9f30a18ca10b14eb16d 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -25,11 +25,11 @@ polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-subsystem = { path = "../../subsystem" } fatality = "0.0.6" -thiserror = "1.0.48" +thiserror = { workspace = true } tokio-util = "0.7.1" [dev-dependencies] -log = "0.4.17" +log = { workspace = true, default-features = true } env_logger = "0.9.0" assert_matches = "1.4.0" 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 5b88efc99d8307594c5ac726d1af5ab141e4718d..1533f2eda5a57d332ea899e1dd81764f31c86dad 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 @@ -90,8 +90,7 @@ impl ValidatorGroupsBuffer { } } - /// Returns discovery ids of validators we have at least one advertised-but-not-fetched - /// collation for. + /// Returns discovery ids of validators we are assigned to in this backing group window. pub fn validators_to_connect(&self) -> Vec { let validators_num = self.validators.len(); let bits = self @@ -99,11 +98,22 @@ impl ValidatorGroupsBuffer { .values() .fold(bitvec![0; validators_num], |acc, next| acc | next); - self.validators + let mut should_be_connected: Vec = self + .validators .iter() .enumerate() .filter_map(|(idx, authority_id)| bits[idx].then_some(authority_id.clone())) - .collect() + .collect(); + + if let Some(last_group) = self.group_infos.iter().last() { + for validator in self.validators.iter().rev().take(last_group.len) { + if !should_be_connected.contains(validator) { + should_be_connected.push(validator.clone()); + } + } + } + + should_be_connected } /// Note a new advertisement, marking that we want to be connected to validators @@ -279,7 +289,7 @@ mod tests { assert_eq!(buf.validators_to_connect(), validators[..2].to_vec()); buf.reset_validator_interest(hash_a, &validators[1]); - assert_eq!(buf.validators_to_connect(), vec![validators[0].clone()]); + assert_eq!(buf.validators_to_connect(), validators[0..2].to_vec()); buf.note_collation_advertised(hash_b, 0, GroupIndex(1), &validators[2..]); assert_eq!(buf.validators_to_connect(), validators[2..].to_vec()); @@ -287,7 +297,11 @@ mod tests { for validator in &validators[2..] { buf.reset_validator_interest(hash_b, validator); } - assert!(buf.validators_to_connect().is_empty()); + let mut expected = validators[2..].to_vec(); + expected.sort(); + let mut result = buf.validators_to_connect(); + result.sort(); + assert_eq!(result, expected); } #[test] @@ -320,10 +334,18 @@ mod tests { } buf.reset_validator_interest(hashes[1], &validators[0]); - assert_eq!(buf.validators_to_connect(), validators[..2].to_vec()); + let mut expected: Vec<_> = validators[..4].iter().cloned().collect(); + let mut result = buf.validators_to_connect(); + expected.sort(); + result.sort(); + assert_eq!(result, expected); buf.reset_validator_interest(hashes[0], &validators[0]); - assert_eq!(buf.validators_to_connect(), vec![validators[1].clone()]); + let mut expected: Vec<_> = validators[1..4].iter().cloned().collect(); + expected.sort(); + let mut result = buf.validators_to_connect(); + result.sort(); + assert_eq!(result, expected); buf.note_collation_advertised(hashes[3], 0, GroupIndex(1), &validators[2..4]); buf.note_collation_advertised( 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 48ad3c711a6db9c5e9e09c26d1a6290ffbed60f4..a1b93fff348f2f0621e9859418e5ceffb6829028 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -1883,7 +1883,7 @@ async fn disconnect_inactive_peers( ) { for (peer, peer_data) in peers { if peer_data.is_inactive(&eviction_policy) { - gum::trace!(target: LOG_TARGET, "Disconnecting inactive peer"); + gum::trace!(target: LOG_TARGET, ?peer, "Disconnecting inactive peer"); disconnect_peer(sender, *peer).await; } } diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index 319b743aa586dfb5104eb2b1fe9f3aa042c2c13f..14d59d04f2bff7b838717edb927401035537ff4d 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -24,7 +24,7 @@ polkadot-node-primitives = { path = "../../primitives" } sc-network = { path = "../../../../substrate/client/network" } sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } -thiserror = "1.0.48" +thiserror = { workspace = true } fatality = "0.0.6" schnellru = "0.2.1" indexmap = "2.0.0" diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index c17f39b019de1f6f248236c387742a9033e60df8..8d0edc206d728b16e0448c3339c1719f26d81413 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -38,5 +38,6 @@ polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } assert_matches = "1.4.0" async-trait = "0.1.74" +parking_lot = "0.12.1" lazy_static = "1.4.0" quickcheck = "1.0.3" diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index e9cb8a4de1c47b5e3f6e285f86ad38b3cf5ac342..4dfdd1f7208f66ec4a787ffe8bc7f72c41575c9d 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -63,8 +63,12 @@ use metrics::Metrics; const LOG_TARGET: &str = "parachain::gossip-support"; // How much time should we wait to reissue a connection request // since the last authority discovery resolution failure. +#[cfg(not(test))] const BACKOFF_DURATION: Duration = Duration::from_secs(5); +#[cfg(test)] +const BACKOFF_DURATION: Duration = Duration::from_millis(500); + /// Duration after which we consider low connectivity a problem. /// /// Especially at startup low connectivity is expected (authority discovery cache needs to be @@ -271,8 +275,8 @@ where ) .await?; } - // authority_discovery is just a cache so let's try every leaf to detect if there - // are new authorities there. + // authority_discovery is just a cache so let's try every time we try to re-connect + // if new authorities are present. self.update_authority_ids(sender, session_info.discovery_keys).await; } } diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs index e5ee101c31d857b2dbd540596649ddaf9b826bd5..6817c85f98d87c03b3c252783c464efed88dfdb6 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -25,13 +25,19 @@ use lazy_static::lazy_static; use quickcheck::quickcheck; use rand::seq::SliceRandom as _; +use parking_lot::Mutex; use sc_network::multiaddr::Protocol; use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair; use sp_consensus_babe::{AllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch}; use sp_core::crypto::Pair as PairT; use sp_keyring::Sr25519Keyring; +use std::sync::Arc; -use polkadot_node_network_protocol::grid_topology::{SessionGridTopology, TopologyPeerInfo}; +use polkadot_node_network_protocol::{ + grid_topology::{SessionGridTopology, TopologyPeerInfo}, + peer_set::ValidationVersion, + ObservedRole, +}; use polkadot_node_subsystem::messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt as _; @@ -51,7 +57,6 @@ const AUTHORITY_KEYRINGS: &[Sr25519Keyring] = &[ ]; lazy_static! { - static ref MOCK_AUTHORITY_DISCOVERY: MockAuthorityDiscovery = MockAuthorityDiscovery::new(); static ref AUTHORITIES: Vec = AUTHORITY_KEYRINGS.iter().map(|k| k.public().into()).collect(); @@ -89,17 +94,14 @@ type VirtualOverseer = test_helpers::TestSubsystemContextHandle>, - authorities: HashMap>, + addrs: Arc>>>, + authorities: Arc>>>, } impl MockAuthorityDiscovery { - fn new() -> Self { - let authorities: HashMap<_, _> = PAST_PRESENT_FUTURE_AUTHORITIES - .clone() - .into_iter() - .map(|a| (PeerId::random(), a)) - .collect(); + fn new(authorities: Vec) -> Self { + let authorities: HashMap<_, _> = + authorities.clone().into_iter().map(|a| (PeerId::random(), a)).collect(); let addrs = authorities .clone() .into_iter() @@ -109,10 +111,37 @@ impl MockAuthorityDiscovery { }) .collect(); Self { - addrs, - authorities: authorities.into_iter().map(|(p, a)| (p, HashSet::from([a]))).collect(), + addrs: Arc::new(Mutex::new(addrs)), + authorities: Arc::new(Mutex::new( + authorities.into_iter().map(|(p, a)| (p, HashSet::from([a]))).collect(), + )), } } + + fn authorities(&self) -> HashMap> { + self.authorities.lock().clone() + } + + fn add_more_authorties( + &self, + new_known: Vec, + ) -> HashMap> { + let authorities: HashMap<_, _> = + new_known.clone().into_iter().map(|a| (PeerId::random(), a)).collect(); + let addrs: HashMap> = authorities + .clone() + .into_iter() + .map(|(p, a)| { + let multiaddr = Multiaddr::empty().with(Protocol::P2p(p.into())); + (a, HashSet::from([multiaddr])) + }) + .collect(); + let authorities: HashMap> = + authorities.into_iter().map(|(p, a)| (p, HashSet::from([a]))).collect(); + self.addrs.as_ref().lock().extend(addrs); + self.authorities.as_ref().lock().extend(authorities.clone()); + authorities + } } #[async_trait] @@ -121,19 +150,23 @@ impl AuthorityDiscovery for MockAuthorityDiscovery { &mut self, authority: polkadot_primitives::AuthorityDiscoveryId, ) -> Option> { - self.addrs.get(&authority).cloned() + self.addrs.lock().get(&authority).cloned() } + async fn get_authority_ids_by_peer_id( &mut self, peer_id: polkadot_node_network_protocol::PeerId, ) -> Option> { - self.authorities.get(&peer_id).cloned() + self.authorities.as_ref().lock().get(&peer_id).cloned() } } -async fn get_multiaddrs(authorities: Vec) -> Vec> { +async fn get_multiaddrs( + authorities: Vec, + mock_authority_discovery: MockAuthorityDiscovery, +) -> Vec> { let mut addrs = Vec::with_capacity(authorities.len()); - let mut discovery = MOCK_AUTHORITY_DISCOVERY.clone(); + let mut discovery = mock_authority_discovery.clone(); for authority in authorities.into_iter() { if let Some(addr) = discovery.get_addresses_by_authority_id(authority).await { addrs.push(addr); @@ -144,9 +177,10 @@ async fn get_multiaddrs(authorities: Vec) -> Vec, + mock_authority_discovery: MockAuthorityDiscovery, ) -> HashMap> { let mut addrs = HashMap::with_capacity(authorities.len()); - let mut discovery = MOCK_AUTHORITY_DISCOVERY.clone(); + let mut discovery = mock_authority_discovery.clone(); for authority in authorities.into_iter() { if let Some(addr) = discovery.get_addresses_by_authority_id(authority.clone()).await { addrs.insert(authority, addr); @@ -155,12 +189,10 @@ async fn get_address_map( addrs } -fn make_subsystem() -> GossipSupport { - GossipSupport::new( - make_ferdie_keystore(), - MOCK_AUTHORITY_DISCOVERY.clone(), - Metrics::new_dummy(), - ) +fn make_subsystem_with_authority_discovery( + mock: MockAuthorityDiscovery, +) -> GossipSupport { + GossipSupport::new(make_ferdie_keystore(), mock, Metrics::new_dummy()) } fn test_harness, AD: AuthorityDiscovery>( @@ -291,59 +323,65 @@ async fn test_neighbors(overseer: &mut VirtualOverseer, expected_session: Sessio #[test] fn issues_a_connection_request_on_new_session() { + let mock_authority_discovery = + MockAuthorityDiscovery::new(PAST_PRESENT_FUTURE_AUTHORITIES.clone()); + let mock_authority_discovery_clone = mock_authority_discovery.clone(); let hash = Hash::repeat_byte(0xAA); - let state = test_harness(make_subsystem(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - overseer_signal_active_leaves(overseer, hash).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::SessionIndexForChild(tx), - )) => { - assert_eq!(relay_parent, hash); - tx.send(Ok(1)).unwrap(); - } - ); + let state = test_harness( + make_subsystem_with_authority_discovery(mock_authority_discovery.clone()), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::SessionInfo(s, tx), - )) => { - assert_eq!(relay_parent, hash); - assert_eq!(s, 1); - tx.send(Ok(Some(make_session_info()))).unwrap(); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + tx.send(Ok(Some(make_session_info()))).unwrap(); + } + ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::Authorities(tx), - )) => { - assert_eq!(relay_parent, hash); - tx.send(Ok(AUTHORITIES.clone())).unwrap(); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(AUTHORITIES.clone())).unwrap(); + } + ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { - validator_addrs, - peer_set, - }) => { - assert_eq!(validator_addrs, get_multiaddrs(AUTHORITIES_WITHOUT_US.clone()).await); - assert_eq!(peer_set, PeerSet::Validation); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs, + peer_set, + }) => { + assert_eq!(validator_addrs, get_multiaddrs(AUTHORITIES_WITHOUT_US.clone(), mock_authority_discovery_clone).await); + assert_eq!(peer_set, PeerSet::Validation); + } + ); - test_neighbors(overseer, 1).await; + test_neighbors(overseer, 1).await; - virtual_overseer - }); + virtual_overseer + }, + ); assert_eq!(state.last_session_index, Some(1)); assert!(state.last_failure.is_none()); @@ -363,6 +401,7 @@ fn issues_a_connection_request_on_new_session() { tx.send(Ok(1)).unwrap(); } ); + virtual_overseer }); @@ -414,7 +453,7 @@ fn issues_a_connection_request_on_new_session() { validator_addrs, peer_set, }) => { - assert_eq!(validator_addrs, get_multiaddrs(AUTHORITIES_WITHOUT_US.clone()).await); + assert_eq!(validator_addrs, get_multiaddrs(AUTHORITIES_WITHOUT_US.clone(), mock_authority_discovery.clone()).await); assert_eq!(peer_set, PeerSet::Validation); } ); @@ -430,125 +469,405 @@ fn issues_a_connection_request_on_new_session() { #[test] fn issues_connection_request_to_past_present_future() { let hash = Hash::repeat_byte(0xAA); - test_harness(make_subsystem(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - overseer_signal_active_leaves(overseer, hash).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::SessionIndexForChild(tx), - )) => { - assert_eq!(relay_parent, hash); - tx.send(Ok(1)).unwrap(); + let mock_authority_discovery = + MockAuthorityDiscovery::new(PAST_PRESENT_FUTURE_AUTHORITIES.clone()); + test_harness( + make_subsystem_with_authority_discovery(mock_authority_discovery.clone()), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + tx.send(Ok(Some(make_session_info()))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs, + peer_set, + }) => { + let all_without_ferdie: Vec<_> = PAST_PRESENT_FUTURE_AUTHORITIES + .iter() + .cloned() + .filter(|p| p != &Sr25519Keyring::Ferdie.public().into()) + .collect(); + + let addrs = get_multiaddrs(all_without_ferdie, mock_authority_discovery.clone()).await; + + assert_eq!(validator_addrs, addrs); + assert_eq!(peer_set, PeerSet::Validation); + } + ); + + // Ensure neighbors are unaffected + test_neighbors(overseer, 1).await; + + virtual_overseer + }, + ); +} + +// Test we notify peer about learning of the authority ID after session boundary, when we couldn't +// connect to more than 1/3 of the authorities. +#[test] +fn issues_update_authorities_after_session() { + let hash = Hash::repeat_byte(0xAA); + + let mut authorities = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + let unknown_at_session = authorities.split_off(authorities.len() / 3 - 1); + let mut authority_discovery_mock = MockAuthorityDiscovery::new(authorities); + + test_harness( + make_subsystem_with_authority_discovery(authority_discovery_mock.clone()), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // 1. Initialize with the first leaf in the session. + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs, + peer_set, + }) => { + let all_without_ferdie: Vec<_> = PAST_PRESENT_FUTURE_AUTHORITIES + .iter() + .cloned() + .filter(|p| p != &Sr25519Keyring::Ferdie.public().into()) + .collect(); + + let addrs = get_multiaddrs(all_without_ferdie, authority_discovery_mock.clone()).await; + + assert_eq!(validator_addrs, addrs); + assert_eq!(peer_set, PeerSet::Validation); + } + ); + + // Ensure neighbors are unaffected + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::CurrentBabeEpoch(tx), + )) => { + let _ = tx.send(Ok(BabeEpoch { + epoch_index: 2 as _, + start_slot: 0.into(), + duration: 200, + authorities: vec![(Sr25519Keyring::Alice.public().into(), 1)], + randomness: [0u8; 32], + config: BabeEpochConfiguration { + c: (1, 4), + allowed_slots: AllowedSlots::PrimarySlots, + }, + })).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::NewGossipTopology { + session: _, + local_index: _, + canonical_shuffling: _, + shuffled_indices: _, + }) => { + + } + ); + + // 2. Connect all authorities that are known so far. + let known_authorities = authority_discovery_mock.authorities(); + for (peer_id, _id) in known_authorities.iter() { + let msg = + GossipSupportMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( + *peer_id, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + )); + overseer.send(FromOrchestra::Communication { msg }).await } - ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::SessionInfo(s, tx), - )) => { - assert_eq!(relay_parent, hash); - assert_eq!(s, 1); - tx.send(Ok(Some(make_session_info()))).unwrap(); + Delay::new(BACKOFF_DURATION).await; + // 3. Send a new leaf after BACKOFF_DURATION and check UpdateAuthority is emitted for + // all known connected peers. + let hash = Hash::repeat_byte(0xBB); + overseer_signal_active_leaves(overseer, hash).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs: _, + peer_set: _, + }) => { + } + ); + + for _ in 0..known_authorities.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_eq!(authority_discovery_mock.get_authority_ids_by_peer_id(peer_id).await.unwrap_or_default(), authority_ids); + } + ); } - ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::Authorities(tx), - )) => { - assert_eq!(relay_parent, hash); - tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none()); + // 4. Connect more authorities except one + let newly_added = authority_discovery_mock.add_more_authorties(unknown_at_session); + let mut newly_added_iter = newly_added.iter(); + let unconnected_at_last_retry = newly_added_iter + .next() + .map(|(peer_id, authority_id)| (*peer_id, authority_id.clone())) + .unwrap(); + for (peer_id, _) in newly_added_iter { + let msg = + GossipSupportMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( + *peer_id, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + )); + overseer.send(FromOrchestra::Communication { msg }).await } - ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { - validator_addrs, - peer_set, - }) => { - let all_without_ferdie: Vec<_> = PAST_PRESENT_FUTURE_AUTHORITIES - .iter() - .cloned() - .filter(|p| p != &Sr25519Keyring::Ferdie.public().into()) - .collect(); + // 5. Send a new leaf and check UpdateAuthority is emitted only for the newly connected + // peers. + let hash = Hash::repeat_byte(0xCC); + Delay::new(BACKOFF_DURATION).await; + overseer_signal_active_leaves(overseer, hash).await; - let addrs = get_multiaddrs(all_without_ferdie).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); - assert_eq!(validator_addrs, addrs); - assert_eq!(peer_set, PeerSet::Validation); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + } + ); - // Ensure neighbors are unaffected - test_neighbors(overseer, 1).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); - virtual_overseer - }); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs: _, + peer_set: _, + }) => { + } + ); + + for _ in 1..newly_added.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_ne!(peer_id, unconnected_at_last_retry.0); + assert_eq!(newly_added.get(&peer_id).cloned().unwrap_or_default(), authority_ids); + } + ); + } + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none()); + virtual_overseer + }, + ); } #[test] fn disconnect_when_not_in_past_present_future() { sp_tracing::try_init_simple(); + let mock_authority_discovery = + MockAuthorityDiscovery::new(PAST_PRESENT_FUTURE_AUTHORITIES.clone()); let hash = Hash::repeat_byte(0xAA); - test_harness(make_subsystem(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - overseer_signal_active_leaves(overseer, hash).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::SessionIndexForChild(tx), - )) => { - assert_eq!(relay_parent, hash); - tx.send(Ok(1)).unwrap(); - } - ); + test_harness( + make_subsystem_with_authority_discovery(mock_authority_discovery.clone()), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::SessionInfo(s, tx), - )) => { - assert_eq!(relay_parent, hash); - assert_eq!(s, 1); - let mut heute_leider_nicht = make_session_info(); - heute_leider_nicht.discovery_keys = AUTHORITIES_WITHOUT_US.clone(); - tx.send(Ok(Some(heute_leider_nicht))).unwrap(); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut heute_leider_nicht = make_session_info(); + heute_leider_nicht.discovery_keys = AUTHORITIES_WITHOUT_US.clone(); + tx.send(Ok(Some(heute_leider_nicht))).unwrap(); + } + ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::Authorities(tx), - )) => { - assert_eq!(relay_parent, hash); - tx.send(Ok(AUTHORITIES_WITHOUT_US.clone())).unwrap(); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(AUTHORITIES_WITHOUT_US.clone())).unwrap(); + } + ); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { - validator_addrs, - peer_set, - }) => { - assert!(validator_addrs.is_empty()); - assert_eq!(peer_set, PeerSet::Validation); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs, + peer_set, + }) => { + assert!(validator_addrs.is_empty()); + assert_eq!(peer_set, PeerSet::Validation); + } + ); - virtual_overseer - }); + virtual_overseer + }, + ); } #[test] @@ -579,13 +898,15 @@ fn test_log_output() { #[test] fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { let hash = Hash::repeat_byte(0xAA); - let mut state = make_subsystem(); + let mock_authority_discovery = + MockAuthorityDiscovery::new(PAST_PRESENT_FUTURE_AUTHORITIES.clone()); + let state = make_subsystem_with_authority_discovery(mock_authority_discovery.clone()); // There will be two lookup failures: let alice = Sr25519Keyring::Alice.public().into(); let bob = Sr25519Keyring::Bob.public().into(); - let alice_addr = state.authority_discovery.addrs.remove(&alice); - state.authority_discovery.addrs.remove(&bob); - + let alice_addr = state.authority_discovery.addrs.lock().remove(&alice); + state.authority_discovery.addrs.lock().remove(&bob); + let mock_authority_discovery_clone = mock_authority_discovery.clone(); let mut state = { let alice = alice.clone(); let bob = bob.clone(); @@ -633,7 +954,7 @@ fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { validator_addrs, peer_set, }) => { - let mut expected = get_address_map(AUTHORITIES_WITHOUT_US.clone()).await; + let mut expected = get_address_map(AUTHORITIES_WITHOUT_US.clone(), mock_authority_discovery_clone.clone()).await; expected.remove(&alice); expected.remove(&bob); let expected: HashSet = expected.into_values().flat_map(|v| v.into_iter()).collect(); @@ -652,7 +973,7 @@ fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { assert!(state.last_failure.is_some()); state.last_failure = state.last_failure.and_then(|i| i.checked_sub(BACKOFF_DURATION)); // One error less: - state.authority_discovery.addrs.insert(alice, alice_addr.unwrap()); + state.authority_discovery.addrs.lock().insert(alice, alice_addr.unwrap()); let hash = Hash::repeat_byte(0xBB); let state = test_harness(state, |mut virtual_overseer| async move { @@ -698,7 +1019,7 @@ fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { validator_addrs, peer_set, }) => { - let mut expected = get_address_map(AUTHORITIES_WITHOUT_US.clone()).await; + let mut expected = get_address_map(AUTHORITIES_WITHOUT_US.clone(), mock_authority_discovery.clone()).await; expected.remove(&bob); let expected: HashSet = expected.into_values().flat_map(|v| v.into_iter()).collect(); assert_eq!(validator_addrs.into_iter().flat_map(|v| v.into_iter()).collect::>(), expected); diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index a8b0cf2737eaa12ed3633aac8588ed6f19407ebf..7efa0b8ca820d651d77a53a95d61e7672c5f9737 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -21,7 +21,7 @@ sc-network = { path = "../../../../substrate/client/network" } sc-authority-discovery = { path = "../../../../substrate/client/authority-discovery" } strum = { version = "0.24", features = ["derive"] } futures = "0.3.21" -thiserror = "1.0.48" +thiserror = { workspace = true } fatality = "0.0.6" rand = "0.8" derive_more = "0.99" diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index b07d84390dcdd1e5413889c4749f187ce1ddf1ea..01f7d818c1c52ffd677379e3a0a9d2f543572d92 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -23,7 +23,7 @@ polkadot-node-network-protocol = { path = "../protocol" } arrayvec = "0.7.4" indexmap = "2.0.0" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -thiserror = "1.0.48" +thiserror = { workspace = true } fatality = "0.0.6" bitvec = "1" diff --git a/polkadot/node/network/statement-distribution/src/v2/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/cluster.rs index 619114de9670c8aef50ce129b6c26bf6ff206f70..c09916e56201f20a0fbbbac349681b512f1fd5fe 100644 --- a/polkadot/node/network/statement-distribution/src/v2/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/cluster.rs @@ -55,8 +55,9 @@ //! and to keep track of what we have sent to other validators in the group and what we may //! continue to send them. -use polkadot_primitives::{CandidateHash, CompactStatement, ValidatorIndex}; +use polkadot_primitives::{CandidateHash, CompactStatement, Hash, ValidatorIndex}; +use crate::LOG_TARGET; use std::collections::{HashMap, HashSet}; #[derive(Hash, PartialEq, Eq)] @@ -424,6 +425,28 @@ impl ClusterTracker { fn is_in_group(&self, validator: ValidatorIndex) -> bool { self.validators.contains(&validator) } + + /// Dumps pending statement for this cluster. + /// + /// Normally we should not have pending statements to validators in our cluster, + /// but if we do for all validators in our cluster, then we don't participate + /// in backing. Ocasional pending statements are expected if two authorities + /// can't detect each otehr or after restart, where it takes a while to discover + /// the whole network. + + pub fn warn_if_too_many_pending_statements(&self, parent_hash: Hash) { + if self.pending.iter().filter(|pending| !pending.1.is_empty()).count() >= + self.validators.len() + { + gum::warn!( + target: LOG_TARGET, + pending_statements = ?self.pending, + ?parent_hash, + "Cluster has too many pending statements, something wrong with our connection to our group peers \n + Restart might be needed if validator gets 0 backing rewards for more than 3-4 consecutive sessions" + ); + } + } } /// Incoming statement was accepted. diff --git a/polkadot/node/network/statement-distribution/src/v2/grid.rs b/polkadot/node/network/statement-distribution/src/v2/grid.rs index 19f23053192c12a7e3bcb3ae73dbbd972e1c619d..24d846c840e00c49446a0525b3768353f56ae524 100644 --- a/polkadot/node/network/statement-distribution/src/v2/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/grid.rs @@ -527,12 +527,16 @@ impl GridTracker { } /// Determine the validators which can send a statement to us by direct broadcast. + /// + /// Returns a list of tuples representing each potential sender(ValidatorIndex) + /// and if the sender should already know about the statement, because we just + /// sent it to it. pub fn direct_statement_providers( &self, groups: &Groups, originator: ValidatorIndex, statement: &CompactStatement, - ) -> Vec { + ) -> Vec<(ValidatorIndex, bool)> { let (g, c_h, kind, in_group) = match extract_statement_and_group_info(groups, originator, statement) { None => return Vec::new(), @@ -616,12 +620,13 @@ impl GridTracker { originator: ValidatorIndex, counterparty: ValidatorIndex, statement: &CompactStatement, + received: bool, ) { if let Some((_, c_h, kind, in_group)) = extract_statement_and_group_info(groups, originator, statement) { if let Some(known) = self.confirmed_backed.get_mut(&c_h) { - known.sent_or_received_direct_statement(counterparty, in_group, kind); + known.sent_or_received_direct_statement(counterparty, in_group, kind, received); if let Some(pending) = self.pending_statements.get_mut(&counterparty) { pending.remove(&(originator, statement.clone())); @@ -908,6 +913,12 @@ struct MutualKnowledge { /// `Some` only if we have advertised, acknowledged, or requested the candidate /// from them. local_knowledge: Option, + /// Knowledge peer circulated to us, this is different from `local_knowledge` and + /// `remote_knowledge`, through the fact that includes only statements that we received from + /// peer while the other two, after manifest exchange part will include both what we sent to + /// the peer and what we received from peer, see `sent_or_received_direct_statement` for more + /// details. + received_knowledge: Option, } // A utility struct for keeping track of metadata about candidates @@ -933,10 +944,13 @@ impl KnownBackedCandidate { } fn manifest_sent_to(&mut self, validator: ValidatorIndex, local_knowledge: StatementFilter) { - let k = self - .mutual_knowledge - .entry(validator) - .or_insert_with(|| MutualKnowledge { remote_knowledge: None, local_knowledge: None }); + let k = self.mutual_knowledge.entry(validator).or_insert_with(|| MutualKnowledge { + remote_knowledge: None, + local_knowledge: None, + received_knowledge: None, + }); + k.received_knowledge = + Some(StatementFilter::blank(local_knowledge.seconded_in_group.len())); k.local_knowledge = Some(local_knowledge); } @@ -946,20 +960,24 @@ impl KnownBackedCandidate { validator: ValidatorIndex, remote_knowledge: StatementFilter, ) { - let k = self - .mutual_knowledge - .entry(validator) - .or_insert_with(|| MutualKnowledge { remote_knowledge: None, local_knowledge: None }); + let k = self.mutual_knowledge.entry(validator).or_insert_with(|| MutualKnowledge { + remote_knowledge: None, + local_knowledge: None, + received_knowledge: None, + }); k.remote_knowledge = Some(remote_knowledge); } + /// Returns a list of tuples representing each potential sender(ValidatorIndex) + /// and if the sender should already know about the statement, because we just + /// sent it to it. fn direct_statement_senders( &self, group_index: GroupIndex, originator_index_in_group: usize, statement_kind: StatementKind, - ) -> Vec { + ) -> Vec<(ValidatorIndex, bool)> { if group_index != self.group_index { return Vec::new() } @@ -968,11 +986,18 @@ impl KnownBackedCandidate { .iter() .filter(|(_, k)| k.remote_knowledge.is_some()) .filter(|(_, k)| { - k.local_knowledge + k.received_knowledge .as_ref() .map_or(false, |r| !r.contains(originator_index_in_group, statement_kind)) }) - .map(|(v, _)| *v) + .map(|(v, k)| { + ( + *v, + k.local_knowledge + .as_ref() + .map_or(false, |r| r.contains(originator_index_in_group, statement_kind)), + ) + }) .collect() } @@ -1014,12 +1039,19 @@ impl KnownBackedCandidate { validator: ValidatorIndex, statement_index_in_group: usize, statement_kind: StatementKind, + received: bool, ) { if let Some(k) = self.mutual_knowledge.get_mut(&validator) { if let (Some(r), Some(l)) = (k.remote_knowledge.as_mut(), k.local_knowledge.as_mut()) { r.set(statement_index_in_group, statement_kind); l.set(statement_index_in_group, statement_kind); } + + if received { + k.received_knowledge + .as_mut() + .map(|knowledge| knowledge.set(statement_index_in_group, statement_kind)); + } } } @@ -2238,6 +2270,7 @@ mod tests { validator_index, counterparty, &statement, + false, ); // There should be no pending statements now (for the counterparty). diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 52852657870db30c6851c563e1c9516b156c192e..2c9cdba4ea8eb1155f9307eb01460a777ae9a737 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -93,7 +93,19 @@ mod statement_store; #[cfg(test)] mod tests; -const COST_UNEXPECTED_STATEMENT: Rep = Rep::CostMinor("Unexpected Statement"); +const COST_UNEXPECTED_STATEMENT_NOT_VALIDATOR: Rep = + Rep::CostMinor("Unexpected Statement, not a validator"); +const COST_UNEXPECTED_STATEMENT_VALIDATOR_NOT_FOUND: Rep = + Rep::CostMinor("Unexpected Statement, validator not found"); +const COST_UNEXPECTED_STATEMENT_INVALID_SENDER: Rep = + Rep::CostMinor("Unexpected Statement, invalid sender"); +const COST_UNEXPECTED_STATEMENT_BAD_ADVERTISE: Rep = + Rep::CostMinor("Unexpected Statement, bad advertise"); +const COST_UNEXPECTED_STATEMENT_CLUSTER_REJECTED: Rep = + Rep::CostMinor("Unexpected Statement, cluster rejected"); +const COST_UNEXPECTED_STATEMENT_NOT_IN_GROUP: Rep = + Rep::CostMinor("Unexpected Statement, not in group"); + const COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE: Rep = Rep::CostMinor("Unexpected Statement, missing knowledge for relay parent"); const COST_EXCESSIVE_SECONDED: Rep = Rep::CostMinor("Sent Excessive `Seconded` Statements"); @@ -239,6 +251,13 @@ impl PerSessionState { if local_index.is_some() { self.local_validator.get_or_insert(LocalValidatorIndex::Inactive); } + + gum::info!( + target: LOG_TARGET, + index_in_gossip_topology = ?local_index, + index_in_parachain_authorities = ?self.local_validator, + "Node uses the following topology indices" + ); } /// Returns `true` if local is neither active or inactive validator node. @@ -756,7 +775,15 @@ pub(crate) fn handle_deactivate_leaves(state: &mut State, leaves: &[Hash]) { let pruned = state.implicit_view.deactivate_leaf(*leaf); for pruned_rp in pruned { // clean up per-relay-parent data based on everything removed. - state.per_relay_parent.remove(&pruned_rp); + state + .per_relay_parent + .remove(&pruned_rp) + .as_ref() + .and_then(|pruned| pruned.active_validator_state()) + .map(|active_state| { + active_state.cluster_tracker.warn_if_too_many_pending_statements(pruned_rp) + }); + // clean up requests related to this relay parent. state.request_manager.remove_by_relay_parent(*leaf); } @@ -1086,6 +1113,7 @@ async fn send_pending_grid_messages( originator, peer_validator_id, &compact, + false, ); } @@ -1378,6 +1406,7 @@ async fn circulate_statement( originator, target, &compact_statement, + false, ); }, } @@ -1515,7 +1544,13 @@ async fn handle_incoming_statement( // we shouldn't be receiving statements unless we're a validator // this session. if per_session.is_not_validator() { - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_STATEMENT_NOT_VALIDATOR, + ) + .await; } return }, @@ -1526,7 +1561,13 @@ async fn handle_incoming_statement( match per_session.groups.by_validator_index(statement.unchecked_validator_index()) { Some(g) => g, None => { - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_STATEMENT_VALIDATOR_NOT_FOUND, + ) + .await; return }, }; @@ -1565,38 +1606,45 @@ async fn handle_incoming_statement( (active, idx) }; - let checked_statement = - if let Some((active, cluster_sender_index)) = active.zip(cluster_sender_index) { - match handle_cluster_statement( - relay_parent, - &mut active.cluster_tracker, - per_relay_parent.session, - &per_session.session_info, - statement, - cluster_sender_index, - ) { - Ok(Some(s)) => s, - Ok(None) => return, - Err(rep) => { - modify_reputation(reputation, ctx.sender(), peer, rep).await; - return - }, - } - } else { - let grid_sender_index = local_validator - .grid_tracker - .direct_statement_providers( - &per_session.groups, - statement.unchecked_validator_index(), - statement.unchecked_payload(), - ) - .into_iter() - .filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (i, ad))) - .filter(|(_, ad)| peer_state.is_authority(ad)) - .map(|(i, _)| i) - .next(); + let checked_statement = if let Some((active, cluster_sender_index)) = + active.zip(cluster_sender_index) + { + match handle_cluster_statement( + relay_parent, + &mut active.cluster_tracker, + per_relay_parent.session, + &per_session.session_info, + statement, + cluster_sender_index, + ) { + Ok(Some(s)) => s, + Ok(None) => return, + Err(rep) => { + modify_reputation(reputation, ctx.sender(), peer, rep).await; + return + }, + } + } else { + let grid_sender_index = local_validator + .grid_tracker + .direct_statement_providers( + &per_session.groups, + statement.unchecked_validator_index(), + statement.unchecked_payload(), + ) + .into_iter() + .filter_map(|(i, validator_knows_statement)| { + session_info + .discovery_keys + .get(i.0 as usize) + .map(|ad| (i, ad, validator_knows_statement)) + }) + .filter(|(_, ad, _)| peer_state.is_authority(ad)) + .map(|(i, _, validator_knows_statement)| (i, validator_knows_statement)) + .next(); - if let Some(grid_sender_index) = grid_sender_index { + if let Some((grid_sender_index, validator_knows_statement)) = grid_sender_index { + if !validator_knows_statement { match handle_grid_statement( relay_parent, &mut local_validator.grid_tracker, @@ -1612,11 +1660,22 @@ async fn handle_incoming_statement( }, } } else { - // Not a cluster or grid peer. - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; - return + // Reward the peer for sending us the statement + modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT).await; + return; } - }; + } else { + // Not a cluster or grid peer. + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_STATEMENT_INVALID_SENDER, + ) + .await; + return + } + }; let statement = checked_statement.payload().clone(); let originator_index = checked_statement.validator_index(); @@ -1635,7 +1694,13 @@ async fn handle_incoming_statement( ); if let Err(BadAdvertisement) = res { - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_STATEMENT_BAD_ADVERTISE, + ) + .await; return } } @@ -1743,11 +1808,11 @@ fn handle_cluster_statement( Ok(ClusterAccept::WithPrejudice) => false, Err(ClusterRejectIncoming::ExcessiveSeconded) => return Err(COST_EXCESSIVE_SECONDED), Err(ClusterRejectIncoming::CandidateUnknown | ClusterRejectIncoming::Duplicate) => - return Err(COST_UNEXPECTED_STATEMENT), + return Err(COST_UNEXPECTED_STATEMENT_CLUSTER_REJECTED), Err(ClusterRejectIncoming::NotInGroup) => { // sanity: shouldn't be possible; we already filtered this // out above. - return Err(COST_UNEXPECTED_STATEMENT) + return Err(COST_UNEXPECTED_STATEMENT_NOT_IN_GROUP) }, } }; @@ -1798,6 +1863,7 @@ fn handle_grid_statement( checked_statement.validator_index(), grid_sender_index, &checked_statement.payload(), + true, ); Ok(checked_statement) @@ -2376,6 +2442,7 @@ fn post_acknowledgement_statement_messages( statement.validator_index(), recipient, statement.payload(), + false, ); match peer.1.into() { ValidationVersion::V2 => messages.push(Versioned::V2( @@ -3255,6 +3322,7 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { statement.unchecked_validator_index(), validator_id, statement.unchecked_payload(), + false, ); } } diff --git a/polkadot/node/network/statement-distribution/src/v2/requests.rs b/polkadot/node/network/statement-distribution/src/v2/requests.rs index bed3d5c18ae2b1007a3ee585f00a54d1b98f7c27..bbcb268415e67141ff1c620a134582d06bd8a67f 100644 --- a/polkadot/node/network/statement-distribution/src/v2/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/requests.rs @@ -315,7 +315,16 @@ impl RequestManager { request_props: impl Fn(&CandidateIdentifier) -> Option, peer_advertised: impl Fn(&CandidateIdentifier, &PeerId) -> Option, ) -> Option> { - if response_manager.len() >= MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS as usize { + // The number of parallel requests a node can answer is limited by + // `MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS`, however there is no + // need for the current node to limit itself to the same amount the + // requests, because the requests are going to different nodes anyways. + // While looking at https://github.com/paritytech/polkadot-sdk/issues/3314, + // found out that this requests take around 100ms to fullfill, so it + // would make sense to try to request things as early as we can, given + // we would need to request it for each candidate, around 25 right now + // on kusama. + if response_manager.len() >= 2 * MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS as usize { return None } @@ -1027,6 +1036,7 @@ mod tests { let peer_advertised = |_identifier: &CandidateIdentifier, _peer: &_| { Some(StatementFilter::full(group_size)) }; + let outgoing = request_manager .next_request(&mut response_manager, request_props, peer_advertised) .unwrap(); @@ -1148,6 +1158,7 @@ mod tests { { let request_props = |_identifier: &CandidateIdentifier| Some((&request_properties).clone()); + let outgoing = request_manager .next_request(&mut response_manager, request_props, peer_advertised) .unwrap(); @@ -1230,6 +1241,7 @@ mod tests { { let request_props = |_identifier: &CandidateIdentifier| Some((&request_properties).clone()); + let outgoing = request_manager .next_request(&mut response_manager, request_props, peer_advertised) .unwrap(); 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 7ffed9d47d4bdeca1800f7d665970cd1882ea7b2..a944a9cd6d021364d3b9fa7b349e9a649866cf29 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs @@ -170,7 +170,7 @@ fn cluster_valid_statement_before_seconded_ignored() { overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) => { assert_eq!(p, peer_a); - assert_eq!(r, COST_UNEXPECTED_STATEMENT.into()); + assert_eq!(r, COST_UNEXPECTED_STATEMENT_CLUSTER_REJECTED.into()); } ); @@ -305,7 +305,7 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() { assert_matches!( overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) - if p == peer_a && r == COST_UNEXPECTED_STATEMENT.into() => { } + if p == peer_a && r == COST_UNEXPECTED_STATEMENT_INVALID_SENDER.into() => { } ); overseer @@ -359,7 +359,7 @@ fn statement_from_non_cluster_originator_unexpected() { assert_matches!( overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) - if p == peer_a && r == COST_UNEXPECTED_STATEMENT.into() => { } + if p == peer_a && r == COST_UNEXPECTED_STATEMENT_INVALID_SENDER.into() => { } ); overseer diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index 157594a5099261ca3ced1dedba965c7885b3b348..b4541bcc346c8ce4282947c38e0d9a2591631090 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -22,9 +22,9 @@ sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compres sp-runtime = { path = "../../../substrate/primitives/runtime" } polkadot-parachain-primitives = { path = "../../parachain", default-features = false } schnorrkel = "0.11.4" -thiserror = "1.0.48" +thiserror = { workspace = true } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -serde = { version = "1.0.195", features = ["derive"] } +serde = { features = ["derive"], workspace = true, default-features = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] zstd = { version = "0.12.4", default-features = false } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index e7fd2c46381499f221913a01e7a9c3bc1dacc2d3..d295c21cce1dc9f609c8068fb806cff69612f7d6 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -58,7 +58,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.6.0"; +pub const NODE_VERSION: &'static str = "1.8.0"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 007e3dc595e9d49610e9d302fd28af712b27e300..180de70ad6c5c1a37cfbec46ff798b31c281083b 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -83,16 +83,17 @@ futures = "0.3.21" hex-literal = "0.4.1" is_executable = "1.0.1" gum = { package = "tracing-gum", path = "../gum" } -log = "0.4.17" +log = { workspace = true, default-features = true } schnellru = "0.2.1" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" -thiserror = "1.0.48" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } parity-db = { version = "0.4.12", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } parking_lot = "0.12.1" +bitvec = { version = "1.0.1", optional = true } # Polkadot polkadot-core-primitives = { path = "../../core-primitives" } @@ -184,8 +185,8 @@ full-node = [ ] # Configure the native runtimes to use. -westend-native = ["westend-runtime", "westend-runtime-constants"] -rococo-native = ["rococo-runtime", "rococo-runtime-constants"] +westend-native = ["bitvec", "westend-runtime", "westend-runtime-constants"] +rococo-native = ["bitvec", "rococo-runtime", "rococo-runtime-constants"] runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", @@ -195,6 +196,7 @@ runtime-benchmarks = [ "pallet-babe/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index 979550c7570643380c5a2e0f0f5de7c049c01f85..fd60cb8b6c1d443d47a85afcb7b885b4cf0593ae 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -16,8 +16,8 @@ "/dns/boot-node.helikon.io/tcp/7062/wss/p2p/12D3KooWL4KPqfAsPE2aY1g5Zo1CxsDwcdJ7mmAghK7cg6M2fdbD", "/dns/kusama.bootnode.amforc.com/tcp/30333/p2p/12D3KooWLx6nsj6Fpd8biP1VDyuCUjazvRiGWyBam8PsqRJkbUb9", "/dns/kusama.bootnode.amforc.com/tcp/30334/wss/p2p/12D3KooWLx6nsj6Fpd8biP1VDyuCUjazvRiGWyBam8PsqRJkbUb9", - "/dns/kusama-bootnode.polkadotters.com/tcp/30333/p2p/12D3KooWHB5rTeNkQdXNJ9ynvGz8Lpnmsctt7Tvp7mrYv6bcwbPG", - "/dns/kusama-bootnode.polkadotters.com/tcp/30334/wss/p2p/12D3KooWHB5rTeNkQdXNJ9ynvGz8Lpnmsctt7Tvp7mrYv6bcwbPG", + "/dns/kusama.bootnodes.polkadotters.com/tcp/30311/p2p/12D3KooWHB5rTeNkQdXNJ9ynvGz8Lpnmsctt7Tvp7mrYv6bcwbPG", + "/dns/kusama.bootnodes.polkadotters.com/tcp/30313/wss/p2p/12D3KooWHB5rTeNkQdXNJ9ynvGz8Lpnmsctt7Tvp7mrYv6bcwbPG", "/dns/boot-cr.gatotech.network/tcp/33200/p2p/12D3KooWRNZXf99BfzQDE1C8YhuBbuy7Sj18UEf7FNpD8egbURYD", "/dns/boot-cr.gatotech.network/tcp/35200/wss/p2p/12D3KooWRNZXf99BfzQDE1C8YhuBbuy7Sj18UEf7FNpD8egbURYD", "/dns/boot-kusama.metaspan.io/tcp/23012/p2p/12D3KooWE1tq9ZL9AAxMiUBBqy1ENmh5pwfWabnoBPMo8gFPXhn6", diff --git a/polkadot/node/service/chain-specs/paseo.json b/polkadot/node/service/chain-specs/paseo.json index c8f2b58533c62af5ee3b71ffa5d782c852edd162..8db75ff137b0dbe338859a22ad7361f413c0fbea 100644 --- a/polkadot/node/service/chain-specs/paseo.json +++ b/polkadot/node/service/chain-specs/paseo.json @@ -12,7 +12,9 @@ "/dns/boot-node.helikon.io/tcp/10020/p2p/12D3KooWBetfzZpf6tGihKrqCo5z854Ub4ZNAUUTRT6eYHNh7FYi", "/dns/boot-node.helikon.io/tcp/10022/wss/p2p/12D3KooWBetfzZpf6tGihKrqCo5z854Ub4ZNAUUTRT6eYHNh7FYi", "/dns/pso16.rotko.net/tcp/33246/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", - "/dns/pso16.rotko.net/tcp/35246/wss/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu" + "/dns/pso16.rotko.net/tcp/35246/wss/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", + "/dns/paseo.bootnodes.polkadotters.com/tcp/30538/p2p/12D3KooWPbbFy4TefEGTRF5eTYhq8LEzc4VAHdNUVCbY4nAnhqPP", + "/dns/paseo.bootnodes.polkadotters.com/tcp/30540/wss/p2p/12D3KooWPbbFy4TefEGTRF5eTYhq8LEzc4VAHdNUVCbY4nAnhqPP" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index 71dbb9004038d1394cebe568627e1e6163ee9049..c235cdd09d8b6eee517909052556a02427495d09 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -17,8 +17,8 @@ "/dns/boot-node.helikon.io/tcp/7072/wss/p2p/12D3KooWS9ZcvRxyzrSf6p63QfTCWs12nLoNKhGux865crgxVA4H", "/dns/polkadot.bootnode.amforc.com/tcp/30333/p2p/12D3KooWAsuCEVCzUVUrtib8W82Yne3jgVGhQZN3hizko5FTnDg3", "/dns/polkadot.bootnode.amforc.com/tcp/30334/wss/p2p/12D3KooWAsuCEVCzUVUrtib8W82Yne3jgVGhQZN3hizko5FTnDg3", - "/dns/polkadot-bootnode.polkadotters.com/tcp/30333/p2p/12D3KooWPAVUgBaBk6n8SztLrMk8ESByncbAfRKUdxY1nygb9zG3", - "/dns/polkadot-bootnode.polkadotters.com/tcp/30334/wss/p2p/12D3KooWPAVUgBaBk6n8SztLrMk8ESByncbAfRKUdxY1nygb9zG3", + "/dns/polkadot.bootnodes.polkadotters.com/tcp/30314/p2p/12D3KooWPAVUgBaBk6n8SztLrMk8ESByncbAfRKUdxY1nygb9zG3", + "/dns/polkadot.bootnodes.polkadotters.com/tcp/30316/wss/p2p/12D3KooWPAVUgBaBk6n8SztLrMk8ESByncbAfRKUdxY1nygb9zG3", "/dns/boot-cr.gatotech.network/tcp/33100/p2p/12D3KooWK4E16jKk9nRhvC4RfrDVgcZzExg8Q3Q2G7ABUUitks1w", "/dns/boot-cr.gatotech.network/tcp/35100/wss/p2p/12D3KooWK4E16jKk9nRhvC4RfrDVgcZzExg8Q3Q2G7ABUUitks1w", "/dns/boot-polkadot.metaspan.io/tcp/13012/p2p/12D3KooWRjHFApinuqSBjoaDjQHvxwubQSpEVy5hrgC9Smvh92WF", diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index 697675871fcd7b4b11cac5a25e71c704d471cbde..775f3e72ac75578a0f0166cba96531244af760c9 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -14,8 +14,8 @@ "/dns/boot-node.helikon.io/tcp/7082/wss/p2p/12D3KooWRFDPyT8vA8mLzh6dJoyujn4QNjeqi6Ch79eSMz9beKXC", "/dns/westend.bootnode.amforc.com/tcp/30333/p2p/12D3KooWJ5y9ZgVepBQNW4aabrxgmnrApdVnscqgKWiUu4BNJbC8", "/dns/westend.bootnode.amforc.com/tcp/30334/wss/p2p/12D3KooWJ5y9ZgVepBQNW4aabrxgmnrApdVnscqgKWiUu4BNJbC8", - "/dns/westend-bootnode.polkadotters.com/tcp/30333/p2p/12D3KooWHPHb64jXMtSRJDrYFATWeLnvChL8NtWVttY67DCH1eC5", - "/dns/westend-bootnode.polkadotters.com/tcp/30334/wss/p2p/12D3KooWHPHb64jXMtSRJDrYFATWeLnvChL8NtWVttY67DCH1eC5", + "/dns/westend.bootnodes.polkadotters.com/tcp/30308/p2p/12D3KooWHPHb64jXMtSRJDrYFATWeLnvChL8NtWVttY67DCH1eC5", + "/dns/westend.bootnodes.polkadotters.com/tcp/30310/wss/p2p/12D3KooWHPHb64jXMtSRJDrYFATWeLnvChL8NtWVttY67DCH1eC5", "/dns/boot-cr.gatotech.network/tcp/33300/p2p/12D3KooWQGR1vUhoy6mvQorFp3bZFn6NNezhQZ6NWnVV7tpFgoPd", "/dns/boot-cr.gatotech.network/tcp/35300/wss/p2p/12D3KooWQGR1vUhoy6mvQorFp3bZFn6NNezhQZ6NWnVV7tpFgoPd", "/dns/boot-westend.metaspan.io/tcp/33012/p2p/12D3KooWNTau7iG4G9cUJSwwt2QJP1W88pUf2SgqsHjRU2RL8pfa", diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index 400daf1aee3448f841f9030f24b78a0029fc0830..29acc5c3ca8c3af835e5ea46e14a31e3361162af 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -189,7 +189,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(), @@ -201,11 +201,12 @@ fn westend_sign_call( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), - ); + ) + .into(); let payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -223,7 +224,7 @@ fn westend_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature.clone()), - extra, + tx_ext, ) .into() } @@ -241,7 +242,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(), @@ -253,11 +254,12 @@ fn rococo_sign_call( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), - ); + ) + .into(); let payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -275,7 +277,7 @@ fn rococo_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature.clone()), - extra, + tx_ext, ) .into() } diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index af241d1cbc558c849bbf533dd644848b20fa4491..1c44b17b6fd24810bf896a64953a1b2f53b490da 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -24,6 +24,8 @@ use polkadot_primitives::{AccountId, AccountPublic, AssignmentId, ValidatorId}; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; +#[cfg(any(feature = "rococo-native", feature = "westend-native",))] +use polkadot_primitives::vstaging::SchedulerParams; #[cfg(feature = "rococo-native")] use rococo_runtime as rococo; #[cfg(feature = "rococo-native")] @@ -120,7 +122,9 @@ pub fn wococo_config() -> Result { fn default_parachains_host_configuration( ) -> polkadot_runtime_parachains::configuration::HostConfiguration { - use polkadot_primitives::{AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE}; + use polkadot_primitives::{ + vstaging::node_features::FeatureIndex, AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE, + }; polkadot_runtime_parachains::configuration::HostConfiguration { validation_upgrade_cooldown: 2u32, @@ -129,8 +133,6 @@ fn default_parachains_host_configuration( max_code_size: MAX_CODE_SIZE, max_pov_size: MAX_POV_SIZE, max_head_data_size: 32 * 1024, - group_rotation_frequency: 20, - paras_availability_period: 4, max_upward_queue_count: 8, max_upward_queue_size: 1024 * 1024, max_downward_message_size: 1024 * 1024, @@ -151,11 +153,19 @@ fn default_parachains_host_configuration( relay_vrf_modulo_samples: 2, zeroth_delay_tranche_width: 0, minimum_validation_upgrade_delay: 5, - scheduling_lookahead: 2, async_backing_params: AsyncBackingParams { max_candidate_depth: 3, allowed_ancestry_len: 2, }, + node_features: bitvec::vec::BitVec::from_element( + 1u8 << (FeatureIndex::ElasticScalingMVP as usize), + ), + scheduler_params: SchedulerParams { + lookahead: 2, + group_rotation_frequency: 20, + paras_availability_period: 4, + ..Default::default() + }, ..Default::default() } } @@ -891,7 +901,10 @@ pub fn rococo_testnet_genesis( "sudo": { "key": Some(root_key.clone()) }, "configuration": { "config": polkadot_runtime_parachains::configuration::HostConfiguration { - max_validators_per_core: Some(1), + scheduler_params: SchedulerParams { + max_validators_per_core: Some(1), + ..default_parachains_host_configuration().scheduler_params + }, ..default_parachains_host_configuration() }, }, diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index ccc3da22400dfc38f5e94aa4f6e89969499dbee8..085ea93fdc78526f793b726bf385124ec6418e5d 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -60,7 +60,7 @@ sp_api::impl_runtime_apis! { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 6dcdec07ca84bd0fe9456e2bc29cbdf6cee6a9f8..83a0afc077e7edfb4a60fb8ed4109157f020695b 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -92,6 +92,7 @@ pub use chain_spec::{GenericChainSpec, RococoChainSpec, WestendChainSpec}; pub use consensus_common::{Proposal, SelectChain}; use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use mmr_gadget::MmrGadget; +use polkadot_node_subsystem_types::DefaultSubsystemClient; pub use polkadot_primitives::{Block, BlockId, BlockNumber, CollatorPair, Hash, Id as ParaId}; pub use sc_client_api::{Backend, CallExecutor}; pub use sc_consensus::{BlockImport, LongestChain}; @@ -1081,12 +1082,17 @@ pub fn new_full( None }; + let runtime_client = Arc::new(DefaultSubsystemClient::new( + overseer_client.clone(), + OffchainTransactionPoolFactory::new(transaction_pool.clone()), + )); + let overseer_handle = if let Some(authority_discovery_service) = authority_discovery_service { let (overseer, overseer_handle) = overseer_gen - .generate::( + .generate::>( overseer_connector, OverseerGenArgs { - runtime_client: overseer_client.clone(), + runtime_client, network_service: network.clone(), sync_service: sync_service.clone(), authority_discovery_service, @@ -1099,9 +1105,6 @@ pub fn new_full( overseer_message_channel_capacity_override, req_protocol_names, peerset_protocol_names, - offchain_transaction_pool_factory: OffchainTransactionPoolFactory::new( - transaction_pool.clone(), - ), notification_services, }, ext_overseer_args, diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index b2b0786bfc24e5f702ddd82aec0676f0f9f795a8..a8167370464937ac91ae44056ea0b17b7184927a 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -14,10 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use super::{AuthorityDiscoveryApi, Block, Error, Hash, IsParachainNode, Registry}; -use polkadot_node_subsystem_types::DefaultSubsystemClient; +use super::{Block, Error, Hash, IsParachainNode, Registry}; +use polkadot_node_subsystem_types::{ChainApiBackend, RuntimeApiSubsystemClient}; use polkadot_overseer::{DummySubsystem, InitializedOverseerBuilder, SubsystemError}; -use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_core::traits::SpawnNamed; use polkadot_availability_distribution::IncomingRequestReceivers; @@ -40,14 +39,10 @@ use polkadot_overseer::{ }; use parking_lot::Mutex; -use polkadot_primitives::runtime_api::ParachainHost; use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_client_api::AuxStore; use sc_keystore::LocalKeystore; use sc_network::{NetworkStateInfo, NotificationService}; -use sp_api::ProvideRuntimeApi; -use sp_blockchain::HeaderBackend; -use sp_consensus_babe::BabeApi; use std::{collections::HashMap, sync::Arc}; pub use polkadot_approval_distribution::ApprovalDistribution as ApprovalDistributionSubsystem; @@ -80,8 +75,6 @@ pub use polkadot_statement_distribution::StatementDistributionSubsystem; /// Arguments passed for overseer construction. pub struct OverseerGenArgs<'a, Spawner, RuntimeClient> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, Spawner: 'static + SpawnNamed + Clone + Unpin, { /// Runtime client generic, providing the `ProvieRuntimeApi` trait besides others. @@ -89,7 +82,7 @@ where /// Underlying network service implementation. pub network_service: Arc>, /// Underlying syncing service implementation. - pub sync_service: Arc>, + pub sync_service: Arc, /// Underlying authority discovery service. pub authority_discovery_service: AuthorityDiscoveryService, /// Collations request receiver for network protocol v1. @@ -111,8 +104,6 @@ where pub req_protocol_names: ReqProtocolNames, /// `PeerSet` protocol names to protocols mapping. pub peerset_protocol_names: PeerSetProtocolNames, - /// The offchain transaction pool factory. - pub offchain_transaction_pool_factory: OffchainTransactionPoolFactory, /// Notification services for validation/collation protocols. pub notification_services: HashMap>, } @@ -160,7 +151,6 @@ pub fn validator_overseer_builder( overseer_message_channel_capacity_override, req_protocol_names, peerset_protocol_names, - offchain_transaction_pool_factory, notification_services, }: OverseerGenArgs, ExtendedOverseerGenArgs { @@ -180,7 +170,7 @@ pub fn validator_overseer_builder( ) -> Result< InitializedOverseerBuilder< SpawnGlue, - Arc>, + Arc, CandidateValidationSubsystem, PvfCheckerSubsystem, CandidateBackingSubsystem, @@ -190,7 +180,7 @@ pub fn validator_overseer_builder( BitfieldSigningSubsystem, BitfieldDistributionSubsystem, ProvisionerSubsystem, - RuntimeApiSubsystem>, + RuntimeApiSubsystem, AvailabilityStoreSubsystem, NetworkBridgeRxSubsystem< Arc>, @@ -214,8 +204,7 @@ pub fn validator_overseer_builder( Error, > where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { use polkadot_node_subsystem_util::metrics::Metrics; @@ -227,11 +216,6 @@ where let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; - let runtime_api_client = Arc::new(DefaultSubsystemClient::new( - runtime_client.clone(), - offchain_transaction_pool_factory, - )); - let builder = Overseer::builder() .network_bridge_tx(NetworkBridgeTxSubsystem::new( network_service.clone(), @@ -298,7 +282,7 @@ where }) .provisioner(ProvisionerSubsystem::new(Metrics::register(registry)?)) .runtime_api(RuntimeApiSubsystem::new( - runtime_api_client.clone(), + runtime_client.clone(), Metrics::register(registry)?, spawner.clone(), )) @@ -339,7 +323,7 @@ where .activation_external_listeners(Default::default()) .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) - .supports_parachains(runtime_api_client) + .supports_parachains(runtime_client) .metrics(metrics) .spawner(spawner); @@ -367,13 +351,12 @@ pub fn collator_overseer_builder( overseer_message_channel_capacity_override, req_protocol_names, peerset_protocol_names, - offchain_transaction_pool_factory, notification_services, }: OverseerGenArgs, ) -> Result< InitializedOverseerBuilder< SpawnGlue, - Arc>, + Arc, DummySubsystem, DummySubsystem, DummySubsystem, @@ -383,7 +366,7 @@ pub fn collator_overseer_builder( DummySubsystem, DummySubsystem, DummySubsystem, - RuntimeApiSubsystem>, + RuntimeApiSubsystem, DummySubsystem, NetworkBridgeRxSubsystem< Arc>, @@ -407,24 +390,17 @@ pub fn collator_overseer_builder( Error, > where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, Spawner: 'static + SpawnNamed + Clone + Unpin, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, { use polkadot_node_subsystem_util::metrics::Metrics; - let metrics = ::register(registry)?; let notification_sinks = Arc::new(Mutex::new(HashMap::new())); let spawner = SpawnGlue(spawner); let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; - let runtime_api_client = Arc::new(DefaultSubsystemClient::new( - runtime_client.clone(), - offchain_transaction_pool_factory, - )); - let builder = Overseer::builder() .network_bridge_tx(NetworkBridgeTxSubsystem::new( network_service.clone(), @@ -475,7 +451,7 @@ where }) .provisioner(DummySubsystem) .runtime_api(RuntimeApiSubsystem::new( - runtime_api_client.clone(), + runtime_client.clone(), Metrics::register(registry)?, spawner.clone(), )) @@ -490,8 +466,8 @@ where .activation_external_listeners(Default::default()) .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) - .supports_parachains(runtime_api_client) - .metrics(metrics) + .supports_parachains(runtime_client) + .metrics(Metrics::register(registry)?) .spawner(spawner); let builder = if let Some(capacity) = overseer_message_channel_capacity_override { @@ -510,13 +486,9 @@ pub trait OverseerGen { connector: OverseerConnector, args: OverseerGenArgs, ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin; // It would be nice to make `create_subsystems` part of this trait, @@ -533,13 +505,9 @@ impl OverseerGen for ValidatorOverseerGen { connector: OverseerConnector, args: OverseerGenArgs, ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { let ext_args = ext_args.ok_or(Error::Overseer(SubsystemError::Context( @@ -561,13 +529,9 @@ impl OverseerGen for CollatorOverseerGen { connector: OverseerConnector, args: OverseerGenArgs, _ext_args: Option, - ) -> Result< - (Overseer, Arc>>, OverseerHandle), - Error, - > + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { collator_overseer_builder(args)? diff --git a/polkadot/node/service/src/parachains_db/upgrade.rs b/polkadot/node/service/src/parachains_db/upgrade.rs index d22eebb5c8d4edebdd2174f3cb1ba144fea0b130..2eceb391b15c278825b243fdb8dc21e8ef540390 100644 --- a/polkadot/node/service/src/parachains_db/upgrade.rs +++ b/polkadot/node/service/src/parachains_db/upgrade.rs @@ -93,7 +93,7 @@ pub(crate) fn try_upgrade_db( } /// Try upgrading parachain's database to the next version. -/// If successfull, it returns the current version. +/// If successful, it returns the current version. pub(crate) fn try_upgrade_db_to_next_version( db_path: &Path, db_kind: DatabaseKind, diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 136eccbf685482f05b34b8de20007c7ef548320d..7c60ff48269c41c291b1649fe58c75056cc50f9a 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -8,9 +8,13 @@ license.workspace = true readme = "README.md" publish = false +[lib] +name = "polkadot_subsystem_bench" +path = "src/lib/lib.rs" + [[bin]] name = "subsystem-bench" -path = "src/subsystem-bench.rs" +path = "src/cli/subsystem-bench.rs" # Prevent rustdoc error. Already documented from top-level Cargo.toml. doc = false @@ -35,7 +39,7 @@ async-trait = "0.1.57" sp-keystore = { path = "../../../substrate/primitives/keystore" } sc-keystore = { path = "../../../substrate/client/keystore" } sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" bincode = "1.3.3" @@ -43,7 +47,7 @@ sha1 = "0.10.6" hex = "0.4.3" gum = { package = "tracing-gum", path = "../gum" } polkadot-erasure-coding = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } -log = "0.4.17" +log = { workspace = true, default-features = true } env_logger = "0.9.0" rand = "0.8.5" # `rand` only supports uniform distribution, we need normal distribution for latency. @@ -65,8 +69,8 @@ itertools = "0.11.0" polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } prometheus_endpoint = { package = "substrate-prometheus-endpoint", path = "../../../substrate/utils/prometheus" } prometheus = { version = "0.13.0", default-features = false } -serde = "1.0.195" -serde_yaml = "0.9" +serde = { workspace = true, default-features = true } +serde_yaml = { workspace = true } polkadot-node-core-approval-voting = { path = "../core/approval-voting" } polkadot-approval-distribution = { path = "../network/approval-distribution" } @@ -74,8 +78,9 @@ sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-timestamp = { path = "../../../substrate/primitives/timestamp" } -schnorrkel = { version = "0.9.1", default-features = false } -rand_core = "0.6.2" # should match schnorrkel +schnorrkel = { version = "0.11.4", default-features = false } +# rand_core should match schnorrkel +rand_core = "0.6.2" rand_chacha = { version = "0.3.1" } paste = "1.0.14" orchestra = { version = "0.3.5", default-features = false, features = ["futures_channel"] } diff --git a/polkadot/node/subsystem-bench/README.md b/polkadot/node/subsystem-bench/README.md index e090a0392cb733ffc2a4b21edc73da44e5aed708..94a449ed0bb8949816ac7aa5671883b6cb17100c 100644 --- a/polkadot/node/subsystem-bench/README.md +++ b/polkadot/node/subsystem-bench/README.md @@ -1,6 +1,6 @@ # Subsystem benchmark client -Run parachain consensus stress and performance tests on your development machine. +Run parachain consensus stress and performance tests on your development machine or in CI. ## Motivation @@ -32,7 +32,8 @@ a local Grafana/Prometheus stack is needed. ### Run Prometheus, Pyroscope and Graphana in Docker -If docker is not usable, then follow the next sections to manually install Prometheus, Pyroscope and Graphana on your machine. +If docker is not usable, then follow the next sections to manually install Prometheus, Pyroscope and Graphana +on your machine. ```bash cd polkadot/node/subsystem-bench/docker @@ -44,7 +45,7 @@ docker compose up Please follow the [official installation guide](https://prometheus.io/docs/prometheus/latest/installation/) for your platform/OS. -After succesfully installing and starting up Prometheus, we need to alter it's configuration such that it +After successfully installing and starting up Prometheus, we need to alter it's configuration such that it will scrape the benchmark prometheus endpoint `127.0.0.1:9999`. Please check the prometheus official documentation regarding the location of `prometheus.yml`. On MacOS for example the full path `/opt/homebrew/etc/prometheus.yml` @@ -95,39 +96,16 @@ If you are running the servers in Docker, use the following URLs: Follow [this guide](https://grafana.com/docs/grafana/latest/dashboards/manage-dashboards/#export-and-import-dashboards) to import the dashboards from the repository `grafana` folder. -## How to run a test - -To run a test, you need to first choose a test objective. Currently, we support the following: - -``` -target/testnet/subsystem-bench --help -The almighty Subsystem Benchmark Tool™️ - -Usage: subsystem-bench [OPTIONS] - -Commands: - data-availability-read Benchmark availability recovery strategies +### Standard test options ``` +$ subsystem-bench --help +Usage: subsystem-bench [OPTIONS] -Note: `test-sequence` is a special test objective that wraps up an arbitrary number of test objectives. It is tipically - used to run a suite of tests defined in a `yaml` file like in this [example](examples/availability_read.yaml). +Arguments: + Path to the test sequence configuration file -### Standard test options - -``` - --network The type of network to be emulated [default: ideal] [possible values: ideal, healthy, - degraded] - --n-cores Number of cores to fetch availability for [default: 100] - --n-validators Number of validators to fetch chunks from [default: 500] - --min-pov-size The minimum pov size in KiB [default: 5120] - --max-pov-size The maximum pov size bytes [default: 5120] - -n, --num-blocks The number of blocks the test is going to run [default: 1] - -p, --peer-bandwidth The bandwidth of emulated remote peers in KiB - -b, --bandwidth The bandwidth of our node in KiB - --connectivity Emulated peer connection ratio [0-100] - --peer-mean-latency Mean remote peer latency in milliseconds [0-5000] - --peer-latency-std-dev Remote peer latency standard deviation +Options: --profile Enable CPU Profiling with Pyroscope --pyroscope-url Pyroscope Server URL [default: http://localhost:4040] --pyroscope-sample-rate Pyroscope Sample Rate [default: 113] @@ -135,27 +113,17 @@ Note: `test-sequence` is a special test objective that wraps up an arbitrary num -h, --help Print help ``` -These apply to all test objectives, except `test-sequence` which relies on the values being specified in a file. - -### Test objectives - -Each test objective can have it's specific configuration options, in contrast with the standard test options. +## How to run a test -For `data-availability-read` the recovery strategy to be used is configurable. +To run a test, you need to use a path to a test objective: ``` -target/testnet/subsystem-bench data-availability-read --help -Benchmark availability recovery strategies - -Usage: subsystem-bench data-availability-read [OPTIONS] - -Options: - -f, --fetch-from-backers Turbo boost AD Read by fetching the full availability datafrom backers first. Saves CPU - as we don't need to re-construct from chunks. Tipically this is only faster if nodes - have enough bandwidth - -h, --help Print help +target/testnet/subsystem-bench polkadot/node/subsystem-bench/examples/availability_read.yaml ``` +Note: test objectives may be wrapped up into a test sequence. +It is tipically used to run a suite of tests like in this [example](examples/availability_read.yaml). + ### Understanding the test configuration A single test configuration `TestConfiguration` struct applies to a single run of a certain test objective. @@ -175,36 +143,65 @@ the test is started. ### Example run -Let's run an availabilty read test which will recover availability for 10 cores with max PoV size on a 500 +Let's run an availabilty read test which will recover availability for 200 cores with max PoV size on a 1000 node validator network. + + ``` - target/testnet/subsystem-bench --n-cores 10 data-availability-read -[2023-11-28T09:01:59Z INFO subsystem_bench::core::display] n_validators = 500, n_cores = 10, pov_size = 5120 - 5120, - latency = None -[2023-11-28T09:01:59Z INFO subsystem-bench::availability] Generating template candidate index=0 pov_size=5242880 -[2023-11-28T09:01:59Z INFO subsystem-bench::availability] Created test environment. -[2023-11-28T09:01:59Z INFO subsystem-bench::availability] Pre-generating 10 candidates. -[2023-11-28T09:02:01Z INFO subsystem-bench::core] Initializing network emulation for 500 peers. -[2023-11-28T09:02:01Z INFO substrate_prometheus_endpoint] 〽️ Prometheus exporter started at 127.0.0.1:9999 -[2023-11-28T09:02:01Z INFO subsystem-bench::availability] Current block 1/1 -[2023-11-28T09:02:01Z INFO subsystem_bench::availability] 10 recoveries pending -[2023-11-28T09:02:04Z INFO subsystem_bench::availability] Block time 3231ms -[2023-11-28T09:02:04Z INFO subsystem-bench::availability] Sleeping till end of block (2768ms) -[2023-11-28T09:02:07Z INFO subsystem_bench::availability] All blocks processed in 6001ms -[2023-11-28T09:02:07Z INFO subsystem_bench::availability] Throughput: 51200 KiB/block -[2023-11-28T09:02:07Z INFO subsystem_bench::availability] Block time: 6001 ms -[2023-11-28T09:02:07Z INFO subsystem_bench::availability] - - Total received from network: 66 MiB - Total sent to network: 58 KiB - Total subsystem CPU usage 4.16s - CPU usage per block 4.16s - Total test environment CPU usage 0.00s - CPU usage per block 0.00s +target/testnet/subsystem-bench polkadot/node/subsystem-bench/examples/availability_write.yaml +[2024-02-19T14:10:32.981Z INFO subsystem_bench] Sequence contains 1 step(s) +[2024-02-19T14:10:32.981Z INFO subsystem-bench::cli] Step 1/1 +[2024-02-19T14:10:32.981Z INFO subsystem-bench::cli] [objective = DataAvailabilityWrite] n_validators = 1000, n_cores = 200, pov_size = 5120 - 5120, connectivity = 75, latency = Some(PeerLatency { mean_latency_ms: 30, std_dev: 2.0 }) +[2024-02-19T14:10:32.982Z INFO subsystem-bench::availability] Generating template candidate index=0 pov_size=5242880 +[2024-02-19T14:10:33.106Z INFO subsystem-bench::availability] Created test environment. +[2024-02-19T14:10:33.106Z INFO subsystem-bench::availability] Pre-generating 600 candidates. +[2024-02-19T14:10:34.096Z INFO subsystem-bench::network] Initializing emulation for a 1000 peer network. +[2024-02-19T14:10:34.096Z INFO subsystem-bench::network] connectivity 75%, latency Some(PeerLatency { mean_latency_ms: 30, std_dev: 2.0 }) +[2024-02-19T14:10:34.098Z INFO subsystem-bench::network] Network created, connected validator count 749 +[2024-02-19T14:10:34.099Z INFO subsystem-bench::availability] Seeding availability store with candidates ... +[2024-02-19T14:10:34.100Z INFO substrate_prometheus_endpoint] 〽️ Prometheus exporter started at 127.0.0.1:9999 +[2024-02-19T14:10:34.387Z INFO subsystem-bench::availability] Done +[2024-02-19T14:10:34.387Z INFO subsystem-bench::availability] Current block #1 +[2024-02-19T14:10:34.389Z INFO subsystem-bench::availability] Waiting for all emulated peers to receive their chunk from us ... +[2024-02-19T14:10:34.625Z INFO subsystem-bench::availability] All chunks received in 237ms +[2024-02-19T14:10:34.626Z INFO polkadot_subsystem_bench::availability] Waiting for 749 bitfields to be received and processed +[2024-02-19T14:10:35.710Z INFO subsystem-bench::availability] All bitfields processed +[2024-02-19T14:10:35.710Z INFO subsystem-bench::availability] All work for block completed in 1322ms +[2024-02-19T14:10:35.710Z INFO subsystem-bench::availability] Current block #2 +[2024-02-19T14:10:35.712Z INFO subsystem-bench::availability] Waiting for all emulated peers to receive their chunk from us ... +[2024-02-19T14:10:35.947Z INFO subsystem-bench::availability] All chunks received in 236ms +[2024-02-19T14:10:35.947Z INFO polkadot_subsystem_bench::availability] Waiting for 749 bitfields to be received and processed +[2024-02-19T14:10:37.038Z INFO subsystem-bench::availability] All bitfields processed +[2024-02-19T14:10:37.038Z INFO subsystem-bench::availability] All work for block completed in 1328ms +[2024-02-19T14:10:37.039Z INFO subsystem-bench::availability] Current block #3 +[2024-02-19T14:10:37.040Z INFO subsystem-bench::availability] Waiting for all emulated peers to receive their chunk from us ... +[2024-02-19T14:10:37.276Z INFO subsystem-bench::availability] All chunks received in 237ms +[2024-02-19T14:10:37.276Z INFO polkadot_subsystem_bench::availability] Waiting for 749 bitfields to be received and processed +[2024-02-19T14:10:38.362Z INFO subsystem-bench::availability] All bitfields processed +[2024-02-19T14:10:38.362Z INFO subsystem-bench::availability] All work for block completed in 1323ms +[2024-02-19T14:10:38.362Z INFO subsystem-bench::availability] All blocks processed in 3974ms +[2024-02-19T14:10:38.362Z INFO subsystem-bench::availability] Avg block time: 1324 ms +[2024-02-19T14:10:38.362Z INFO parachain::availability-store] received `Conclude` signal, exiting +[2024-02-19T14:10:38.362Z INFO parachain::bitfield-distribution] Conclude +[2024-02-19T14:10:38.362Z INFO subsystem-bench::network] Downlink channel closed, network interface task exiting + +polkadot/node/subsystem-bench/examples/availability_write.yaml #1 DataAvailabilityWrite + +Network usage, KiB total per block +Received from peers 12922.000 4307.333 +Sent to peers 47705.000 15901.667 + +CPU usage, seconds total per block +availability-distribution 0.045 0.015 +bitfield-distribution 0.104 0.035 +availability-store 0.304 0.101 +Test environment 3.213 1.071 ``` -`Block time` in the context of `data-availability-read` has a different meaning. It measures the amount of time it + + +`Block time` in the current context has a different meaning. It measures the amount of time it took the subsystem to finish processing all of the messages sent in the context of the current test block. ### Test logs @@ -214,7 +211,7 @@ You can select log target, subtarget and verbosity just like with Polkadot node ### View test metrics -Assuming the Grafana/Prometheus stack installation steps completed succesfully, you should be able to +Assuming the Grafana/Prometheus stack installation steps completed successfully, you should be able to view the test progress in real time by accessing [this link](http://localhost:3000/goto/SM5B8pNSR?orgId=1). Now run @@ -233,8 +230,9 @@ Since the execution will be very slow, it's recommended not to run it together w benchmark results into account. A report is saved in a file `cachegrind_report.txt`. Example run results: + ``` -$ target/testnet/subsystem-bench --n-cores 10 --cache-misses data-availability-read +$ target/testnet/subsystem-bench --cache-misses cache-misses-data-availability-read.yaml $ cat cachegrind_report.txt I refs: 64,622,081,485 I1 misses: 3,018,168 @@ -275,7 +273,7 @@ happy and negative scenarios (low bandwidth, network errors and low connectivity To faster write a new test objective you need to use some higher level wrappers and logic: `TestEnvironment`, `TestConfiguration`, `TestAuthorities`, `NetworkEmulator`. To create the `TestEnvironment` you will -need to also build an `Overseer`, but that should be easy using the mockups for subsystems in`core::mock`. +need to also build an `Overseer`, but that should be easy using the mockups for subsystems in `mock`. ### Mocking diff --git a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml index 758c7fbbf1121a249ff3094bc74967e3ad2420da..146da57d44c4aaf973e13c886a357028cdbe3559 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml @@ -1,14 +1,14 @@ TestConfiguration: # Test 1 - objective: !ApprovalVoting - last_considered_tranche: 89 coalesce_mean: 3.0 coalesce_std_dev: 1.0 + enable_assignments_v2: true + last_considered_tranche: 89 stop_when_approved: true coalesce_tranche_diff: 12 - workdir_prefix: "/tmp/" - enable_assignments_v2: true num_no_shows_per_candidate: 10 + workdir_prefix: "/tmp/" n_validators: 500 n_cores: 100 min_pov_size: 1120 diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml index 9eeeefc53a4277aae51e44ee5940a2eb65111cd3..6b17e62c20aa3f69153fb596d1a303a2e0320ddd 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml @@ -7,11 +7,10 @@ TestConfiguration: last_considered_tranche: 89 stop_when_approved: false coalesce_tranche_diff: 12 - workdir_prefix: "/tmp" num_no_shows_per_candidate: 0 + workdir_prefix: "/tmp" n_validators: 500 n_cores: 100 - n_included_candidates: 100 min_pov_size: 1120 max_pov_size: 5120 peer_bandwidth: 524288000000 diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml index 370bb31a5c4c102174c29382ab6de70ca336278e..e946c28e8ef5d4e38736ffc21e56d8b1c6cd0ddc 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml @@ -7,8 +7,8 @@ TestConfiguration: last_considered_tranche: 89 stop_when_approved: true coalesce_tranche_diff: 12 - workdir_prefix: "/tmp/" num_no_shows_per_candidate: 0 + workdir_prefix: "/tmp/" n_validators: 500 n_cores: 100 min_pov_size: 1120 diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml index 30b9ac8dc50fec25bc4952ef3706f9878aa2bbd7..8f4b050e72f27dd4b5bb0c52bd49162cd0bb83ec 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput_no_optimisations_enabled.yaml @@ -7,8 +7,8 @@ TestConfiguration: last_considered_tranche: 89 stop_when_approved: false coalesce_tranche_diff: 12 - workdir_prefix: "/tmp/" num_no_shows_per_candidate: 0 + workdir_prefix: "/tmp/" n_validators: 500 n_cores: 100 min_pov_size: 1120 diff --git a/polkadot/node/subsystem-bench/src/availability/cli.rs b/polkadot/node/subsystem-bench/src/availability/cli.rs deleted file mode 100644 index 65df8c1552aa8266497eb2738cc562f656050b68..0000000000000000000000000000000000000000 --- a/polkadot/node/subsystem-bench/src/availability/cli.rs +++ /dev/null @@ -1,37 +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 serde::{Deserialize, Serialize}; - -#[derive(clap::ValueEnum, Clone, Copy, Debug, PartialEq)] -#[value(rename_all = "kebab-case")] -#[non_exhaustive] -pub enum NetworkEmulation { - Ideal, - Healthy, - Degraded, -} - -#[derive(Debug, Clone, Serialize, Deserialize, clap::Parser)] -#[clap(rename_all = "kebab-case")] -#[allow(missing_docs)] -pub struct DataAvailabilityReadOptions { - #[clap(short, long, default_value_t = false)] - /// Turbo boost AD Read by fetching the full availability datafrom backers first. Saves CPU as - /// we don't need to re-construct from chunks. Tipically this is only faster if nodes have - /// enough bandwidth. - pub fetch_from_backers: bool, -} diff --git a/polkadot/node/subsystem-bench/src/cli.rs b/polkadot/node/subsystem-bench/src/cli.rs deleted file mode 100644 index 21f5e6a85629392654c5c41556a6797c5d47e192..0000000000000000000000000000000000000000 --- a/polkadot/node/subsystem-bench/src/cli.rs +++ /dev/null @@ -1,82 +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::availability::DataAvailabilityReadOptions; -use crate::approval::ApprovalsOptions; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize, clap::Parser)] -#[clap(rename_all = "kebab-case")] -#[allow(missing_docs)] -pub struct TestSequenceOptions { - #[clap(short, long, ignore_case = true)] - pub path: String, -} - -/// Supported test objectives -#[derive(Debug, Clone, clap::Parser, Serialize, Deserialize)] -#[command(rename_all = "kebab-case")] -pub enum TestObjective { - /// Benchmark availability recovery strategies. - DataAvailabilityRead(DataAvailabilityReadOptions), - /// Benchmark availability and bitfield distribution. - DataAvailabilityWrite, - /// Run a test sequence specified in a file - TestSequence(TestSequenceOptions), - /// Benchmark the approval-voting and approval-distribution subsystems. - ApprovalVoting(ApprovalsOptions), - Unimplemented, -} - -impl std::fmt::Display for TestObjective { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self { - Self::DataAvailabilityRead(_) => "DataAvailabilityRead", - Self::DataAvailabilityWrite => "DataAvailabilityWrite", - Self::TestSequence(_) => "TestSequence", - Self::ApprovalVoting(_) => "ApprovalVoting", - Self::Unimplemented => "Unimplemented", - } - ) - } -} - -#[derive(Debug, clap::Parser)] -#[clap(rename_all = "kebab-case")] -#[allow(missing_docs)] -pub struct StandardTestOptions { - #[clap(long, ignore_case = true, default_value_t = 100)] - /// Number of cores to fetch availability for. - pub n_cores: usize, - - #[clap(long, ignore_case = true, default_value_t = 500)] - /// Number of validators to fetch chunks from. - pub n_validators: usize, - - #[clap(long, ignore_case = true, default_value_t = 5120)] - /// The minimum pov size in KiB - pub min_pov_size: usize, - - #[clap(long, ignore_case = true, default_value_t = 5120)] - /// The maximum pov size bytes - pub max_pov_size: usize, - - #[clap(short, long, ignore_case = true, default_value_t = 1)] - /// The number of blocks the test is going to run. - pub num_blocks: usize, -} diff --git a/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs new file mode 100644 index 0000000000000000000000000000000000000000..deb351360d74ede1ea78494a34f7c459dc544cdd --- /dev/null +++ b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs @@ -0,0 +1,202 @@ +// 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 . + +//! A tool for running subsystem benchmark tests +//! designed for development and CI regression testing. + +use clap::Parser; +use color_eyre::eyre; +use colored::Colorize; +use polkadot_subsystem_bench::{approval, availability, configuration}; +use pyroscope::PyroscopeAgent; +use pyroscope_pprofrs::{pprof_backend, PprofConfig}; +use serde::{Deserialize, Serialize}; +use std::path::Path; + +mod valgrind; + +const LOG_TARGET: &str = "subsystem-bench::cli"; + +/// Supported test objectives +#[derive(Debug, Clone, Parser, Serialize, Deserialize)] +#[command(rename_all = "kebab-case")] +pub enum TestObjective { + /// Benchmark availability recovery strategies. + DataAvailabilityRead(availability::DataAvailabilityReadOptions), + /// Benchmark availability and bitfield distribution. + DataAvailabilityWrite, + /// Benchmark the approval-voting and approval-distribution subsystems. + ApprovalVoting(approval::ApprovalsOptions), +} + +impl std::fmt::Display for TestObjective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::DataAvailabilityRead(_) => "DataAvailabilityRead", + Self::DataAvailabilityWrite => "DataAvailabilityWrite", + Self::ApprovalVoting(_) => "ApprovalVoting", + } + ) + } +} + +/// The test input parameters +#[derive(Clone, Debug, Serialize, Deserialize)] +struct CliTestConfiguration { + /// Test Objective + pub objective: TestObjective, + /// Test Configuration + #[serde(flatten)] + pub test_config: configuration::TestConfiguration, +} + +#[derive(Serialize, Deserialize)] +pub struct TestSequence { + #[serde(rename(serialize = "TestConfiguration", deserialize = "TestConfiguration"))] + test_configurations: Vec, +} + +impl TestSequence { + fn new_from_file(path: &Path) -> std::io::Result { + let string = String::from_utf8(std::fs::read(path)?).expect("File is valid UTF8"); + Ok(serde_yaml::from_str(&string).expect("File is valid test sequence YA")) + } +} + +#[derive(Debug, Parser)] +#[allow(missing_docs)] +struct BenchCli { + #[clap(long, default_value_t = false)] + /// Enable CPU Profiling with Pyroscope + pub profile: bool, + + #[clap(long, requires = "profile", default_value_t = String::from("http://localhost:4040"))] + /// Pyroscope Server URL + pub pyroscope_url: String, + + #[clap(long, requires = "profile", default_value_t = 113)] + /// Pyroscope Sample Rate + pub pyroscope_sample_rate: u32, + + #[clap(long, default_value_t = false)] + /// Enable Cache Misses Profiling with Valgrind. Linux only, Valgrind must be in the PATH + pub cache_misses: bool, + + #[arg(required = true)] + /// Path to the test sequence configuration file + pub path: String, +} + +impl BenchCli { + fn launch(self) -> eyre::Result<()> { + let is_valgrind_running = valgrind::is_valgrind_running(); + if !is_valgrind_running && self.cache_misses { + return valgrind::relaunch_in_valgrind_mode() + } + + let agent_running = if self.profile { + let agent = PyroscopeAgent::builder(self.pyroscope_url.as_str(), "subsystem-bench") + .backend(pprof_backend(PprofConfig::new().sample_rate(self.pyroscope_sample_rate))) + .build()?; + + Some(agent.start()?) + } else { + None + }; + + let test_sequence = TestSequence::new_from_file(Path::new(&self.path)) + .expect("File exists") + .test_configurations; + let num_steps = test_sequence.len(); + gum::info!("{}", format!("Sequence contains {} step(s)", num_steps).bright_purple()); + + for (index, CliTestConfiguration { objective, mut test_config }) in + test_sequence.into_iter().enumerate() + { + let benchmark_name = format!("{} #{} {}", &self.path, index + 1, objective); + gum::info!(target: LOG_TARGET, "{}", format!("Step {}/{}", index + 1, num_steps).bright_purple(),); + gum::info!(target: LOG_TARGET, "[{}] {}", format!("objective = {:?}", objective).green(), test_config); + test_config.generate_pov_sizes(); + + let usage = match objective { + TestObjective::DataAvailabilityRead(opts) => { + let mut state = availability::TestState::new(&test_config); + let (mut env, _protocol_config) = availability::prepare_test( + test_config, + &mut state, + availability::TestDataAvailability::Read(opts), + true, + ); + env.runtime().block_on(availability::benchmark_availability_read( + &benchmark_name, + &mut env, + state, + )) + }, + TestObjective::DataAvailabilityWrite => { + let mut state = availability::TestState::new(&test_config); + let (mut env, _protocol_config) = availability::prepare_test( + test_config, + &mut state, + availability::TestDataAvailability::Write, + true, + ); + env.runtime().block_on(availability::benchmark_availability_write( + &benchmark_name, + &mut env, + state, + )) + }, + TestObjective::ApprovalVoting(ref options) => { + let (mut env, state) = + approval::prepare_test(test_config.clone(), options.clone(), true); + env.runtime().block_on(approval::bench_approvals( + &benchmark_name, + &mut env, + state, + )) + }, + }; + println!("{}", usage); + } + + if let Some(agent_running) = agent_running { + let agent_ready = agent_running.stop()?; + agent_ready.shutdown(); + } + + Ok(()) + } +} + +fn main() -> eyre::Result<()> { + color_eyre::install()?; + env_logger::builder() + .filter(Some("hyper"), log::LevelFilter::Info) + // Avoid `Terminating due to subsystem exit subsystem` warnings + .filter(Some("polkadot_overseer"), log::LevelFilter::Error) + .filter(None, log::LevelFilter::Info) + .format_timestamp_millis() + .try_init() + .unwrap(); + + let cli: BenchCli = BenchCli::parse(); + cli.launch()?; + Ok(()) +} diff --git a/polkadot/node/subsystem-bench/src/valgrind.rs b/polkadot/node/subsystem-bench/src/cli/valgrind.rs similarity index 100% rename from polkadot/node/subsystem-bench/src/valgrind.rs rename to polkadot/node/subsystem-bench/src/cli/valgrind.rs diff --git a/polkadot/node/subsystem-bench/src/approval/helpers.rs b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs similarity index 99% rename from polkadot/node/subsystem-bench/src/approval/helpers.rs rename to polkadot/node/subsystem-bench/src/lib/approval/helpers.rs index 7cbe3ba75949339646b9157452f358f479bca657..af5ff5aa1facc11f2d0caa8ec77276976a0554a5 100644 --- a/polkadot/node/subsystem-bench/src/approval/helpers.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs @@ -11,7 +11,10 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use crate::core::configuration::TestAuthorities; +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::configuration::TestAuthorities; use itertools::Itertools; use polkadot_node_core_approval_voting::time::{Clock, SystemClock, Tick}; use polkadot_node_network_protocol::{ @@ -39,9 +42,6 @@ use sp_keyring::sr25519::Keyring as Sr25519Keyring; use sp_runtime::{Digest, DigestItem}; use std::sync::{atomic::AtomicU64, Arc}; -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - /// A fake system clock used for driving the approval voting and make /// it process blocks, assignments and approvals from the past. #[derive(Clone)] diff --git a/polkadot/node/subsystem-bench/src/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs similarity index 95% rename from polkadot/node/subsystem-bench/src/approval/message_generator.rs rename to polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index 4318dcdf8902a6672a73ac208e43efbf34da3e66..c1b31a509f6dd21c3f23bb44afec8859e51fa76a 100644 --- a/polkadot/node/subsystem-bench/src/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -14,15 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{ - cmp::max, - collections::{BTreeMap, HashSet}, - fs, - io::Write, - path::{Path, PathBuf}, - time::Duration, +use crate::{ + approval::{ + helpers::{generate_babe_epoch, generate_topology}, + test_message::{MessagesBundle, TestMessageInfo}, + ApprovalTestState, ApprovalsOptions, BlockTestData, GeneratedState, + BUFFER_FOR_GENERATION_MILLIS, LOG_TARGET, SLOT_DURATION_MILLIS, + }, + configuration::{TestAuthorities, TestConfiguration}, + mock::runtime_api::session_info_for_peers, + NODE_UNDER_TEST, }; - use futures::SinkExt; use itertools::Itertools; use parity_scale_codec::Encode; @@ -30,8 +32,9 @@ use polkadot_node_core_approval_voting::{ criteria::{compute_assignments, Config}, time::tranche_to_tick, }; -use polkadot_node_network_protocol::grid_topology::{ - GridNeighbors, RandomRouting, RequiredRouting, SessionGridTopology, +use polkadot_node_network_protocol::{ + grid_topology::{GridNeighbors, RandomRouting, RequiredRouting, SessionGridTopology}, + v3 as protocol_v3, }; use polkadot_node_primitives::approval::{ self, @@ -39,37 +42,28 @@ use polkadot_node_primitives::approval::{ }; use polkadot_primitives::{ vstaging::ApprovalVoteMultipleCandidates, CandidateEvent, CandidateHash, CandidateIndex, - CoreIndex, SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, + CoreIndex, Hash, SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, }; use rand::{seq::SliceRandom, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; use rand_distr::{Distribution, Normal}; use sc_keystore::LocalKeystore; use sc_network::PeerId; +use sc_service::SpawnTaskHandle; use sha1::Digest; use sp_application_crypto::AppCrypto; use sp_consensus_babe::SlotDuration; use sp_keystore::Keystore; use sp_timestamp::Timestamp; - -use super::{ - test_message::{MessagesBundle, TestMessageInfo}, - ApprovalTestState, ApprovalsOptions, BlockTestData, -}; -use crate::{ - approval::{ - helpers::{generate_babe_epoch, generate_topology}, - GeneratedState, BUFFER_FOR_GENERATION_MILLIS, LOG_TARGET, SLOT_DURATION_MILLIS, - }, - core::{ - configuration::{TestAuthorities, TestConfiguration, TestObjective}, - mock::session_info_for_peers, - NODE_UNDER_TEST, - }, +use std::{ + cmp::max, + collections::{BTreeMap, HashSet}, + fs, + io::Write, + path::{Path, PathBuf}, + time::Duration, }; -use polkadot_node_network_protocol::v3 as protocol_v3; -use polkadot_primitives::Hash; -use sc_service::SpawnTaskHandle; + /// A generator of messages coming from a given Peer/Validator pub struct PeerMessagesGenerator { /// The grid neighbors of the node under test. @@ -135,11 +129,7 @@ impl PeerMessagesGenerator { options: &ApprovalsOptions, ) -> String { let mut fingerprint = options.fingerprint(); - let mut exclude_objective = configuration.clone(); - // The objective contains the full content of `ApprovalOptions`, we don't want to put all of - // that in fingerprint, so execlute it because we add it manually see above. - exclude_objective.objective = TestObjective::Unimplemented; - let configuration_bytes = bincode::serialize(&exclude_objective).unwrap(); + let configuration_bytes = bincode::serialize(&configuration).unwrap(); fingerprint.extend(configuration_bytes); let mut sha1 = sha1::Sha1::new(); sha1.update(fingerprint); diff --git a/polkadot/node/subsystem-bench/src/approval/mock_chain_selection.rs b/polkadot/node/subsystem-bench/src/lib/approval/mock_chain_selection.rs similarity index 95% rename from polkadot/node/subsystem-bench/src/approval/mock_chain_selection.rs rename to polkadot/node/subsystem-bench/src/lib/approval/mock_chain_selection.rs index ab23a8ced484eb7584eaa3d90c5a0e967ba897f7..77ba80d4b2bbcbc7616c00ad6f5069ceb22979bc 100644 --- a/polkadot/node/subsystem-bench/src/approval/mock_chain_selection.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mock_chain_selection.rs @@ -14,9 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use crate::approval::{LOG_TARGET, SLOT_DURATION_MILLIS}; - -use super::{ApprovalTestState, PastSystemClock}; +use crate::approval::{ApprovalTestState, PastSystemClock, LOG_TARGET, SLOT_DURATION_MILLIS}; use futures::FutureExt; use polkadot_node_core_approval_voting::time::{slot_number_to_tick, Clock, TICK_DURATION_MILLIS}; use polkadot_node_subsystem::{overseer, SpawnedSubsystem, SubsystemError}; diff --git a/polkadot/node/subsystem-bench/src/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs similarity index 95% rename from polkadot/node/subsystem-bench/src/approval/mod.rs rename to polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 055aeb1934567f49d789712efaf759394c28b25e..450faf06123f61db9ee91d1d935721d3c128e701 100644 --- a/polkadot/node/subsystem-bench/src/approval/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs @@ -14,35 +14,31 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use self::{ - helpers::{make_candidates, make_header}, - test_message::{MessagesBundle, TestMessageInfo}, -}; use crate::{ approval::{ helpers::{ generate_babe_epoch, generate_new_session_topology, generate_peer_view_change_for, - PastSystemClock, + make_header, PastSystemClock, }, message_generator::PeerMessagesGenerator, mock_chain_selection::MockChainSelection, + test_message::{MessagesBundle, TestMessageInfo}, }, - core::{ - configuration::{TestAuthorities, TestConfiguration}, - environment::{ - BenchmarkUsage, TestEnvironment, TestEnvironmentDependencies, MAX_TIME_OF_FLIGHT, - }, - mock::{ - dummy_builder, - network_bridge::{MockNetworkBridgeRx, MockNetworkBridgeTx}, - AlwaysSupportsParachains, ChainApiState, MockChainApi, MockRuntimeApi, TestSyncOracle, - }, - network::{ - new_network, HandleNetworkMessage, NetworkEmulatorHandle, NetworkInterface, - NetworkInterfaceReceiver, - }, - NODE_UNDER_TEST, + configuration::{TestAuthorities, TestConfiguration}, + dummy_builder, + environment::{TestEnvironment, TestEnvironmentDependencies, MAX_TIME_OF_FLIGHT}, + mock::{ + chain_api::{ChainApiState, MockChainApi}, + network_bridge::{MockNetworkBridgeRx, MockNetworkBridgeTx}, + runtime_api::MockRuntimeApi, + AlwaysSupportsParachains, TestSyncOracle, + }, + network::{ + new_network, HandleNetworkMessage, NetworkEmulatorHandle, NetworkInterface, + NetworkInterfaceReceiver, }, + usage::BenchmarkUsage, + NODE_UNDER_TEST, }; use colored::Colorize; use futures::channel::oneshot; @@ -91,8 +87,7 @@ mod message_generator; mod mock_chain_selection; mod test_message; -pub const LOG_TARGET: &str = "subsystem-bench::approval"; -const DATA_COL: u32 = 0; +pub(crate) const LOG_TARGET: &str = "subsystem-bench::approval"; pub(crate) const NUM_COLUMNS: u32 = 1; pub(crate) const SLOT_DURATION_MILLIS: u64 = 6000; pub(crate) const TEST_CONFIG: ApprovalVotingConfig = ApprovalVotingConfig { @@ -100,6 +95,8 @@ pub(crate) const TEST_CONFIG: ApprovalVotingConfig = ApprovalVotingConfig { slot_duration_millis: SLOT_DURATION_MILLIS, }; +const DATA_COL: u32 = 0; + /// Start generating messages for a slot into the future, so that the /// generation nevers falls behind the current slot. const BUFFER_FOR_GENERATION_MILLIS: u64 = 30_000; @@ -234,7 +231,7 @@ impl CandidateTestData { #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] struct GeneratedState { /// All assignments and approvals - all_messages: Option>, + all_messages: Option>, /// The first slot in the test. initial_slot: Slot, } @@ -367,7 +364,7 @@ impl ApprovalTestState { block_number: block_number as BlockNumber, hash: block_hash, header, - candidates: make_candidates( + candidates: helpers::make_candidates( block_hash, block_number as BlockNumber, configuration.n_cores as u32, @@ -471,11 +468,9 @@ impl ApprovalTestState { impl HandleNetworkMessage for ApprovalTestState { fn handle( &self, - _message: crate::core::network::NetworkMessage, - _node_sender: &mut futures::channel::mpsc::UnboundedSender< - crate::core::network::NetworkMessage, - >, - ) -> Option { + _message: crate::network::NetworkMessage, + _node_sender: &mut futures::channel::mpsc::UnboundedSender, + ) -> Option { self.total_sent_messages_from_node .as_ref() .fetch_add(1, std::sync::atomic::Ordering::SeqCst); @@ -504,12 +499,16 @@ struct PeerMessageProducer { impl PeerMessageProducer { /// Generates messages by spawning a blocking task in the background which begins creating /// the assignments/approvals and peer view changes at the begining of each block. - fn produce_messages(mut self, env: &TestEnvironment, all_messages: Vec) { + fn produce_messages( + mut self, + env: &TestEnvironment, + all_messages: Vec, + ) { env.spawn_blocking("produce-messages", async move { let mut initialized_blocks = HashSet::new(); let mut per_candidate_data: HashMap<(Hash, CandidateIndex), CandidateTestData> = self.initialize_candidates_test_data(); - let mut skipped_messages: Vec = Vec::new(); + let mut skipped_messages: Vec = Vec::new(); let mut re_process_skipped = false; let system_clock = @@ -606,9 +605,9 @@ impl PeerMessageProducer { // send the message in our simulation. pub fn process_message( &mut self, - bundle: MessagesBundle, + bundle: test_message::MessagesBundle, per_candidate_data: &mut HashMap<(Hash, CandidateIndex), CandidateTestData>, - skipped_messages: &mut Vec, + skipped_messages: &mut Vec, ) -> bool { let mut reprocess_skipped = false; let block_info = self @@ -836,8 +835,14 @@ fn build_overseer( pub fn prepare_test( config: TestConfiguration, options: ApprovalsOptions, + with_prometheus_endpoint: bool, ) -> (TestEnvironment, ApprovalTestState) { - prepare_test_inner(config, TestEnvironmentDependencies::default(), options) + prepare_test_inner( + config, + TestEnvironmentDependencies::default(), + options, + with_prometheus_endpoint, + ) } /// Build the test environment for an Approval benchmark. @@ -845,6 +850,7 @@ fn prepare_test_inner( config: TestConfiguration, dependencies: TestEnvironmentDependencies, options: ApprovalsOptions, + with_prometheus_endpoint: bool, ) -> (TestEnvironment, ApprovalTestState) { gum::info!("Prepare test state"); let state = ApprovalTestState::new(&config, options, &dependencies); @@ -873,6 +879,7 @@ fn prepare_test_inner( overseer, overseer_handle, state.test_authorities.clone(), + with_prometheus_endpoint, ), state, ) diff --git a/polkadot/node/subsystem-bench/src/approval/test_message.rs b/polkadot/node/subsystem-bench/src/lib/approval/test_message.rs similarity index 98% rename from polkadot/node/subsystem-bench/src/approval/test_message.rs rename to polkadot/node/subsystem-bench/src/lib/approval/test_message.rs index ea578776f261d07e7124f8abc12d5e1c03f00987..63e383509be9ff6da6e1d5dd61baebc99c574bc4 100644 --- a/polkadot/node/subsystem-bench/src/approval/test_message.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/test_message.rs @@ -14,12 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use super::{ApprovalsOptions, BlockTestData, CandidateTestData}; -use crate::core::configuration::TestAuthorities; +use crate::{ + approval::{ApprovalsOptions, BlockTestData, CandidateTestData}, + configuration::TestAuthorities, +}; use itertools::Itertools; use parity_scale_codec::{Decode, Encode}; use polkadot_node_network_protocol::v3 as protocol_v3; - use polkadot_primitives::{CandidateIndex, Hash, ValidatorIndex}; use sc_network::PeerId; use std::collections::{HashMap, HashSet}; diff --git a/polkadot/node/subsystem-bench/src/availability/av_store_helpers.rs b/polkadot/node/subsystem-bench/src/lib/availability/av_store_helpers.rs similarity index 89% rename from polkadot/node/subsystem-bench/src/availability/av_store_helpers.rs rename to polkadot/node/subsystem-bench/src/lib/availability/av_store_helpers.rs index e6827f1d8aeaa63678561fb295a4a5166eb50b28..3300def2235ee0ea90f466316f9bc5a7a965869c 100644 --- a/polkadot/node/subsystem-bench/src/availability/av_store_helpers.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/av_store_helpers.rs @@ -14,16 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use crate::core::mock::TestSyncOracle; - -use super::*; - +use crate::{environment::TestEnvironmentDependencies, mock::TestSyncOracle}; +use polkadot_node_core_av_store::{AvailabilityStoreSubsystem, Config}; use polkadot_node_metrics::metrics::Metrics; - -use polkadot_node_core_av_store::Config; use polkadot_node_subsystem_util::database::Database; - -use polkadot_node_core_av_store::AvailabilityStoreSubsystem; +use std::sync::Arc; mod columns { pub const DATA: u32 = 0; diff --git a/polkadot/node/subsystem-bench/src/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs similarity index 93% rename from polkadot/node/subsystem-bench/src/availability/mod.rs rename to polkadot/node/subsystem-bench/src/lib/availability/mod.rs index 56ec6705b7e358bf0f45795694600f9c354b6933..dc4e1e4031025ca3f868265ac2e8c902f6fc8c23 100644 --- a/polkadot/node/subsystem-bench/src/availability/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs @@ -13,74 +13,85 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + use crate::{ - core::{environment::BenchmarkUsage, mock::ChainApiState}, - TestEnvironment, + configuration::TestConfiguration, + dummy_builder, + environment::{TestEnvironment, TestEnvironmentDependencies, GENESIS_HASH}, + mock::{ + av_store::{self, MockAvailabilityStore}, + chain_api::{ChainApiState, MockChainApi}, + network_bridge::{self, MockNetworkBridgeRx, MockNetworkBridgeTx}, + runtime_api::{self, MockRuntimeApi}, + AlwaysSupportsParachains, + }, + network::new_network, + usage::BenchmarkUsage, }; use av_store::NetworkAvailabilityState; +use av_store_helpers::new_av_store; use bitvec::bitvec; use colored::Colorize; +use futures::{channel::oneshot, stream::FuturesUnordered, StreamExt}; use itertools::Itertools; +use parity_scale_codec::Encode; use polkadot_availability_bitfield_distribution::BitfieldDistribution; -use polkadot_node_core_av_store::AvailabilityStoreSubsystem; -use polkadot_node_subsystem::{Overseer, OverseerConnector, SpawnGlue}; -use polkadot_node_subsystem_types::{ - messages::{AvailabilityStoreMessage, NetworkBridgeEvent}, - Span, -}; -use polkadot_overseer::{metrics::Metrics as OverseerMetrics, Handle as OverseerHandle}; -use sc_network::{request_responses::ProtocolConfig, PeerId}; -use sp_core::H256; -use std::{collections::HashMap, iter::Cycle, ops::Sub, sync::Arc, time::Instant}; - -use av_store_helpers::new_av_store; -use futures::{channel::oneshot, stream::FuturesUnordered, StreamExt}; use polkadot_availability_distribution::{ AvailabilityDistributionSubsystem, IncomingRequestReceivers, }; -use polkadot_node_metrics::metrics::Metrics; - use polkadot_availability_recovery::AvailabilityRecoverySubsystem; -use polkadot_node_primitives::{AvailableData, ErasureChunk}; - -use crate::GENESIS_HASH; -use parity_scale_codec::Encode; +use polkadot_node_core_av_store::AvailabilityStoreSubsystem; +use polkadot_node_metrics::metrics::Metrics; use polkadot_node_network_protocol::{ request_response::{v1::ChunkFetchingRequest, IncomingRequest, ReqProtocolNames}, OurView, Versioned, VersionedValidationProtocol, }; -use sc_network::request_responses::IncomingRequest as RawIncomingRequest; - -use polkadot_node_primitives::{BlockData, PoV}; -use polkadot_node_subsystem::messages::{AllMessages, AvailabilityRecoveryMessage}; - -use crate::core::{ - environment::TestEnvironmentDependencies, - mock::{ - av_store, - network_bridge::{self, MockNetworkBridgeRx, MockNetworkBridgeTx}, - runtime_api, MockAvailabilityStore, MockChainApi, MockRuntimeApi, - }, +use polkadot_node_primitives::{AvailableData, BlockData, ErasureChunk, PoV}; +use polkadot_node_subsystem::{ + messages::{AllMessages, AvailabilityRecoveryMessage}, + Overseer, OverseerConnector, SpawnGlue, }; - -use super::core::{configuration::TestConfiguration, mock::dummy_builder, network::*}; - -const LOG_TARGET: &str = "subsystem-bench::availability"; - -use super::{cli::TestObjective, core::mock::AlwaysSupportsParachains}; use polkadot_node_subsystem_test_helpers::{ derive_erasure_chunks_with_proofs_and_root, mock::new_block_import_info, }; +use polkadot_node_subsystem_types::{ + messages::{AvailabilityStoreMessage, NetworkBridgeEvent}, + Span, +}; +use polkadot_overseer::{metrics::Metrics as OverseerMetrics, Handle as OverseerHandle}; use polkadot_primitives::{ AvailabilityBitfield, BlockNumber, CandidateHash, CandidateReceipt, GroupIndex, Hash, HeadData, Header, PersistedValidationData, Signed, SigningContext, ValidatorIndex, }; use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; +use sc_network::{ + request_responses::{IncomingRequest as RawIncomingRequest, ProtocolConfig}, + PeerId, +}; use sc_service::SpawnTaskHandle; +use serde::{Deserialize, Serialize}; +use sp_core::H256; +use std::{collections::HashMap, iter::Cycle, ops::Sub, sync::Arc, time::Instant}; mod av_store_helpers; -mod cli; -pub use cli::{DataAvailabilityReadOptions, NetworkEmulation}; + +const LOG_TARGET: &str = "subsystem-bench::availability"; + +#[derive(Debug, Clone, Serialize, Deserialize, clap::Parser)] +#[clap(rename_all = "kebab-case")] +#[allow(missing_docs)] +pub struct DataAvailabilityReadOptions { + #[clap(short, long, default_value_t = false)] + /// Turbo boost AD Read by fetching the full availability datafrom backers first. Saves CPU as + /// we don't need to re-construct from chunks. Tipically this is only faster if nodes have + /// enough bandwidth. + pub fetch_from_backers: bool, +} + +pub enum TestDataAvailability { + Read(DataAvailabilityReadOptions), + Write, +} fn build_overseer_for_availability_read( spawn_task_handle: SpawnTaskHandle, @@ -142,14 +153,24 @@ fn build_overseer_for_availability_write( pub fn prepare_test( config: TestConfiguration, state: &mut TestState, + mode: TestDataAvailability, + with_prometheus_endpoint: bool, ) -> (TestEnvironment, Vec) { - prepare_test_inner(config, state, TestEnvironmentDependencies::default()) + prepare_test_inner( + config, + state, + mode, + TestEnvironmentDependencies::default(), + with_prometheus_endpoint, + ) } fn prepare_test_inner( config: TestConfiguration, state: &mut TestState, + mode: TestDataAvailability, dependencies: TestEnvironmentDependencies, + with_prometheus_endpoint: bool, ) -> (TestEnvironment, Vec) { // Generate test authorities. let test_authorities = config.generate_authorities(); @@ -217,8 +238,8 @@ fn prepare_test_inner( let network_bridge_rx = network_bridge::MockNetworkBridgeRx::new(network_receiver, Some(chunk_req_cfg.clone())); - let (overseer, overseer_handle) = match &state.config().objective { - TestObjective::DataAvailabilityRead(options) => { + let (overseer, overseer_handle) = match &mode { + TestDataAvailability::Read(options) => { let use_fast_path = options.fetch_from_backers; let subsystem = if use_fast_path { @@ -248,7 +269,7 @@ fn prepare_test_inner( &dependencies, ) }, - TestObjective::DataAvailabilityWrite => { + TestDataAvailability::Write => { let availability_distribution = AvailabilityDistributionSubsystem::new( test_authorities.keyring.keystore(), IncomingRequestReceivers { pov_req_receiver, chunk_req_receiver }, @@ -285,9 +306,6 @@ fn prepare_test_inner( &dependencies, ) }, - _ => { - unimplemented!("Invalid test objective") - }, }; ( @@ -298,6 +316,7 @@ fn prepare_test_inner( overseer, overseer_handle, test_authorities, + with_prometheus_endpoint, ), req_cfgs, ) @@ -327,10 +346,6 @@ pub struct TestState { } impl TestState { - fn config(&self) -> &TestConfiguration { - &self.config - } - pub fn next_candidate(&mut self) -> Option { let candidate = self.candidates.next(); let candidate_hash = candidate.as_ref().unwrap().hash(); @@ -583,7 +598,7 @@ pub async fn benchmark_availability_write( gum::info!(target: LOG_TARGET, "Waiting for all emulated peers to receive their chunk from us ..."); for receiver in receivers.into_iter() { - let response = receiver.await.expect("Chunk is always served succesfully"); + let response = receiver.await.expect("Chunk is always served successfully"); // TODO: check if chunk is the one the peer expects to receive. assert!(response.result.is_ok()); } diff --git a/polkadot/node/subsystem-bench/src/core/configuration.rs b/polkadot/node/subsystem-bench/src/lib/configuration.rs similarity index 64% rename from polkadot/node/subsystem-bench/src/core/configuration.rs rename to polkadot/node/subsystem-bench/src/lib/configuration.rs index 0c8a78c504c8c22ca83eb0d7362aca3e2bcda916..17c81c4fd355bd15c5e2a6c1005e90313ca80615 100644 --- a/polkadot/node/subsystem-bench/src/core/configuration.rs +++ b/polkadot/node/subsystem-bench/src/lib/configuration.rs @@ -13,31 +13,18 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -// + //! Test configuration definition and helpers. -use super::*; -use itertools::Itertools; -use keyring::Keyring; -use sc_network::PeerId; -use sp_consensus_babe::AuthorityId; -use std::{collections::HashMap, path::Path}; -pub use crate::cli::TestObjective; +use crate::keyring::Keyring; +use itertools::Itertools; use polkadot_primitives::{AssignmentId, AuthorityDiscoveryId, ValidatorId}; use rand::thread_rng; use rand_distr::{Distribution, Normal, Uniform}; - +use sc_network::PeerId; use serde::{Deserialize, Serialize}; - -pub fn random_pov_size(min_pov_size: usize, max_pov_size: usize) -> usize { - random_uniform_sample(min_pov_size, max_pov_size) -} - -fn random_uniform_sample + From>(min_value: T, max_value: T) -> T { - Uniform::from(min_value.into()..=max_value.into()) - .sample(&mut thread_rng()) - .into() -} +use sp_consensus_babe::AuthorityId; +use std::collections::HashMap; /// Peer networking latency configuration. #[derive(Clone, Debug, Default, Serialize, Deserialize)] @@ -48,19 +35,34 @@ pub struct PeerLatency { pub std_dev: f64, } +// Based on Kusama `max_validators` +fn default_n_validators() -> usize { + 300 +} + +// Based on Kusama cores +fn default_n_cores() -> usize { + 60 +} + // Default PoV size in KiB. fn default_pov_size() -> usize { - 5120 + 5 * 1024 } -// Default bandwidth in bytes +// Default bandwidth in bytes, based stats from Kusama validators fn default_bandwidth() -> usize { - 52428800 + 42 * 1024 * 1024 +} + +// Default peer latency +fn default_peer_latency() -> Option { + Some(PeerLatency { mean_latency_ms: 30, std_dev: 2.0 }) } // Default connectivity percentage fn default_connectivity() -> usize { - 100 + 90 } // Default backing group size @@ -76,6 +78,7 @@ fn default_needed_approvals() -> usize { fn default_zeroth_delay_tranche_width() -> usize { 0 } + fn default_relay_vrf_modulo_samples() -> usize { 6 } @@ -90,11 +93,11 @@ fn default_no_show_slots() -> usize { /// The test input parameters #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TestConfiguration { - /// The test objective - pub objective: TestObjective, /// Number of validators + #[serde(default = "default_n_validators")] pub n_validators: usize, /// Number of cores + #[serde(default = "default_n_cores")] pub n_cores: usize, /// The number of needed votes to approve a candidate. #[serde(default = "default_needed_approvals")] @@ -118,7 +121,7 @@ pub struct TestConfiguration { pub max_pov_size: usize, /// Randomly sampled pov_sizes #[serde(skip)] - pov_sizes: Vec, + pub pov_sizes: Vec, /// The amount of bandiwdth remote validators have. #[serde(default = "default_bandwidth")] pub peer_bandwidth: usize, @@ -126,66 +129,42 @@ pub struct TestConfiguration { #[serde(default = "default_bandwidth")] pub bandwidth: usize, /// Optional peer emulation latency (round trip time) wrt node under test - #[serde(default)] + #[serde(default = "default_peer_latency")] pub latency: Option, - /// Connectivity ratio, the percentage of peers we are not connected to, but ar part of - /// the topology. + /// Connectivity ratio, the percentage of peers we are connected to, but as part of the + /// topology. #[serde(default = "default_connectivity")] pub connectivity: usize, /// Number of blocks to run the test for pub num_blocks: usize, } -fn generate_pov_sizes(count: usize, min_kib: usize, max_kib: usize) -> Vec { - (0..count).map(|_| random_pov_size(min_kib * 1024, max_kib * 1024)).collect() -} - -#[derive(Serialize, Deserialize)] -pub struct TestSequence { - #[serde(rename(serialize = "TestConfiguration", deserialize = "TestConfiguration"))] - test_configurations: Vec, -} - -impl TestSequence { - pub fn into_vec(self) -> Vec { - self.test_configurations - .into_iter() - .map(|mut config| { - config.pov_sizes = - generate_pov_sizes(config.n_cores, config.min_pov_size, config.max_pov_size); - config - }) - .collect() - } -} - -impl TestSequence { - pub fn new_from_file(path: &Path) -> std::io::Result { - let string = String::from_utf8(std::fs::read(path)?).expect("File is valid UTF8"); - Ok(serde_yaml::from_str(&string).expect("File is valid test sequence YA")) +impl Default for TestConfiguration { + fn default() -> Self { + Self { + n_validators: default_n_validators(), + n_cores: default_n_cores(), + needed_approvals: default_needed_approvals(), + zeroth_delay_tranche_width: default_zeroth_delay_tranche_width(), + relay_vrf_modulo_samples: default_relay_vrf_modulo_samples(), + n_delay_tranches: default_n_delay_tranches(), + no_show_slots: default_no_show_slots(), + max_validators_per_core: default_backing_group_size(), + min_pov_size: default_pov_size(), + max_pov_size: default_pov_size(), + pov_sizes: Default::default(), + peer_bandwidth: default_bandwidth(), + bandwidth: default_bandwidth(), + latency: default_peer_latency(), + connectivity: default_connectivity(), + num_blocks: Default::default(), + } } } -/// Helper struct for authority related state. -#[derive(Clone)] -pub struct TestAuthorities { - pub keyring: Keyring, - pub validator_public: Vec, - pub validator_authority_id: Vec, - pub validator_babe_id: Vec, - pub validator_assignment_id: Vec, - pub key_seeds: Vec, - pub peer_ids: Vec, - pub peer_id_to_authority: HashMap, -} - impl TestConfiguration { - #[allow(unused)] - pub fn write_to_disk(&self) { - // Serialize a slice of configurations - let yaml = serde_yaml::to_string(&TestSequence { test_configurations: vec![self.clone()] }) - .unwrap(); - std::fs::write("last_test.yaml", yaml).unwrap(); + pub fn generate_pov_sizes(&mut self) { + self.pov_sizes = generate_pov_sizes(self.n_cores, self.min_pov_size, self.max_pov_size); } pub fn pov_sizes(&self) -> &[usize] { @@ -240,95 +219,33 @@ impl TestConfiguration { peer_id_to_authority, } } +} - /// An unconstrained standard configuration matching Polkadot/Kusama - pub fn ideal_network( - objective: TestObjective, - num_blocks: usize, - n_validators: usize, - n_cores: usize, - min_pov_size: usize, - max_pov_size: usize, - ) -> TestConfiguration { - Self { - objective, - n_cores, - n_validators, - max_validators_per_core: 5, - pov_sizes: generate_pov_sizes(n_cores, min_pov_size, max_pov_size), - bandwidth: 50 * 1024 * 1024, - peer_bandwidth: 50 * 1024 * 1024, - // No latency - latency: None, - num_blocks, - min_pov_size, - max_pov_size, - connectivity: 100, - needed_approvals: default_needed_approvals(), - n_delay_tranches: default_n_delay_tranches(), - no_show_slots: default_no_show_slots(), - relay_vrf_modulo_samples: default_relay_vrf_modulo_samples(), - zeroth_delay_tranche_width: default_zeroth_delay_tranche_width(), - } - } +fn random_uniform_sample + From>(min_value: T, max_value: T) -> T { + Uniform::from(min_value.into()..=max_value.into()) + .sample(&mut thread_rng()) + .into() +} - pub fn healthy_network( - objective: TestObjective, - num_blocks: usize, - n_validators: usize, - n_cores: usize, - min_pov_size: usize, - max_pov_size: usize, - ) -> TestConfiguration { - Self { - objective, - n_cores, - n_validators, - max_validators_per_core: 5, - pov_sizes: generate_pov_sizes(n_cores, min_pov_size, max_pov_size), - bandwidth: 50 * 1024 * 1024, - peer_bandwidth: 50 * 1024 * 1024, - latency: Some(PeerLatency { mean_latency_ms: 50, std_dev: 12.5 }), - num_blocks, - min_pov_size, - max_pov_size, - connectivity: 95, - needed_approvals: default_needed_approvals(), - n_delay_tranches: default_n_delay_tranches(), - no_show_slots: default_no_show_slots(), - relay_vrf_modulo_samples: default_relay_vrf_modulo_samples(), - zeroth_delay_tranche_width: default_zeroth_delay_tranche_width(), - } - } +fn random_pov_size(min_pov_size: usize, max_pov_size: usize) -> usize { + random_uniform_sample(min_pov_size, max_pov_size) +} - pub fn degraded_network( - objective: TestObjective, - num_blocks: usize, - n_validators: usize, - n_cores: usize, - min_pov_size: usize, - max_pov_size: usize, - ) -> TestConfiguration { - Self { - objective, - n_cores, - n_validators, - max_validators_per_core: 5, - pov_sizes: generate_pov_sizes(n_cores, min_pov_size, max_pov_size), - bandwidth: 50 * 1024 * 1024, - peer_bandwidth: 50 * 1024 * 1024, - latency: Some(PeerLatency { mean_latency_ms: 150, std_dev: 40.0 }), - num_blocks, - min_pov_size, - max_pov_size, - connectivity: 67, - needed_approvals: default_needed_approvals(), - n_delay_tranches: default_n_delay_tranches(), - no_show_slots: default_no_show_slots(), - relay_vrf_modulo_samples: default_relay_vrf_modulo_samples(), - zeroth_delay_tranche_width: default_zeroth_delay_tranche_width(), - } - } +fn generate_pov_sizes(count: usize, min_kib: usize, max_kib: usize) -> Vec { + (0..count).map(|_| random_pov_size(min_kib * 1024, max_kib * 1024)).collect() +} + +/// Helper struct for authority related state. +#[derive(Clone)] +pub struct TestAuthorities { + pub keyring: Keyring, + pub validator_public: Vec, + pub validator_authority_id: Vec, + pub validator_babe_id: Vec, + pub validator_assignment_id: Vec, + pub key_seeds: Vec, + pub peer_ids: Vec, + pub peer_id_to_authority: HashMap, } /// Sample latency (in milliseconds) from a normal distribution with parameters diff --git a/polkadot/node/subsystem-bench/src/core/display.rs b/polkadot/node/subsystem-bench/src/lib/display.rs similarity index 88% rename from polkadot/node/subsystem-bench/src/core/display.rs rename to polkadot/node/subsystem-bench/src/lib/display.rs index b130afdcfad578e2565d4556f67b76280df7de11..b153d54a7c36f43bc110dde9443f2413a34d9af6 100644 --- a/polkadot/node/subsystem-bench/src/core/display.rs +++ b/polkadot/node/subsystem-bench/src/lib/display.rs @@ -13,12 +13,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -// + //! Display implementations and helper methods for parsing prometheus metrics //! to a format that can be displayed in the CLI. //! //! Currently histogram buckets are skipped. -use super::{configuration::TestConfiguration, LOG_TARGET}; + +use crate::configuration::TestConfiguration; use colored::Colorize; use prometheus::{ proto::{MetricFamily, MetricType}, @@ -26,6 +27,8 @@ use prometheus::{ }; use std::fmt::Display; +const LOG_TARGET: &str = "subsystem-bench::display"; + #[derive(Default, Debug)] pub struct MetricCollection(Vec); @@ -84,6 +87,7 @@ impl Display for MetricCollection { Ok(()) } } + #[derive(Debug, Clone)] pub struct TestMetric { name: String, @@ -183,15 +187,16 @@ pub fn parse_metrics(registry: &Registry) -> MetricCollection { test_metrics.into() } -pub fn display_configuration(test_config: &TestConfiguration) { - gum::info!( - "[{}] {}, {}, {}, {}, {}", - format!("objective = {:?}", test_config.objective).green(), - format!("n_validators = {}", test_config.n_validators).blue(), - format!("n_cores = {}", test_config.n_cores).blue(), - format!("pov_size = {} - {}", test_config.min_pov_size, test_config.max_pov_size) - .bright_black(), - format!("connectivity = {}", test_config.connectivity).bright_black(), - format!("latency = {:?}", test_config.latency).bright_black(), - ); +impl Display for TestConfiguration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}, {}, {}, {}, {}", + format!("n_validators = {}", self.n_validators).blue(), + format!("n_cores = {}", self.n_cores).blue(), + format!("pov_size = {} - {}", self.min_pov_size, self.max_pov_size).bright_black(), + format!("connectivity = {}", self.connectivity).bright_black(), + format!("latency = {:?}", self.latency).bright_black(), + ) + } } diff --git a/polkadot/node/subsystem-bench/src/core/environment.rs b/polkadot/node/subsystem-bench/src/lib/environment.rs similarity index 88% rename from polkadot/node/subsystem-bench/src/core/environment.rs rename to polkadot/node/subsystem-bench/src/lib/environment.rs index cffda38f21108e9a5330b163bca02b499678300a..958ed50d0894b76ddb66978950971620dceb4aa0 100644 --- a/polkadot/node/subsystem-bench/src/core/environment.rs +++ b/polkadot/node/subsystem-bench/src/lib/environment.rs @@ -13,29 +13,28 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Test environment implementation + use crate::{ - core::{mock::AlwaysSupportsParachains, network::NetworkEmulatorHandle}, - TestConfiguration, + configuration::{TestAuthorities, TestConfiguration}, + mock::AlwaysSupportsParachains, + network::NetworkEmulatorHandle, + usage::{BenchmarkUsage, ResourceUsage}, }; -use colored::Colorize; use core::time::Duration; use futures::{Future, FutureExt}; -use polkadot_overseer::{BlockInfo, Handle as OverseerHandle}; -use serde::{Deserialize, Serialize}; - use polkadot_node_subsystem::{messages::AllMessages, Overseer, SpawnGlue, TimeoutExt}; use polkadot_node_subsystem_types::Hash; use polkadot_node_subsystem_util::metrics::prometheus::{ self, Gauge, Histogram, PrometheusError, Registry, U64, }; - +use polkadot_overseer::{BlockInfo, Handle as OverseerHandle}; use sc_service::{SpawnTaskHandle, TaskManager}; use std::net::{Ipv4Addr, SocketAddr}; use tokio::runtime::Handle; const LOG_TARGET: &str = "subsystem-bench::environment"; -use super::configuration::TestAuthorities; /// Test environment/configuration metrics #[derive(Clone)] @@ -202,6 +201,7 @@ impl TestEnvironment { overseer: Overseer, AlwaysSupportsParachains>, overseer_handle: OverseerHandle, authorities: TestAuthorities, + with_prometheus_endpoint: bool, ) -> Self { let metrics = TestEnvironmentMetrics::new(&dependencies.registry) .expect("Metrics need to be registered"); @@ -209,19 +209,21 @@ impl TestEnvironment { let spawn_handle = dependencies.task_manager.spawn_handle(); spawn_handle.spawn_blocking("overseer", "overseer", overseer.run().boxed()); - let registry_clone = dependencies.registry.clone(); - dependencies.task_manager.spawn_handle().spawn_blocking( - "prometheus", - "test-environment", - async move { - prometheus_endpoint::init_prometheus( - SocketAddr::new(std::net::IpAddr::V4(Ipv4Addr::LOCALHOST), 9999), - registry_clone, - ) - .await - .unwrap(); - }, - ); + if with_prometheus_endpoint { + let registry_clone = dependencies.registry.clone(); + dependencies.task_manager.spawn_handle().spawn_blocking( + "prometheus", + "test-environment", + async move { + prometheus_endpoint::init_prometheus( + SocketAddr::new(std::net::IpAddr::V4(Ipv4Addr::LOCALHOST), 9999), + registry_clone, + ) + .await + .unwrap(); + }, + ); + } TestEnvironment { runtime_handle: dependencies.runtime.handle().clone(), @@ -409,41 +411,3 @@ impl TestEnvironment { usage } } - -#[derive(Debug, Serialize, Deserialize)] -pub struct BenchmarkUsage { - benchmark_name: String, - network_usage: Vec, - cpu_usage: Vec, -} - -impl std::fmt::Display for BenchmarkUsage { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "\n{}\n\n{}\n{}\n\n{}\n{}\n", - self.benchmark_name.purple(), - format!("{:<32}{:>12}{:>12}", "Network usage, KiB", "total", "per block").blue(), - self.network_usage - .iter() - .map(|v| v.to_string()) - .collect::>() - .join("\n"), - format!("{:<32}{:>12}{:>12}", "CPU usage in seconds", "total", "per block").blue(), - self.cpu_usage.iter().map(|v| v.to_string()).collect::>().join("\n") - ) - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct ResourceUsage { - resource_name: String, - total: f64, - per_block: f64, -} - -impl std::fmt::Display for ResourceUsage { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:<32}{:>12.3}{:>12.3}", self.resource_name.cyan(), self.total, self.per_block) - } -} diff --git a/polkadot/node/subsystem-bench/src/core/keyring.rs b/polkadot/node/subsystem-bench/src/lib/keyring.rs similarity index 100% rename from polkadot/node/subsystem-bench/src/core/keyring.rs rename to polkadot/node/subsystem-bench/src/lib/keyring.rs diff --git a/polkadot/node/subsystem-bench/src/core/mod.rs b/polkadot/node/subsystem-bench/src/lib/lib.rs similarity index 82% rename from polkadot/node/subsystem-bench/src/core/mod.rs rename to polkadot/node/subsystem-bench/src/lib/lib.rs index 507dd1aa83f6634583182c0faf77872ce556d52a..d06f2822a8958169a15f449e71251e3cc62eb9d6 100644 --- a/polkadot/node/subsystem-bench/src/core/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/lib.rs @@ -14,13 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -const LOG_TARGET: &str = "subsystem-bench::core"; // The validator index that represent the node that is under test. pub const NODE_UNDER_TEST: u32 = 0; +pub mod approval; +pub mod availability; pub mod configuration; -pub mod display; -pub mod environment; -pub mod keyring; -pub mod mock; -pub mod network; +pub(crate) mod display; +pub(crate) mod environment; +pub(crate) mod keyring; +pub(crate) mod mock; +pub(crate) mod network; +pub mod usage; diff --git a/polkadot/node/subsystem-bench/src/core/mock/av_store.rs b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs similarity index 98% rename from polkadot/node/subsystem-bench/src/core/mock/av_store.rs rename to polkadot/node/subsystem-bench/src/lib/mock/av_store.rs index 76609ab5dba607865d28e5402f9bff5571ea403d..9064f17940f004fc123bc25f24ad5de1704e2d38 100644 --- a/polkadot/node/subsystem-bench/src/core/mock/av_store.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs @@ -13,30 +13,24 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! + //! A generic av store subsystem mockup suitable to be used in benchmarks. +use crate::network::{HandleNetworkMessage, NetworkMessage}; +use futures::{channel::oneshot, FutureExt}; use parity_scale_codec::Encode; use polkadot_node_network_protocol::request_response::{ v1::{AvailableDataFetchingResponse, ChunkFetchingResponse, ChunkResponse}, Requests, }; -use polkadot_primitives::CandidateHash; -use sc_network::ProtocolName; - -use std::collections::HashMap; - -use futures::{channel::oneshot, FutureExt}; - use polkadot_node_primitives::{AvailableData, ErasureChunk}; - use polkadot_node_subsystem::{ messages::AvailabilityStoreMessage, overseer, SpawnedSubsystem, SubsystemError, }; - use polkadot_node_subsystem_types::OverseerSignal; - -use crate::core::network::{HandleNetworkMessage, NetworkMessage}; +use polkadot_primitives::CandidateHash; +use sc_network::ProtocolName; +use std::collections::HashMap; pub struct AvailabilityStoreState { candidate_hashes: HashMap, @@ -103,7 +97,7 @@ impl HandleNetworkMessage for NetworkAvailabilityState { outgoing_request .pending_response .send(response) - .expect("Response is always sent succesfully"); + .expect("Response is always sent successfully"); None }, _ => Some(NetworkMessage::RequestFromNode(peer, request)), diff --git a/polkadot/node/subsystem-bench/src/core/mock/chain_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/chain_api.rs similarity index 99% rename from polkadot/node/subsystem-bench/src/core/mock/chain_api.rs rename to polkadot/node/subsystem-bench/src/lib/mock/chain_api.rs index 7a5ee80de8007fcd9d4c362676ebb391f0b268d9..bee15c3cefdfbda061a1313db6c631e52fd91c12 100644 --- a/polkadot/node/subsystem-bench/src/core/mock/chain_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/chain_api.rs @@ -13,21 +13,19 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! + //! A generic runtime api subsystem mockup suitable to be used in benchmarks. +use futures::FutureExt; use itertools::Itertools; -use polkadot_primitives::Header; - use polkadot_node_subsystem::{ messages::ChainApiMessage, overseer, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_types::OverseerSignal; +use polkadot_primitives::Header; use sp_core::H256; use std::collections::HashMap; -use futures::FutureExt; - const LOG_TARGET: &str = "subsystem-bench::chain-api-mock"; /// State used to respond to `BlockHeader` requests. diff --git a/polkadot/node/subsystem-bench/src/core/mock/dummy.rs b/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs similarity index 99% rename from polkadot/node/subsystem-bench/src/core/mock/dummy.rs rename to polkadot/node/subsystem-bench/src/lib/mock/dummy.rs index a0a908750c5181619fe836cdbf86c42ba8b99596..8783b35f1c04a9c59bf415340689b1a9ae29ee6a 100644 --- a/polkadot/node/subsystem-bench/src/core/mock/dummy.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs @@ -13,10 +13,11 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Dummy subsystem mocks. -use paste::paste; use futures::FutureExt; +use paste::paste; use polkadot_node_subsystem::{overseer, SpawnedSubsystem, SubsystemError}; use std::time::Duration; use tokio::time::sleep; diff --git a/polkadot/node/subsystem-bench/src/core/mock/mod.rs b/polkadot/node/subsystem-bench/src/lib/mock/mod.rs similarity index 95% rename from polkadot/node/subsystem-bench/src/core/mock/mod.rs rename to polkadot/node/subsystem-bench/src/lib/mock/mod.rs index e766b07e8b16479f9ce654e8a56f430b60136432..6dda9a47d398f3e6e952cd054bce9769e8942e70 100644 --- a/polkadot/node/subsystem-bench/src/core/mock/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/mod.rs @@ -16,6 +16,7 @@ use polkadot_node_subsystem::HeadSupportsParachains; use polkadot_node_subsystem_types::Hash; +use sp_consensus::SyncOracle; pub mod av_store; pub mod chain_api; @@ -23,11 +24,8 @@ pub mod dummy; pub mod network_bridge; pub mod runtime_api; -pub use av_store::*; -pub use chain_api::*; -pub use runtime_api::*; - pub struct AlwaysSupportsParachains {} + #[async_trait::async_trait] impl HeadSupportsParachains for AlwaysSupportsParachains { async fn head_supports_parachains(&self, _head: &Hash) -> bool { @@ -36,9 +34,10 @@ impl HeadSupportsParachains for AlwaysSupportsParachains { } // An orchestra with dummy subsystems +#[macro_export] macro_rules! dummy_builder { ($spawn_task_handle: ident, $metrics: ident) => {{ - use super::core::mock::dummy::*; + use $crate::mock::dummy::*; // Initialize a mock overseer. // All subsystem except approval_voting and approval_distribution are mock subsystems. @@ -75,9 +74,6 @@ macro_rules! dummy_builder { }}; } -pub(crate) use dummy_builder; -use sp_consensus::SyncOracle; - #[derive(Clone)] pub struct TestSyncOracle {} diff --git a/polkadot/node/subsystem-bench/src/core/mock/network_bridge.rs b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs similarity index 99% rename from polkadot/node/subsystem-bench/src/core/mock/network_bridge.rs rename to polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs index a171deb2e715d09093b7b0df1f0d9836551e9f84..d598f6447d3d43ece5e1d0fa6364508403c032e9 100644 --- a/polkadot/node/subsystem-bench/src/core/mock/network_bridge.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs @@ -13,28 +13,25 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! + //! Mocked `network-bridge` subsystems that uses a `NetworkInterface` to access //! the emulated network. + +use crate::{ + configuration::TestAuthorities, + network::{NetworkEmulatorHandle, NetworkInterfaceReceiver, NetworkMessage, RequestExt}, +}; use futures::{channel::mpsc::UnboundedSender, FutureExt, StreamExt}; +use polkadot_node_network_protocol::Versioned; +use polkadot_node_subsystem::{ + messages::NetworkBridgeTxMessage, overseer, SpawnedSubsystem, SubsystemError, +}; use polkadot_node_subsystem_types::{ messages::{ApprovalDistributionMessage, BitfieldDistributionMessage, NetworkBridgeEvent}, OverseerSignal, }; - use sc_network::{request_responses::ProtocolConfig, RequestFailure}; -use polkadot_node_subsystem::{ - messages::NetworkBridgeTxMessage, overseer, SpawnedSubsystem, SubsystemError, -}; - -use polkadot_node_network_protocol::Versioned; - -use crate::core::{ - configuration::TestAuthorities, - network::{NetworkEmulatorHandle, NetworkInterfaceReceiver, NetworkMessage, RequestExt}, -}; - const LOG_TARGET: &str = "subsystem-bench::network-bridge"; const CHUNK_REQ_PROTOCOL_NAME_V1: &str = "/ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff/req_chunk/1"; diff --git a/polkadot/node/subsystem-bench/src/core/mock/runtime_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs similarity index 99% rename from polkadot/node/subsystem-bench/src/core/mock/runtime_api.rs rename to polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs index ca6896dbb29d50fbf25a040e5e0981debed93e35..53faf562f03c005238d5297c29117fd261b49eca 100644 --- a/polkadot/node/subsystem-bench/src/core/mock/runtime_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs @@ -13,28 +13,26 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! -//! A generic runtime api subsystem mockup suitable to be used in benchmarks. -use itertools::Itertools; -use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateEvent, CandidateReceipt, CoreState, GroupIndex, IndexedVec, - OccupiedCore, SessionIndex, SessionInfo, ValidatorIndex, -}; +//! A generic runtime api subsystem mockup suitable to be used in benchmarks. +use crate::configuration::{TestAuthorities, TestConfiguration}; use bitvec::prelude::BitVec; +use futures::FutureExt; +use itertools::Itertools; use polkadot_node_subsystem::{ messages::{RuntimeApiMessage, RuntimeApiRequest}, overseer, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_types::OverseerSignal; +use polkadot_primitives::{ + vstaging::NodeFeatures, CandidateEvent, CandidateReceipt, CoreState, GroupIndex, IndexedVec, + OccupiedCore, SessionIndex, SessionInfo, ValidatorIndex, +}; use sp_consensus_babe::Epoch as BabeEpoch; use sp_core::H256; use std::collections::HashMap; -use crate::core::configuration::{TestAuthorities, TestConfiguration}; -use futures::FutureExt; - const LOG_TARGET: &str = "subsystem-bench::runtime-api-mock"; /// Minimal state to answer requests. diff --git a/polkadot/node/subsystem-bench/src/core/network.rs b/polkadot/node/subsystem-bench/src/lib/network.rs similarity index 98% rename from polkadot/node/subsystem-bench/src/core/network.rs rename to polkadot/node/subsystem-bench/src/lib/network.rs index 8e7c28140635377785ff1a2646128cda741d17de..1bc35a014ff5bf616bb02b0f8740679ef6b67489 100644 --- a/polkadot/node/subsystem-bench/src/core/network.rs +++ b/polkadot/node/subsystem-bench/src/lib/network.rs @@ -12,10 +12,10 @@ // 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 . -//! + //! Implements network emulation and interfaces to control and specialize //! network peer behaviour. -// + // [TestEnvironment] // [NetworkEmulatorHandle] // || @@ -33,20 +33,22 @@ // | // Subsystems under test -use crate::core::configuration::random_latency; - -use super::{ - configuration::{TestAuthorities, TestConfiguration}, +use crate::{ + configuration::{random_latency, TestAuthorities, TestConfiguration}, environment::TestEnvironmentDependencies, - *, + NODE_UNDER_TEST, }; use colored::Colorize; use futures::{ - channel::{mpsc, oneshot}, + channel::{ + mpsc, + mpsc::{UnboundedReceiver, UnboundedSender}, + oneshot, + }, lock::Mutex, stream::FuturesUnordered, + Future, FutureExt, StreamExt, }; - use itertools::Itertools; use net_protocol::{ peer_set::{ProtocolVersion, ValidationVersion}, @@ -54,7 +56,11 @@ use net_protocol::{ ObservedRole, VersionedValidationProtocol, }; use parity_scale_codec::Encode; +use polkadot_node_network_protocol::{self as net_protocol, Versioned}; use polkadot_node_subsystem_types::messages::{ApprovalDistributionMessage, NetworkBridgeEvent}; +use polkadot_node_subsystem_util::metrics::prometheus::{ + self, CounterVec, Opts, PrometheusError, Registry, +}; use polkadot_overseer::AllMessages; use polkadot_primitives::AuthorityDiscoveryId; use prometheus_endpoint::U64; @@ -67,14 +73,12 @@ use sc_service::SpawnTaskHandle; use std::{ collections::HashMap, sync::Arc, + task::Poll, time::{Duration, Instant}, }; -use polkadot_node_network_protocol::{self as net_protocol, Versioned}; - -use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender}; +const LOG_TARGET: &str = "subsystem-bench::network"; -use futures::{Future, FutureExt, StreamExt}; // An emulated node egress traffic rate_limiter. #[derive(Debug)] pub struct RateLimit { @@ -202,8 +206,6 @@ struct ProxiedResponse { pub result: Result, RequestFailure>, } -use std::task::Poll; - impl Future for ProxiedRequest { // The sender and result. type Output = ProxiedResponse; @@ -217,7 +219,7 @@ impl Future for ProxiedRequest { Poll::Ready(response) => Poll::Ready(ProxiedResponse { sender: self.sender.take().expect("sender already used"), result: response - .expect("Response is always succesfully received.") + .expect("Response is always successfully received.") .result .map_err(|_| RequestFailure::Refused), }), @@ -265,9 +267,9 @@ impl NetworkInterface { task_rx_limiter.lock().await.reap(size).await; rx_network.inc_received(size); - // To be able to apply the configured bandwidth limits for responses being sent - // over channels, we need to implement a simple proxy that allows this loop - // to receive the response and enforce the configured bandwidth before + // To be able to apply the configured bandwidth limits for responses being sent + // over channels, we need to implement a simple proxy that allows this loop + // to receive the response and enforce the configured bandwidth before // sending it to the original recipient. if let NetworkMessage::RequestFromPeer(request) = peer_message { let (response_sender, response_receiver) = oneshot::channel(); @@ -759,7 +761,7 @@ pub fn new_network( gum::info!(target: LOG_TARGET, "{}",format!("connectivity {}%, latency {:?}", config.connectivity, config.latency).bright_black()); let metrics = - Metrics::new(&dependencies.registry).expect("Metrics always register succesfully"); + Metrics::new(&dependencies.registry).expect("Metrics always register successfully"); let mut validator_authority_id_mapping = HashMap::new(); // Create the channel from `peer` to `NetworkInterface` . @@ -914,10 +916,6 @@ impl NetworkEmulatorHandle { } } -use polkadot_node_subsystem_util::metrics::prometheus::{ - self, CounterVec, Opts, PrometheusError, Registry, -}; - /// Emulated network metrics. #[derive(Clone)] pub(crate) struct Metrics { @@ -1036,9 +1034,8 @@ impl RequestExt for Requests { #[cfg(test)] mod tests { - use std::time::Instant; - use super::RateLimit; + use std::time::Instant; #[tokio::test] async fn test_expected_rate() { diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs new file mode 100644 index 0000000000000000000000000000000000000000..b83ef7d98d918e2c398f9f4b28558b1b93851051 --- /dev/null +++ b/polkadot/node/subsystem-bench/src/lib/usage.rs @@ -0,0 +1,146 @@ +// 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 usage implementation + +use colored::Colorize; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Debug, Serialize, Deserialize)] +pub struct BenchmarkUsage { + pub benchmark_name: String, + pub network_usage: Vec, + pub cpu_usage: Vec, +} + +impl std::fmt::Display for BenchmarkUsage { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "\n{}\n\n{}\n{}\n\n{}\n{}\n", + self.benchmark_name.purple(), + format!("{:<32}{:>12}{:>12}", "Network usage, KiB", "total", "per block").blue(), + self.network_usage + .iter() + .map(|v| v.to_string()) + .collect::>() + .join("\n"), + format!("{:<32}{:>12}{:>12}", "CPU usage, seconds", "total", "per block").blue(), + self.cpu_usage.iter().map(|v| v.to_string()).collect::>().join("\n") + ) + } +} + +impl BenchmarkUsage { + pub fn average(usages: &[Self]) -> Self { + let all_network_usages: Vec<&ResourceUsage> = + usages.iter().flat_map(|v| &v.network_usage).collect(); + let all_cpu_usage: Vec<&ResourceUsage> = usages.iter().flat_map(|v| &v.cpu_usage).collect(); + + Self { + benchmark_name: usages.first().map(|v| v.benchmark_name.clone()).unwrap_or_default(), + network_usage: ResourceUsage::average_by_resource_name(&all_network_usages), + cpu_usage: ResourceUsage::average_by_resource_name(&all_cpu_usage), + } + } + + pub fn check_network_usage(&self, checks: &[ResourceUsageCheck]) -> Vec { + check_usage(&self.benchmark_name, &self.network_usage, checks) + } + + pub fn check_cpu_usage(&self, checks: &[ResourceUsageCheck]) -> Vec { + check_usage(&self.benchmark_name, &self.cpu_usage, checks) + } + + pub fn cpu_usage_diff(&self, other: &Self, resource_name: &str) -> Option { + let self_res = self.cpu_usage.iter().find(|v| v.resource_name == resource_name); + let other_res = other.cpu_usage.iter().find(|v| v.resource_name == resource_name); + + match (self_res, other_res) { + (Some(self_res), Some(other_res)) => Some(self_res.diff(other_res)), + _ => None, + } + } +} + +fn check_usage( + benchmark_name: &str, + usage: &[ResourceUsage], + checks: &[ResourceUsageCheck], +) -> Vec { + checks + .iter() + .filter_map(|check| { + check_resource_usage(usage, check) + .map(|message| format!("{}: {}", benchmark_name, message)) + }) + .collect() +} + +fn check_resource_usage( + usage: &[ResourceUsage], + (resource_name, base, precision): &ResourceUsageCheck, +) -> Option { + if let Some(usage) = usage.iter().find(|v| v.resource_name == *resource_name) { + let diff = (base - usage.per_block).abs() / base; + if diff < *precision { + None + } else { + Some(format!( + "The resource `{}` is expected to be equal to {} with a precision {}, but the current value is {}", + resource_name, base, precision, usage.per_block + )) + } + } else { + Some(format!("The resource `{}` is not found", resource_name)) + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ResourceUsage { + pub resource_name: String, + pub total: f64, + pub per_block: f64, +} + +impl std::fmt::Display for ResourceUsage { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:<32}{:>12.3}{:>12.3}", self.resource_name.cyan(), self.total, self.per_block) + } +} + +impl ResourceUsage { + fn average_by_resource_name(usages: &[&Self]) -> Vec { + let mut by_name: HashMap> = Default::default(); + for usage in usages { + by_name.entry(usage.resource_name.clone()).or_default().push(usage); + } + let mut average = vec![]; + for (resource_name, values) in by_name { + let total = values.iter().map(|v| v.total).sum::() / values.len() as f64; + let per_block = values.iter().map(|v| v.per_block).sum::() / values.len() as f64; + average.push(Self { resource_name, total, per_block }); + } + average + } + + fn diff(&self, other: &Self) -> f64 { + (self.per_block - other.per_block).abs() / self.per_block + } +} + +type ResourceUsageCheck<'a> = (&'a str, f64, f64); diff --git a/polkadot/node/subsystem-bench/src/subsystem-bench.rs b/polkadot/node/subsystem-bench/src/subsystem-bench.rs deleted file mode 100644 index 433354f6525d9e143dc2c2cac7e9f1a5712e1520..0000000000000000000000000000000000000000 --- a/polkadot/node/subsystem-bench/src/subsystem-bench.rs +++ /dev/null @@ -1,297 +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 . - -//! A tool for running subsystem benchmark tests designed for development and -//! CI regression testing. -use clap::Parser; - -use colored::Colorize; - -use color_eyre::eyre; -use pyroscope::PyroscopeAgent; -use pyroscope_pprofrs::{pprof_backend, PprofConfig}; - -use std::path::Path; - -pub(crate) mod approval; -pub(crate) mod availability; -pub(crate) mod cli; -pub(crate) mod core; -mod valgrind; - -const LOG_TARGET: &str = "subsystem-bench"; - -use availability::{prepare_test, NetworkEmulation, TestState}; -use cli::TestObjective; - -use core::{ - configuration::TestConfiguration, - environment::{TestEnvironment, GENESIS_HASH}, -}; - -use clap_num::number_range; - -use crate::{approval::bench_approvals, core::display::display_configuration}; - -fn le_100(s: &str) -> Result { - number_range(s, 0, 100) -} - -fn le_5000(s: &str) -> Result { - number_range(s, 0, 5000) -} - -#[derive(Debug, Parser)] -#[allow(missing_docs)] -struct BenchCli { - #[arg(long, value_enum, ignore_case = true, default_value_t = NetworkEmulation::Ideal)] - /// The type of network to be emulated - pub network: NetworkEmulation, - - #[clap(flatten)] - pub standard_configuration: cli::StandardTestOptions, - - #[clap(short, long)] - /// The bandwidth of emulated remote peers in KiB - pub peer_bandwidth: Option, - - #[clap(short, long)] - /// The bandwidth of our node in KiB - pub bandwidth: Option, - - #[clap(long, value_parser=le_100)] - /// Emulated peer connection ratio [0-100]. - pub connectivity: Option, - - #[clap(long, value_parser=le_5000)] - /// Mean remote peer latency in milliseconds [0-5000]. - pub peer_mean_latency: Option, - - #[clap(long, value_parser=le_5000)] - /// Remote peer latency standard deviation - pub peer_latency_std_dev: Option, - - #[clap(long, default_value_t = false)] - /// Enable CPU Profiling with Pyroscope - pub profile: bool, - - #[clap(long, requires = "profile", default_value_t = String::from("http://localhost:4040"))] - /// Pyroscope Server URL - pub pyroscope_url: String, - - #[clap(long, requires = "profile", default_value_t = 113)] - /// Pyroscope Sample Rate - pub pyroscope_sample_rate: u32, - - #[clap(long, default_value_t = false)] - /// Enable Cache Misses Profiling with Valgrind. Linux only, Valgrind must be in the PATH - pub cache_misses: bool, - - #[clap(long, default_value_t = false)] - /// Shows the output in YAML format - pub yaml_output: bool, - - #[command(subcommand)] - pub objective: cli::TestObjective, -} - -impl BenchCli { - fn create_test_configuration(&self) -> TestConfiguration { - let configuration = &self.standard_configuration; - - match self.network { - NetworkEmulation::Healthy => TestConfiguration::healthy_network( - self.objective.clone(), - configuration.num_blocks, - configuration.n_validators, - configuration.n_cores, - configuration.min_pov_size, - configuration.max_pov_size, - ), - NetworkEmulation::Degraded => TestConfiguration::degraded_network( - self.objective.clone(), - configuration.num_blocks, - configuration.n_validators, - configuration.n_cores, - configuration.min_pov_size, - configuration.max_pov_size, - ), - NetworkEmulation::Ideal => TestConfiguration::ideal_network( - self.objective.clone(), - configuration.num_blocks, - configuration.n_validators, - configuration.n_cores, - configuration.min_pov_size, - configuration.max_pov_size, - ), - } - } - - fn launch(self) -> eyre::Result<()> { - let is_valgrind_running = valgrind::is_valgrind_running(); - if !is_valgrind_running && self.cache_misses { - return valgrind::relaunch_in_valgrind_mode() - } - - let agent_running = if self.profile { - let agent = PyroscopeAgent::builder(self.pyroscope_url.as_str(), "subsystem-bench") - .backend(pprof_backend(PprofConfig::new().sample_rate(self.pyroscope_sample_rate))) - .build()?; - - Some(agent.start()?) - } else { - None - }; - - let mut test_config = match self.objective { - TestObjective::TestSequence(options) => { - let test_sequence = - core::configuration::TestSequence::new_from_file(Path::new(&options.path)) - .expect("File exists") - .into_vec(); - let num_steps = test_sequence.len(); - gum::info!( - "{}", - format!("Sequence contains {} step(s)", num_steps).bright_purple() - ); - for (index, test_config) in test_sequence.into_iter().enumerate() { - let benchmark_name = - format!("{} #{} {}", &options.path, index + 1, test_config.objective); - gum::info!(target: LOG_TARGET, "{}", format!("Step {}/{}", index + 1, num_steps).bright_purple(),); - display_configuration(&test_config); - - let usage = match test_config.objective { - TestObjective::DataAvailabilityRead(ref _opts) => { - let mut state = TestState::new(&test_config); - let (mut env, _protocol_config) = prepare_test(test_config, &mut state); - env.runtime().block_on(availability::benchmark_availability_read( - &benchmark_name, - &mut env, - state, - )) - }, - TestObjective::ApprovalVoting(ref options) => { - let (mut env, state) = - approval::prepare_test(test_config.clone(), options.clone()); - env.runtime().block_on(bench_approvals( - &benchmark_name, - &mut env, - state, - )) - }, - TestObjective::DataAvailabilityWrite => { - let mut state = TestState::new(&test_config); - let (mut env, _protocol_config) = prepare_test(test_config, &mut state); - env.runtime().block_on(availability::benchmark_availability_write( - &benchmark_name, - &mut env, - state, - )) - }, - TestObjective::TestSequence(_) => todo!(), - TestObjective::Unimplemented => todo!(), - }; - - let output = if self.yaml_output { - serde_yaml::to_string(&vec![usage])? - } else { - usage.to_string() - }; - println!("{}", output); - } - - return Ok(()) - }, - TestObjective::DataAvailabilityRead(ref _options) => self.create_test_configuration(), - TestObjective::DataAvailabilityWrite => self.create_test_configuration(), - TestObjective::ApprovalVoting(_) => todo!(), - TestObjective::Unimplemented => todo!(), - }; - - let mut latency_config = test_config.latency.clone().unwrap_or_default(); - - if let Some(latency) = self.peer_mean_latency { - latency_config.mean_latency_ms = latency; - } - - if let Some(std_dev) = self.peer_latency_std_dev { - latency_config.std_dev = std_dev; - } - - // Write back the updated latency. - test_config.latency = Some(latency_config); - - if let Some(connectivity) = self.connectivity { - test_config.connectivity = connectivity; - } - - if let Some(bandwidth) = self.peer_bandwidth { - // CLI expects bw in KiB - test_config.peer_bandwidth = bandwidth * 1024; - } - - if let Some(bandwidth) = self.bandwidth { - // CLI expects bw in KiB - test_config.bandwidth = bandwidth * 1024; - } - - display_configuration(&test_config); - - let mut state = TestState::new(&test_config); - let (mut env, _protocol_config) = prepare_test(test_config, &mut state); - - let benchmark_name = format!("{}", self.objective); - let usage = match self.objective { - TestObjective::DataAvailabilityRead(_options) => env.runtime().block_on( - availability::benchmark_availability_read(&benchmark_name, &mut env, state), - ), - TestObjective::DataAvailabilityWrite => env.runtime().block_on( - availability::benchmark_availability_write(&benchmark_name, &mut env, state), - ), - TestObjective::TestSequence(_options) => todo!(), - TestObjective::ApprovalVoting(_) => todo!(), - TestObjective::Unimplemented => todo!(), - }; - - if let Some(agent_running) = agent_running { - let agent_ready = agent_running.stop()?; - agent_ready.shutdown(); - } - - let output = - if self.yaml_output { serde_yaml::to_string(&vec![usage])? } else { usage.to_string() }; - println!("{}", output); - - Ok(()) - } -} - -fn main() -> eyre::Result<()> { - color_eyre::install()?; - env_logger::builder() - .filter(Some("hyper"), log::LevelFilter::Info) - // Avoid `Terminating due to subsystem exit subsystem` warnings - .filter(Some("polkadot_overseer"), log::LevelFilter::Error) - .filter(None, log::LevelFilter::Info) - .format_timestamp_millis() - // .filter(None, log::LevelFilter::Trace) - .try_init() - .unwrap(); - - let cli: BenchCli = BenchCli::parse(); - cli.launch()?; - Ok(()) -} diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index ffd05cca2e9306ca8cb311cc8c93e9a65c0732ff..54c8f7e2ade773f1df84fc8cef1825c266364633 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -28,6 +28,6 @@ sc-client-api = { path = "../../../substrate/client/api" } sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } smallvec = "1.8.0" substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } -thiserror = "1.0.48" +thiserror = { workspace = true } async-trait = "0.1.74" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 549e43a671d6b4f9bd59659647cdaff8a69125d4..f11291fd0ea8c157d72a24349e94196178529446 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -1112,6 +1112,9 @@ pub struct ProspectiveValidationDataRequest { /// is present in and the depths of that tree the candidate is present in. pub type FragmentTreeMembership = Vec<(Hash, Vec)>; +/// A collection of ancestor candidates of a parachain. +pub type Ancestors = HashSet; + /// Messages sent to the Prospective Parachains subsystem. #[derive(Debug)] pub enum ProspectiveParachainsMessage { @@ -1128,15 +1131,18 @@ pub enum ProspectiveParachainsMessage { /// has been backed. This requires that the candidate was successfully introduced in /// the past. CandidateBacked(ParaId, CandidateHash), - /// Get N backable candidate hashes along with their relay parents for the given parachain, - /// under the given relay-parent hash, which is a descendant of the given candidate hashes. + /// Try getting N backable candidate hashes along with their relay parents for the given + /// parachain, under the given relay-parent hash, which is a descendant of the given ancestors. + /// Timed out ancestors should not be included in the collection. /// N should represent the number of scheduled cores of this ParaId. - /// Returns `None` on the channel if no such candidate exists. + /// A timed out ancestor frees the cores of all of its descendants, so if there's a hole in the + /// supplied ancestor path, we'll get candidates that backfill those timed out slots first. It + /// may also return less/no candidates, if there aren't enough backable candidates recorded. GetBackableCandidates( Hash, ParaId, u32, - Vec, + Ancestors, oneshot::Sender>, ), /// Get the hypothetical frontier membership of candidates with the given properties diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 7f6183076101b4474e8059435b42a69b108fbb05..4039fc9127da95e19e0aca427740793c39131ab9 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -26,13 +26,13 @@ use polkadot_primitives::{ PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; -use sc_client_api::HeaderBackend; +use sc_client_api::{AuxStore, HeaderBackend}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_api::{ApiError, ApiExt, ProvideRuntimeApi}; use sp_authority_discovery::AuthorityDiscoveryApi; -use sp_blockchain::Info; +use sp_blockchain::{BlockStatus, Info}; use sp_consensus_babe::{BabeApi, Epoch}; -use sp_runtime::traits::{Header as HeaderT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{collections::BTreeMap, sync::Arc}; /// Offers header utilities. @@ -595,3 +595,61 @@ where self.client.runtime_api().approval_voting_params(at) } } + +impl HeaderBackend for DefaultSubsystemClient +where + Client: HeaderBackend, + Block: sp_runtime::traits::Block, +{ + fn header( + &self, + hash: Block::Hash, + ) -> sc_client_api::blockchain::Result> { + self.client.header(hash) + } + + fn info(&self) -> Info { + self.client.info() + } + + fn status(&self, hash: Block::Hash) -> sc_client_api::blockchain::Result { + self.client.status(hash) + } + + fn number( + &self, + hash: Block::Hash, + ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> { + self.client.number(hash) + } + + fn hash( + &self, + number: NumberFor, + ) -> sc_client_api::blockchain::Result> { + self.client.hash(number) + } +} + +impl AuxStore for DefaultSubsystemClient +where + Client: AuxStore, +{ + fn insert_aux< + 'a, + 'b: 'a, + 'c: 'a, + I: IntoIterator, + D: IntoIterator, + >( + &self, + insert: I, + delete: D, + ) -> sp_blockchain::Result<()> { + self.client.insert_aux(insert, delete) + } + + fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result>> { + self.client.get_aux(key) + } +} diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 5f615e05abd4f2cf7526935d3093e2c9492b9eba..a668f8de76a0bdf15b1e4498924279b5fc467d3e 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -18,7 +18,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ parking_lot = "0.12.1" pin-project = "1.0.9" rand = "0.8.5" -thiserror = "1.0.48" +thiserror = { workspace = true } fatality = "0.0.6" gum = { package = "tracing-gum", path = "../gum" } derive_more = "0.99.17" @@ -46,7 +46,7 @@ parity-db = { version = "0.4.12" } assert_matches = "1.4.0" env_logger = "0.9.0" futures = { version = "0.3.21", features = ["thread-pool"] } -log = "0.4.17" +log = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } lazy_static = "1.4.0" polkadot-primitives-test-helpers = { path = "../../primitives/test-helpers" } diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index f04108537995f1caa0eb72833af2ca558fe931ec..02b227e6f345758d8b53b7da0b0cf3ddc2b77d05 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.21" hex = "0.4.3" gum = { package = "tracing-gum", path = "../../gum" } rand = "0.8.5" -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } tempfile = "3.2.0" tokio = "1.24.2" @@ -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 0295090b9521551533d012addeda064595dbeac3..f14fa9fde58b4426690cd1bd0e16129f095c34ec 100644 --- a/polkadot/node/test/service/src/chain_spec.rs +++ b/polkadot/node/test/service/src/chain_spec.rs @@ -19,7 +19,9 @@ use babe_primitives::AuthorityId as BabeId; use grandpa::AuthorityId as GrandpaId; use pallet_staking::Forcing; -use polkadot_primitives::{AccountId, AssignmentId, ValidatorId, MAX_CODE_SIZE, MAX_POV_SIZE}; +use polkadot_primitives::{ + vstaging::SchedulerParams, AccountId, AssignmentId, ValidatorId, MAX_CODE_SIZE, MAX_POV_SIZE, +}; use polkadot_service::chain_spec::{get_account_id_from_seed, get_from_seed, Extensions}; use polkadot_test_runtime::BABE_GENESIS_EPOCH_CONFIG; use sc_chain_spec::{ChainSpec, ChainType}; @@ -165,10 +167,14 @@ fn polkadot_testnet_genesis( max_code_size: MAX_CODE_SIZE, max_pov_size: MAX_POV_SIZE, max_head_data_size: 32 * 1024, - group_rotation_frequency: 20, - paras_availability_period: 4, no_show_slots: 10, minimum_validation_upgrade_delay: 5, + max_downward_message_size: 1024, + scheduler_params: SchedulerParams { + group_rotation_frequency: 20, + paras_availability_period: 4, + ..Default::default() + }, ..Default::default() }, } diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index e4eec32baf2abc3d766f6daf444528ea3ad2a528..1876595c7b40b6b8a9311a606a8430e6fcd42a08 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, }; @@ -44,8 +44,8 @@ use sc_network::{ }; use sc_service::{ config::{ - DatabaseSource, KeystoreConfig, MultiaddrWithPeerId, WasmExecutionMethod, - WasmtimeInstantiationStrategy, + DatabaseSource, KeystoreConfig, MultiaddrWithPeerId, RpcBatchRequestConfig, + WasmExecutionMethod, WasmtimeInstantiationStrategy, }, BasePath, BlocksPruning, Configuration, Role, RpcHandlers, TaskManager, }; @@ -186,6 +186,8 @@ pub fn node_config( rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, rpc_message_buffer_capacity: Default::default(), + rpc_batch_config: RpcBatchRequestConfig::Unlimited, + rpc_rate_limit: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, @@ -380,7 +382,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(), @@ -389,10 +391,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, @@ -409,7 +412,7 @@ pub fn construct_extrinsic( function.clone(), polkadot_test_runtime::Address::Id(caller.public().into()), polkadot_primitives::Signature::Sr25519(signature.clone()), - extra.clone(), + tx_ext.clone(), ) } diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index 6af7a8d6e380a0180bb83f670fd15deee7dfc21b..fa99490a997434eedee977121f13d8dcc1a9b5a1 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -19,7 +19,7 @@ futures-util = "0.3.30" lazy_static = "1.4.0" parity-scale-codec = { version = "3.6.1", features = ["derive"] } reqwest = { version = "0.11", features = ["rustls-tls"], default-features = false } -thiserror = "1.0.48" +thiserror = { workspace = true } gum = { package = "tracing-gum", path = "../gum" } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0.111" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index e5ff1051d25a3a972f22e9521a864b035332d500..d8c3cea7ad8b16062f346c12842d5f652936797c 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -24,7 +24,7 @@ derive_more = "0.99.11" bounded-collections = { version = "0.2.0", default-features = false, features = ["serde"] } # all optional crates. -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"] } +serde = { features = ["alloc", "derive"], workspace = true } [features] default = ["std"] diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 7dd0d9a563c5087b9295d5de5d6a6ee812033578..8ce4ceb47c245b621dcbf0199b7a73ad29b1a6f5 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -16,10 +16,10 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" -log = "0.4.17" +log = { workspace = true, default-features = true } test-parachain-adder = { path = ".." } polkadot-primitives = { path = "../../../../primitives" } diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index 19e1261db1e7c4f17308061929d559df34943159..82ceebcf4eee99f36140908580b41c13b04ea87e 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -17,7 +17,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ sp-std = { path = "../../../../substrate/primitives/std", default-features = false } tiny-keccak = { version = "2.0.2", features = ["keccak"] } dlmalloc = { version = "0.2.4", features = ["global"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } # We need to make sure the global allocator is disabled until we have support of full substrate externalities sp-io = { path = "../../../../substrate/primitives/io", default-features = false, features = ["disable_allocator"] } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 001c48476b58929852075fd914154b0b86daa93a..25fdbfa74ea08ae3a2b389927073aeadd066cb7d 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -16,10 +16,10 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" -log = "0.4.17" +log = { workspace = true, default-features = true } test-parachain-undying = { path = ".." } polkadot-primitives = { path = "../../../../primitives" } diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index c2fdf331568d6e69350542f5c4186b916474987a..e63fb621c7880c03fe0282a5500df69d20528f99 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -14,7 +14,8 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "se hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"] } +log = { workspace = true, default-features = false } +serde = { features = ["alloc", "derive"], workspace = true } application-crypto = { package = "sp-application-crypto", path = "../../substrate/primitives/application-crypto", default-features = false, features = ["serde"] } inherents = { package = "sp-inherents", path = "../../substrate/primitives/inherents", default-features = false } @@ -38,6 +39,7 @@ std = [ "application-crypto/std", "bitvec/std", "inherents/std", + "log/std", "parity-scale-codec/std", "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 2570bcadf606ab8ef0809a1f258a6068263f1db1..2ddd9b58dfe45d6560e9dc5c62f3d047ad8d9850 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -57,8 +57,8 @@ pub use v6::{ UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, ValidityError, ASSIGNMENT_KEY_TYPE_ID, LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID, - MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, - PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, + MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, MIN_CODE_SIZE, + ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, }; #[cfg(feature = "std")] diff --git a/polkadot/primitives/src/v6/executor_params.rs b/polkadot/primitives/src/v6/executor_params.rs index 112a529f62b0570e9270d1f09e397e6b9dc358b0..1e19f3b23fec9b9889d5976380f52ab6b66072b4 100644 --- a/polkadot/primitives/src/v6/executor_params.rs +++ b/polkadot/primitives/src/v6/executor_params.rs @@ -159,7 +159,9 @@ impl sp_std::fmt::LowerHex for ExecutorParamsHash { // into individual fields of the structure. Thus, complex migrations shall be avoided when adding // new entries and removing old ones. At the moment, there's no mandatory parameters defined. If // they show up, they must be clearly documented as mandatory ones. -#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize)] +#[derive( + Clone, Debug, Default, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize, +)] pub struct ExecutorParams(Vec); impl ExecutorParams { @@ -334,9 +336,3 @@ impl From<&[ExecutorParam]> for ExecutorParams { ExecutorParams(arr.to_vec()) } } - -impl Default for ExecutorParams { - fn default() -> Self { - ExecutorParams(vec![]) - } -} diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index fd0b32db799434d1b76071d53edf1e20a491c109..cab34deeb503b5a5606fef1934c0ef4238b03e31 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -16,7 +16,7 @@ //! `V6` Primitives. -use bitvec::vec::BitVec; +use bitvec::{field::BitField, slice::BitSlice, vec::BitVec}; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_std::{ @@ -72,6 +72,7 @@ pub use metrics::{ /// The key type ID for a collator key. pub const COLLATOR_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"coll"); +const LOG_TARGET: &str = "runtime::primitives"; mod collator_app { use application_crypto::{app_crypto, sr25519}; @@ -362,6 +363,9 @@ pub const PARACHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0"; /// The key type ID for parachain assignment key. pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn"); +/// Compressed or not the wasm blob can never be less than 9 bytes. +pub const MIN_CODE_SIZE: u32 = 9; + /// Maximum compressed code size we support right now. /// At the moment we have runtime upgrade on chain, which restricts scalability severely. If we want /// to have bigger values, we should fix that first. @@ -529,18 +533,6 @@ impl CandidateReceipt { } } -/// All data pertaining to the execution of a para candidate. -#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] -pub struct FullCandidateReceipt { - /// The inner candidate receipt. - pub inner: CandidateReceipt, - /// The validation data derived from the relay-chain state at that - /// point. The hash of the persisted validation data should - /// match the `persisted_validation_data_hash` in the descriptor - /// of the receipt. - pub validation_data: PersistedValidationData, -} - /// A candidate-receipt with commitments directly included. #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Hash))] @@ -703,19 +695,50 @@ pub type UncheckedSignedAvailabilityBitfields = Vec { /// The candidate referred to. - pub candidate: CommittedCandidateReceipt, + candidate: CommittedCandidateReceipt, /// The validity votes themselves, expressed as signatures. - pub validity_votes: Vec, - /// The indices of the validators within the group, expressed as a bitfield. - pub validator_indices: BitVec, + validity_votes: Vec, + /// The indices of the validators within the group, expressed as a bitfield. May be extended + /// beyond the backing group size to contain the assigned core index, if ElasticScalingMVP is + /// enabled. + validator_indices: BitVec, } impl BackedCandidate { - /// Get a reference to the descriptor of the para. + /// Constructor + pub fn new( + candidate: CommittedCandidateReceipt, + validity_votes: Vec, + validator_indices: BitVec, + core_index: Option, + ) -> Self { + let mut instance = Self { candidate, validity_votes, validator_indices }; + if let Some(core_index) = core_index { + instance.inject_core_index(core_index); + } + instance + } + + /// Get a reference to the descriptor of the candidate. pub fn descriptor(&self) -> &CandidateDescriptor { &self.candidate.descriptor } + /// Get a reference to the committed candidate receipt of the candidate. + pub fn candidate(&self) -> &CommittedCandidateReceipt { + &self.candidate + } + + /// Get a reference to the validity votes of the candidate. + pub fn validity_votes(&self) -> &[ValidityAttestation] { + &self.validity_votes + } + + /// Get a mutable reference to validity votes of the para. + pub fn validity_votes_mut(&mut self) -> &mut Vec { + &mut self.validity_votes + } + /// Compute this candidate's hash. pub fn hash(&self) -> CandidateHash where @@ -731,6 +754,48 @@ impl BackedCandidate { { self.candidate.to_plain() } + + /// Get a copy of the validator indices and the assumed core index, if any. + pub fn validator_indices_and_core_index( + &self, + core_index_enabled: bool, + ) -> (&BitSlice, Option) { + // This flag tells us if the block producers must enable Elastic Scaling MVP hack. + // It extends `BackedCandidate::validity_indices` to store a 8 bit core index. + if core_index_enabled { + let core_idx_offset = self.validator_indices.len().saturating_sub(8); + if core_idx_offset > 0 { + let (validator_indices_slice, core_idx_slice) = + self.validator_indices.split_at(core_idx_offset); + return ( + validator_indices_slice, + Some(CoreIndex(core_idx_slice.load::() as u32)), + ); + } + } + + (&self.validator_indices, None) + } + + /// Inject a core index in the validator_indices bitvec. + fn inject_core_index(&mut self, core_index: CoreIndex) { + let core_index_to_inject: BitVec = + BitVec::from_vec(vec![core_index.0 as u8]); + self.validator_indices.extend(core_index_to_inject); + } + + /// Update the validator indices and core index in the candidate. + pub fn set_validator_indices_and_core_index( + &mut self, + new_indices: BitVec, + maybe_core_index: Option, + ) { + self.validator_indices = new_indices; + + if let Some(core_index) = maybe_core_index { + self.inject_core_index(core_index); + } + } } /// Verify the backing of the given candidate. @@ -743,43 +808,65 @@ impl BackedCandidate { /// /// Returns either an error, indicating that one of the signatures was invalid or that the index /// was out-of-bounds, or the number of signatures checked. -pub fn check_candidate_backing + Clone + Encode>( - backed: &BackedCandidate, +pub fn check_candidate_backing + Clone + Encode + core::fmt::Debug>( + candidate_hash: CandidateHash, + validity_votes: &[ValidityAttestation], + validator_indices: &BitSlice, signing_context: &SigningContext, group_len: usize, validator_lookup: impl Fn(usize) -> Option, ) -> Result { - if backed.validator_indices.len() != group_len { + if validator_indices.len() != group_len { + log::debug!( + target: LOG_TARGET, + "Check candidate backing: indices mismatch: group_len = {} , indices_len = {}", + group_len, + validator_indices.len(), + ); return Err(()) } - if backed.validity_votes.len() > group_len { + if validity_votes.len() > group_len { + log::debug!( + target: LOG_TARGET, + "Check candidate backing: Too many votes, expected: {}, found: {}", + group_len, + validity_votes.len(), + ); return Err(()) } - // this is known, even in runtime, to be blake2-256. - let hash = backed.candidate.hash(); - let mut signed = 0; - for ((val_in_group_idx, _), attestation) in backed - .validator_indices + for ((val_in_group_idx, _), attestation) in validator_indices .iter() .enumerate() .filter(|(_, signed)| **signed) - .zip(backed.validity_votes.iter()) + .zip(validity_votes.iter()) { let validator_id = validator_lookup(val_in_group_idx).ok_or(())?; - let payload = attestation.signed_payload(hash, signing_context); + let payload = attestation.signed_payload(candidate_hash, signing_context); let sig = attestation.signature(); if sig.verify(&payload[..], &validator_id) { signed += 1; } else { + log::debug!( + target: LOG_TARGET, + "Check candidate backing: Invalid signature. validator_id = {:?}, validator_index = {} ", + validator_id, + val_in_group_idx, + ); return Err(()) } } - if signed != backed.validity_votes.len() { + if signed != validity_votes.len() { + log::error!( + target: LOG_TARGET, + "Check candidate backing: Too many signatures, expected = {}, found = {}", + validity_votes.len(), + signed, + ); return Err(()) } @@ -1856,6 +1943,34 @@ pub enum PvfExecKind { #[cfg(test)] mod tests { use super::*; + use bitvec::bitvec; + use primitives::sr25519; + + pub fn dummy_committed_candidate_receipt() -> CommittedCandidateReceipt { + let zeros = Hash::zero(); + + CommittedCandidateReceipt { + descriptor: CandidateDescriptor { + para_id: 0.into(), + relay_parent: zeros, + collator: CollatorId::from(sr25519::Public::from_raw([0; 32])), + persisted_validation_data_hash: zeros, + pov_hash: zeros, + erasure_root: zeros, + signature: CollatorSignature::from(sr25519::Signature([0u8; 64])), + para_head: zeros, + validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(), + }, + commitments: CandidateCommitments { + head_data: HeadData(vec![]), + upward_messages: vec![].try_into().expect("empty vec fits within bounds"), + new_validation_code: None, + horizontal_messages: vec![].try_into().expect("empty vec fits within bounds"), + processed_downward_messages: 0, + hrmp_watermark: 0_u32, + }, + } + } #[test] fn group_rotation_info_calculations() { @@ -1930,4 +2045,73 @@ mod tests { assert!(zero_b.leading_zeros() >= zero_u.leading_zeros()); } + + #[test] + fn test_backed_candidate_injected_core_index() { + let initial_validator_indices = bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1]; + let mut candidate = BackedCandidate::new( + dummy_committed_candidate_receipt(), + vec![], + initial_validator_indices.clone(), + None, + ); + + // No core index supplied, ElasticScalingMVP is off. + let (validator_indices, core_index) = candidate.validator_indices_and_core_index(false); + assert_eq!(validator_indices, initial_validator_indices.as_bitslice()); + assert!(core_index.is_none()); + + // No core index supplied, ElasticScalingMVP is on. Still, decoding will be ok if backing + // group size is <= 8, to give a chance to parachains that don't have multiple cores + // assigned. + let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true); + assert_eq!(validator_indices, initial_validator_indices.as_bitslice()); + assert!(core_index.is_none()); + + let encoded_validator_indices = candidate.validator_indices.clone(); + candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index); + assert_eq!(candidate.validator_indices, encoded_validator_indices); + + // No core index supplied, ElasticScalingMVP is on. Decoding is corrupted if backing group + // size larger than 8. + let candidate = BackedCandidate::new( + dummy_committed_candidate_receipt(), + vec![], + bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0], + None, + ); + let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true); + assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0].as_bitslice()); + assert!(core_index.is_some()); + + // Core index supplied, ElasticScalingMVP is off. Core index will be treated as normal + // validator indices. Runtime will check against this. + let candidate = BackedCandidate::new( + dummy_committed_candidate_receipt(), + vec![], + bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1], + Some(CoreIndex(10)), + ); + let (validator_indices, core_index) = candidate.validator_indices_and_core_index(false); + assert_eq!( + validator_indices, + bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0] + ); + assert!(core_index.is_none()); + + // Core index supplied, ElasticScalingMVP is on. + let mut candidate = BackedCandidate::new( + dummy_committed_candidate_receipt(), + vec![], + bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1], + Some(CoreIndex(10)), + ); + let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true); + assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1]); + assert_eq!(core_index, Some(CoreIndex(10))); + + let encoded_validator_indices = candidate.validator_indices.clone(); + candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index); + assert_eq!(candidate.validator_indices, encoded_validator_indices); + } } diff --git a/polkadot/primitives/src/v6/slashing.rs b/polkadot/primitives/src/v6/slashing.rs index efffb932cdc0d997e08f9d195e2c42b857a7c8f5..bcd7d0c2fc4455e2ebf01fab027dbf0618f63dba 100644 --- a/polkadot/primitives/src/v6/slashing.rs +++ b/polkadot/primitives/src/v6/slashing.rs @@ -54,7 +54,7 @@ impl DisputesTimeSlot { /// is required to identify and verify it. #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug)] pub struct DisputeProof { - /// Time slot when the dispute occured. + /// Time slot when the dispute occurred. pub time_slot: DisputesTimeSlot, /// The dispute outcome. pub kind: SlashingOffenceKind, diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 630bcf8679ad3046ce734042a1557058ea440110..bd2a5106c44de5895fb327957161c84f13a983b0 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -23,6 +23,7 @@ use sp_std::prelude::*; use parity_scale_codec::{Decode, Encode}; use primitives::RuntimeDebug; use scale_info::TypeInfo; +use sp_arithmetic::Perbill; /// Approval voting configuration parameters #[derive( @@ -50,6 +51,81 @@ impl Default for ApprovalVotingParams { } } +/// Scheduler configuration parameters. All coretime/ondemand parameters are here. +#[derive( + RuntimeDebug, + Copy, + Clone, + PartialEq, + Encode, + Decode, + TypeInfo, + serde::Serialize, + serde::Deserialize, +)] +pub struct SchedulerParams { + /// How often parachain groups should be rotated across parachains. + /// + /// Must be non-zero. + pub group_rotation_frequency: BlockNumber, + /// Availability timeout for a block on a core, measured in blocks. + /// + /// This is the maximum amount of blocks after a core became occupied that validators have time + /// to make the block available. + /// + /// This value only has effect on group rotations. If backers backed something at the end of + /// their rotation, the occupied core affects the backing group that comes afterwards. We limit + /// the effect one backing group can have on the next to `paras_availability_period` blocks. + /// + /// Within a group rotation there is no timeout as backers are only affecting themselves. + /// + /// Must be at least 1. With a value of 1, the previous group will not be able to negatively + /// affect the following group at the expense of a tight availability timeline at group + /// rotation boundaries. + pub paras_availability_period: BlockNumber, + /// The maximum number of validators to have per core. + /// + /// `None` means no maximum. + pub max_validators_per_core: Option, + /// The amount of blocks ahead to schedule paras. + 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. + pub max_availability_timeouts: u32, + /// The maximum queue size of the pay as you go module. + pub on_demand_queue_max_size: u32, + /// The target utilization of the spot price queue in percentages. + pub on_demand_target_queue_utilization: Perbill, + /// How quickly the fee rises in reaction to increased utilization. + /// The lower the number the slower the increase. + 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 claimqueue before getting cleared. + /// This number should go reasonably higher than the number of blocks in the async backing + /// lookahead. + pub ttl: BlockNumber, +} + +impl> Default for SchedulerParams { + fn default() -> Self { + Self { + group_rotation_frequency: 1u32.into(), + paras_availability_period: 1u32.into(), + max_validators_per_core: Default::default(), + lookahead: 1, + num_cores: Default::default(), + max_availability_timeouts: Default::default(), + on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + on_demand_target_queue_utilization: Perbill::from_percent(25), + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_base_fee: 10_000_000u128, + ttl: 5u32.into(), + } + } +} + use bitvec::vec::BitVec; /// Bit indices in the `HostConfiguration.node_features` that correspond to different node features. @@ -64,9 +140,13 @@ pub mod node_features { /// Tells if tranch0 assignments could be sent in a single certificate. /// Reserved for: `` EnableAssignmentsV2 = 0, + /// This feature enables the extension of `BackedCandidate::validator_indices` by 8 bits. + /// The value stored there represents the assumed core index where the candidates + /// are backed. This is needed for the elastic scaling MVP. + ElasticScalingMVP = 1, /// First unassigned feature bit. /// Every time a new feature flag is assigned it should take this value. /// and this should be incremented. - FirstUnassigned = 1, + FirstUnassigned = 2, } } diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index d532d6ff57f4a34c53d7099d011f1ca68bf6cf5f..c0118f5960a47eabe205c4d2cf6bcf6d295ce347 100644 --- a/polkadot/primitives/test-helpers/src/lib.rs +++ b/polkadot/primitives/test-helpers/src/lib.rs @@ -126,7 +126,7 @@ pub fn dummy_candidate_descriptor>(relay_parent: H) -> CandidateD /// Create meaningless validation code. pub fn dummy_validation_code() -> ValidationCode { - ValidationCode(vec![1, 2, 3]) + ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]) } /// Create meaningless head data. diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md index e0984bd58d1dd8ea22b145a15b4a3bab8779de80..39a317a07c847aa734e78f85de524f5541c8ddf6 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md @@ -125,6 +125,14 @@ execution request: reason, which may or may not be independent of the candidate or PVF. 5. **Internal errors:** See "Internal Errors" section. In this case, after the retry we abstain from voting. +6. **RuntimeConstruction** error. The precheck handles a general case of a wrong + artifact but doesn't guarantee its consistency between the preparation and + the execution. If something happened with the artifact between + the preparation of the artifact and its execution (e.g. the artifact was + corrupted on disk or a dirty node upgrade happened when the prepare worker + has a wasmtime version different from the execute worker's wasmtime version). + We treat such an error as possibly transient due to local issues and retry + one time. ### Preparation timeouts diff --git a/polkadot/roadmap/implementers-guide/src/types/README.md b/polkadot/roadmap/implementers-guide/src/types/README.md index 87092bf3a005353b09d375b89f599c2918295ef5..5fd3050f94906f04e876e9018698edb1a5218e2f 100644 --- a/polkadot/roadmap/implementers-guide/src/types/README.md +++ b/polkadot/roadmap/implementers-guide/src/types/README.md @@ -55,17 +55,6 @@ digraph { CandidateCommitmentsHash [label = "Hash", shape="doublecircle", fill="gray90"] CandidateCommitmentsHash -> CandidateCommitments:name - FullCandidateReceipt [label = < - - - - -
FullCandidateReceipt<H = Hash, N = BlockNumber>
innerCandidateReceipt<H>
validation_dataValidationData<N>
- >] - - FullCandidateReceipt:inner -> CandidateReceipt:name - FullCandidateReceipt:validation_data -> ValidationData:name - CommittedCandidateReceipt [label = < diff --git a/polkadot/roadmap/implementers-guide/src/types/candidate.md b/polkadot/roadmap/implementers-guide/src/types/candidate.md index 00176229e5a4356a9f88ae91c16eb46617b47216..399d7854ac4a057f49435702adb1a815c960c593 100644 --- a/polkadot/roadmap/implementers-guide/src/types/candidate.md +++ b/polkadot/roadmap/implementers-guide/src/types/candidate.md @@ -20,12 +20,8 @@ struct ParaId(u32); ## Candidate Receipt -Much info in a [`FullCandidateReceipt`](#full-candidate-receipt) is duplicated from the relay-chain state. When the -corresponding relay-chain state is considered widely available, the Candidate Receipt should be favored over the -`FullCandidateReceipt`. - -Examples of situations where the state is readily available includes within the scope of work done by subsystems working -on a given relay-parent, or within the logic of the runtime importing a backed candidate. +Compact representation of the result of a validation. This is what validators +receive from collators, together with the PoV. ```rust /// A candidate-receipt. @@ -37,24 +33,6 @@ struct CandidateReceipt { } ``` -## Full Candidate Receipt - -This is the full receipt type. The `PersistedValidationData` are technically redundant with the `inner.relay_parent`, -which uniquely describes the block in the blockchain from whose state these values are derived. The -[`CandidateReceipt`](#candidate-receipt) variant is often used instead for this reason. - -However, the Full Candidate Receipt type is useful as a means of avoiding the implicit dependency on availability of old -blockchain state. In situations such as availability and approval, having the full description of the candidate within a -self-contained struct is convenient. - -```rust -/// All data pertaining to the execution of a para candidate. -struct FullCandidateReceipt { - inner: CandidateReceipt, - validation_data: PeristedValidationData, -} -``` - ## Committed Candidate Receipt This is a variant of the candidate receipt which includes the commitments of the candidate receipt alongside the diff --git a/polkadot/roadmap/implementers-guide/src/types/runtime.md b/polkadot/roadmap/implementers-guide/src/types/runtime.md index 4b97409f8df3e4f3581161ef47713bfdfbcb9654..1dfabd96db7cdb929c416201eeeb233af11f5dbb 100644 --- a/polkadot/roadmap/implementers-guide/src/types/runtime.md +++ b/polkadot/roadmap/implementers-guide/src/types/runtime.md @@ -4,106 +4,24 @@ Types used within the runtime exclusively and pervasively. ## Host Configuration -The internal-to-runtime configuration of the parachain host. This is expected to be altered only by governance procedures. - -```rust -struct HostConfiguration { - /// The minimum period, in blocks, between which parachains can update their validation code. - pub validation_upgrade_cooldown: BlockNumber, - /// The delay, in blocks, before a validation upgrade is applied. - pub validation_upgrade_delay: BlockNumber, - /// How long to keep code on-chain, in blocks. This should be sufficiently long that disputes - /// have concluded. - pub code_retention_period: BlockNumber, - /// The maximum validation code size, in bytes. - pub max_code_size: u32, - /// The maximum head-data size, in bytes. - pub max_head_data_size: u32, - /// The amount of availability cores to dedicate to parathreads (on-demand parachains). - pub parathread_cores: u32, - /// The number of retries that a parathread (on-demand parachain) author has to submit their block. - pub parathread_retries: u32, - /// How often parachain groups should be rotated across parachains. - pub group_rotation_frequency: BlockNumber, - /// The availability period, in blocks, for parachains. This is the amount of blocks - /// after inclusion that validators have to make the block available and signal its availability to - /// the chain. Must be at least 1. - pub chain_availability_period: BlockNumber, - /// The availability period, in blocks, for parathreads (on-demand parachains). Same as the `chain_availability_period`, - /// but a differing timeout due to differing requirements. Must be at least 1. - pub thread_availability_period: BlockNumber, - /// The amount of blocks ahead to schedule on-demand parachains. - pub scheduling_lookahead: u32, - /// The maximum number of validators to have per core. `None` means no maximum. - pub max_validators_per_core: Option, - /// The maximum number of validators to use for parachains, in total. `None` means no maximum. - pub max_validators: Option, - /// The amount of sessions to keep for disputes. - pub dispute_period: SessionIndex, - /// How long after dispute conclusion to accept statements. - pub dispute_post_conclusion_acceptance_period: BlockNumber, - /// The maximum number of dispute spam slots - pub dispute_max_spam_slots: u32, - /// The amount of consensus slots that must pass between submitting an assignment and - /// submitting an approval vote before a validator is considered a no-show. - /// Must be at least 1. - pub no_show_slots: u32, - /// The number of delay tranches in total. - pub n_delay_tranches: u32, - /// The width of the zeroth delay tranche for approval assignments. This many delay tranches - /// beyond 0 are all consolidated to form a wide 0 tranche. - pub zeroth_delay_tranche_width: u32, - /// The number of validators needed to approve a block. - pub needed_approvals: u32, - /// The number of samples to use in `RelayVRFModulo` or `RelayVRFModuloCompact` approval assignment criterions. - pub relay_vrf_modulo_samples: u32, - /// Total number of individual messages allowed in the parachain -> relay-chain message queue. - pub max_upward_queue_count: u32, - /// Total size of messages allowed in the parachain -> relay-chain message queue before which - /// no further messages may be added to it. If it exceeds this then the queue may contain only - /// a single message. - pub max_upward_queue_size: u32, - /// The maximum size of an upward message that can be sent by a candidate. - /// - /// This parameter affects the upper bound of size of `CandidateCommitments`. - pub max_upward_message_size: u32, - /// The maximum number of messages that a candidate can contain. - /// - /// This parameter affects the upper bound of size of `CandidateCommitments`. - pub max_upward_message_num_per_candidate: u32, - /// The maximum size of a message that can be put in a downward message queue. - /// - /// Since we require receiving at least one DMP message the obvious upper bound of the size is - /// the PoV size. Of course, there is a lot of other different things that a parachain may - /// decide to do with its PoV so this value in practice will be picked as a fraction of the PoV - /// size. - pub max_downward_message_size: u32, - /// The deposit that the sender should provide for opening an HRMP channel. - pub hrmp_sender_deposit: u32, - /// The deposit that the recipient should provide for accepting opening an HRMP channel. - pub hrmp_recipient_deposit: u32, - /// The maximum number of messages allowed in an HRMP channel at once. - pub hrmp_channel_max_capacity: u32, - /// The maximum total size of messages in bytes allowed in an HRMP channel at once. - pub hrmp_channel_max_total_size: u32, - /// The maximum number of inbound HRMP channels a parachain is allowed to accept. - pub hrmp_max_parachain_inbound_channels: u32, - /// The maximum number of inbound HRMP channels a parathread (on-demand parachain) is allowed to accept. - pub hrmp_max_parathread_inbound_channels: u32, - /// The maximum size of a message that could ever be put into an HRMP channel. - /// - /// This parameter affects the upper bound of size of `CandidateCommitments`. - pub hrmp_channel_max_message_size: u32, - /// The maximum number of outbound HRMP channels a parachain is allowed to open. - pub hrmp_max_parachain_outbound_channels: u32, - /// The maximum number of outbound HRMP channels a parathread (on-demand parachain) is allowed to open. - pub hrmp_max_parathread_outbound_channels: u32, - /// The maximum number of outbound HRMP messages can be sent by a candidate. - /// - /// This parameter affects the upper bound of size of `CandidateCommitments`. - pub hrmp_max_message_num_per_candidate: u32, -} -``` +The internal-to-runtime configuration of the parachain host is kept in `struct HostConfiguration`. This is expected to +be altered only by governance procedures or via migrations from the Polkadot-SDK codebase. The latest definition of +`HostConfiguration` can be found in the project repo +[here](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/runtime/parachains/src/configuration.rs). Each +parameter has got a doc comment so for any details please refer to the code. + +Some related parameters in `HostConfiguration` are grouped together so that they can be managed easily. These are: +* `async_backing_params` in `struct AsyncBackingParams` +* `executor_params` in `struct ExecutorParams` +* `approval_voting_params` in `struct ApprovalVotingParams` +* `scheduler_params` in `struct SchedulerParams` + +Check the definitions of these structs for further details. + +### Configuration migrations +Modifying `HostConfiguration` requires a storage migration. These migrations are located in the +[`migrations`](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/runtime/parachains/src/configuration.rs) +subfolder of Polkadot-SDK repo. ## ParaInherentData diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index 98ce2e482ce1a381ec0df08a68ab124781294387..5af5e63b175380f7e695deb973ea48df52c326e4 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -10,7 +10,7 @@ description = "Polkadot specific RPC functionality." workspace = true [dependencies] -jsonrpsee = { version = "0.20.3", features = ["server"] } +jsonrpsee = { version = "0.22", features = ["server"] } polkadot-primitives = { path = "../primitives" } sc-client-api = { path = "../../substrate/client/api" } sp-blockchain = { path = "../../substrate/primitives/blockchain" } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index acbc845c41a3cbc6077bd0d4c743066369db6885..c2205938295e38f8e683a211a09b6e3bce777e38 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -13,11 +13,11 @@ workspace = true impl-trait-for-tuples = "0.2.2" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc"] } -serde_derive = { version = "1.0.117" } +serde = { features = ["alloc"], workspace = true } +serde_derive = { workspace = true } static_assertions = "1.1.0" sp-api = { path = "../../../substrate/primitives/api", default-features = false } @@ -58,8 +58,6 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac slot-range-helper = { path = "slot_range_helper", default-features = false } xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false, optional = true } - -pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } [dev-dependencies] @@ -69,7 +67,7 @@ pallet-babe = { path = "../../../substrate/frame/babe" } pallet-treasury = { path = "../../../substrate/frame/treasury" } sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-keyring = { path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } libsecp256k1 = "0.7.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } @@ -99,7 +97,6 @@ std = [ "pallet-transaction-payment/std", "pallet-treasury/std", "pallet-vesting/std", - "pallet-xcm-benchmarks/std", "parity-scale-codec/std", "primitives/std", "runtime-parachains/std", @@ -135,9 +132,9 @@ 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", - "pallet-xcm-benchmarks/runtime-benchmarks", "primitives/runtime-benchmarks", "runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index ba3108c0aa38b9b9a2dabba0559d74ec3c97d0ed..def6bad692a235d3282774b0db3fabdaf33c89b3 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -29,14 +29,14 @@ pub mod v1 { impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - let onchain_version = Pallet::::on_chain_storage_version(); - ensure!(onchain_version < 1, "assigned_slots::MigrateToV1 migration can be deleted"); + let on_chain_version = Pallet::::on_chain_storage_version(); + ensure!(on_chain_version < 1, "assigned_slots::MigrateToV1 migration can be deleted"); Ok(Default::default()) } fn on_runtime_upgrade() -> frame_support::weights::Weight { - let onchain_version = Pallet::::on_chain_storage_version(); - if onchain_version < 1 { + let on_chain_version = Pallet::::on_chain_storage_version(); + if on_chain_version < 1 { const MAX_PERMANENT_SLOTS: u32 = 100; const MAX_TEMPORARY_SLOTS: u32 = 100; @@ -52,8 +52,8 @@ pub mod v1 { #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - let onchain_version = Pallet::::on_chain_storage_version(); - ensure!(onchain_version == 1, "assigned_slots::MigrateToV1 needs to be run"); + let on_chain_version = Pallet::::on_chain_storage_version(); + ensure!(on_chain_version == 1, "assigned_slots::MigrateToV1 needs to be run"); assert_eq!(>::get(), 100); assert_eq!(>::get(), 100); Ok(()) diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index 3419e3497f7d446f7bea02bf8134932c0a0cdbf6..4f032f4dfa3bd76b2e3ced899cec3a0bb5b06ffe 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -107,7 +107,7 @@ type LeasePeriodOf = <::Leaser as Leaser>>::Le pub mod pallet { use super::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 86550ea8b4ebf97054ce6713fffcdd0dd2cf628e..57a95b22af3801dc22ba19cdee61b26c1cfe6f78 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -29,7 +29,11 @@ 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, CheckedSub, DispatchInfoOf, Dispatchable, TransactionExtension, + TransactionExtensionBase, Zero, + }, transaction_validity::{ InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, @@ -50,6 +54,7 @@ pub trait WeightInfo { fn claim_attest() -> Weight; fn attest() -> Weight; fn move_claim() -> Weight; + fn prevalidate_attests() -> Weight; } pub struct TestWeightInfo; @@ -69,6 +74,9 @@ 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. @@ -84,7 +92,7 @@ pub enum StatementKind { impl StatementKind { /// Convert this to the (English) statement it represents. - fn to_text(self) -> &'static [u8] { + pub fn to_text(self) -> &'static [u8] { match self { StatementKind::Regular => &b"I hereby agree to the terms of the statement whose SHA-256 multihash is \ @@ -166,6 +174,13 @@ pub mod pallet { #[pallet::without_storage_info] pub struct Pallet(_); + #[cfg(feature = "runtime-benchmarks")] + /// Helper trait to benchmark the `PrevalidateAttests` transaction extension. + pub trait BenchmarkHelperTrait { + /// `Call` to be used when benchmarking the transaction extension. + fn default_call_and_info() -> (RuntimeCall, DispatchInfo); + } + /// Configuration trait. #[pallet::config] pub trait Config: frame_system::Config { @@ -176,6 +191,12 @@ pub mod pallet { type Prefix: Get<&'static [u8]>; type MoveClaimOrigin: EnsureOrigin; type WeightInfo: WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + /// Benchmark helper + type BenchmarkHelper: BenchmarkHelperTrait< + Self::RuntimeCall, + DispatchInfoOf, + >; } #[pallet::event] @@ -402,7 +423,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 @@ -612,46 +633,46 @@ impl PrevalidateAttests where ::RuntimeCall: IsSubType>, { - /// Create new `SignedExtension` to check runtime version. + /// Create new `TransactionExtension` to check runtime version. pub fn new() -> Self { Self(sp_std::marker::PhantomData) } } -impl SignedExtension for PrevalidateAttests +impl TransactionExtensionBase for PrevalidateAttests where ::RuntimeCall: IsSubType>, { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); const IDENTIFIER: &'static str = "PrevalidateAttests"; + type Implicit = (); +} - 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(|_| ()) - } +impl TransactionExtension for PrevalidateAttests +where + ::RuntimeCall: IsSubType>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + Clone, +{ + type Pre = (); + type Val = (); // // 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 { + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; if let Some(local_call) = call.is_sub_type() { if let Call::attest { statement: attested_statement } = local_call { let signer = Preclaims::::get(who) @@ -662,8 +683,9 @@ where } } } - Ok(ValidTransaction::default()) + Ok((ValidTransaction::default(), (), origin)) } + impl_tx_ext_default!(T::RuntimeCall; Context; prepare); } #[cfg(any(test, feature = "runtime-benchmarks"))] @@ -696,13 +718,12 @@ mod secp_utils { } #[cfg(test)] -mod tests { +pub(super) mod tests { use super::*; use hex_literal::hex; use secp_utils::*; use parity_scale_codec::Encode; - 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 crate::claims; @@ -715,7 +736,7 @@ mod tests { }; use pallet_balances; use sp_runtime::{ - traits::{BlakeTwo256, Identity, IdentityLookup}, + traits::{DispatchTransaction, Identity}, transaction_validity::TransactionLongevity, BuildStorage, DispatchError::BadOrigin, @@ -734,34 +755,13 @@ mod tests { } ); - parameter_types! { - pub const BlockHashCount: u32 = 250; - } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -815,6 +815,19 @@ mod tests { type Prefix = Prefix; type MoveClaimOrigin = frame_system::EnsureSignedBy; type WeightInfo = TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + } + + #[cfg(feature = "runtime-benchmarks")] + impl BenchmarkHelperTrait> for () { + fn default_call_and_info() -> (RuntimeCall, DispatchInfoOf) { + let call = RuntimeCall::Claims(crate::claims::Call::attest { + statement: StatementKind::Regular.to_text().to_vec(), + }); + let info = call.get_dispatch_info(); + (call, info) + } } fn alice() -> libsecp256k1::SecretKey { @@ -1096,8 +1109,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); + assert_eq!(r.unwrap().0, ValidTransaction::default()); }); } @@ -1109,13 +1122,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); 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); assert!(r.is_err()); }); } @@ -1469,14 +1482,17 @@ mod tests { } #[cfg(feature = "runtime-benchmarks")] -mod benchmarking { +pub(super) mod benchmarking { use super::*; use crate::claims::Call; use frame_benchmarking::{account, benchmarks}; use frame_support::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; @@ -1512,6 +1528,11 @@ mod benchmarking { } benchmarks! { + where_clause { where ::RuntimeCall: IsSubType>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner + Clone, + <::RuntimeCall as Dispatchable>::PostInfo: Default, + } + // Benchmark `claim` including `validate_unsigned` logic. claim { let c = MAX_CLAIMS; @@ -1690,6 +1711,38 @@ mod benchmarking { } } + prevalidate_attests { + let c = MAX_CLAIMS; + + for i in 0 .. c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + + let ext = PrevalidateAttests::::new(); + let (call, info) = T::BenchmarkHelper::default_call_and_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; + let signature = sig::(&secret_key, &account.encode(), statement.to_text()); + 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())); + }: { + assert!(ext.test_run( + RawOrigin::Signed(account).into(), + &call, + &info, + 0, + |_| { + Ok(Default::default()) + } + ).unwrap().is_ok()); + } + impl_benchmark_test_suite!( Pallet, crate::claims::tests::new_test_ext(), diff --git a/polkadot/runtime/common/src/crowdloan/migration.rs b/polkadot/runtime/common/src/crowdloan/migration.rs index 5133c14ada9276a56ae91f38e8a67b4846979866..3afd6b3fbc94b5b30bad162cfcf8236a029b77da 100644 --- a/polkadot/runtime/common/src/crowdloan/migration.rs +++ b/polkadot/runtime/common/src/crowdloan/migration.rs @@ -24,9 +24,9 @@ use frame_support::{ pub struct MigrateToTrackInactiveV2(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToTrackInactiveV2 { fn on_runtime_upgrade() -> Weight { - let onchain_version = Pallet::::on_chain_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); - if onchain_version == 1 { + if on_chain_version == 1 { let mut translated = 0u64; for item in Funds::::iter_values() { let b = diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index 7d1b892dfa7fc6c4057a7da8731e39a9a4b2d3e8..35d075f2ff6c2f5ee3c1fb4a159eed346d6c6781 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -180,7 +180,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] diff --git a/polkadot/runtime/common/src/identity_migrator.rs b/polkadot/runtime/common/src/identity_migrator.rs index 0dfb03b06ba32b65941165ec993bc694b84a1389..bf334a63e9588411f57ecc8b6ee2fca72861d7aa 100644 --- a/polkadot/runtime/common/src/identity_migrator.rs +++ b/polkadot/runtime/common/src/identity_migrator.rs @@ -31,7 +31,7 @@ use pallet_identity; use sp_core::Get; #[cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, BenchmarkError}; +use frame_benchmarking::{account, v2::*, BenchmarkError}; pub trait WeightInfo { fn reap_identity(r: u32, s: u32) -> Weight; diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 1ddad37831b68582cfc14f882870922c67058f1d..4ba85a3c8353565ad17cfb5db29c3d4e1dfa8a44 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -107,7 +107,7 @@ pub fn era_payout( )] pub enum VersionedLocatableAsset { #[codec(index = 3)] - V3 { location: xcm::v3::MultiLocation, asset_id: xcm::v3::AssetId }, + V3 { location: xcm::v3::Location, asset_id: xcm::v3::AssetId }, #[codec(index = 4)] V4 { location: xcm::v4::Location, asset_id: xcm::v4::AssetId }, } @@ -140,7 +140,7 @@ impl TryConvert<&VersionedLocation, xcm::latest::Location> for VersionedLocation ) -> Result { let latest = match location.clone() { VersionedLocation::V2(l) => { - let v3: xcm::v3::MultiLocation = l.try_into().map_err(|_| location)?; + let v3: xcm::v3::Location = l.try_into().map_err(|_| location)?; v3.try_into().map_err(|_| location)? }, VersionedLocation::V3(l) => l.try_into().map_err(|_| location)?, @@ -191,11 +191,11 @@ pub mod benchmarks { { fn create_asset_kind(seed: u32) -> VersionedLocatableAsset { VersionedLocatableAsset::V3 { - location: xcm::v3::MultiLocation::new( + location: xcm::v3::Location::new( Parents::get(), [xcm::v3::Junction::Parachain(ParaId::get())], ), - asset_id: xcm::v3::MultiLocation::new( + asset_id: xcm::v3::Location::new( 0, [ xcm::v3::Junction::PalletInstance(seed.try_into().unwrap()), diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index f551743b395cbdb3ffa1748b75c2a48d782a0d4a..3aa291f0f1f3075670cea40cee25645456057bdb 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -36,6 +36,7 @@ use pallet_identity::{self, legacy::IdentityInfo}; use parity_scale_codec::Encode; use primitives::{ BlockNumber, HeadData, Id as ParaId, SessionIndex, ValidationCode, LOWEST_PUBLIC_ID, + MAX_CODE_SIZE, }; use runtime_parachains::{ configuration, origin, paras, shared, Origin as ParaOrigin, ParaLifecycle, @@ -315,7 +316,7 @@ pub fn new_test_ext() -> TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); configuration::GenesisConfig:: { config: configuration::HostConfiguration { - max_code_size: 2 * 1024 * 1024, // 2 MB + max_code_size: MAX_CODE_SIZE, max_head_data_size: 1 * 1024 * 1024, // 1 MB ..Default::default() }, diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index c05c8a1ae00ba4e8a5a97095ad15a0a9a618cbbe..4541b88ec6fe187988a949cda1338de59f258541 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -26,7 +26,7 @@ use frame_support::{ traits::{Currency, Get, ReservableCurrency}, }; use frame_system::{self, ensure_root, ensure_signed}; -use primitives::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID}; +use primitives::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID, MIN_CODE_SIZE}; use runtime_parachains::{ configuration, ensure_parachain, paras::{self, ParaGenesisArgs, SetGoAhead}, @@ -106,7 +106,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] @@ -182,8 +182,8 @@ pub mod pallet { ParaLocked, /// The ID given for registration has not been reserved. NotReserved, - /// Registering parachain with empty code is not allowed. - EmptyCode, + /// The validation code is invalid. + InvalidCode, /// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras /// are correct for the swap to work. CannotSwap, @@ -657,7 +657,7 @@ impl Pallet { para_kind: ParaKind, ) -> Result<(ParaGenesisArgs, BalanceOf), sp_runtime::DispatchError> { let config = configuration::Pallet::::config(); - ensure!(validation_code.0.len() > 0, Error::::EmptyCode); + ensure!(validation_code.0.len() >= MIN_CODE_SIZE as usize, Error::::InvalidCode); ensure!(validation_code.0.len() <= config.max_code_size as usize, Error::::CodeTooLarge); ensure!( genesis_head.0.len() <= config.max_head_data_size as usize, @@ -712,7 +712,7 @@ mod tests { }; use frame_system::limits; use pallet_balances::Error as BalancesError; - use primitives::{Balance, BlockNumber, SessionIndex}; + use primitives::{Balance, BlockNumber, SessionIndex, MAX_CODE_SIZE}; use runtime_parachains::{configuration, origin, shared}; use sp_core::H256; use sp_io::TestExternalities; @@ -849,7 +849,7 @@ mod tests { configuration::GenesisConfig:: { config: configuration::HostConfiguration { - max_code_size: 2 * 1024 * 1024, // 2 MB + max_code_size: MAX_CODE_SIZE, max_head_data_size: 1 * 1024 * 1024, // 1 MB ..Default::default() }, @@ -1032,6 +1032,51 @@ mod tests { }); } + #[test] + fn schedule_code_upgrade_validates_code() { + new_test_ext().execute_with(|| { + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + let para_id = LOWEST_PUBLIC_ID; + assert!(!Parachains::is_parathread(para_id)); + + let validation_code = test_validation_code(32); + assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); + assert_eq!(Balances::reserved_balance(&1), ::ParaDeposit::get()); + assert_ok!(Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(32), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + run_to_session(START_SESSION_INDEX + 2); + assert!(Parachains::is_parathread(para_id)); + + let new_code = test_validation_code(0); + assert_noop!( + Registrar::schedule_code_upgrade( + RuntimeOrigin::signed(1), + para_id, + new_code.clone(), + ), + paras::Error::::InvalidCode + ); + + let new_code = test_validation_code(max_code_size() as usize + 1); + assert_noop!( + Registrar::schedule_code_upgrade( + RuntimeOrigin::signed(1), + para_id, + new_code.clone(), + ), + paras::Error::::InvalidCode + ); + }); + } + #[test] fn register_handles_basic_errors() { new_test_ext().execute_with(|| { @@ -1310,7 +1355,7 @@ mod tests { RuntimeOrigin::signed(1), para_id, vec![1; 3].into(), - vec![1, 2, 3].into(), + test_validation_code(32) )); assert_noop!(Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin); @@ -1473,7 +1518,7 @@ mod benchmarking { use crate::traits::Registrar as RegistrarT; use frame_support::assert_ok; use frame_system::RawOrigin; - use primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE}; + use primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MIN_CODE_SIZE}; use runtime_parachains::{paras, shared, Origin as ParaOrigin}; use sp_runtime::traits::Bounded; @@ -1604,7 +1649,7 @@ mod benchmarking { } schedule_code_upgrade { - let b in 1 .. MAX_CODE_SIZE; + let b in MIN_CODE_SIZE .. MAX_CODE_SIZE; let new_code = ValidationCode(vec![0; b as usize]); let para_id = ParaId::from(1000); }: _(RawOrigin::Root, para_id, new_code) diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index 7f1100a13619a8c5e1048afd4a34d2d977aa8914..46d09afcfb2c80215ed7ab18eb7be5750de1fcf6 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -136,7 +136,7 @@ where } } -/// Implementation of `pallet_xcm_benchmarks::EnsureDelivery` which helps to ensure delivery to the +/// Implementation of `xcm_builder::EnsureDelivery` which helps to ensure delivery to the /// `ParaId` parachain (sibling or child). Deposits existential deposit for origin (if needed). /// Deposits estimated fee to the origin account (if needed). /// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if neeeded). @@ -164,7 +164,7 @@ impl< PriceForDelivery: PriceForMessageDelivery, Parachain: Get, ToParachainHelper: EnsureForParachain, - > pallet_xcm_benchmarks::EnsureDelivery + > xcm_builder::EnsureDelivery for ToParachainDeliveryHelper< XcmConfig, ExistentialDeposit, @@ -175,7 +175,7 @@ impl< { fn ensure_successful_delivery( origin_ref: &Location, - _dest: &Location, + dest: &Location, fee_reason: xcm_executor::traits::FeeReason, ) -> (Option, Option) { use xcm_executor::{ @@ -183,6 +183,15 @@ impl< FeesMode, }; + // check if the destination matches the expected `Parachain`. + if let Some(Parachain(para_id)) = dest.first_interior() { + if ParaId::from(*para_id) != Parachain::get().into() { + return (None, None) + } + } else { + return (None, None) + } + let mut fees_mode = None; if !XcmConfig::FeeManager::is_waived(Some(origin_ref), fee_reason) { // if not waived, we need to set up accounts for paying and receiving fees diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 507df01ac4816c07b5dd8533fff483c5489631a9..6104014547638dbf13c5b080a280e7cf369293c9 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -13,10 +13,10 @@ workspace = true impl-trait-for-tuples = "0.2.2" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"] } +serde = { features = ["alloc", "derive"], workspace = true } derive_more = "0.99.17" bitflags = "1.3.2" @@ -69,7 +69,8 @@ sp-tracing = { path = "../../../substrate/primitives/tracing" } sp-crypto-hashing = { path = "../../../substrate/primitives/crypto/hashing" } thousands = "0.2.0" assert_matches = "1" -serde_json = "1.0.111" +rstest = "0.18.2" +serde_json = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/polkadot/runtime/parachains/src/assigner_coretime/mock_helpers.rs b/polkadot/runtime/parachains/src/assigner_coretime/mock_helpers.rs index 71c3f1fa39f7c6c127ac954b8299fb16a323e72d..e2ba0b4f7ea5d5ca2eb49c903afb764229e0491f 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/mock_helpers.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/mock_helpers.rs @@ -64,11 +64,12 @@ impl GenesisConfigBuilder { pub(super) fn build(self) -> MockGenesisConfig { let mut genesis = default_genesis_config(); let config = &mut genesis.configuration.config; - config.coretime_cores = self.on_demand_cores; - config.on_demand_base_fee = self.on_demand_base_fee; - config.on_demand_fee_variability = self.on_demand_fee_variability; - config.on_demand_queue_max_size = self.on_demand_max_queue_size; - config.on_demand_target_queue_utilization = self.on_demand_target_queue_utilization; + 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 { diff --git a/polkadot/runtime/parachains/src/assigner_coretime/mod.rs b/polkadot/runtime/parachains/src/assigner_coretime/mod.rs index 9da81dc816cabeb7019e44b8f88c0f526582830d..e2da89fadd4800f5de32650178766e1ed85bbd17 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/mod.rs @@ -30,7 +30,7 @@ mod tests; use crate::{ assigner_on_demand, configuration, paras::AssignCoretime, - scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig}, + scheduler::common::{Assignment, AssignmentProvider}, ParaId, }; @@ -316,14 +316,6 @@ impl AssignmentProvider> for Pallet { } } - fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig> { - let config = >::config(); - AssignmentProviderConfig { - max_availability_timeouts: config.on_demand_retries, - ttl: config.on_demand_ttl, - } - } - #[cfg(any(feature = "runtime-benchmarks", test))] fn get_mock_assignment(_: CoreIndex, para_id: primitives::Id) -> Assignment { // Given that we are not tracking anything in `Bulk` assignments, it is safe to always @@ -333,7 +325,7 @@ impl AssignmentProvider> for Pallet { fn session_core_count() -> u32 { let config = >::config(); - config.coretime_cores + config.scheduler_params.num_cores } } @@ -482,8 +474,8 @@ impl AssignCoretime for Pallet { // Add a new core and assign the para to it. let mut config = >::config(); - let core = config.coretime_cores; - config.coretime_cores.saturating_inc(); + let core = config.scheduler_params.num_cores; + config.scheduler_params.num_cores.saturating_inc(); // `assign_coretime` is only called at genesis or by root, so setting the active // config here is fine. diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs b/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs index 5a6060cd2b4eab88867088dee30b6fb1047bdf20..8360e7a78d0a5a155f5b9d63ffae05bb85e44f32 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs @@ -43,7 +43,7 @@ where { ParasShared::::set_session_index(SESSION_INDEX); let mut config = HostConfiguration::default(); - config.coretime_cores = 1; + config.scheduler_params.num_cores = 1; ConfigurationPallet::::force_set_active_config(config); let mut parachains = ParachainsCache::new(); ParasPallet::::initialize_para_now( diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mock_helpers.rs b/polkadot/runtime/parachains/src/assigner_on_demand/mock_helpers.rs index de30330ac84e0a7715799d71d26fb42ce48efff8..f8d1a894f0e4d5c619377ba4c34158c8f6d60597 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mock_helpers.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/mock_helpers.rs @@ -63,11 +63,12 @@ impl GenesisConfigBuilder { pub(super) fn build(self) -> MockGenesisConfig { let mut genesis = default_genesis_config(); let config = &mut genesis.configuration.config; - config.coretime_cores = self.on_demand_cores; - config.on_demand_base_fee = self.on_demand_base_fee; - config.on_demand_fee_variability = self.on_demand_fee_variability; - config.on_demand_queue_max_size = self.on_demand_max_queue_size; - config.on_demand_target_queue_utilization = self.on_demand_target_queue_utilization; + 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 { diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs index 1b746e88694c9f105db119d351a76e336fd3fdba..bc450dc78129ad7404627e49b9882e2723c09f08 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs @@ -201,10 +201,10 @@ pub mod pallet { let old_traffic = SpotTraffic::::get(); match Self::calculate_spot_traffic( old_traffic, - config.on_demand_queue_max_size, + config.scheduler_params.on_demand_queue_max_size, Self::queue_size(), - config.on_demand_target_queue_utilization, - config.on_demand_fee_variability, + config.scheduler_params.on_demand_target_queue_utilization, + config.scheduler_params.on_demand_fee_variability, ) { Ok(new_traffic) => { // Only update storage on change @@ -330,8 +330,9 @@ where let traffic = SpotTraffic::::get(); // Calculate spot price - let spot_price: BalanceOf = - traffic.saturating_mul_int(config.on_demand_base_fee.saturated_into::>()); + let spot_price: BalanceOf = traffic.saturating_mul_int( + config.scheduler_params.on_demand_base_fee.saturated_into::>(), + ); // Is the current price higher than `max_amount` ensure!(spot_price.le(&max_amount), Error::::SpotPriceHigherThanMaxAmount); @@ -450,7 +451,10 @@ where OnDemandQueue::::try_mutate(|queue| { // Abort transaction if queue is too large - ensure!(Self::queue_size() < config.on_demand_queue_max_size, Error::::QueueFull); + ensure!( + Self::queue_size() < config.scheduler_params.on_demand_queue_max_size, + Error::::QueueFull + ); match location { QueuePushDirection::Back => queue.push_back(order), QueuePushDirection::Front => queue.push_front(order), @@ -472,7 +476,7 @@ where target: LOG_TARGET, "Failed to fetch the on demand queue size, returning the max size." ); - return config.on_demand_queue_max_size + return config.scheduler_params.on_demand_queue_max_size }, } } diff --git a/polkadot/runtime/parachains/src/assigner_parachains.rs b/polkadot/runtime/parachains/src/assigner_parachains.rs index 34b5d3c1ec51811e8e4c50255592b1e9344014d8..b5f342563e9763e9dba0fa8cbc7afd8e84dc59da 100644 --- a/polkadot/runtime/parachains/src/assigner_parachains.rs +++ b/polkadot/runtime/parachains/src/assigner_parachains.rs @@ -27,7 +27,7 @@ use primitives::CoreIndex; use crate::{ configuration, paras, - scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig}, + scheduler::common::{Assignment, AssignmentProvider}, }; pub use pallet::*; @@ -58,16 +58,6 @@ impl AssignmentProvider> for Pallet { /// this is a no-op in the case of a bulk assignment slot. fn push_back_assignment(_: Assignment) {} - fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig> { - AssignmentProviderConfig { - // The next assignment already goes to the same [`ParaId`], no timeout tracking needed. - max_availability_timeouts: 0, - // The next assignment already goes to the same [`ParaId`], this can be any number - // that's high enough to clear the time it takes to clear backing/availability. - ttl: 10u32.into(), - } - } - #[cfg(any(feature = "runtime-benchmarks", test))] fn get_mock_assignment(_: CoreIndex, para_id: primitives::Id) -> Assignment { Assignment::Bulk(para_id) diff --git a/polkadot/runtime/parachains/src/assigner_parachains/mock_helpers.rs b/polkadot/runtime/parachains/src/assigner_parachains/mock_helpers.rs index e6e9fb074aa97e87e6fe92819cc57e5bfa2ca656..a46e114daeaf458fb6bc985a5bb2ebad951d7e3b 100644 --- a/polkadot/runtime/parachains/src/assigner_parachains/mock_helpers.rs +++ b/polkadot/runtime/parachains/src/assigner_parachains/mock_helpers.rs @@ -60,11 +60,12 @@ impl GenesisConfigBuilder { pub(super) fn build(self) -> MockGenesisConfig { let mut genesis = default_genesis_config(); let config = &mut genesis.configuration.config; - config.coretime_cores = self.on_demand_cores; - config.on_demand_base_fee = self.on_demand_base_fee; - config.on_demand_fee_variability = self.on_demand_fee_variability; - config.on_demand_queue_max_size = self.on_demand_max_queue_size; - config.on_demand_target_queue_utilization = self.on_demand_target_queue_utilization; + 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 { diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 016b3fca589a5b845110d9f25199cc8b8aef5bfe..5b218addb1a2552d3f9daa3dbb7baf352023f919 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -18,23 +18,20 @@ use crate::{ configuration, inclusion, initializer, paras, paras::ParaKind, paras_inherent, - scheduler::{ - self, - common::{AssignmentProvider, AssignmentProviderConfig}, - CoreOccupied, ParasEntry, - }, + scheduler::{self, common::AssignmentProvider, CoreOccupied, ParasEntry}, session_info, shared, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use primitives::{ - collator_signature_payload, AvailabilityBitfield, BackedCandidate, CandidateCommitments, - CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt, - CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData, - Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, InvalidDisputeStatementKind, - PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned, - ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation, + collator_signature_payload, vstaging::node_features::FeatureIndex, AvailabilityBitfield, + BackedCandidate, CandidateCommitments, CandidateDescriptor, CandidateHash, CollatorId, + CollatorSignature, CommittedCandidateReceipt, CompactStatement, CoreIndex, DisputeStatement, + DisputeStatementSet, GroupIndex, HeadData, Id as ParaId, IndexedVec, + InherentData as ParachainsInherentData, InvalidDisputeStatementKind, PersistedValidationData, + SessionIndex, SigningContext, UncheckedSigned, ValidDisputeStatementKind, ValidationCode, + ValidatorId, ValidatorIndex, ValidityAttestation, }; use sp_core::{sr25519, H256}; use sp_runtime::{ @@ -197,7 +194,10 @@ impl BenchBuilder { /// Maximum number of validators per core (a.k.a. max validators per group). This value is used /// if none is explicitly set on the builder. pub(crate) fn fallback_max_validators_per_core() -> u32 { - configuration::Pallet::::config().max_validators_per_core.unwrap_or(5) + configuration::Pallet::::config() + .scheduler_params + .max_validators_per_core + .unwrap_or(5) } /// Specify a mapping of core index/ para id to the number of dispute statements for the @@ -510,7 +510,7 @@ impl BenchBuilder { .iter() .map(|(seed, num_votes)| { assert!(*num_votes <= validators.len() as u32); - let (para_id, _core_idx, group_idx) = self.create_indexes(*seed); + let (para_id, core_idx, group_idx) = self.create_indexes(*seed); // This generates a pair and adds it to the keystore, returning just the public. let collator_public = CollatorId::generate_pair(None); @@ -587,11 +587,19 @@ impl BenchBuilder { }) .collect(); - BackedCandidate:: { + // Check if the elastic scaling bit is set, if so we need to supply the core index + // in the generated candidate. + let core_idx = configuration::Pallet::::config() + .node_features + .get(FeatureIndex::ElasticScalingMVP as usize) + .map(|_the_bit| core_idx); + + BackedCandidate::::new( candidate, validity_votes, - validator_indices: bitvec::bitvec![u8, bitvec::order::Lsb0; 1; group_validators.len()], - } + bitvec::bitvec![u8, bitvec::order::Lsb0; 1; group_validators.len()], + core_idx, + ) }) .collect() } @@ -683,7 +691,7 @@ impl BenchBuilder { // We are currently in Session 0, so these changes will take effect in Session 2. Self::setup_para_ids(used_cores); configuration::ActiveConfig::::mutate(|c| { - c.coretime_cores = used_cores; + c.scheduler_params.num_cores = used_cores; }); let validator_ids = Self::generate_validator_pairs(self.max_validators()); @@ -714,8 +722,7 @@ impl BenchBuilder { let cores = (0..used_cores) .into_iter() .map(|i| { - let AssignmentProviderConfig { ttl, .. } = - scheduler::Pallet::::assignment_provider_config(CoreIndex(i)); + let ttl = configuration::Pallet::::config().scheduler_params.ttl; // Load an assignment into provider so that one is present to pop let assignment = ::AssignmentProvider::get_mock_assignment( CoreIndex(i), @@ -730,8 +737,7 @@ impl BenchBuilder { let cores = (0..used_cores) .into_iter() .map(|i| { - let AssignmentProviderConfig { ttl, .. } = - scheduler::Pallet::::assignment_provider_config(CoreIndex(i)); + let ttl = configuration::Pallet::::config().scheduler_params.ttl; // Load an assignment into provider so that one is present to pop let assignment = ::AssignmentProvider::get_mock_assignment( diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 4619313590ebc2d5d92dfc85a4e845c381c61607..364a15215d38c5eae477b3a73987a43d0216278b 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -29,7 +29,6 @@ use primitives::{ vstaging::{ApprovalVotingParams, NodeFeatures}, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, - ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill}; use sp_std::prelude::*; @@ -43,6 +42,7 @@ mod benchmarking; pub mod migration; pub use pallet::*; +use primitives::vstaging::SchedulerParams; const LOG_TARGET: &str = "runtime::configuration"; @@ -118,9 +118,9 @@ pub struct HostConfiguration { /// been completed. /// /// Note, there are situations in which `expected_at` in the past. For example, if - /// [`paras_availability_period`](Self::paras_availability_period) is less than the delay set - /// by this field or if PVF pre-check took more time than the delay. In such cases, the upgrade - /// is further at the earliest possible time determined by + /// [`paras_availability_period`](SchedulerParams::paras_availability_period) is less than the + /// delay set by this field or if PVF pre-check took more time than the delay. In such cases, + /// the upgrade is further at the earliest possible time determined by /// [`minimum_validation_upgrade_delay`](Self::minimum_validation_upgrade_delay). /// /// The rationale for this delay has to do with relay-chain reversions. In case there is an @@ -172,48 +172,7 @@ pub struct HostConfiguration { /// How long to keep code on-chain, in blocks. This should be sufficiently long that disputes /// have concluded. pub code_retention_period: BlockNumber, - /// How many cores are managed by the coretime chain. - pub coretime_cores: u32, - /// The number of retries that a on demand author has to submit their block. - pub on_demand_retries: u32, - /// The maximum queue size of the pay as you go module. - pub on_demand_queue_max_size: u32, - /// The target utilization of the spot price queue in percentages. - pub on_demand_target_queue_utilization: Perbill, - /// How quickly the fee rises in reaction to increased utilization. - /// The lower the number the slower the increase. - 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 an on demand claim stays in the scheduler's claimqueue before getting - /// cleared. This number should go reasonably higher than the number of blocks in the async - /// backing lookahead. - pub on_demand_ttl: BlockNumber, - /// How often parachain groups should be rotated across parachains. - /// - /// Must be non-zero. - pub group_rotation_frequency: BlockNumber, - /// The minimum availability period, in blocks. - /// - /// This is the minimum amount of blocks after a core became occupied that validators have time - /// to make the block available. - /// - /// This value only has effect on group rotations. If backers backed something at the end of - /// their rotation, the occupied core affects the backing group that comes afterwards. We limit - /// the effect one backing group can have on the next to `paras_availability_period` blocks. - /// - /// Within a group rotation there is no timeout as backers are only affecting themselves. - /// - /// Must be at least 1. With a value of 1, the previous group will not be able to negatively - /// affect the following group at the expense of a tight availability timeline at group - /// rotation boundaries. - pub paras_availability_period: BlockNumber, - /// The amount of blocks ahead to schedule paras. - pub scheduling_lookahead: u32, - /// The maximum number of validators to have per core. - /// - /// `None` means no maximum. - pub max_validators_per_core: Option, + /// The maximum number of validators to use for parachain consensus, period. /// /// `None` means no maximum. @@ -257,7 +216,7 @@ pub struct HostConfiguration { /// scheduled. This number is controlled by this field. /// /// This value should be greater than - /// [`paras_availability_period`](Self::paras_availability_period). + /// [`paras_availability_period`](SchedulerParams::paras_availability_period). pub minimum_validation_upgrade_delay: BlockNumber, /// The minimum number of valid backing statements required to consider a parachain candidate /// backable. @@ -266,6 +225,8 @@ pub struct HostConfiguration { pub node_features: NodeFeatures, /// Params used by approval-voting pub approval_voting_params: ApprovalVotingParams, + /// Scheduler parameters + pub scheduler_params: SchedulerParams, } impl> Default for HostConfiguration { @@ -275,19 +236,13 @@ impl> Default for HostConfiguration> Default for HostConfiguration { ZeroMinimumBackingVotes, /// `executor_params` are inconsistent. InconsistentExecutorParams { inner: ExecutorParamError }, + /// TTL should be bigger than lookahead + LookaheadExceedsTTL, } impl HostConfiguration @@ -373,11 +326,11 @@ where pub fn check_consistency(&self) -> Result<(), InconsistentError> { use InconsistentError::*; - if self.group_rotation_frequency.is_zero() { + if self.scheduler_params.group_rotation_frequency.is_zero() { return Err(ZeroGroupRotationFrequency) } - if self.paras_availability_period.is_zero() { + if self.scheduler_params.paras_availability_period.is_zero() { return Err(ZeroParasAvailabilityPeriod) } @@ -399,10 +352,11 @@ where return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size }) } - if self.minimum_validation_upgrade_delay <= self.paras_availability_period { + if self.minimum_validation_upgrade_delay <= self.scheduler_params.paras_availability_period + { return Err(MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod { minimum_validation_upgrade_delay: self.minimum_validation_upgrade_delay.clone(), - paras_availability_period: self.paras_availability_period.clone(), + paras_availability_period: self.scheduler_params.paras_availability_period.clone(), }) } @@ -447,6 +401,10 @@ where return Err(InconsistentExecutorParams { inner }) } + if self.scheduler_params.ttl < self.scheduler_params.lookahead.into() { + return Err(LookaheadExceedsTTL) + } + Ok(()) } @@ -471,6 +429,7 @@ pub trait WeightInfo { fn set_config_with_executor_params() -> Weight; fn set_config_with_perbill() -> Weight; fn set_node_feature() -> Weight; + fn set_config_with_scheduler_params() -> Weight; } pub struct TestWeightInfo; @@ -499,13 +458,16 @@ impl WeightInfo for TestWeightInfo { fn set_node_feature() -> Weight { Weight::MAX } + fn set_config_with_scheduler_params() -> Weight { + Weight::MAX + } } #[frame_support::pallet] pub mod pallet { use super::*; - /// The current storage version. + /// The in-code storage version. /// /// v0-v1: /// v1-v2: @@ -520,7 +482,8 @@ pub mod pallet { /// v8-v9: /// v9-v10: /// v10-11: - const STORAGE_VERSION: StorageVersion = StorageVersion::new(11); + /// v11-12: + const STORAGE_VERSION: StorageVersion = StorageVersion::new(12); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -679,16 +642,16 @@ pub mod pallet { Self::set_coretime_cores_unchecked(new) } - /// Set the number of retries for a particular on demand. + /// 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_on_demand_retries(origin: OriginFor, new: u32) -> DispatchResult { + pub fn set_max_availability_timeouts(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.on_demand_retries = new; + config.scheduler_params.max_availability_timeouts = new; }) } @@ -704,7 +667,7 @@ pub mod pallet { ) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.group_rotation_frequency = new; + config.scheduler_params.group_rotation_frequency = new; }) } @@ -720,7 +683,7 @@ pub mod pallet { ) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.paras_availability_period = new; + config.scheduler_params.paras_availability_period = new; }) } @@ -733,7 +696,7 @@ pub mod pallet { pub fn set_scheduling_lookahead(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.scheduling_lookahead = new; + config.scheduler_params.lookahead = new; }) } @@ -749,7 +712,7 @@ pub mod pallet { ) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.max_validators_per_core = new; + config.scheduler_params.max_validators_per_core = new; }) } @@ -1141,7 +1104,7 @@ pub mod pallet { pub fn set_on_demand_base_fee(origin: OriginFor, new: Balance) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.on_demand_base_fee = new; + config.scheduler_params.on_demand_base_fee = new; }) } @@ -1154,7 +1117,7 @@ pub mod pallet { pub fn set_on_demand_fee_variability(origin: OriginFor, new: Perbill) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.on_demand_fee_variability = new; + config.scheduler_params.on_demand_fee_variability = new; }) } @@ -1167,7 +1130,7 @@ pub mod pallet { pub fn set_on_demand_queue_max_size(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.on_demand_queue_max_size = new; + config.scheduler_params.on_demand_queue_max_size = new; }) } /// Set the on demand (parathreads) fee variability. @@ -1182,7 +1145,7 @@ pub mod pallet { ) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.on_demand_target_queue_utilization = new; + config.scheduler_params.on_demand_target_queue_utilization = new; }) } /// Set the on demand (parathreads) ttl in the claimqueue. @@ -1194,7 +1157,7 @@ pub mod pallet { pub fn set_on_demand_ttl(origin: OriginFor, new: BlockNumberFor) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.on_demand_ttl = new; + config.scheduler_params.ttl = new; }) } @@ -1244,6 +1207,22 @@ pub mod pallet { config.approval_voting_params = new; }) } + + /// Set scheduler-params. + #[pallet::call_index(55)] + #[pallet::weight(( + T::WeightInfo::set_config_with_scheduler_params(), + DispatchClass::Operational, + ))] + pub fn set_scheduler_params( + origin: OriginFor, + new: SchedulerParams>, + ) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.scheduler_params = new; + }) + } } impl Pallet { @@ -1252,7 +1231,7 @@ pub mod pallet { /// To be used if authorization is checked otherwise. pub fn set_coretime_cores_unchecked(new: u32) -> DispatchResult { Self::schedule_config_update(|config| { - config.coretime_cores = new; + config.scheduler_params.num_cores = new; }) } } @@ -1393,7 +1372,7 @@ impl Pallet { let base_config_consistent = base_config.check_consistency().is_ok(); // Now, we need to decide what the new configuration should be. - // We also move the `base_config` to `new_config` to empahsize that the base config was + // We also move the `base_config` to `new_config` to emphasize that the base config was // destroyed by the `updater`. updater(&mut base_config); let new_config = base_config; diff --git a/polkadot/runtime/parachains/src/configuration/benchmarking.rs b/polkadot/runtime/parachains/src/configuration/benchmarking.rs index 67daf1c459884d42378056b6528605da29578c95..882b5aab096ad2f8227aa7ad0efaddfd2078c3ad 100644 --- a/polkadot/runtime/parachains/src/configuration/benchmarking.rs +++ b/polkadot/runtime/parachains/src/configuration/benchmarking.rs @@ -51,6 +51,8 @@ benchmarks! { set_node_feature{}: set_node_feature(RawOrigin::Root, 255, true) + set_config_with_scheduler_params {} : set_scheduler_params(RawOrigin::Root, SchedulerParams::default()) + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext(Default::default()), diff --git a/polkadot/runtime/parachains/src/configuration/migration.rs b/polkadot/runtime/parachains/src/configuration/migration.rs index 2838b73092dbab4a029a684948a85123aa489906..87b30b177e735bdc1ec618a6e403c4c74a801533 100644 --- a/polkadot/runtime/parachains/src/configuration/migration.rs +++ b/polkadot/runtime/parachains/src/configuration/migration.rs @@ -18,6 +18,7 @@ pub mod v10; pub mod v11; +pub mod v12; pub mod v6; pub mod v7; pub mod v8; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v11.rs b/polkadot/runtime/parachains/src/configuration/migration/v11.rs index a69061ac1381e253cdbaef6d4681511973f83e86..f6e0e0431640ba271f592759308cc0d07efcfa71 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v11.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v11.rs @@ -21,13 +21,122 @@ use frame_support::{ migrations::VersionedMigration, pallet_prelude::*, traits::Defensive, weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; -use primitives::{vstaging::ApprovalVotingParams, SessionIndex}; +use primitives::{ + vstaging::ApprovalVotingParams, AsyncBackingParams, ExecutorParams, SessionIndex, + LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, +}; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; +use polkadot_core_primitives::Balance; +use primitives::vstaging::NodeFeatures; +use sp_arithmetic::Perbill; use super::v10::V10HostConfiguration; -type V11HostConfiguration = configuration::HostConfiguration; + +#[derive(Clone, Encode, PartialEq, Decode, Debug)] +pub struct V11HostConfiguration { + pub max_code_size: u32, + pub max_head_data_size: u32, + pub max_upward_queue_count: u32, + pub max_upward_queue_size: u32, + pub max_upward_message_size: u32, + pub max_upward_message_num_per_candidate: u32, + pub hrmp_max_message_num_per_candidate: u32, + pub validation_upgrade_cooldown: BlockNumber, + pub validation_upgrade_delay: BlockNumber, + pub async_backing_params: AsyncBackingParams, + pub max_pov_size: u32, + pub max_downward_message_size: u32, + pub hrmp_max_parachain_outbound_channels: u32, + pub hrmp_sender_deposit: Balance, + pub hrmp_recipient_deposit: Balance, + pub hrmp_channel_max_capacity: u32, + pub hrmp_channel_max_total_size: u32, + pub hrmp_max_parachain_inbound_channels: u32, + pub hrmp_channel_max_message_size: u32, + pub executor_params: ExecutorParams, + pub code_retention_period: BlockNumber, + pub coretime_cores: u32, + pub on_demand_retries: u32, + pub on_demand_queue_max_size: u32, + pub on_demand_target_queue_utilization: Perbill, + pub on_demand_fee_variability: Perbill, + pub on_demand_base_fee: Balance, + pub on_demand_ttl: BlockNumber, + pub group_rotation_frequency: BlockNumber, + pub paras_availability_period: BlockNumber, + pub scheduling_lookahead: u32, + pub max_validators_per_core: Option, + pub max_validators: Option, + pub dispute_period: SessionIndex, + pub dispute_post_conclusion_acceptance_period: BlockNumber, + pub no_show_slots: u32, + pub n_delay_tranches: u32, + pub zeroth_delay_tranche_width: u32, + pub needed_approvals: u32, + pub relay_vrf_modulo_samples: u32, + pub pvf_voting_ttl: SessionIndex, + pub minimum_validation_upgrade_delay: BlockNumber, + pub minimum_backing_votes: u32, + pub node_features: NodeFeatures, + pub approval_voting_params: ApprovalVotingParams, +} + +impl> Default for V11HostConfiguration { + fn default() -> Self { + Self { + async_backing_params: AsyncBackingParams { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, + group_rotation_frequency: 1u32.into(), + paras_availability_period: 1u32.into(), + no_show_slots: 1u32.into(), + validation_upgrade_cooldown: Default::default(), + validation_upgrade_delay: 2u32.into(), + code_retention_period: Default::default(), + max_code_size: Default::default(), + max_pov_size: Default::default(), + max_head_data_size: Default::default(), + coretime_cores: Default::default(), + on_demand_retries: Default::default(), + scheduling_lookahead: 1, + max_validators_per_core: Default::default(), + max_validators: None, + dispute_period: 6, + dispute_post_conclusion_acceptance_period: 100.into(), + n_delay_tranches: Default::default(), + zeroth_delay_tranche_width: Default::default(), + needed_approvals: Default::default(), + relay_vrf_modulo_samples: Default::default(), + max_upward_queue_count: Default::default(), + max_upward_queue_size: Default::default(), + max_downward_message_size: Default::default(), + max_upward_message_size: Default::default(), + max_upward_message_num_per_candidate: Default::default(), + hrmp_sender_deposit: Default::default(), + hrmp_recipient_deposit: Default::default(), + hrmp_channel_max_capacity: Default::default(), + hrmp_channel_max_total_size: Default::default(), + hrmp_max_parachain_inbound_channels: Default::default(), + hrmp_channel_max_message_size: Default::default(), + hrmp_max_parachain_outbound_channels: Default::default(), + hrmp_max_message_num_per_candidate: Default::default(), + pvf_voting_ttl: 2u32.into(), + minimum_validation_upgrade_delay: 2.into(), + executor_params: Default::default(), + approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 }, + on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + on_demand_base_fee: 10_000_000u128, + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_target_queue_utilization: Perbill::from_percent(25), + on_demand_ttl: 5u32.into(), + minimum_backing_votes: LEGACY_MIN_BACKING_VOTES, + node_features: NodeFeatures::EMPTY, + } + } +} mod v10 { use super::*; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v12.rs b/polkadot/runtime/parachains/src/configuration/migration/v12.rs new file mode 100644 index 0000000000000000000000000000000000000000..4295a79893e8ee52632d54772bd108b4de37cc3f --- /dev/null +++ b/polkadot/runtime/parachains/src/configuration/migration/v12.rs @@ -0,0 +1,349 @@ +// 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 . + +//! A module that is responsible for migration of storage. + +use crate::configuration::{self, migration::v11::V11HostConfiguration, Config, Pallet}; +use frame_support::{ + migrations::VersionedMigration, + pallet_prelude::*, + traits::{Defensive, OnRuntimeUpgrade}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use primitives::vstaging::SchedulerParams; +use sp_core::Get; +use sp_staking::SessionIndex; +use sp_std::vec::Vec; + +type V12HostConfiguration = configuration::HostConfiguration; + +mod v11 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V11HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V11HostConfiguration>)>, + OptionQuery, + >; +} + +mod v12 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V12HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V12HostConfiguration>)>, + OptionQuery, + >; +} + +pub type MigrateToV12 = VersionedMigration< + 11, + 12, + UncheckedMigrateToV12, + Pallet, + ::DbWeight, +>; + +pub struct UncheckedMigrateToV12(sp_std::marker::PhantomData); + +impl OnRuntimeUpgrade for UncheckedMigrateToV12 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV12"); + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV12 started"); + let weight_consumed = migrate_to_v12::(); + + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV12 executed successfully"); + + weight_consumed + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade() for HostConfiguration MigrateToV12"); + ensure!( + StorageVersion::get::>() >= 12, + "Storage version should be >= 12 after the migration" + ); + + Ok(()) + } +} + +fn migrate_to_v12() -> Weight { + // Unusual formatting is justified: + // - make it easier to verify that fields assign what they supposed to assign. + // - this code is transient and will be removed after all migrations are done. + // - this code is important enough to optimize for legibility sacrificing consistency. + #[rustfmt::skip] + let translate = + |pre: V11HostConfiguration>| -> + V12HostConfiguration> + { + V12HostConfiguration { + max_code_size : pre.max_code_size, + max_head_data_size : pre.max_head_data_size, + max_upward_queue_count : pre.max_upward_queue_count, + max_upward_queue_size : pre.max_upward_queue_size, + max_upward_message_size : pre.max_upward_message_size, + max_upward_message_num_per_candidate : pre.max_upward_message_num_per_candidate, + hrmp_max_message_num_per_candidate : pre.hrmp_max_message_num_per_candidate, + validation_upgrade_cooldown : pre.validation_upgrade_cooldown, + validation_upgrade_delay : pre.validation_upgrade_delay, + max_pov_size : pre.max_pov_size, + max_downward_message_size : pre.max_downward_message_size, + hrmp_sender_deposit : pre.hrmp_sender_deposit, + hrmp_recipient_deposit : pre.hrmp_recipient_deposit, + hrmp_channel_max_capacity : pre.hrmp_channel_max_capacity, + hrmp_channel_max_total_size : pre.hrmp_channel_max_total_size, + hrmp_max_parachain_inbound_channels : pre.hrmp_max_parachain_inbound_channels, + hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels, + hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size, + code_retention_period : pre.code_retention_period, + max_validators : pre.max_validators, + dispute_period : pre.dispute_period, + dispute_post_conclusion_acceptance_period: pre.dispute_post_conclusion_acceptance_period, + no_show_slots : pre.no_show_slots, + n_delay_tranches : pre.n_delay_tranches, + zeroth_delay_tranche_width : pre.zeroth_delay_tranche_width, + needed_approvals : pre.needed_approvals, + relay_vrf_modulo_samples : pre.relay_vrf_modulo_samples, + pvf_voting_ttl : pre.pvf_voting_ttl, + minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay, + async_backing_params : pre.async_backing_params, + executor_params : pre.executor_params, + minimum_backing_votes : pre.minimum_backing_votes, + node_features : pre.node_features, + approval_voting_params : pre.approval_voting_params, + scheduler_params: SchedulerParams { + group_rotation_frequency : pre.group_rotation_frequency, + paras_availability_period : pre.paras_availability_period, + max_validators_per_core : pre.max_validators_per_core, + lookahead : pre.scheduling_lookahead, + num_cores : pre.coretime_cores, + max_availability_timeouts : pre.on_demand_retries, + on_demand_queue_max_size : pre.on_demand_queue_max_size, + on_demand_target_queue_utilization : pre.on_demand_target_queue_utilization, + on_demand_fee_variability : pre.on_demand_fee_variability, + on_demand_base_fee : pre.on_demand_base_fee, + ttl : pre.on_demand_ttl, + } + } + }; + + let v11 = v11::ActiveConfig::::get() + .defensive_proof("Could not decode old config") + .unwrap_or_default(); + let v12 = translate(v11); + v12::ActiveConfig::::set(Some(v12)); + + // Allowed to be empty. + let pending_v11 = v11::PendingConfigs::::get().unwrap_or_default(); + let mut pending_v12 = Vec::new(); + + for (session, v11) in pending_v11.into_iter() { + let v12 = translate(v11); + pending_v12.push((session, v12)); + } + v12::PendingConfigs::::set(Some(pending_v12.clone())); + + let num_configs = (pending_v12.len() + 1) as u64; + T::DbWeight::get().reads_writes(num_configs, num_configs) +} + +#[cfg(test)] +mod tests { + use primitives::LEGACY_MIN_BACKING_VOTES; + use sp_arithmetic::Perbill; + + use super::*; + use crate::mock::{new_test_ext, Test}; + + #[test] + fn v12_deserialized_from_actual_data() { + // Example how to get new `raw_config`: + // We'll obtain the raw_config at a specified a block + // Steps: + // 1. Go to Polkadot.js -> Developer -> Chain state -> Storage: https://polkadot.js.org/apps/#/chainstate + // 2. Set these parameters: + // 2.1. selected state query: configuration; activeConfig(): + // PolkadotRuntimeParachainsConfigurationHostConfiguration + // 2.2. blockhash to query at: + // 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of + // the block) + // 2.3. Note the value of encoded storage key -> + // 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the + // referenced block. + // 2.4. You'll also need the decoded values to update the test. + // 3. Go to Polkadot.js -> Developer -> Chain state -> Raw storage + // 3.1 Enter the encoded storage key and you get the raw config. + + // This exceeds the maximal line width length, but that's fine, since this is not code and + // doesn't need to be read and also leaving it as one line allows to easily copy it. + let raw_config = + hex_literal::hex![ + "0000300000800000080000000000100000c8000005000000050000000200000002000000000000000000000000005000000010000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000000100000b004000000060000006400000002000000190000000000000002000000020000000200000005000000020000000001000000140000000400000001010000000100000001000000000000001027000080b2e60e80c3c9018096980000000000000000000000000005000000" + ]; + + let v12 = + V12HostConfiguration::::decode(&mut &raw_config[..]).unwrap(); + + // We check only a sample of the values here. If we missed any fields or messed up data + // types that would skew all the fields coming after. + assert_eq!(v12.max_code_size, 3_145_728); + assert_eq!(v12.validation_upgrade_cooldown, 2); + assert_eq!(v12.max_pov_size, 5_242_880); + assert_eq!(v12.hrmp_channel_max_message_size, 1_048_576); + assert_eq!(v12.n_delay_tranches, 25); + assert_eq!(v12.minimum_validation_upgrade_delay, 5); + assert_eq!(v12.minimum_backing_votes, LEGACY_MIN_BACKING_VOTES); + assert_eq!(v12.approval_voting_params.max_approval_coalesce_count, 1); + assert_eq!(v12.scheduler_params.group_rotation_frequency, 20); + 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); + assert_eq!(v12.scheduler_params.on_demand_queue_max_size, 10_000); + assert_eq!( + v12.scheduler_params.on_demand_target_queue_utilization, + Perbill::from_percent(25) + ); + 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); + } + + #[test] + fn test_migrate_to_v12() { + // Host configuration has lots of fields. However, in this migration we only add one + // field. The most important part to check are a couple of the last fields. We also pick + // extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and + // also their type. + // + // We specify only the picked fields and the rest should be provided by the `Default` + // implementation. That implementation is copied over between the two types and should work + // fine. + let v11 = V11HostConfiguration:: { + needed_approvals: 69, + paras_availability_period: 55, + hrmp_recipient_deposit: 1337, + max_pov_size: 1111, + minimum_validation_upgrade_delay: 20, + on_demand_ttl: 3, + on_demand_retries: 10, + ..Default::default() + }; + + let mut pending_configs = Vec::new(); + pending_configs.push((100, v11.clone())); + pending_configs.push((300, v11.clone())); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v10 version in the state. + v11::ActiveConfig::::set(Some(v11.clone())); + v11::PendingConfigs::::set(Some(pending_configs)); + + migrate_to_v12::(); + + let v12 = v12::ActiveConfig::::get().unwrap(); + assert_eq!(v12.approval_voting_params.max_approval_coalesce_count, 1); + + let mut configs_to_check = v12::PendingConfigs::::get().unwrap(); + configs_to_check.push((0, v12.clone())); + + for (_, v12) in configs_to_check { + #[rustfmt::skip] + { + assert_eq!(v11.max_code_size , v12.max_code_size); + assert_eq!(v11.max_head_data_size , v12.max_head_data_size); + assert_eq!(v11.max_upward_queue_count , v12.max_upward_queue_count); + assert_eq!(v11.max_upward_queue_size , v12.max_upward_queue_size); + assert_eq!(v11.max_upward_message_size , v12.max_upward_message_size); + assert_eq!(v11.max_upward_message_num_per_candidate , v12.max_upward_message_num_per_candidate); + assert_eq!(v11.hrmp_max_message_num_per_candidate , v12.hrmp_max_message_num_per_candidate); + assert_eq!(v11.validation_upgrade_cooldown , v12.validation_upgrade_cooldown); + assert_eq!(v11.validation_upgrade_delay , v12.validation_upgrade_delay); + assert_eq!(v11.max_pov_size , v12.max_pov_size); + assert_eq!(v11.max_downward_message_size , v12.max_downward_message_size); + assert_eq!(v11.hrmp_max_parachain_outbound_channels , v12.hrmp_max_parachain_outbound_channels); + assert_eq!(v11.hrmp_sender_deposit , v12.hrmp_sender_deposit); + assert_eq!(v11.hrmp_recipient_deposit , v12.hrmp_recipient_deposit); + assert_eq!(v11.hrmp_channel_max_capacity , v12.hrmp_channel_max_capacity); + assert_eq!(v11.hrmp_channel_max_total_size , v12.hrmp_channel_max_total_size); + assert_eq!(v11.hrmp_max_parachain_inbound_channels , v12.hrmp_max_parachain_inbound_channels); + assert_eq!(v11.hrmp_channel_max_message_size , v12.hrmp_channel_max_message_size); + assert_eq!(v11.code_retention_period , v12.code_retention_period); + assert_eq!(v11.max_validators , v12.max_validators); + assert_eq!(v11.dispute_period , v12.dispute_period); + assert_eq!(v11.no_show_slots , v12.no_show_slots); + assert_eq!(v11.n_delay_tranches , v12.n_delay_tranches); + assert_eq!(v11.zeroth_delay_tranche_width , v12.zeroth_delay_tranche_width); + assert_eq!(v11.needed_approvals , v12.needed_approvals); + assert_eq!(v11.relay_vrf_modulo_samples , v12.relay_vrf_modulo_samples); + assert_eq!(v11.pvf_voting_ttl , v12.pvf_voting_ttl); + assert_eq!(v11.minimum_validation_upgrade_delay , v12.minimum_validation_upgrade_delay); + assert_eq!(v11.async_backing_params.allowed_ancestry_len, v12.async_backing_params.allowed_ancestry_len); + assert_eq!(v11.async_backing_params.max_candidate_depth , v12.async_backing_params.max_candidate_depth); + assert_eq!(v11.executor_params , v12.executor_params); + assert_eq!(v11.minimum_backing_votes , v12.minimum_backing_votes); + assert_eq!(v11.group_rotation_frequency , v12.scheduler_params.group_rotation_frequency); + assert_eq!(v11.paras_availability_period , v12.scheduler_params.paras_availability_period); + assert_eq!(v11.max_validators_per_core , v12.scheduler_params.max_validators_per_core); + assert_eq!(v11.scheduling_lookahead , v12.scheduler_params.lookahead); + assert_eq!(v11.coretime_cores , v12.scheduler_params.num_cores); + assert_eq!(v11.on_demand_retries , v12.scheduler_params.max_availability_timeouts); + assert_eq!(v11.on_demand_queue_max_size , v12.scheduler_params.on_demand_queue_max_size); + assert_eq!(v11.on_demand_target_queue_utilization , v12.scheduler_params.on_demand_target_queue_utilization); + assert_eq!(v11.on_demand_fee_variability , v12.scheduler_params.on_demand_fee_variability); + assert_eq!(v11.on_demand_base_fee , v12.scheduler_params.on_demand_base_fee); + assert_eq!(v11.on_demand_ttl , v12.scheduler_params.ttl); + }; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression. + } + }); + } + + // Test that migration doesn't panic in case there are no pending configurations upgrades in + // pallet's storage. + #[test] + fn test_migrate_to_v12_no_pending() { + let v11 = V11HostConfiguration::::default(); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v10 version in the state. + v11::ActiveConfig::::set(Some(v11)); + // Ensure there are no pending configs. + v12::PendingConfigs::::set(None); + + // Shouldn't fail. + migrate_to_v12::(); + }); + } +} diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index f1570017dd7ba75db429eac4f00f26fa277de2d6..254511231cac1729981706775bb9f844ca9f1c5c 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -226,8 +226,11 @@ fn invariants() { ); ActiveConfig::::put(HostConfiguration { - paras_availability_period: 10, minimum_validation_upgrade_delay: 11, + scheduler_params: SchedulerParams { + paras_availability_period: 10, + ..Default::default() + }, ..Default::default() }); assert_err!( @@ -283,12 +286,6 @@ fn setting_pending_config_members() { max_code_size: 100_000, max_pov_size: 1024, max_head_data_size: 1_000, - coretime_cores: 2, - on_demand_retries: 5, - group_rotation_frequency: 20, - paras_availability_period: 10, - scheduling_lookahead: 3, - max_validators_per_core: None, max_validators: None, dispute_period: 239, dispute_post_conclusion_acceptance_period: 10, @@ -314,13 +311,21 @@ fn setting_pending_config_members() { minimum_validation_upgrade_delay: 20, executor_params: Default::default(), approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 }, - on_demand_queue_max_size: 10_000u32, - on_demand_base_fee: 10_000_000u128, - on_demand_fee_variability: Perbill::from_percent(3), - on_demand_target_queue_utilization: Perbill::from_percent(25), - on_demand_ttl: 5u32, minimum_backing_votes: 5, node_features: bitvec![u8, Lsb0; 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], + 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, + on_demand_queue_max_size: 10_000u32, + on_demand_base_fee: 10_000_000u128, + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_target_queue_utilization: Perbill::from_percent(25), + ttl: 5u32, + }, }; Configuration::set_validation_upgrade_cooldown( @@ -342,13 +347,19 @@ fn setting_pending_config_members() { Configuration::set_max_pov_size(RuntimeOrigin::root(), new_config.max_pov_size).unwrap(); Configuration::set_max_head_data_size(RuntimeOrigin::root(), new_config.max_head_data_size) .unwrap(); - Configuration::set_coretime_cores(RuntimeOrigin::root(), new_config.coretime_cores) - .unwrap(); - Configuration::set_on_demand_retries(RuntimeOrigin::root(), new_config.on_demand_retries) - .unwrap(); + Configuration::set_coretime_cores( + RuntimeOrigin::root(), + 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.group_rotation_frequency, + new_config.scheduler_params.group_rotation_frequency, ) .unwrap(); // This comes out of order to satisfy the validity criteria for the chain and thread @@ -360,17 +371,17 @@ fn setting_pending_config_members() { .unwrap(); Configuration::set_paras_availability_period( RuntimeOrigin::root(), - new_config.paras_availability_period, + new_config.scheduler_params.paras_availability_period, ) .unwrap(); Configuration::set_scheduling_lookahead( RuntimeOrigin::root(), - new_config.scheduling_lookahead, + new_config.scheduler_params.lookahead, ) .unwrap(); Configuration::set_max_validators_per_core( RuntimeOrigin::root(), - new_config.max_validators_per_core, + new_config.scheduler_params.max_validators_per_core, ) .unwrap(); Configuration::set_max_validators(RuntimeOrigin::root(), new_config.max_validators) diff --git a/polkadot/runtime/parachains/src/coretime/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs index 9bc0a20ef5b4afce7d63da9bb1d231d39bf445ab..03fecc58570fba65df79ca48930acb3346d3f556 100644 --- a/polkadot/runtime/parachains/src/coretime/migration.rs +++ b/polkadot/runtime/parachains/src/coretime/migration.rs @@ -114,7 +114,7 @@ mod v_coretime { let legacy_paras = paras::Parachains::::get(); let config = >::config(); - let total_core_count = config.coretime_cores + legacy_paras.len() as u32; + let total_core_count = config.scheduler_params.num_cores + legacy_paras.len() as u32; let dmp_queue_size = crate::dmp::Pallet::::dmq_contents(T::BrokerId::get().into()).len() as u32; @@ -150,7 +150,7 @@ mod v_coretime { // Migrate to Coretime. // - // NOTE: Also migrates coretime_cores config value in configuration::ActiveConfig. + // NOTE: Also migrates `num_cores` config value in configuration::ActiveConfig. fn migrate_to_coretime< T: Config, SendXcm: xcm::v4::SendXcm, @@ -176,8 +176,8 @@ mod v_coretime { } let config = >::config(); - // coretime_cores was on_demand_cores until now: - for on_demand in 0..config.coretime_cores { + // num_cores was on_demand_cores until now: + for on_demand in 0..config.scheduler_params.num_cores { let core = CoreIndex(legacy_count.saturating_add(on_demand as _)); let r = assigner_coretime::Pallet::::assign_core( core, @@ -189,9 +189,9 @@ mod v_coretime { log::error!("Creating assignment for existing on-demand core, failed: {:?}", err); } } - let total_cores = config.coretime_cores + legacy_count; + let total_cores = config.scheduler_params.num_cores + legacy_count; configuration::ActiveConfig::::mutate(|c| { - c.coretime_cores = total_cores; + c.scheduler_params.num_cores = total_cores; }); if let Err(err) = migrate_send_assignments_to_coretime_chain::() { @@ -200,7 +200,9 @@ mod v_coretime { let single_weight = ::WeightInfo::assign_core(1); single_weight - .saturating_mul(u64::from(legacy_count.saturating_add(config.coretime_cores))) + .saturating_mul(u64::from( + legacy_count.saturating_add(config.scheduler_params.num_cores), + )) // Second read from sending assignments to the coretime chain. .saturating_add(T::DbWeight::get().reads_writes(2, 1)) } @@ -244,7 +246,8 @@ mod v_coretime { Some(mk_coretime_call(crate::coretime::CoretimeCalls::SetLease(p.into(), time_slice))) }); - let core_count: u16 = configuration::Pallet::::config().coretime_cores.saturated_into(); + let core_count: u16 = + configuration::Pallet::::config().scheduler_params.num_cores.saturated_into(); let set_core_count = iter::once(mk_coretime_call( crate::coretime::CoretimeCalls::NotifyCoreCount(core_count), )); diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs index 531f5c2e4e470095989bbb73429cc2180ff4f321..eb9646d7e869d35763a5b0cdf8a408de66126b78 100644 --- a/polkadot/runtime/parachains/src/coretime/mod.rs +++ b/polkadot/runtime/parachains/src/coretime/mod.rs @@ -214,8 +214,8 @@ impl Pallet { } pub fn initializer_on_new_session(notification: &SessionChangeNotification>) { - let old_core_count = notification.prev_config.coretime_cores; - let new_core_count = notification.new_config.coretime_cores; + let old_core_count = notification.prev_config.scheduler_params.num_cores; + let new_core_count = notification.new_config.scheduler_params.num_cores; if new_core_count != old_core_count { let core_count: u16 = new_core_count.saturated_into(); let message = Xcm(vec![ diff --git a/polkadot/runtime/parachains/src/disputes.rs b/polkadot/runtime/parachains/src/disputes.rs index c2383dad3053882b7abec959446b23d149aa4a5f..da95b060c14a3fad03e98f5e2a75ac54eef1928c 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -379,7 +379,7 @@ pub mod pallet { type WeightInfo: WeightInfo; } - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] diff --git a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs index 2cb49c88d437cb3e0a4c01a40d343a179316ec9d..c6baf2f30cf58279b58b644df76e5ea255f7ec4f 100644 --- a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs +++ b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs @@ -22,7 +22,7 @@ use crate::{ paras::{Pallet as Paras, ParaKind, ParachainsCache}, shared::Pallet as Shared, }; -use frame_benchmarking::{impl_benchmark_test_suite, v2::*, whitelisted_caller}; +use frame_benchmarking::{v2::*, whitelisted_caller}; use frame_support::{assert_ok, traits::Currency}; type BalanceOf = diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index 90af9cde00a8faaec13101b490ea3ba92f4a827c..16e2e93b5617f2c85bbb308ff5d057c7ed99db9c 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -47,10 +47,7 @@ use scale_info::TypeInfo; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; #[cfg(feature = "std")] use sp_std::fmt; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - prelude::*, -}; +use sp_std::{collections::btree_set::BTreeSet, prelude::*}; pub use pallet::*; @@ -601,18 +598,16 @@ impl Pallet { /// scheduled cores. If these conditions are not met, the execution of the function fails. pub(crate) fn process_candidates( allowed_relay_parents: &AllowedRelayParentsTracker>, - candidates: Vec>, - scheduled: &BTreeMap, + candidates: Vec<(BackedCandidate, CoreIndex)>, group_validators: GV, + core_index_enabled: bool, ) -> Result, DispatchError> where GV: Fn(GroupIndex) -> Option>, { let now = >::block_number(); - ensure!(candidates.len() <= scheduled.len(), Error::::UnscheduledCandidate); - - if scheduled.is_empty() { + if candidates.is_empty() { return Ok(ProcessedCandidates::default()) } @@ -648,7 +643,7 @@ impl Pallet { // // In the meantime, we do certain sanity checks on the candidates and on the scheduled // list. - for (candidate_idx, backed_candidate) in candidates.iter().enumerate() { + for (candidate_idx, (backed_candidate, core_index)) in candidates.iter().enumerate() { let relay_parent_hash = backed_candidate.descriptor().relay_parent; let para_id = backed_candidate.descriptor().para_id; @@ -663,7 +658,7 @@ impl Pallet { let relay_parent_number = match check_ctx.verify_backed_candidate( &allowed_relay_parents, candidate_idx, - backed_candidate, + backed_candidate.candidate(), )? { Err(FailedToCreatePVD) => { log::debug!( @@ -679,11 +674,22 @@ impl Pallet { Ok(rpn) => rpn, }; - let para_id = backed_candidate.descriptor().para_id; + let (validator_indices, _) = + backed_candidate.validator_indices_and_core_index(core_index_enabled); + + log::debug!( + target: LOG_TARGET, + "Candidate {:?} on {:?}, + core_index_enabled = {}", + backed_candidate.hash(), + core_index, + core_index_enabled + ); + + check_assignment_in_order(core_index)?; + let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; - let core_idx = *scheduled.get(¶_id).ok_or(Error::::UnscheduledCandidate)?; - check_assignment_in_order(core_idx)?; ensure!( >::get(¶_id).is_none() && >::get(¶_id).is_none(), @@ -694,7 +700,7 @@ impl Pallet { // assigned to core at block `N + 1`. Thus, `relay_parent_number + 1` // will always land in the current session. let group_idx = >::group_assigned_to_core( - core_idx, + *core_index, relay_parent_number + One::one(), ) .ok_or_else(|| { @@ -711,7 +717,9 @@ impl Pallet { // check the signatures in the backing and that it is a majority. { let maybe_amount_validated = primitives::check_candidate_backing( - &backed_candidate, + backed_candidate.candidate().hash(), + backed_candidate.validity_votes(), + validator_indices, &signing_context, group_vals.len(), |intra_group_vi| { @@ -738,16 +746,15 @@ impl Pallet { let mut backer_idx_and_attestation = Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity( - backed_candidate.validator_indices.count_ones(), + validator_indices.count_ones(), ); let candidate_receipt = backed_candidate.receipt(); - for ((bit_idx, _), attestation) in backed_candidate - .validator_indices + for ((bit_idx, _), attestation) in validator_indices .iter() .enumerate() .filter(|(_, signed)| **signed) - .zip(backed_candidate.validity_votes.iter().cloned()) + .zip(backed_candidate.validity_votes().iter().cloned()) { let val_idx = group_vals.get(bit_idx).expect("this query succeeded above; qed"); @@ -760,7 +767,7 @@ impl Pallet { } core_indices_and_backers.push(( - (core_idx, para_id), + (*core_index, para_id), backers, group_idx, relay_parent_number, @@ -772,7 +779,7 @@ impl Pallet { // one more sweep for actually writing to storage. let core_indices = core_indices_and_backers.iter().map(|(c, ..)| *c).collect(); - for (candidate, (core, backers, group, relay_parent_number)) in + for ((candidate, _), (core, backers, group, relay_parent_number)) in candidates.into_iter().zip(core_indices_and_backers) { let para_id = candidate.descriptor().para_id; @@ -782,16 +789,18 @@ impl Pallet { bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; Self::deposit_event(Event::::CandidateBacked( - candidate.candidate.to_plain(), - candidate.candidate.commitments.head_data.clone(), + candidate.candidate().to_plain(), + candidate.candidate().commitments.head_data.clone(), core.0, group, )); - let candidate_hash = candidate.candidate.hash(); + let candidate_hash = candidate.candidate().hash(); - let (descriptor, commitments) = - (candidate.candidate.descriptor, candidate.candidate.commitments); + let (descriptor, commitments) = ( + candidate.candidate().descriptor.clone(), + candidate.candidate().commitments.clone(), + ); >::insert( ¶_id, @@ -1195,10 +1204,10 @@ impl CandidateCheckContext { &self, allowed_relay_parents: &AllowedRelayParentsTracker>, candidate_idx: usize, - backed_candidate: &BackedCandidate<::Hash>, + backed_candidate_receipt: &CommittedCandidateReceipt<::Hash>, ) -> Result, FailedToCreatePVD>, Error> { - let para_id = backed_candidate.descriptor().para_id; - let relay_parent = backed_candidate.descriptor().relay_parent; + let para_id = backed_candidate_receipt.descriptor().para_id; + let relay_parent = backed_candidate_receipt.descriptor().relay_parent; // Check that the relay-parent is one of the allowed relay-parents. let (relay_parent_storage_root, relay_parent_number) = { @@ -1223,13 +1232,13 @@ impl CandidateCheckContext { let expected = persisted_validation_data.hash(); ensure!( - expected == backed_candidate.descriptor().persisted_validation_data_hash, + expected == backed_candidate_receipt.descriptor().persisted_validation_data_hash, Error::::ValidationDataHashMismatch, ); } ensure!( - backed_candidate.descriptor().check_collator_signature().is_ok(), + backed_candidate_receipt.descriptor().check_collator_signature().is_ok(), Error::::NotCollatorSigned, ); @@ -1237,25 +1246,25 @@ impl CandidateCheckContext { // A candidate for a parachain without current validation code is not scheduled. .ok_or_else(|| Error::::UnscheduledCandidate)?; ensure!( - backed_candidate.descriptor().validation_code_hash == validation_code_hash, + backed_candidate_receipt.descriptor().validation_code_hash == validation_code_hash, Error::::InvalidValidationCodeHash, ); ensure!( - backed_candidate.descriptor().para_head == - backed_candidate.candidate.commitments.head_data.hash(), + backed_candidate_receipt.descriptor().para_head == + backed_candidate_receipt.commitments.head_data.hash(), Error::::ParaHeadMismatch, ); if let Err(err) = self.check_validation_outputs( para_id, relay_parent_number, - &backed_candidate.candidate.commitments.head_data, - &backed_candidate.candidate.commitments.new_validation_code, - backed_candidate.candidate.commitments.processed_downward_messages, - &backed_candidate.candidate.commitments.upward_messages, - BlockNumberFor::::from(backed_candidate.candidate.commitments.hrmp_watermark), - &backed_candidate.candidate.commitments.horizontal_messages, + &backed_candidate_receipt.commitments.head_data, + &backed_candidate_receipt.commitments.new_validation_code, + backed_candidate_receipt.commitments.processed_downward_messages, + &backed_candidate_receipt.commitments.upward_messages, + BlockNumberFor::::from(backed_candidate_receipt.commitments.hrmp_watermark), + &backed_candidate_receipt.commitments.horizontal_messages, ) { log::debug!( target: LOG_TARGET, diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 232e65d78ed2aef86aa7903d88cbe99236ba9ec1..3fe7d7f0c7d4698c6b8301a41dca552e9c067509 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -47,10 +47,10 @@ use test_helpers::{dummy_collator, dummy_collator_signature, dummy_validation_co fn default_config() -> HostConfiguration { let mut config = HostConfiguration::default(); - config.coretime_cores = 1; + config.scheduler_params.num_cores = 1; config.max_code_size = 0b100000; config.max_head_data_size = 0b100000; - config.group_rotation_frequency = u32::MAX; + config.scheduler_params.group_rotation_frequency = u32::MAX; config } @@ -120,6 +120,7 @@ pub(crate) fn back_candidate( keystore: &KeystorePtr, signing_context: &SigningContext, kind: BackingKind, + core_index: Option, ) -> BackedCandidate { let mut validator_indices = bitvec::bitvec![u8, BitOrderLsb0; 0; group.len()]; let threshold = effective_minimum_backing_votes( @@ -155,15 +156,20 @@ pub(crate) fn back_candidate( validity_votes.push(ValidityAttestation::Explicit(signature).into()); } - let backed = BackedCandidate { candidate, validity_votes, validator_indices }; + let backed = + BackedCandidate::new(candidate, validity_votes, validator_indices.clone(), core_index); - let successfully_backed = - primitives::check_candidate_backing(&backed, signing_context, group.len(), |i| { - Some(validators[group[i].0 as usize].public().into()) - }) - .ok() - .unwrap_or(0) >= - threshold; + let successfully_backed = primitives::check_candidate_backing( + backed.candidate().hash(), + backed.validity_votes(), + validator_indices.as_bitslice(), + signing_context, + group.len(), + |i| Some(validators[group[i].0 as usize].public().into()), + ) + .ok() + .unwrap_or(0) >= + threshold; match kind { BackingKind::Unanimous | BackingKind::Threshold => assert!(successfully_backed), @@ -218,7 +224,7 @@ pub(crate) fn run_to_block( } pub(crate) fn expected_bits() -> usize { - Paras::parachains().len() + Configuration::config().coretime_cores as usize + Paras::parachains().len() + Configuration::config().scheduler_params.num_cores as usize } fn default_bitfield() -> AvailabilityBitfield { @@ -380,7 +386,7 @@ fn collect_pending_cleans_up_pending() { (thread_a, ParaKind::Parathread), ]; let mut config = genesis_config(paras); - config.configuration.config.group_rotation_frequency = 3; + config.configuration.config.scheduler_params.group_rotation_frequency = 3; new_test_ext(config).execute_with(|| { let default_candidate = TestCandidateBuilder::default().build(); >::insert( @@ -919,38 +925,16 @@ fn candidate_checks() { let thread_a_assignment = (thread_a, CoreIndex::from(2)); let allowed_relay_parents = default_allowed_relay_parent_tracker(); - // unscheduled candidate. - { - let mut candidate = TestCandidateBuilder { - para_id: chain_a, - relay_parent: System::parent_hash(), - pov_hash: Hash::repeat_byte(1), - persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), - hrmp_watermark: RELAY_PARENT_NUM, - ..Default::default() - } - .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let backed = back_candidate( - candidate, - &validators, - group_validators(GroupIndex::from(0)).unwrap().as_ref(), - &keystore, - &signing_context, - BackingKind::Threshold, - ); - - assert_noop!( - ParaInclusion::process_candidates( - &allowed_relay_parents, - vec![backed], - &[chain_b_assignment].into_iter().collect(), - &group_validators, - ), - Error::::UnscheduledCandidate - ); - } + // no candidates. + assert_eq!( + ParaInclusion::process_candidates( + &allowed_relay_parents, + vec![], + &group_validators, + false + ), + Ok(ProcessedCandidates::default()) + ); // candidates out of order. { @@ -984,6 +968,7 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); let backed_b = back_candidate( @@ -993,15 +978,16 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); // out-of-order manifests as unscheduled. assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed_b, backed_a], - &[chain_a_assignment, chain_b_assignment].into_iter().collect(), + vec![(backed_b, chain_b_assignment.1), (backed_a, chain_a_assignment.1)], &group_validators, + false ), Error::::ScheduledOutOfOrder ); @@ -1027,14 +1013,15 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Lacking, + None, ); assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[chain_a_assignment].into_iter().collect(), + vec![(backed, chain_a_assignment.1)], &group_validators, + false ), Error::::InsufficientBacking ); @@ -1075,6 +1062,7 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); let backed_b = back_candidate( @@ -1084,14 +1072,15 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed_b, backed_a], - &[chain_a_assignment, chain_b_assignment].into_iter().collect(), + vec![(backed_b, chain_b_assignment.1), (backed_a, chain_a_assignment.1)], &group_validators, + false ), Error::::DisallowedRelayParent ); @@ -1122,14 +1111,15 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[thread_a_assignment].into_iter().collect(), + vec![(backed, thread_a_assignment.1)], &group_validators, + false ), Error::::NotCollatorSigned ); @@ -1156,6 +1146,7 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); let candidate = TestCandidateBuilder::default().build(); @@ -1177,9 +1168,9 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[chain_a_assignment].into_iter().collect(), + vec![(backed, chain_a_assignment.1)], &group_validators, + false ), Error::::CandidateScheduledBeforeParaFree ); @@ -1212,14 +1203,15 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[chain_a_assignment].into_iter().collect(), + vec![(backed, chain_a_assignment.1)], &group_validators, + false ), Error::::CandidateScheduledBeforeParaFree ); @@ -1233,7 +1225,7 @@ fn candidate_checks() { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), - new_validation_code: Some(vec![5, 6, 7, 8].into()), + new_validation_code: Some(dummy_validation_code()), persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), hrmp_watermark: RELAY_PARENT_NUM, ..Default::default() @@ -1249,6 +1241,7 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); { @@ -1257,7 +1250,7 @@ fn candidate_checks() { assert_eq!(expected_at, 12); Paras::schedule_code_upgrade( chain_a, - vec![1, 2, 3, 4].into(), + vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into(), expected_at, &cfg, SetGoAhead::Yes, @@ -1267,9 +1260,9 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[chain_a_assignment].into_iter().collect(), + vec![(backed, chain_a_assignment.1)], &group_validators, + false ), Error::::PrematureCodeUpgrade ); @@ -1296,14 +1289,15 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); assert_eq!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[chain_a_assignment].into_iter().collect(), + vec![(backed, chain_a_assignment.1)], &group_validators, + false ), Err(Error::::ValidationDataHashMismatch.into()), ); @@ -1317,7 +1311,7 @@ fn candidate_checks() { pov_hash: Hash::repeat_byte(1), persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![1]), + validation_code: ValidationCode(vec![9, 8, 7, 6, 5, 4, 3, 2, 1]), ..Default::default() } .build(); @@ -1331,14 +1325,15 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[chain_a_assignment].into_iter().collect(), + vec![(backed, chain_a_assignment.1)], &group_validators, + false ), Error::::InvalidValidationCodeHash ); @@ -1366,14 +1361,15 @@ fn candidate_checks() { &keystore, &signing_context, BackingKind::Threshold, + None, ); assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed], - &[chain_a_assignment].into_iter().collect(), + vec![(backed, chain_a_assignment.1)], &group_validators, + false ), Error::::ParaHeadMismatch ); @@ -1486,6 +1482,7 @@ fn backing_works() { &keystore, &signing_context, BackingKind::Threshold, + None, ); let backed_b = back_candidate( @@ -1495,6 +1492,7 @@ fn backing_works() { &keystore, &signing_context, BackingKind::Threshold, + None, ); let backed_c = back_candidate( @@ -1504,15 +1502,20 @@ fn backing_works() { &keystore, &signing_context, BackingKind::Threshold, + None, ); - let backed_candidates = vec![backed_a.clone(), backed_b.clone(), backed_c]; + let backed_candidates = vec![ + (backed_a.clone(), chain_a_assignment.1), + (backed_b.clone(), chain_b_assignment.1), + (backed_c, thread_a_assignment.1), + ]; let get_backing_group_idx = { // the order defines the group implicitly for this test case let backed_candidates_with_groups = backed_candidates .iter() .enumerate() - .map(|(idx, backed_candidate)| (backed_candidate.hash(), GroupIndex(idx as _))) + .map(|(idx, (backed_candidate, _))| (backed_candidate.hash(), GroupIndex(idx as _))) .collect::>(); move |candidate_hash_x: CandidateHash| -> Option { @@ -1532,10 +1535,8 @@ fn backing_works() { } = ParaInclusion::process_candidates( &allowed_relay_parents, backed_candidates.clone(), - &[chain_a_assignment, chain_b_assignment, thread_a_assignment] - .into_iter() - .collect(), &group_validators, + false, ) .expect("candidates scheduled, in order, and backed"); @@ -1554,22 +1555,22 @@ fn backing_works() { CandidateHash, (CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>), >::new(); - backed_candidates.into_iter().for_each(|backed_candidate| { + backed_candidates.into_iter().for_each(|(backed_candidate, _)| { let candidate_receipt_with_backers = intermediate .entry(backed_candidate.hash()) .or_insert_with(|| (backed_candidate.receipt(), Vec::new())); - - assert_eq!( - backed_candidate.validity_votes.len(), - backed_candidate.validator_indices.count_ones() - ); + let (validator_indices, None) = + backed_candidate.validator_indices_and_core_index(false) + else { + panic!("Expected no injected core index") + }; + assert_eq!(backed_candidate.validity_votes().len(), validator_indices.count_ones()); candidate_receipt_with_backers.1.extend( - backed_candidate - .validator_indices + validator_indices .iter() .enumerate() .filter(|(_, signed)| **signed) - .zip(backed_candidate.validity_votes.iter().cloned()) + .zip(backed_candidate.validity_votes().iter().cloned()) .filter_map(|((validator_index_within_group, _), attestation)| { let grp_idx = get_backing_group_idx(backed_candidate.hash()).unwrap(); group_validators(grp_idx).map(|validator_indices| { @@ -1666,6 +1667,257 @@ fn backing_works() { }); } +#[test] +fn backing_works_with_elastic_scaling_mvp() { + let chain_a = ParaId::from(1_u32); + let chain_b = ParaId::from(2_u32); + let thread_a = ParaId::from(3_u32); + + // The block number of the relay-parent for testing. + const RELAY_PARENT_NUM: BlockNumber = 4; + + let paras = vec![ + (chain_a, ParaKind::Parachain), + (chain_b, ParaKind::Parachain), + (thread_a, ParaKind::Parathread), + ]; + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Ferdie, + ]; + let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); + for validator in validators.iter() { + Keystore::sr25519_generate_new( + &*keystore, + PARACHAIN_KEY_TYPE_ID, + Some(&validator.to_seed()), + ) + .unwrap(); + } + let validator_public = validator_pubkeys(&validators); + + new_test_ext(genesis_config(paras)).execute_with(|| { + shared::Pallet::::set_active_validators_ascending(validator_public.clone()); + shared::Pallet::::set_session_index(5); + + run_to_block(5, |_| None); + + let signing_context = + SigningContext { parent_hash: System::parent_hash(), session_index: 5 }; + + let group_validators = |group_index: GroupIndex| { + match group_index { + group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1]), + group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), + group_index if group_index == GroupIndex::from(2) => Some(vec![4]), + _ => panic!("Group index out of bounds for 2 parachains and 1 parathread core"), + } + .map(|vs| vs.into_iter().map(ValidatorIndex).collect::>()) + }; + + // When processing candidates, we compute the group index from scheduler. + let validator_groups = vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2), ValidatorIndex(3)], + vec![ValidatorIndex(4)], + ]; + Scheduler::set_validator_groups(validator_groups); + + let allowed_relay_parents = default_allowed_relay_parent_tracker(); + + let mut candidate_a = TestCandidateBuilder { + para_id: chain_a, + relay_parent: System::parent_hash(), + pov_hash: Hash::repeat_byte(1), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); + + let mut candidate_b_1 = TestCandidateBuilder { + para_id: chain_b, + relay_parent: System::parent_hash(), + pov_hash: Hash::repeat_byte(2), + persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b_1); + + let mut candidate_b_2 = TestCandidateBuilder { + para_id: chain_b, + relay_parent: System::parent_hash(), + pov_hash: Hash::repeat_byte(3), + persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b_2); + + let backed_a = back_candidate( + candidate_a.clone(), + &validators, + group_validators(GroupIndex::from(0)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + None, + ); + + let backed_b_1 = back_candidate( + candidate_b_1.clone(), + &validators, + group_validators(GroupIndex::from(1)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + Some(CoreIndex(1)), + ); + + let backed_b_2 = back_candidate( + candidate_b_2.clone(), + &validators, + group_validators(GroupIndex::from(2)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + Some(CoreIndex(2)), + ); + + let backed_candidates = vec![ + (backed_a.clone(), CoreIndex(0)), + (backed_b_1.clone(), CoreIndex(1)), + (backed_b_2.clone(), CoreIndex(2)), + ]; + let get_backing_group_idx = { + // the order defines the group implicitly for this test case + let backed_candidates_with_groups = backed_candidates + .iter() + .enumerate() + .map(|(idx, (backed_candidate, _))| (backed_candidate.hash(), GroupIndex(idx as _))) + .collect::>(); + + move |candidate_hash_x: CandidateHash| -> Option { + backed_candidates_with_groups.iter().find_map(|(candidate_hash, grp)| { + if *candidate_hash == candidate_hash_x { + Some(*grp) + } else { + None + } + }) + } + }; + + let ProcessedCandidates { + core_indices: occupied_cores, + candidate_receipt_with_backing_validator_indices, + } = ParaInclusion::process_candidates( + &allowed_relay_parents, + backed_candidates.clone(), + &group_validators, + true, + ) + .expect("candidates scheduled, in order, and backed"); + + // Both b candidates will be backed. However, only one will be recorded on-chain and proceed + // with being made available. + 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, + (CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>), + >::new(); + backed_candidates.into_iter().for_each(|(backed_candidate, _)| { + let candidate_receipt_with_backers = expected + .entry(backed_candidate.hash()) + .or_insert_with(|| (backed_candidate.receipt(), Vec::new())); + let (validator_indices, _maybe_core_index) = + backed_candidate.validator_indices_and_core_index(true); + assert_eq!(backed_candidate.validity_votes().len(), validator_indices.count_ones()); + candidate_receipt_with_backers.1.extend( + validator_indices + .iter() + .enumerate() + .filter(|(_, signed)| **signed) + .zip(backed_candidate.validity_votes().iter().cloned()) + .filter_map(|((validator_index_within_group, _), attestation)| { + let grp_idx = get_backing_group_idx(backed_candidate.hash()).unwrap(); + group_validators(grp_idx).map(|validator_indices| { + (validator_indices[validator_index_within_group], attestation) + }) + }), + ); + }); + + assert_eq!( + expected, + candidate_receipt_with_backing_validator_indices + .into_iter() + .map(|c| (c.0.hash(), c)) + .collect() + ); + + let backers = { + let num_backers = effective_minimum_backing_votes( + group_validators(GroupIndex(0)).unwrap().len(), + configuration::Pallet::::config().minimum_backing_votes, + ); + backing_bitfield(&(0..num_backers).collect::>()) + }; + assert_eq!( + >::get(&chain_a), + Some(CandidatePendingAvailability { + core: CoreIndex::from(0), + hash: candidate_a.hash(), + descriptor: candidate_a.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers, + backing_group: GroupIndex::from(0), + }) + ); + assert_eq!( + >::get(&chain_a), + Some(candidate_a.commitments), + ); + + // Only one candidate for b will be recorded on chain. + assert_eq!( + >::get(&chain_b), + Some(CandidatePendingAvailability { + core: CoreIndex::from(2), + hash: candidate_b_2.hash(), + descriptor: candidate_b_2.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers: backing_bitfield(&[4]), + backing_group: GroupIndex::from(2), + }) + ); + assert_eq!( + >::get(&chain_b), + Some(candidate_b_2.commitments), + ); + }); +} + #[test] fn can_include_candidate_with_ok_code_upgrade() { let chain_a = ParaId::from(1_u32); @@ -1726,7 +1978,7 @@ fn can_include_candidate_with_ok_code_upgrade() { relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), - new_validation_code: Some(vec![1, 2, 3].into()), + new_validation_code: Some(vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into()), hrmp_watermark: RELAY_PARENT_NUM, ..Default::default() } @@ -1740,14 +1992,15 @@ fn can_include_candidate_with_ok_code_upgrade() { &keystore, &signing_context, BackingKind::Threshold, + None, ); let ProcessedCandidates { core_indices: occupied_cores, .. } = ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed_a], - &[chain_a_assignment].into_iter().collect(), + vec![(backed_a, chain_a_assignment.1)], &group_validators, + false, ) .expect("candidates scheduled, in order, and backed"); @@ -1809,7 +2062,7 @@ fn check_allowed_relay_parents() { } let validator_public = validator_pubkeys(&validators); let mut config = genesis_config(paras); - config.configuration.config.group_rotation_frequency = 1; + config.configuration.config.scheduler_params.group_rotation_frequency = 1; new_test_ext(config).execute_with(|| { shared::Pallet::::set_active_validators_ascending(validator_public.clone()); @@ -1932,6 +2185,7 @@ fn check_allowed_relay_parents() { &keystore, &signing_context_a, BackingKind::Threshold, + None, ); let backed_b = back_candidate( @@ -1941,6 +2195,7 @@ fn check_allowed_relay_parents() { &keystore, &signing_context_b, BackingKind::Threshold, + None, ); let backed_c = back_candidate( @@ -1950,17 +2205,20 @@ fn check_allowed_relay_parents() { &keystore, &signing_context_c, BackingKind::Threshold, + None, ); - let backed_candidates = vec![backed_a, backed_b, backed_c]; + let backed_candidates = vec![ + (backed_a, chain_a_assignment.1), + (backed_b, chain_b_assignment.1), + (backed_c, thread_a_assignment.1), + ]; ParaInclusion::process_candidates( &allowed_relay_parents, backed_candidates.clone(), - &[chain_a_assignment, chain_b_assignment, thread_a_assignment] - .into_iter() - .collect(), &group_validators, + false, ) .expect("candidates scheduled, in order, and backed"); }); @@ -2133,7 +2391,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { shared::Pallet::::set_active_validators_ascending(validator_public.clone()); shared::Pallet::::set_session_index(5); - let new_validation_code: ValidationCode = vec![1, 2, 3, 4, 5].into(); + let new_validation_code: ValidationCode = vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into(); let new_validation_code_hash = new_validation_code.hash(); // Otherwise upgrade is no-op. @@ -2189,14 +2447,15 @@ fn para_upgrade_delay_scheduled_from_inclusion() { &keystore, &signing_context, BackingKind::Threshold, + None, ); let ProcessedCandidates { core_indices: occupied_cores, .. } = ParaInclusion::process_candidates( &allowed_relay_parents, - vec![backed_a], - &[chain_a_assignment].into_iter().collect(), + vec![(backed_a, chain_a_assignment.1)], &group_validators, + false, ) .expect("candidates scheduled, in order, and backed"); diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index 1925ca19501accce8148e23d5e34c8f6625097a2..e18be03bdeb230d8959e3a1e76828d499c1c52bb 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -23,7 +23,7 @@ use crate::{ initializer, origin, paras, paras::ParaKind, paras_inherent, scheduler, - scheduler::common::{AssignmentProvider, AssignmentProviderConfig}, + scheduler::common::AssignmentProvider, session_info, shared, ParaId, }; use frame_support::pallet_prelude::*; @@ -463,10 +463,6 @@ pub mod mock_assigner { pub(super) type MockAssignmentQueue = StorageValue<_, VecDeque, ValueQuery>; - #[pallet::storage] - pub(super) type MockProviderConfig = - StorageValue<_, AssignmentProviderConfig, OptionQuery>; - #[pallet::storage] pub(super) type MockCoreCount = StorageValue<_, u32, OptionQuery>; } @@ -478,12 +474,6 @@ pub mod mock_assigner { MockAssignmentQueue::::mutate(|queue| queue.push_back(assignment)); } - // This configuration needs to be customized to service `get_provider_config` in - // scheduler tests. - pub fn set_assignment_provider_config(config: AssignmentProviderConfig) { - MockProviderConfig::::set(Some(config)); - } - // 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) { @@ -512,17 +502,6 @@ pub mod mock_assigner { // in the mock assigner. fn push_back_assignment(_assignment: Assignment) {} - // Gets the provider config we set earlier using `set_assignment_provider_config`, falling - // back to the on demand parachain configuration if none was set. - fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig { - match MockProviderConfig::::get() { - Some(config) => config, - None => AssignmentProviderConfig { - max_availability_timeouts: 1, - ttl: BlockNumber::from(5u32), - }, - } - } #[cfg(any(feature = "runtime-benchmarks", test))] fn get_mock_assignment(_: CoreIndex, para_id: ParaId) -> Assignment { Assignment::Bulk(para_id) diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs index 05c4c9c37b4d9241a64539c13a1960f93c80d7c1..53ccc35c477c093f69d06f8c9d6902e41627e0af 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs @@ -27,10 +27,10 @@ const SESSION_INDEX: SessionIndex = 1; const VALIDATOR_NUM: usize = 800; const CAUSES_NUM: usize = 100; fn validation_code() -> ValidationCode { - ValidationCode(vec![0]) + ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]) } fn old_validation_code() -> ValidationCode { - ValidationCode(vec![1]) + ValidationCode(vec![9, 8, 7, 6, 5, 4, 3, 2, 1]) } /// Prepares the PVF check statement and the validator signature to pass into diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index e97df8e4a2b3aaeee4e4d69c3c39262c23780588..5acdb9683bbf17349f35f280c6a268c49ebb5f39 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -119,7 +119,7 @@ use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; use primitives::{ ConsensusLog, HeadData, Id as ParaId, PvfCheckStatement, SessionIndex, UpgradeGoAhead, - UpgradeRestriction, ValidationCode, ValidationCodeHash, ValidatorSignature, + UpgradeRestriction, ValidationCode, ValidationCodeHash, ValidatorSignature, MIN_CODE_SIZE, }; use scale_info::{Type, TypeInfo}; use sp_core::RuntimeDebug; @@ -679,6 +679,8 @@ pub mod pallet { PvfCheckSubjectInvalid, /// Parachain cannot currently schedule a code upgrade. CannotUpgradeCode, + /// Invalid validation code size. + InvalidCode, } /// All currently active PVF pre-checking votes. @@ -1230,6 +1232,10 @@ impl Pallet { // Check that we can schedule an upgrade at all. ensure!(Self::can_upgrade_validation_code(id), Error::::CannotUpgradeCode); let config = configuration::Pallet::::config(); + // Validation code sanity checks: + ensure!(new_code.0.len() >= MIN_CODE_SIZE as usize, Error::::InvalidCode); + ensure!(new_code.0.len() <= config.max_code_size as usize, Error::::InvalidCode); + let current_block = frame_system::Pallet::::block_number(); // Schedule the upgrade with a delay just like if a parachain triggered the upgrade. let upgrade_block = current_block.saturating_add(config.validation_upgrade_delay); @@ -1368,7 +1374,7 @@ impl Pallet { outgoing } - // note replacement of the code of para with given `id`, which occured in the + // note replacement of the code of para with given `id`, which occurred in the // context of the given relay-chain block number. provide the replaced code. // // `at` for para-triggered replacement is the block number of the relay-chain @@ -1890,7 +1896,14 @@ impl Pallet { ) -> Weight { let mut weight = T::DbWeight::get().reads(1); - // Enacting this should be prevented by the `can_schedule_upgrade` + // Should be prevented by checks in `schedule_code_upgrade_external` + let new_code_len = new_code.0.len(); + if new_code_len < MIN_CODE_SIZE as usize || new_code_len > cfg.max_code_size as usize { + log::warn!(target: LOG_TARGET, "attempted to schedule an upgrade with invalid new validation code",); + return weight + } + + // Enacting this should be prevented by the `can_upgrade_validation_code` if FutureCodeHash::::contains_key(&id) { // This branch should never be reached. Signalling an upgrade is disallowed for a para // that already has one upgrade scheduled. diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index cca200c2765e361120b4c5ea8db3dfc7c82bdc13..262ec9d3fdba95c0368d4cfe03b288ccaeb049d1 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -17,7 +17,7 @@ use super::*; use frame_support::{assert_err, assert_ok, assert_storage_noop}; use keyring::Sr25519Keyring; -use primitives::{BlockNumber, PARACHAIN_KEY_TYPE_ID}; +use primitives::{vstaging::SchedulerParams, BlockNumber, PARACHAIN_KEY_TYPE_ID}; use sc_keystore::LocalKeystore; use sp_keystore::{Keystore, KeystorePtr}; use std::sync::Arc; @@ -67,6 +67,16 @@ fn submit_super_majority_pvf_votes( .for_each(sign_and_include_pvf_check_statement); } +fn test_validation_code_1() -> ValidationCode { + let validation_code = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; + ValidationCode(validation_code) +} + +fn test_validation_code_2() -> ValidationCode { + let validation_code = vec![9, 8, 7, 6, 5, 4, 3, 2, 1]; + ValidationCode(validation_code) +} + fn run_to_block(to: BlockNumber, new_session: Option>) { let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); for validator in VALIDATORS.iter() { @@ -284,7 +294,7 @@ fn para_past_code_pruning_in_initialize() { let id = ParaId::from(0u32); let at_block: BlockNumber = 10; let included_block: BlockNumber = 12; - let validation_code = ValidationCode(vec![4, 5, 6]); + let validation_code = test_validation_code_2(); Paras::increase_code_ref(&validation_code.hash(), &validation_code); PastCodeHash::::insert(&(id, at_block), &validation_code.hash()); @@ -377,8 +387,8 @@ fn note_past_code_sets_up_pruning_correctly() { let id_a = ParaId::from(0u32); let id_b = ParaId::from(1u32); - Paras::note_past_code(id_a, 10, 12, ValidationCode(vec![1, 2, 3]).hash()); - Paras::note_past_code(id_b, 20, 23, ValidationCode(vec![4, 5, 6]).hash()); + Paras::note_past_code(id_a, 10, 12, test_validation_code_1().hash()); + Paras::note_past_code(id_b, 20, 23, test_validation_code_2().hash()); assert_eq!(PastCodePruning::::get(), vec![(id_a, 12), (id_b, 23)]); assert_eq!( @@ -398,7 +408,7 @@ fn code_upgrade_applied_after_delay() { let validation_upgrade_delay = 5; let validation_upgrade_cooldown = 10; - let original_code = ValidationCode(vec![1, 2, 3]); + let original_code = test_validation_code_1(); let paras = vec![( 0u32.into(), ParaGenesisArgs { @@ -425,7 +435,7 @@ fn code_upgrade_applied_after_delay() { check_code_is_stored(&original_code); let para_id = ParaId::from(0); - let new_code = ValidationCode(vec![4, 5, 6]); + let new_code = test_validation_code_2(); // Wait for at least one session change to set active validators. const EXPECTED_SESSION: SessionIndex = 1; @@ -516,7 +526,7 @@ fn code_upgrade_applied_without_setting_go_ahead_signal() { let validation_upgrade_delay = 5; let validation_upgrade_cooldown = 10; - let original_code = ValidationCode(vec![1, 2, 3]); + let original_code = test_validation_code_1(); let paras = vec![( 0u32.into(), ParaGenesisArgs { @@ -543,7 +553,7 @@ fn code_upgrade_applied_without_setting_go_ahead_signal() { check_code_is_stored(&original_code); let para_id = ParaId::from(0); - let new_code = ValidationCode(vec![4, 5, 6]); + let new_code = test_validation_code_2(); // Wait for at least one session change to set active validators. const EXPECTED_SESSION: SessionIndex = 1; @@ -637,7 +647,7 @@ fn code_upgrade_applied_after_delay_even_when_late() { let validation_upgrade_delay = 5; let validation_upgrade_cooldown = 10; - let original_code = ValidationCode(vec![1, 2, 3]); + let original_code = test_validation_code_1(); let paras = vec![( 0u32.into(), ParaGenesisArgs { @@ -662,7 +672,7 @@ fn code_upgrade_applied_after_delay_even_when_late() { new_test_ext(genesis_config).execute_with(|| { let para_id = ParaId::from(0); - let new_code = ValidationCode(vec![4, 5, 6]); + let new_code = test_validation_code_2(); // Wait for at least one session change to set active validators. const EXPECTED_SESSION: SessionIndex = 1; @@ -750,8 +760,8 @@ fn submit_code_change_when_not_allowed_is_err() { new_test_ext(genesis_config).execute_with(|| { let para_id = ParaId::from(0); - let new_code = ValidationCode(vec![4, 5, 6]); - let newer_code = ValidationCode(vec![4, 5, 6, 7]); + let new_code = test_validation_code_1(); + let newer_code = test_validation_code_2(); // Wait for at least one session change to set active validators. const EXPECTED_SESSION: SessionIndex = 1; @@ -832,8 +842,8 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { new_test_ext(genesis_config).execute_with(|| { let para_id = 0u32.into(); - let new_code = ValidationCode(vec![4, 5, 6]); - let newer_code = ValidationCode(vec![4, 5, 6, 7]); + let new_code = test_validation_code_1(); + let newer_code = test_validation_code_2(); // Wait for at least one session change to set active validators. const EXPECTED_SESSION: SessionIndex = 1; @@ -880,7 +890,7 @@ fn full_parachain_cleanup_storage() { let code_retention_period = 20; let validation_upgrade_delay = 1 + 5; - let original_code = ValidationCode(vec![1, 2, 3]); + let original_code = test_validation_code_1(); let paras = vec![( 0u32.into(), ParaGenesisArgs { @@ -899,7 +909,10 @@ fn full_parachain_cleanup_storage() { minimum_validation_upgrade_delay: 2, // Those are not relevant to this test. However, HostConfiguration is still a // subject for the consistency check. - paras_availability_period: 1, + scheduler_params: SchedulerParams { + paras_availability_period: 1, + ..Default::default() + }, ..Default::default() }, }, @@ -910,7 +923,7 @@ fn full_parachain_cleanup_storage() { check_code_is_stored(&original_code); let para_id = ParaId::from(0); - let new_code = ValidationCode(vec![4, 5, 6]); + let new_code = test_validation_code_2(); // Wait for at least one session change to set active validators. const EXPECTED_SESSION: SessionIndex = 1; @@ -993,8 +1006,8 @@ fn full_parachain_cleanup_storage() { fn cannot_offboard_ongoing_pvf_check() { let para_id = ParaId::from(0); - let existing_code: ValidationCode = vec![1, 2, 3].into(); - let new_code: ValidationCode = vec![3, 2, 1].into(); + let existing_code = test_validation_code_1(); + let new_code = test_validation_code_2(); let paras = vec![( para_id, @@ -1152,7 +1165,7 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { ParaGenesisArgs { para_kind: ParaKind::Parachain, genesis_head: dummy_head_data(), - validation_code: vec![1, 2, 3].into(), + validation_code: test_validation_code_1(), }, )]; @@ -1174,8 +1187,8 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { const EXPECTED_SESSION: SessionIndex = 1; let para_id = ParaId::from(0); - let old_code: ValidationCode = vec![1, 2, 3].into(); - let new_code: ValidationCode = vec![4, 5, 6].into(); + let old_code = test_validation_code_1(); + let new_code = test_validation_code_2(); Paras::schedule_code_upgrade( para_id, new_code.clone(), @@ -1219,7 +1232,7 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { #[test] fn code_ref_is_cleaned_correctly() { new_test_ext(Default::default()).execute_with(|| { - let code: ValidationCode = vec![1, 2, 3].into(); + let code = test_validation_code_1(); Paras::increase_code_ref(&code.hash(), &code); Paras::increase_code_ref(&code.hash(), &code); @@ -1244,8 +1257,8 @@ fn pvf_check_coalescing_onboarding_and_upgrade() { let a = ParaId::from(111); let b = ParaId::from(222); - let existing_code: ValidationCode = vec![1, 2, 3].into(); - let validation_code: ValidationCode = vec![3, 2, 1].into(); + let existing_code = test_validation_code_1(); + let validation_code = test_validation_code_2(); let paras = vec![( a, @@ -1320,7 +1333,7 @@ fn pvf_check_coalescing_onboarding_and_upgrade() { fn pvf_check_onboarding_reject_on_expiry() { let pvf_voting_ttl = 2; let a = ParaId::from(111); - let validation_code: ValidationCode = vec![3, 2, 1].into(); + let validation_code = test_validation_code_1(); let genesis_config = MockGenesisConfig { configuration: crate::configuration::GenesisConfig { @@ -1368,8 +1381,8 @@ fn pvf_check_onboarding_reject_on_expiry() { #[test] fn pvf_check_upgrade_reject() { let a = ParaId::from(111); - let old_code: ValidationCode = vec![1, 2, 3].into(); - let new_code: ValidationCode = vec![3, 2, 1].into(); + let old_code = test_validation_code_1(); + let new_code = test_validation_code_2(); let paras = vec![( a, @@ -1437,8 +1450,8 @@ fn pvf_check_upgrade_reject() { #[test] fn pvf_check_submit_vote() { - let code_a: ValidationCode = vec![3, 2, 1].into(); - let code_b: ValidationCode = vec![1, 2, 3].into(); + let code_a = test_validation_code_1(); + let code_b = test_validation_code_2(); let check = |stmt: PvfCheckStatement| -> (Result<_, _>, Result<_, _>) { let validators = &[ @@ -1554,8 +1567,8 @@ fn pvf_check_submit_vote() { #[test] fn include_pvf_check_statement_refunds_weight() { let a = ParaId::from(111); - let old_code: ValidationCode = vec![1, 2, 3].into(); - let new_code: ValidationCode = vec![3, 2, 1].into(); + let old_code = test_validation_code_1(); + let new_code = test_validation_code_2(); let paras = vec![( a, @@ -1620,7 +1633,7 @@ fn include_pvf_check_statement_refunds_weight() { fn add_trusted_validation_code_inserts_with_no_users() { // This test is to ensure that trusted validation code is inserted into the storage // with the reference count equal to 0. - let validation_code = ValidationCode(vec![1, 2, 3]); + let validation_code = test_validation_code_1(); new_test_ext(Default::default()).execute_with(|| { assert_ok!(Paras::add_trusted_validation_code( RuntimeOrigin::root(), @@ -1634,7 +1647,7 @@ fn add_trusted_validation_code_inserts_with_no_users() { fn add_trusted_validation_code_idempotent() { // This test makes sure that calling add_trusted_validation_code twice with the same // parameters is a no-op. - let validation_code = ValidationCode(vec![1, 2, 3]); + let validation_code = test_validation_code_1(); new_test_ext(Default::default()).execute_with(|| { assert_ok!(Paras::add_trusted_validation_code( RuntimeOrigin::root(), @@ -1653,7 +1666,7 @@ fn add_trusted_validation_code_idempotent() { fn poke_unused_validation_code_removes_code_cleanly() { // This test makes sure that calling poke_unused_validation_code with a code that is currently // in the storage but has no users will remove it cleanly from the storage. - let validation_code = ValidationCode(vec![1, 2, 3]); + let validation_code = test_validation_code_1(); new_test_ext(Default::default()).execute_with(|| { assert_ok!(Paras::add_trusted_validation_code( RuntimeOrigin::root(), @@ -1672,7 +1685,7 @@ fn poke_unused_validation_code_removes_code_cleanly() { #[test] fn poke_unused_validation_code_doesnt_remove_code_with_users() { let para_id = 100.into(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let validation_code = test_validation_code_1(); new_test_ext(Default::default()).execute_with(|| { // First we add the code to the storage. assert_ok!(Paras::add_trusted_validation_code( @@ -1708,7 +1721,7 @@ fn increase_code_ref_doesnt_have_allergy_on_add_trusted_validation_code() { // to a disaster. // NOTE that this test is extra paranoid, as it is not really possible to hit // `decrease_code_ref` without calling `increase_code_ref` first. - let code = ValidationCode(vec![1, 2, 3]); + let code = test_validation_code_1(); new_test_ext(Default::default()).execute_with(|| { assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), code.clone())); @@ -1732,7 +1745,7 @@ fn add_trusted_validation_code_insta_approval() { // `add_trusted_validation_code` and uses the `CodeByHash::contains_key` which is what // `add_trusted_validation_code` uses. let para_id = 100.into(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let validation_code = test_validation_code_1(); let validation_upgrade_delay = 25; let minimum_validation_upgrade_delay = 2; let genesis_config = MockGenesisConfig { @@ -1779,7 +1792,7 @@ fn add_trusted_validation_code_enacts_existing_pvf_vote() { // already going through PVF pre-checking voting will conclude the voting and enact the // code upgrade. let para_id = 100.into(); - let validation_code = ValidationCode(vec![1, 2, 3]); + let validation_code = test_validation_code_1(); let validation_upgrade_delay = 25; let minimum_validation_upgrade_delay = 2; let genesis_config = MockGenesisConfig { @@ -1868,7 +1881,7 @@ fn verify_para_head_is_externally_accessible() { #[test] fn most_recent_context() { - let validation_code: ValidationCode = vec![1, 2, 3].into(); + let validation_code = test_validation_code_1(); let genesis_config = MockGenesisConfig::default(); diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index 0f6b23ae1b39213f8afbd37798f8f7f31a024cf9..ad3fa8e0dc712b64141231250e251498803c52b1 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -120,7 +120,7 @@ benchmarks! { // with `v` validity votes. // let votes = v as usize; let votes = min(scheduler::Pallet::::group_validators(GroupIndex::from(0)).unwrap().len(), v as usize); - assert_eq!(benchmark.backed_candidates.get(0).unwrap().validity_votes.len(), votes); + assert_eq!(benchmark.backed_candidates.get(0).unwrap().validity_votes().len(), votes); benchmark.bitfields.clear(); benchmark.disputes.clear(); @@ -177,7 +177,7 @@ benchmarks! { // There is 1 backed assert_eq!(benchmark.backed_candidates.len(), 1); assert_eq!( - benchmark.backed_candidates.get(0).unwrap().validity_votes.len(), + benchmark.backed_candidates.get(0).unwrap().validity_votes().len(), votes, ); diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 81e092f0a991cd216bac3c1d8e48ae8bcea59144..723a15bdba7a88d73a2610b90910f53c6150475f 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -43,15 +43,14 @@ use frame_support::{ use frame_system::pallet_prelude::*; use pallet_babe::{self, ParentBlockRandomness}; use primitives::{ - effective_minimum_backing_votes, BackedCandidate, CandidateHash, CandidateReceipt, - CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CoreIndex, DisputeStatementSet, - InherentData as ParachainsInherentData, MultiDisputeStatementSet, ScrapedOnChainVotes, - SessionIndex, SignedAvailabilityBitfields, SigningContext, UncheckedSignedAvailabilityBitfield, - UncheckedSignedAvailabilityBitfields, ValidatorId, ValidatorIndex, ValidityAttestation, - PARACHAINS_INHERENT_IDENTIFIER, + effective_minimum_backing_votes, vstaging::node_features::FeatureIndex, BackedCandidate, + CandidateHash, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, + CoreIndex, DisputeStatementSet, InherentData as ParachainsInherentData, + MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SignedAvailabilityBitfields, + SigningContext, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, + ValidatorId, ValidatorIndex, ValidityAttestation, PARACHAINS_INHERENT_IDENTIFIER, }; use rand::{seq::SliceRandom, SeedableRng}; - use scale_info::TypeInfo; use sp_runtime::traits::{Header as HeaderT, One}; use sp_std::{ @@ -145,6 +144,10 @@ pub mod pallet { DisputeInvalid, /// A candidate was backed by a disabled validator BackedByDisabled, + /// A candidate was backed even though the paraid was not scheduled. + BackedOnUnscheduledCore, + /// Too many candidates supplied. + UnscheduledCandidate, } /// Whether the paras inherent was included within this block. @@ -585,25 +588,39 @@ impl Pallet { let freed = collect_all_freed_cores::(freed_concluded.iter().cloned()); >::free_cores_and_fill_claimqueue(freed, now); - let scheduled = >::scheduled_paras() - .map(|(core_idx, para_id)| (para_id, core_idx)) - .collect(); METRICS.on_candidates_processed_total(backed_candidates.len() as u64); - let SanitizedBackedCandidates { backed_candidates, votes_from_disabled_were_dropped } = - sanitize_backed_candidates::( - backed_candidates, - &allowed_relay_parents, - |candidate_idx: usize, - backed_candidate: &BackedCandidate<::Hash>| - -> bool { - let para_id = backed_candidate.descriptor().para_id; - let prev_context = >::para_most_recent_context(para_id); - let check_ctx = CandidateCheckContext::::new(prev_context); - - // never include a concluded-invalid candidate - current_concluded_invalid_disputes.contains(&backed_candidate.hash()) || + let core_index_enabled = configuration::Pallet::::config() + .node_features + .get(FeatureIndex::ElasticScalingMVP as usize) + .map(|b| *b) + .unwrap_or(false); + + let mut scheduled: BTreeMap> = BTreeMap::new(); + let mut total_scheduled_cores = 0; + + for (core_idx, para_id) in >::scheduled_paras() { + total_scheduled_cores += 1; + scheduled.entry(para_id).or_default().insert(core_idx); + } + + let SanitizedBackedCandidates { + backed_candidates_with_core, + votes_from_disabled_were_dropped, + dropped_unscheduled_candidates, + } = sanitize_backed_candidates::( + backed_candidates, + &allowed_relay_parents, + |candidate_idx: usize, + backed_candidate: &BackedCandidate<::Hash>| + -> bool { + let para_id = backed_candidate.descriptor().para_id; + let prev_context = >::para_most_recent_context(para_id); + let check_ctx = CandidateCheckContext::::new(prev_context); + + // never include a concluded-invalid candidate + current_concluded_invalid_disputes.contains(&backed_candidate.hash()) || // Instead of checking the candidates with code upgrades twice // move the checking up here and skip it in the training wheels fallback. // That way we avoid possible duplicate checks while assuring all @@ -611,13 +628,19 @@ impl Pallet { // // NOTE: this is the only place where we check the relay-parent. check_ctx - .verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate) + .verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate.candidate()) .is_err() - }, - &scheduled, - ); + }, + scheduled, + core_index_enabled, + ); - METRICS.on_candidates_sanitized(backed_candidates.len() as u64); + ensure!( + backed_candidates_with_core.len() <= total_scheduled_cores, + Error::::UnscheduledCandidate + ); + + METRICS.on_candidates_sanitized(backed_candidates_with_core.len() as u64); // In `Enter` context (invoked during execution) there should be no backing votes from // disabled validators because they should have been filtered out during inherent data @@ -626,15 +649,22 @@ impl Pallet { ensure!(!votes_from_disabled_were_dropped, Error::::BackedByDisabled); } + // In `Enter` context (invoked during execution) we shouldn't have filtered any candidates + // due to a para not being scheduled. They have been filtered during inherent data + // preparation (`ProvideInherent` context). Abort in such cases. + if context == ProcessInherentDataContext::Enter { + ensure!(!dropped_unscheduled_candidates, Error::::BackedOnUnscheduledCore); + } + // Process backed candidates according to scheduled cores. let inclusion::ProcessedCandidates::< as HeaderT>::Hash> { core_indices: occupied, candidate_receipt_with_backing_validator_indices, } = >::process_candidates( &allowed_relay_parents, - backed_candidates.clone(), - &scheduled, + backed_candidates_with_core.clone(), >::group_validators, + core_index_enabled, )?; // Note which of the scheduled cores were actually occupied by a backed candidate. >::occupied(occupied.into_iter().map(|e| (e.0, e.1)).collect()); @@ -651,8 +681,15 @@ impl Pallet { let bitfields = bitfields.into_iter().map(|v| v.into_unchecked()).collect(); - let processed = - ParachainsInherentData { bitfields, backed_candidates, disputes, parent_header }; + let processed = ParachainsInherentData { + bitfields, + backed_candidates: backed_candidates_with_core + .into_iter() + .map(|(candidate, _)| candidate) + .collect(), + disputes, + parent_header, + }; Ok((processed, Some(all_weight_after).into())) } } @@ -751,7 +788,7 @@ fn random_sel Weight>( /// Assumes disputes are already filtered by the time this is called. /// /// Returns the total weight consumed by `bitfields` and `candidates`. -fn apply_weight_limit( +pub(crate) fn apply_weight_limit( candidates: &mut Vec::Hash>>, bitfields: &mut UncheckedSignedAvailabilityBitfields, max_consumable_weight: Weight, @@ -768,35 +805,71 @@ fn apply_weight_limit( return total } - // Prefer code upgrades, they tend to be large and hence stand no chance to be picked - // late while maintaining the weight bounds. - let preferred_indices = candidates + // Invariant: block author provides candidate in the order in which they form a chain + // wrt elastic scaling. If the invariant is broken, we'd fail later when filtering candidates + // which are unchained. + + let mut chained_candidates: Vec> = Vec::new(); + let mut current_para_id = None; + + for candidate in sp_std::mem::take(candidates).into_iter() { + let candidate_para_id = candidate.descriptor().para_id; + if Some(candidate_para_id) == current_para_id { + let chain = chained_candidates + .last_mut() + .expect("if the current_para_id is Some, then vec is not empty; qed"); + chain.push(candidate); + } else { + current_para_id = Some(candidate_para_id); + chained_candidates.push(vec![candidate]); + } + } + + // Elastic scaling: we prefer chains that have a code upgrade among the candidates, + // as the candidates containing the upgrade tend to be large and hence stand no chance to + // be picked late while maintaining the weight bounds. + // + // Limitations: For simplicity if total weight of a chain of candidates is larger than + // the remaining weight, the chain will still not be included while it could still be possible + // to include part of that chain. + let preferred_chain_indices = chained_candidates .iter() .enumerate() - .filter_map(|(idx, candidate)| { - candidate.candidate.commitments.new_validation_code.as_ref().map(|_code| idx) + .filter_map(|(idx, candidates)| { + // Check if any of the candidate in chain contains a code upgrade. + if candidates + .iter() + .any(|candidate| candidate.candidate().commitments.new_validation_code.is_some()) + { + Some(idx) + } else { + None + } }) .collect::>(); - // There is weight remaining to be consumed by a subset of candidates + // There is weight remaining to be consumed by a subset of chained candidates // which are going to be picked now. if let Some(max_consumable_by_candidates) = max_consumable_weight.checked_sub(&total_bitfields_weight) { - let (acc_candidate_weight, indices) = - random_sel::::Hash>, _>( + let (acc_candidate_weight, chained_indices) = + random_sel::::Hash>>, _>( rng, - &candidates, - preferred_indices, - |c| backed_candidate_weight::(c), + &chained_candidates, + preferred_chain_indices, + |candidates| backed_candidates_weight::(&candidates), max_consumable_by_candidates, ); - log::debug!(target: LOG_TARGET, "Indices Candidates: {:?}, size: {}", indices, candidates.len()); - candidates.indexed_retain(|idx, _backed_candidate| indices.binary_search(&idx).is_ok()); + log::debug!(target: LOG_TARGET, "Indices Candidates: {:?}, size: {}", chained_indices, candidates.len()); + chained_candidates + .indexed_retain(|idx, _backed_candidates| chained_indices.binary_search(&idx).is_ok()); // pick all bitfields, and // fill the remaining space with candidates let total_consumed = acc_candidate_weight.saturating_add(total_bitfields_weight); + *candidates = chained_candidates.into_iter().flatten().collect::>(); + return total_consumed } @@ -916,16 +989,22 @@ pub(crate) fn sanitize_bitfields( // Result from `sanitize_backed_candidates` #[derive(Debug, PartialEq)] struct SanitizedBackedCandidates { - // Sanitized backed candidates. The `Vec` is sorted according to the occupied core index. - backed_candidates: Vec>, + // Sanitized backed candidates along with the assigned core. The `Vec` is sorted according to + // the occupied core index. + backed_candidates_with_core: Vec<(BackedCandidate, CoreIndex)>, // Set to true if any votes from disabled validators were dropped from the input. votes_from_disabled_were_dropped: bool, + // Set to true if any candidates were dropped due to filtering done in + // `map_candidates_to_cores` + dropped_unscheduled_candidates: bool, } /// Filter out: /// 1. any candidates that have a concluded invalid dispute -/// 2. all backing votes from disabled validators -/// 3. any candidates that end up with less than `effective_minimum_backing_votes` backing votes +/// 2. any unscheduled candidates, as well as candidates whose paraid has multiple cores assigned +/// but have no injected core index. +/// 3. all backing votes from disabled validators +/// 4. any candidates that end up with less than `effective_minimum_backing_votes` backing votes /// /// `scheduled` follows the same naming scheme as provided in the /// guide: Currently `free` but might become `occupied`. @@ -944,7 +1023,8 @@ fn sanitize_backed_candidates< mut backed_candidates: Vec>, allowed_relay_parents: &AllowedRelayParentsTracker>, mut candidate_has_concluded_invalid_dispute_or_is_invalid: F, - scheduled: &BTreeMap, + scheduled: BTreeMap>, + core_index_enabled: bool, ) -> SanitizedBackedCandidates { // Remove any candidates that were concluded invalid. // This does not assume sorting. @@ -952,22 +1032,23 @@ fn sanitize_backed_candidates< !candidate_has_concluded_invalid_dispute_or_is_invalid(candidate_idx, backed_candidate) }); - // Assure the backed candidate's `ParaId`'s core is free. - // This holds under the assumption that `Scheduler::schedule` is called _before_. - // We don't check the relay-parent because this is done in the closure when - // constructing the inherent and during actual processing otherwise. - - backed_candidates.retain(|backed_candidate| { - let desc = backed_candidate.descriptor(); + let initial_candidate_count = backed_candidates.len(); + // Map candidates to scheduled cores. Filter out any unscheduled candidates. + let mut backed_candidates_with_core = map_candidates_to_cores::( + &allowed_relay_parents, + scheduled, + core_index_enabled, + backed_candidates, + ); - scheduled.get(&desc.para_id).is_some() - }); + let dropped_unscheduled_candidates = + initial_candidate_count != backed_candidates_with_core.len(); // Filter out backing statements from disabled validators - let dropped_disabled = filter_backed_statements_from_disabled_validators::( - &mut backed_candidates, + let votes_from_disabled_were_dropped = filter_backed_statements_from_disabled_validators::( + &mut backed_candidates_with_core, &allowed_relay_parents, - scheduled, + core_index_enabled, ); // Sort the `Vec` last, once there is a guarantee that these @@ -975,14 +1056,12 @@ fn sanitize_backed_candidates< // but more importantly are scheduled for a free core. // This both avoids extra work for obviously invalid candidates, // but also allows this to be done in place. - backed_candidates.sort_by(|x, y| { - // Never panics, since we filtered all panic arguments out in the previous `fn retain`. - scheduled[&x.descriptor().para_id].cmp(&scheduled[&y.descriptor().para_id]) - }); + backed_candidates_with_core.sort_by(|(_x, core_x), (_y, core_y)| core_x.cmp(&core_y)); SanitizedBackedCandidates { - backed_candidates, - votes_from_disabled_were_dropped: dropped_disabled, + dropped_unscheduled_candidates, + votes_from_disabled_were_dropped, + backed_candidates_with_core, } } @@ -1071,9 +1150,12 @@ fn limit_and_sanitize_disputes< // few more sanity checks. Returns `true` if at least one statement is removed and `false` // otherwise. fn filter_backed_statements_from_disabled_validators( - backed_candidates: &mut Vec::Hash>>, + backed_candidates_with_core: &mut Vec<( + BackedCandidate<::Hash>, + CoreIndex, + )>, allowed_relay_parents: &AllowedRelayParentsTracker>, - scheduled: &BTreeMap, + core_index_enabled: bool, ) -> bool { let disabled_validators = BTreeSet::<_>::from_iter(shared::Pallet::::disabled_validators().into_iter()); @@ -1083,7 +1165,7 @@ fn filter_backed_statements_from_disabled_validators *core_idx, - None => { - log::debug!(target: LOG_TARGET, "Can't get core idx of a backed candidate for para id {:?}. Dropping the candidate.", bc.descriptor().para_id); - return false - } - }; + backed_candidates_with_core.retain_mut(|(bc, core_idx)| { + let (validator_indices, maybe_core_index) = bc.validator_indices_and_core_index(core_index_enabled); + let mut validator_indices = BitVec::<_>::from(validator_indices); // Get relay parent block number of the candidate. We need this to get the group index assigned to this core at this block number let relay_parent_block_number = match allowed_relay_parents @@ -1116,7 +1192,7 @@ fn filter_backed_statements_from_disabled_validators>::group_assigned_to_core( - core_idx, + *core_idx, relay_parent_block_number + One::one(), ) { Some(group_idx) => group_idx, @@ -1138,12 +1214,15 @@ fn filter_backed_statements_from_disabled_validators::from_iter(validator_group.iter().map(|idx| disabled_validators.contains(idx))); // The indices of statements from disabled validators in `BackedCandidate`. We have to drop these. - let indices_to_drop = disabled_indices.clone() & &bc.validator_indices; + let indices_to_drop = disabled_indices.clone() & &validator_indices; // Apply the bitmask to drop the disabled validator from `validator_indices` - bc.validator_indices &= !disabled_indices; + validator_indices &= !disabled_indices; + // Update the backed candidate + bc.set_validator_indices_and_core_index(validator_indices, maybe_core_index); + // Remove the corresponding votes from `validity_votes` for idx in indices_to_drop.iter_ones().rev() { - bc.validity_votes.remove(idx); + bc.validity_votes_mut().remove(idx); } // If at least one statement was dropped we need to return `true` @@ -1154,10 +1233,9 @@ fn filter_backed_statements_from_disabled_validators( + allowed_relay_parents: &AllowedRelayParentsTracker>, + mut scheduled: BTreeMap>, + core_index_enabled: bool, + candidates: Vec>, +) -> Vec<(BackedCandidate, CoreIndex)> { + let mut backed_candidates_with_core = Vec::with_capacity(candidates.len()); + + // We keep a candidate if the parachain has only one core assigned or if + // a core index is provided by block author and it's indeed scheduled. + for backed_candidate in candidates { + let maybe_injected_core_index = get_injected_core_index::( + allowed_relay_parents, + &backed_candidate, + core_index_enabled, + ); + + let scheduled_cores = scheduled.get_mut(&backed_candidate.descriptor().para_id); + // Candidates without scheduled cores are silently filtered out. + if let Some(scheduled_cores) = scheduled_cores { + if let Some(core_idx) = maybe_injected_core_index { + if scheduled_cores.contains(&core_idx) { + scheduled_cores.remove(&core_idx); + backed_candidates_with_core.push((backed_candidate, core_idx)); + } + } else if scheduled_cores.len() == 1 { + backed_candidates_with_core + .push((backed_candidate, scheduled_cores.pop_first().expect("Length is 1"))); + } + } + } + + backed_candidates_with_core +} + +fn get_injected_core_index( + allowed_relay_parents: &AllowedRelayParentsTracker>, + candidate: &BackedCandidate, + core_index_enabled: bool, +) -> Option { + // After stripping the 8 bit extensions, the `validator_indices` field length is expected + // to be equal to backing group size. If these don't match, the `CoreIndex` is badly encoded, + // or not supported. + let (validator_indices, maybe_core_idx) = + candidate.validator_indices_and_core_index(core_index_enabled); + + let Some(core_idx) = maybe_core_idx else { return None }; + + let relay_parent_block_number = + match allowed_relay_parents.acquire_info(candidate.descriptor().relay_parent, None) { + Some((_, block_num)) => block_num, + None => { + log::debug!( + target: LOG_TARGET, + "Relay parent {:?} for candidate {:?} is not in the allowed relay parents. Dropping the candidate.", + candidate.descriptor().relay_parent, + candidate.candidate().hash(), + ); + return None + }, + }; + + // Get the backing group of the candidate backed at `core_idx`. + let group_idx = match >::group_assigned_to_core( + core_idx, + relay_parent_block_number + One::one(), + ) { + Some(group_idx) => group_idx, + None => { + log::debug!( + target: LOG_TARGET, + "Can't get the group index for core idx {:?}. Dropping the candidate {:?}.", + core_idx, + candidate.candidate().hash(), + ); + return None + }, + }; + + let group_validators = match >::group_validators(group_idx) { + Some(validators) => validators, + None => return None, + }; + + if group_validators.len() == validator_indices.len() { + Some(core_idx) + } else { + None + } } diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index 6f3eac35685a82b32c69b27e5379620988c956b7..fb4d1bd2226ed77c406a062c78a1ca26c4958e40 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -22,15 +22,19 @@ use super::*; #[cfg(not(feature = "runtime-benchmarks"))] mod enter { - use super::*; + use super::{inclusion::tests::TestCandidateBuilder, *}; use crate::{ builder::{Bench, BenchBuilder}, mock::{mock_assigner, new_test_ext, BlockLength, BlockWeights, MockGenesisConfig, Test}, - scheduler::common::Assignment, + scheduler::{ + common::{Assignment, AssignmentProvider}, + ParasEntry, + }, }; use assert_matches::assert_matches; use frame_support::assert_ok; use frame_system::limits; + use primitives::vstaging::SchedulerParams; use sp_runtime::Perbill; use sp_std::collections::btree_map::BTreeMap; @@ -84,7 +88,7 @@ mod enter { // `create_inherent` and will not cause `enter` to early. fn include_backed_candidates() { let config = MockGenesisConfig::default(); - assert!(config.configuration.config.scheduling_lookahead > 0); + assert!(config.configuration.config.scheduler_params.lookahead > 0); new_test_ext(config).execute_with(|| { let dispute_statements = BTreeMap::new(); @@ -622,7 +626,7 @@ mod enter { #[test] fn limit_candidates_over_weight_1() { let config = MockGenesisConfig::default(); - assert!(config.configuration.config.scheduling_lookahead > 0); + assert!(config.configuration.config.scheduler_params.lookahead > 0); new_test_ext(config).execute_with(|| { // Create the inherent data for this block @@ -697,6 +701,25 @@ mod enter { 2 ); + // One core was scheduled. We should put the assignment back, before calling enter(). + let now = >::block_number() + 1; + let used_cores = 5; + let cores = (0..used_cores) + .into_iter() + .map(|i| { + let SchedulerParams { ttl, .. } = + >::config().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()) + }) + .collect(); + scheduler::ClaimQueue::::set(cores); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -902,6 +925,129 @@ mod enter { }); } + // Helper fn that builds chained dummy candidates for elastic scaling tests + fn build_backed_candidate_chain( + para_id: ParaId, + len: usize, + start_core_index: usize, + code_upgrade_index: Option, + ) -> Vec { + if let Some(code_upgrade_index) = code_upgrade_index { + assert!(code_upgrade_index < len, "Code upgrade index out of bounds"); + } + + (0..len) + .into_iter() + .map(|idx| { + let mut builder = TestCandidateBuilder::default(); + builder.para_id = para_id; + let mut ccr = builder.build(); + + if Some(idx) == code_upgrade_index { + ccr.commitments.new_validation_code = Some(vec![1, 2, 3, 4].into()); + } + + ccr.commitments.processed_downward_messages = idx as u32; + let core_index = start_core_index + idx; + + BackedCandidate::new( + ccr.into(), + Default::default(), + Default::default(), + Some(CoreIndex(core_index as u32)), + ) + }) + .collect::>() + } + + // Ensure that overweight parachain inherents are always rejected by the runtime. + // Runtime should panic and return `InherentOverweight` error. + #[test] + fn test_backed_candidates_apply_weight_works_for_elastic_scaling() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let seed = [ + 1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, + 0, 0, 0, 0, 0, 2, 92, + ]; + let mut rng = rand_chacha::ChaChaRng::from_seed(seed); + + // Create an overweight inherent and oversized block + let mut backed_and_concluding = BTreeMap::new(); + + for i in 0..30 { + backed_and_concluding.insert(i, i); + } + + let scenario = make_inherent_data(TestConfig { + dispute_statements: Default::default(), + dispute_sessions: vec![], // 3 cores with disputes + backed_and_concluding, + num_validators_per_core: 5, + code_upgrade: None, + fill_claimqueue: false, + }); + + let mut para_inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (5 validators per core, 30 backed candidates, 0 disputes + // => 5*30 = 150) + assert_eq!(para_inherent_data.bitfields.len(), 150); + // * 30 backed candidates + assert_eq!(para_inherent_data.backed_candidates.len(), 30); + + let mut input_candidates = + build_backed_candidate_chain(ParaId::from(1000), 3, 0, Some(1)); + let chained_candidates_weight = backed_candidates_weight::(&input_candidates); + + input_candidates.append(&mut para_inherent_data.backed_candidates); + let input_bitfields = para_inherent_data.bitfields; + + // Test if weight insufficient even for 1 candidate (which doesn't contain a code + // upgrade). + let max_weight = backed_candidate_weight::(&input_candidates[0]) + + signed_bitfields_weight::(&input_bitfields); + let mut backed_candidates = input_candidates.clone(); + let mut bitfields = input_bitfields.clone(); + apply_weight_limit::( + &mut backed_candidates, + &mut bitfields, + max_weight, + &mut rng, + ); + + // The chained candidates are not picked, instead a single other candidate is picked + assert_eq!(backed_candidates.len(), 1); + assert_ne!(backed_candidates[0].descriptor().para_id, ParaId::from(1000)); + + // All bitfields are kept. + assert_eq!(bitfields.len(), 150); + + // Test if para_id 1000 chained candidates make it if there is enough room for its 3 + // candidates. + let max_weight = + chained_candidates_weight + signed_bitfields_weight::(&input_bitfields); + let mut backed_candidates = input_candidates.clone(); + let mut bitfields = input_bitfields.clone(); + apply_weight_limit::( + &mut backed_candidates, + &mut bitfields, + max_weight, + &mut rng, + ); + + // Only the chained candidates should pass filter. + assert_eq!(backed_candidates.len(), 3); + // Check the actual candidates + assert_eq!(backed_candidates[0].descriptor().para_id, ParaId::from(1000)); + assert_eq!(backed_candidates[1].descriptor().para_id, ParaId::from(1000)); + assert_eq!(backed_candidates[2].descriptor().para_id, ParaId::from(1000)); + + // All bitfields are kept. + assert_eq!(bitfields.len(), 150); + }); + } + // Ensure that overweight parachain inherents are always rejected by the runtime. // Runtime should panic and return `InherentOverweight` error. #[test] @@ -980,6 +1126,7 @@ mod sanitizers { AvailabilityBitfield, GroupIndex, Hash, Id as ParaId, SignedAvailabilityBitfield, ValidatorIndex, }; + use rstest::rstest; use sp_core::crypto::UncheckedFrom; use crate::mock::Test; @@ -1238,12 +1385,13 @@ mod sanitizers { // Backed candidates and scheduled parachains used for `sanitize_backed_candidates` testing struct TestData { backed_candidates: Vec, - scheduled_paras: BTreeMap, + all_backed_candidates_with_core: Vec<(BackedCandidate, CoreIndex)>, + scheduled_paras: BTreeMap>, } // Generate test data for the candidates and assert that the evnironment is set as expected // (check the comments for details) - fn get_test_data() -> TestData { + fn get_test_data(core_index_enabled: bool) -> TestData { const RELAY_PARENT_NUM: u32 = 3; // Add the relay parent to `shared` pallet. Otherwise some code (e.g. filtering backing @@ -1285,9 +1433,14 @@ mod sanitizers { shared::Pallet::::set_active_validators_ascending(validator_ids); // Two scheduled parachains - ParaId(1) on CoreIndex(0) and ParaId(2) on CoreIndex(1) - let scheduled = (0_usize..2) + let scheduled: BTreeMap> = (0_usize..2) .into_iter() - .map(|idx| (ParaId::from(1_u32 + idx as u32), CoreIndex::from(idx as u32))) + .map(|idx| { + ( + ParaId::from(1_u32 + idx as u32), + [CoreIndex::from(idx as u32)].into_iter().collect(), + ) + }) .collect::>(); // Set the validator groups in `scheduler` @@ -1301,7 +1454,7 @@ mod sanitizers { ( CoreIndex::from(0), VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, RELAY_PARENT_NUM, )]), ), @@ -1319,12 +1472,12 @@ mod sanitizers { match group_index { group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1]), group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), - _ => panic!("Group index out of bounds for 2 parachains and 1 parathread core"), + _ => panic!("Group index out of bounds"), } .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) }; - // Two backed candidates from each parachain + // One backed candidate from each parachain let backed_candidates = (0_usize..2) .into_iter() .map(|idx0| { @@ -1348,6 +1501,7 @@ mod sanitizers { &keystore, &signing_context, BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(idx0 as u32)), ); backed }) @@ -1369,13 +1523,373 @@ mod sanitizers { ] ); - TestData { backed_candidates, scheduled_paras: scheduled } + let all_backed_candidates_with_core = backed_candidates + .iter() + .map(|candidate| { + // Only one entry for this test data. + ( + candidate.clone(), + scheduled + .get(&candidate.descriptor().para_id) + .unwrap() + .first() + .copied() + .unwrap(), + ) + }) + .collect(); + + TestData { + backed_candidates, + scheduled_paras: scheduled, + all_backed_candidates_with_core, + } + } + + // Generate test data for the candidates and assert that the evnironment is set as expected + // (check the comments for details) + // Para 1 scheduled on core 0 and core 1. Two candidates are supplied. + // Para 2 scheduled on cores 2 and 3. One candidate supplied. + // Para 3 scheduled on core 4. One candidate supplied. + // Para 4 scheduled on core 5. Two candidates supplied. + // Para 5 scheduled on core 6. No candidates supplied. + fn get_test_data_multiple_cores_per_para(core_index_enabled: bool) -> TestData { + const RELAY_PARENT_NUM: u32 = 3; + + // Add the relay parent to `shared` pallet. Otherwise some code (e.g. filtering backing + // votes) won't behave correctly + shared::Pallet::::add_allowed_relay_parent( + default_header().hash(), + Default::default(), + RELAY_PARENT_NUM, + 1, + ); + + let header = default_header(); + let relay_parent = header.hash(); + let session_index = SessionIndex::from(0_u32); + + let keystore = LocalKeystore::in_memory(); + let keystore = Arc::new(keystore) as KeystorePtr; + let signing_context = SigningContext { parent_hash: relay_parent, session_index }; + + let validators = vec![ + keyring::Sr25519Keyring::Alice, + keyring::Sr25519Keyring::Bob, + keyring::Sr25519Keyring::Charlie, + keyring::Sr25519Keyring::Dave, + keyring::Sr25519Keyring::Eve, + keyring::Sr25519Keyring::Ferdie, + keyring::Sr25519Keyring::One, + ]; + for validator in validators.iter() { + Keystore::sr25519_generate_new( + &*keystore, + PARACHAIN_KEY_TYPE_ID, + Some(&validator.to_seed()), + ) + .unwrap(); + } + + // Set active validators in `shared` pallet + let validator_ids = + validators.iter().map(|v| v.public().into()).collect::>(); + shared::Pallet::::set_active_validators_ascending(validator_ids); + + // Set the validator groups in `scheduler` + scheduler::Pallet::::set_validator_groups(vec![ + vec![ValidatorIndex(0)], + vec![ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3)], + vec![ValidatorIndex(4)], + vec![ValidatorIndex(5)], + vec![ValidatorIndex(6)], + ]); + + // Update scheduler's claimqueue with the parachains + scheduler::Pallet::::set_claimqueue(BTreeMap::from([ + ( + CoreIndex::from(0), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(1), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(2), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(2) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(3), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(4), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(4) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(5), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(5) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(6), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 5.into(), core_index: CoreIndex(6) }, + RELAY_PARENT_NUM, + )]), + ), + ])); + + // Callback used for backing candidates + let group_validators = |group_index: GroupIndex| { + match group_index { + group_index if group_index == GroupIndex::from(0) => Some(vec![0]), + group_index if group_index == GroupIndex::from(1) => Some(vec![1]), + group_index if group_index == GroupIndex::from(2) => Some(vec![2]), + group_index if group_index == GroupIndex::from(3) => Some(vec![3]), + group_index if group_index == GroupIndex::from(4) => Some(vec![4]), + group_index if group_index == GroupIndex::from(5) => Some(vec![5]), + group_index if group_index == GroupIndex::from(6) => Some(vec![6]), + + _ => panic!("Group index out of bounds"), + } + .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) + }; + + let mut backed_candidates = vec![]; + let mut all_backed_candidates_with_core = vec![]; + + // Para 1 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + relay_parent, + pov_hash: Hash::repeat_byte(1 as u8), + persisted_validation_data_hash: [42u8; 32].into(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed: BackedCandidate = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(0 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(0 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + all_backed_candidates_with_core.push((backed, CoreIndex(0))); + } + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + relay_parent, + pov_hash: Hash::repeat_byte(2 as u8), + persisted_validation_data_hash: [42u8; 32].into(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(1 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(1 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + all_backed_candidates_with_core.push((backed, CoreIndex(1))); + } + } + + // Para 2 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: [42u8; 32].into(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(2 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(2 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + all_backed_candidates_with_core.push((backed, CoreIndex(2))); + } + } + + // Para 3 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(3), + relay_parent, + pov_hash: Hash::repeat_byte(4 as u8), + persisted_validation_data_hash: [42u8; 32].into(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(4 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(4 as u32)), + ); + backed_candidates.push(backed.clone()); + all_backed_candidates_with_core.push((backed, CoreIndex(4))); + } + + // Para 4 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(4), + relay_parent, + pov_hash: Hash::repeat_byte(5 as u8), + persisted_validation_data_hash: [42u8; 32].into(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + None, + ); + backed_candidates.push(backed.clone()); + all_backed_candidates_with_core.push((backed, CoreIndex(5))); + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(4), + relay_parent, + pov_hash: Hash::repeat_byte(6 as u8), + persisted_validation_data_hash: [42u8; 32].into(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(5 as u32)), + ); + backed_candidates.push(backed.clone()); + } + + // No candidate for para 5. + + // State sanity checks + assert_eq!( + >::scheduled_paras().collect::>(), + vec![ + (CoreIndex(0), ParaId::from(1)), + (CoreIndex(1), ParaId::from(1)), + (CoreIndex(2), ParaId::from(2)), + (CoreIndex(3), ParaId::from(2)), + (CoreIndex(4), ParaId::from(3)), + (CoreIndex(5), ParaId::from(4)), + (CoreIndex(6), ParaId::from(5)), + ] + ); + let mut scheduled: BTreeMap> = BTreeMap::new(); + for (core_idx, para_id) in >::scheduled_paras() { + scheduled.entry(para_id).or_default().insert(core_idx); + } + + assert_eq!( + shared::Pallet::::active_validator_indices(), + vec![ + ValidatorIndex(0), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(4), + ValidatorIndex(5), + ValidatorIndex(6), + ] + ); + + TestData { + backed_candidates, + scheduled_paras: scheduled, + all_backed_candidates_with_core, + } } - #[test] - fn happy_path() { + #[rstest] + #[case(false)] + #[case(true)] + fn happy_path(#[case] core_index_enabled: bool) { new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { backed_candidates, scheduled_paras: scheduled } = get_test_data(); + let TestData { + backed_candidates, + all_backed_candidates_with_core, + scheduled_paras: scheduled, + } = get_test_data(core_index_enabled); let has_concluded_invalid = |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; @@ -1385,47 +1899,95 @@ mod sanitizers { backed_candidates.clone(), &>::allowed_relay_parents(), has_concluded_invalid, - &scheduled + scheduled, + core_index_enabled ), SanitizedBackedCandidates { - backed_candidates, - votes_from_disabled_were_dropped: false + backed_candidates_with_core: all_backed_candidates_with_core, + votes_from_disabled_were_dropped: false, + dropped_unscheduled_candidates: false } ); + }); + } - {} + #[rstest] + #[case(false)] + #[case(true)] + fn test_with_multiple_cores_per_para(#[case] core_index_enabled: bool) { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let TestData { + backed_candidates, + all_backed_candidates_with_core: expected_all_backed_candidates_with_core, + scheduled_paras: scheduled, + } = get_test_data_multiple_cores_per_para(core_index_enabled); + + let has_concluded_invalid = + |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; + + assert_eq!( + sanitize_backed_candidates::( + backed_candidates.clone(), + &>::allowed_relay_parents(), + has_concluded_invalid, + scheduled, + core_index_enabled + ), + SanitizedBackedCandidates { + backed_candidates_with_core: expected_all_backed_candidates_with_core, + votes_from_disabled_were_dropped: false, + dropped_unscheduled_candidates: true + } + ); }); } // nothing is scheduled, so no paraids match, thus all backed candidates are skipped - #[test] - fn nothing_scheduled() { + #[rstest] + #[case(false, false)] + #[case(true, true)] + #[case(false, true)] + #[case(true, false)] + fn nothing_scheduled( + #[case] core_index_enabled: bool, + #[case] multiple_cores_per_para: bool, + ) { new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { backed_candidates, scheduled_paras: _ } = get_test_data(); - let scheduled = &BTreeMap::new(); + let TestData { backed_candidates, .. } = if multiple_cores_per_para { + get_test_data_multiple_cores_per_para(core_index_enabled) + } else { + get_test_data(core_index_enabled) + }; + let scheduled = BTreeMap::new(); let has_concluded_invalid = |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; let SanitizedBackedCandidates { - backed_candidates: sanitized_backed_candidates, + backed_candidates_with_core: sanitized_backed_candidates, votes_from_disabled_were_dropped, + dropped_unscheduled_candidates, } = sanitize_backed_candidates::( backed_candidates.clone(), &>::allowed_relay_parents(), has_concluded_invalid, - &scheduled, + scheduled, + core_index_enabled, ); assert!(sanitized_backed_candidates.is_empty()); assert!(!votes_from_disabled_were_dropped); + assert!(dropped_unscheduled_candidates); }); } // candidates that have concluded as invalid are filtered out - #[test] - fn invalid_are_filtered_out() { + #[rstest] + #[case(false)] + #[case(true)] + fn invalid_are_filtered_out(#[case] core_index_enabled: bool) { new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { backed_candidates, scheduled_paras: scheduled } = get_test_data(); + let TestData { backed_candidates, scheduled_paras: scheduled, .. } = + get_test_data(core_index_enabled); // mark every second one as concluded invalid let set = { @@ -1440,45 +2002,55 @@ mod sanitizers { let has_concluded_invalid = |_idx: usize, candidate: &BackedCandidate| set.contains(&candidate.hash()); let SanitizedBackedCandidates { - backed_candidates: sanitized_backed_candidates, + backed_candidates_with_core: sanitized_backed_candidates, votes_from_disabled_were_dropped, + dropped_unscheduled_candidates, } = sanitize_backed_candidates::( backed_candidates.clone(), &>::allowed_relay_parents(), has_concluded_invalid, - &scheduled, + scheduled, + core_index_enabled, ); assert_eq!(sanitized_backed_candidates.len(), backed_candidates.len() / 2); assert!(!votes_from_disabled_were_dropped); + assert!(!dropped_unscheduled_candidates); }); } - #[test] - fn disabled_non_signing_validator_doesnt_get_filtered() { + #[rstest] + #[case(false)] + #[case(true)] + fn disabled_non_signing_validator_doesnt_get_filtered(#[case] core_index_enabled: bool) { new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { mut backed_candidates, scheduled_paras } = get_test_data(); + let TestData { mut all_backed_candidates_with_core, .. } = + get_test_data(core_index_enabled); // Disable Eve set_disabled_validators(vec![4]); - let before = backed_candidates.clone(); + let before = all_backed_candidates_with_core.clone(); // Eve is disabled but no backing statement is signed by it so nothing should be // filtered assert!(!filter_backed_statements_from_disabled_validators::( - &mut backed_candidates, + &mut all_backed_candidates_with_core, &>::allowed_relay_parents(), - &scheduled_paras + core_index_enabled )); - assert_eq!(backed_candidates, before); + assert_eq!(all_backed_candidates_with_core, before); }); } - - #[test] - fn drop_statements_from_disabled_without_dropping_candidate() { + #[rstest] + #[case(false)] + #[case(true)] + fn drop_statements_from_disabled_without_dropping_candidate( + #[case] core_index_enabled: bool, + ) { new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { mut backed_candidates, scheduled_paras } = get_test_data(); + let TestData { mut all_backed_candidates_with_core, .. } = + get_test_data(core_index_enabled); // Disable Alice set_disabled_validators(vec![0]); @@ -1491,61 +2063,83 @@ mod sanitizers { configuration::Pallet::::force_set_active_config(hc); // Verify the initial state is as expected - assert_eq!(backed_candidates.get(0).unwrap().validity_votes.len(), 2); - assert_eq!( - backed_candidates.get(0).unwrap().validator_indices.get(0).unwrap(), - true - ); assert_eq!( - backed_candidates.get(0).unwrap().validator_indices.get(1).unwrap(), - true + all_backed_candidates_with_core.get(0).unwrap().0.validity_votes().len(), + 2 ); - let untouched = backed_candidates.get(1).unwrap().clone(); + let (validator_indices, maybe_core_index) = all_backed_candidates_with_core + .get(0) + .unwrap() + .0 + .validator_indices_and_core_index(core_index_enabled); + if core_index_enabled { + assert!(maybe_core_index.is_some()); + } else { + assert!(maybe_core_index.is_none()); + } + + assert_eq!(validator_indices.get(0).unwrap(), true); + assert_eq!(validator_indices.get(1).unwrap(), true); + let untouched = all_backed_candidates_with_core.get(1).unwrap().0.clone(); assert!(filter_backed_statements_from_disabled_validators::( - &mut backed_candidates, + &mut all_backed_candidates_with_core, &>::allowed_relay_parents(), - &scheduled_paras + core_index_enabled )); + let (validator_indices, maybe_core_index) = all_backed_candidates_with_core + .get(0) + .unwrap() + .0 + .validator_indices_and_core_index(core_index_enabled); + if core_index_enabled { + assert!(maybe_core_index.is_some()); + } else { + assert!(maybe_core_index.is_none()); + } + // there should still be two backed candidates - assert_eq!(backed_candidates.len(), 2); + assert_eq!(all_backed_candidates_with_core.len(), 2); // but the first one should have only one validity vote - assert_eq!(backed_candidates.get(0).unwrap().validity_votes.len(), 1); - // Validator 0 vote should be dropped, validator 1 - retained - assert_eq!( - backed_candidates.get(0).unwrap().validator_indices.get(0).unwrap(), - false - ); assert_eq!( - backed_candidates.get(0).unwrap().validator_indices.get(1).unwrap(), - true + all_backed_candidates_with_core.get(0).unwrap().0.validity_votes().len(), + 1 ); + // Validator 0 vote should be dropped, validator 1 - retained + assert_eq!(validator_indices.get(0).unwrap(), false); + assert_eq!(validator_indices.get(1).unwrap(), true); // the second candidate shouldn't be modified - assert_eq!(*backed_candidates.get(1).unwrap(), untouched); + assert_eq!(all_backed_candidates_with_core.get(1).unwrap().0, untouched); }); } - #[test] - fn drop_candidate_if_all_statements_are_from_disabled() { + #[rstest] + #[case(false)] + #[case(true)] + fn drop_candidate_if_all_statements_are_from_disabled(#[case] core_index_enabled: bool) { new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { mut backed_candidates, scheduled_paras } = get_test_data(); + let TestData { mut all_backed_candidates_with_core, .. } = + get_test_data(core_index_enabled); // Disable Alice and Bob set_disabled_validators(vec![0, 1]); // Verify the initial state is as expected - assert_eq!(backed_candidates.get(0).unwrap().validity_votes.len(), 2); - let untouched = backed_candidates.get(1).unwrap().clone(); + assert_eq!( + all_backed_candidates_with_core.get(0).unwrap().0.validity_votes().len(), + 2 + ); + let untouched = all_backed_candidates_with_core.get(1).unwrap().0.clone(); assert!(filter_backed_statements_from_disabled_validators::( - &mut backed_candidates, + &mut all_backed_candidates_with_core, &>::allowed_relay_parents(), - &scheduled_paras + core_index_enabled )); - assert_eq!(backed_candidates.len(), 1); - assert_eq!(*backed_candidates.get(0).unwrap(), untouched); + assert_eq!(all_backed_candidates_with_core.len(), 1); + assert_eq!(all_backed_candidates_with_core.get(0).unwrap().0, untouched); }); } } diff --git a/polkadot/runtime/parachains/src/paras_inherent/weights.rs b/polkadot/runtime/parachains/src/paras_inherent/weights.rs index 05cc53fae04652c188d62b57fa5281aa6bb88e22..0f4e5be572a66d16c1476ada7671c495a27bbc83 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/weights.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/weights.rs @@ -149,11 +149,11 @@ pub fn backed_candidate_weight( candidate: &BackedCandidate, ) -> Weight { set_proof_size_to_tx_size( - if candidate.candidate.commitments.new_validation_code.is_some() { + if candidate.candidate().commitments.new_validation_code.is_some() { <::WeightInfo as WeightInfo>::enter_backed_candidate_code_upgrade() } else { <::WeightInfo as WeightInfo>::enter_backed_candidates_variable( - candidate.validity_votes.len() as u32, + candidate.validity_votes().len() as u32, ) }, candidate, diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 3dbb050fb4e5e40dc6f7b512bf55c45368a3ac5d..f231864a85e7261d999c1c1ec34679bb0825d56c 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -37,7 +37,7 @@ //! availability cores over time. use crate::{configuration, initializer::SessionChangeNotification, paras}; -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, traits::Defensive}; use frame_system::pallet_prelude::BlockNumberFor; pub use polkadot_core_primitives::v2::BlockNumber; use primitives::{ @@ -51,7 +51,7 @@ use sp_std::{ pub mod common; -use common::{Assignment, AssignmentProvider, AssignmentProviderConfig}; +use common::{Assignment, AssignmentProvider}; pub use pallet::*; @@ -59,6 +59,7 @@ pub use pallet::*; mod tests; const LOG_TARGET: &str = "runtime::parachains::scheduler"; + pub mod migration; #[frame_support::pallet] @@ -88,10 +89,8 @@ pub mod pallet { #[pallet::getter(fn validator_groups)] pub(crate) type ValidatorGroups = StorageValue<_, Vec>, ValueQuery>; - /// One entry for each availability core. Entries are `None` if the core is not currently - /// occupied. Can be temporarily `Some` if scheduled but not occupied. - /// The i'th parachain belongs to the i'th core, with the remaining cores all being - /// parathread-multiplexers. + /// 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 @@ -146,7 +145,7 @@ pub mod pallet { /// 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. + /// a block. Runtime APIs should be used to determine scheduled cores for the upcoming block. #[pallet::storage] #[pallet::getter(fn claimqueue)] pub(crate) type ClaimQueue = @@ -222,7 +221,7 @@ impl Pallet { let n_cores = core::cmp::max( T::AssignmentProvider::session_core_count(), - match config.max_validators_per_core { + match config.scheduler_params.max_validators_per_core { Some(x) if x != 0 => validators.len() as u32 / x, _ => 0, }, @@ -236,8 +235,16 @@ impl Pallet { if n_cores == 0 || validators.is_empty() { ValidatorGroups::::set(Vec::new()); } else { - let group_base_size = validators.len() / n_cores as usize; - let n_larger_groups = validators.len() % n_cores as usize; + let group_base_size = validators + .len() + .checked_div(n_cores as usize) + .defensive_proof("n_cores should not be 0") + .unwrap_or(0); + let n_larger_groups = validators + .len() + .checked_rem(n_cores as usize) + .defensive_proof("n_cores should not be 0") + .unwrap_or(0); // Groups contain indices into the validators from the session change notification, // which are already shuffled. @@ -350,6 +357,7 @@ impl Pallet { fn drop_expired_claims_from_claimqueue() { let now = >::block_number(); let availability_cores = AvailabilityCores::::get(); + let ttl = >::config().scheduler_params.ttl; ClaimQueue::::mutate(|cq| { for (idx, _) in (0u32..).zip(availability_cores) { @@ -382,8 +390,6 @@ impl Pallet { if let Some(assignment) = T::AssignmentProvider::pop_assignment_for_core(core_idx) { - let AssignmentProviderConfig { ttl, .. } = - T::AssignmentProvider::get_provider_config(core_idx); core_claimqueue.push_back(ParasEntry::new(assignment, now + ttl)); } } @@ -428,7 +434,7 @@ impl Pallet { } let rotations_since_session_start: BlockNumberFor = - (at - session_start_block) / config.group_rotation_frequency; + (at - session_start_block) / config.scheduler_params.group_rotation_frequency; let rotations_since_session_start = as TryInto>::try_into(rotations_since_session_start) @@ -460,9 +466,9 @@ impl Pallet { // Note: blocks backed in this rotation will never time out here as backed_in + // config.paras_availability_period will always be > now for these blocks, as // otherwise above condition would not be true. - pending_since + config.paras_availability_period + pending_since + config.scheduler_params.paras_availability_period } else { - next_rotation + config.paras_availability_period + next_rotation + config.scheduler_params.paras_availability_period }; AvailabilityTimeoutStatus { timed_out: time_out_at <= now, live_until: time_out_at } @@ -478,7 +484,8 @@ impl Pallet { let now = >::block_number() + One::one(); let rotation_info = Self::group_rotation_info(now); - let current_window = rotation_info.last_rotation_at() + config.paras_availability_period; + let current_window = + rotation_info.last_rotation_at() + config.scheduler_params.paras_availability_period; now < current_window } @@ -488,7 +495,7 @@ impl Pallet { ) -> GroupRotationInfo> { let session_start_block = Self::session_start_block(); let group_rotation_frequency = - >::config().group_rotation_frequency; + >::config().scheduler_params.group_rotation_frequency; GroupRotationInfo { session_start_block, now, group_rotation_frequency } } @@ -508,6 +515,8 @@ impl Pallet { /// 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 = + >::config().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 @@ -515,16 +524,12 @@ impl Pallet { let cores = AvailabilityCores::::get(); cores.get(core.0 as usize).and_then(|c| match c { CoreOccupied::Free => None, - CoreOccupied::Paras(pe) => { - let AssignmentProviderConfig { max_availability_timeouts, .. } = - T::AssignmentProvider::get_provider_config(core); - + CoreOccupied::Paras(pe) => if pe.availability_timeouts < max_availability_timeouts { Some(Self::paras_entry_to_scheduled_core(pe)) } else { None - } - }, + }, }) }) } @@ -566,7 +571,7 @@ impl Pallet { // ClaimQueue related functions // fn claimqueue_lookahead() -> u32 { - >::config().scheduling_lookahead + >::config().scheduler_params.lookahead } /// Frees cores and fills the free claimqueue spots by popping from the `AssignmentProvider`. @@ -585,15 +590,15 @@ impl Pallet { let n_lookahead = Self::claimqueue_lookahead().max(1); let n_session_cores = T::AssignmentProvider::session_core_count(); let cq = ClaimQueue::::get(); - let ttl = >::config().on_demand_ttl; + let config = >::config(); + let max_availability_timeouts = config.scheduler_params.max_availability_timeouts; + let ttl = config.scheduler_params.ttl; for core_idx in 0..n_session_cores { let core_idx = CoreIndex::from(core_idx); // add previously timedout paras back into the queue if let Some(mut entry) = timedout_paras.remove(&core_idx) { - let AssignmentProviderConfig { max_availability_timeouts, .. } = - T::AssignmentProvider::get_provider_config(core_idx); if entry.availability_timeouts < max_availability_timeouts { // Increment the timeout counter. entry.availability_timeouts += 1; @@ -668,13 +673,6 @@ impl Pallet { .filter_map(|(core_idx, v)| v.front().map(|e| (core_idx, e.assignment.para_id()))) } - #[cfg(any(feature = "runtime-benchmarks", test))] - pub(crate) fn assignment_provider_config( - core_idx: CoreIndex, - ) -> AssignmentProviderConfig> { - T::AssignmentProvider::get_provider_config(core_idx) - } - #[cfg(any(feature = "try-runtime", test))] fn claimqueue_len() -> usize { ClaimQueue::::get().iter().map(|la_vec| la_vec.1.len()).sum() diff --git a/polkadot/runtime/parachains/src/scheduler/common.rs b/polkadot/runtime/parachains/src/scheduler/common.rs index 2eb73385803c6e62a88fc55526e3ba18218cf06d..66a4e6d30be0830650295d5311b7d7e1fc3b1d20 100644 --- a/polkadot/runtime/parachains/src/scheduler/common.rs +++ b/polkadot/runtime/parachains/src/scheduler/common.rs @@ -48,22 +48,10 @@ impl Assignment { } } -#[derive(Encode, Decode, TypeInfo)] -/// A set of variables required by the scheduler in order to operate. -pub struct AssignmentProviderConfig { - /// How many times a collation can time out on availability. - /// Zero timeouts still means that a collation can be provided as per the slot auction - /// assignment provider. - pub max_availability_timeouts: u32, - - /// How long the collator has to provide a collation to the backing group before being dropped. - pub ttl: BlockNumber, -} - pub trait AssignmentProvider { /// Pops an [`Assignment`] from the provider for a specified [`CoreIndex`]. /// - /// This is where assignments come into existance. + /// This is where assignments come into existence. fn pop_assignment_for_core(core_idx: CoreIndex) -> Option; /// A previously popped `Assignment` has been fully processed. @@ -77,14 +65,11 @@ pub trait AssignmentProvider { /// Push back a previously popped assignment. /// /// If the assignment could not be processed within the current session, it can be pushed back - /// to the assignment provider in order to be poppped again later. + /// to the assignment provider in order to be popped again later. /// /// This is the second way the life of an assignment can come to an end. fn push_back_assignment(assignment: Assignment); - /// Returns a set of variables needed by the scheduler - fn get_provider_config(core_idx: CoreIndex) -> AssignmentProviderConfig; - /// Push some assignment for mocking/benchmarks purposes. /// /// Useful for benchmarks and testing. The returned assignment is "valid" and can if need be diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index 9af23ce64bd67ab0901dd1a03e849d51cfffe342..e6a1e66b3a531906fa6cbf763f248f6f6108a0f3 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -18,7 +18,9 @@ use super::*; use frame_support::assert_ok; use keyring::Sr25519Keyring; -use primitives::{BlockNumber, SessionIndex, ValidationCode, ValidatorId}; +use primitives::{ + vstaging::SchedulerParams, BlockNumber, SessionIndex, ValidationCode, ValidatorId, +}; use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use crate::{ @@ -103,15 +105,19 @@ fn run_to_end_of_block( fn default_config() -> HostConfiguration { HostConfiguration { - coretime_cores: 3, - group_rotation_frequency: 10, - paras_availability_period: 3, - scheduling_lookahead: 2, // This field does not affect anything that scheduler does. However, `HostConfiguration` // is still a subject to consistency test. It requires that // `minimum_validation_upgrade_delay` is greater than `chain_availability_period` and // `thread_availability_period`. minimum_validation_upgrade_delay: 6, + scheduler_params: SchedulerParams { + group_rotation_frequency: 10, + paras_availability_period: 3, + lookahead: 2, + num_cores: 3, + max_availability_timeouts: 1, + ..Default::default() + }, ..Default::default() } } @@ -155,7 +161,7 @@ fn scheduled_entries() -> impl Iterator(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); @@ -217,7 +223,7 @@ fn claimqueue_ttl_drop_fn_works() { Scheduler::add_to_claimqueue(core_idx, paras_entry_expired.clone()); Scheduler::add_to_claimqueue(core_idx, paras_entry_non_expired.clone()); let cq = Scheduler::claimqueue(); - assert!(cq.get(&core_idx).unwrap().len() == 3); + assert_eq!(cq.get(&core_idx).unwrap().len(), 3); // Add a claim to the test assignment provider. let assignment = Assignment::Bulk(para_id); @@ -229,8 +235,9 @@ fn claimqueue_ttl_drop_fn_works() { let cq = Scheduler::claimqueue(); let cqc = cq.get(&core_idx).unwrap(); - // Same number of claims - assert!(cqc.len() == 3); + // 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. @@ -290,7 +297,7 @@ fn session_change_shuffles_validators() { fn session_change_takes_only_max_per_core() { let config = { let mut config = default_config(); - config.max_validators_per_core = Some(1); + config.scheduler_params.max_validators_per_core = Some(1); config }; @@ -330,7 +337,8 @@ fn session_change_takes_only_max_per_core() { #[test] fn fill_claimqueue_fills() { - let genesis_config = genesis_config(&default_config()); + let config = default_config(); + let genesis_config = genesis_config(&config); let para_a = ParaId::from(3_u32); let para_b = ParaId::from(4_u32); @@ -342,22 +350,20 @@ fn fill_claimqueue_fills() { new_test_ext(genesis_config).execute_with(|| { MockAssigner::set_core_count(2); - let AssignmentProviderConfig { ttl: config_ttl, .. } = - MockAssigner::get_provider_config(CoreIndex(0)); + 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); - // 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(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), ], ..Default::default() }), @@ -381,7 +387,7 @@ fn fill_claimqueue_fills() { &ParasEntry { assignment: assignment_a.clone(), availability_timeouts: 0, - ttl: 2 + config_ttl + ttl: 2 + coretime_ttl }, ); // Sits on the same core as `para_a` @@ -390,7 +396,7 @@ fn fill_claimqueue_fills() { ParasEntry { assignment: assignment_b.clone(), availability_timeouts: 0, - ttl: 2 + config_ttl + ttl: 2 + coretime_ttl } ); assert_eq!( @@ -398,7 +404,7 @@ fn fill_claimqueue_fills() { &ParasEntry { assignment: assignment_c.clone(), availability_timeouts: 0, - ttl: 2 + config_ttl + ttl: 2 + coretime_ttl }, ); } @@ -410,7 +416,7 @@ fn schedule_schedules_including_just_freed() { 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.scheduling_lookahead = 1; + config.scheduler_params.lookahead = 1; let genesis_config = genesis_config(&config); let para_a = ParaId::from(3_u32); @@ -479,7 +485,7 @@ fn schedule_schedules_including_just_freed() { // All `core_queue`s should be empty Scheduler::claimqueue() .iter() - .for_each(|(_core_idx, core_queue)| assert!(core_queue.len() == 0)) + .for_each(|(_core_idx, core_queue)| assert_eq!(core_queue.len(), 0)) } // add a couple more para claims - the claim on `b` will go to the 3rd core @@ -557,7 +563,7 @@ fn schedule_schedules_including_just_freed() { #[test] fn schedule_clears_availability_cores() { let mut config = default_config(); - config.scheduling_lookahead = 1; + config.scheduler_params.lookahead = 1; let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); @@ -659,11 +665,11 @@ fn schedule_clears_availability_cores() { fn schedule_rotates_groups() { let config = { let mut config = default_config(); - config.scheduling_lookahead = 1; + config.scheduler_params.lookahead = 1; config }; - let rotation_frequency = config.group_rotation_frequency; + let rotation_frequency = config.scheduler_params.group_rotation_frequency; let on_demand_cores = 2; let genesis_config = genesis_config(&config); @@ -742,9 +748,12 @@ fn schedule_rotates_groups() { #[test] fn on_demand_claims_are_pruned_after_timing_out() { - let max_retries = 20; + let max_timeouts = 20; let mut config = default_config(); - config.scheduling_lookahead = 1; + 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); @@ -753,11 +762,6 @@ fn on_demand_claims_are_pruned_after_timing_out() { new_test_ext(genesis_config).execute_with(|| { MockAssigner::set_core_count(2); - // Need more timeouts for this test - MockAssigner::set_assignment_provider_config(AssignmentProviderConfig { - max_availability_timeouts: max_retries, - ttl: BlockNumber::from(5u32), - }); schedule_blank_para(para_a); // #1 @@ -794,7 +798,7 @@ fn on_demand_claims_are_pruned_after_timing_out() { // 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_retries + 1) { + for n in now..=(now + max_timeouts + 1) { // #n run_to_block(n, |_| None); // Time out on core 0. @@ -806,7 +810,7 @@ fn on_demand_claims_are_pruned_after_timing_out() { Scheduler::free_cores_and_fill_claimqueue(just_updated, now); // ParaId a exists in the claim queue until max_retries is reached. - if n < max_retries + now { + if n < max_timeouts + now { assert!(claimqueue_contains_para_ids::(vec![para_a])); } else { assert!(!claimqueue_contains_para_ids::(vec![para_a])); @@ -822,7 +826,7 @@ fn on_demand_claims_are_pruned_after_timing_out() { assert!(!availability_cores_contains_para_ids::(vec![para_a])); // #25 - now += max_retries + 2; + now += max_timeouts + 2; // Add assignment back to the mix. MockAssigner::add_test_assignment(assignment_a.clone()); @@ -833,7 +837,7 @@ fn on_demand_claims_are_pruned_after_timing_out() { // #26 now += 1; // Run to block #n but this time have group 1 conclude the availabilty. - for n in now..=(now + max_retries + 1) { + 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. @@ -874,10 +878,8 @@ fn on_demand_claims_are_pruned_after_timing_out() { fn availability_predicate_works() { let genesis_config = genesis_config(&default_config()); - let HostConfiguration { group_rotation_frequency, paras_availability_period, .. } = - default_config(); - - assert!(paras_availability_period < group_rotation_frequency); + let SchedulerParams { group_rotation_frequency, paras_availability_period, .. } = + default_config().scheduler_params; new_test_ext(genesis_config).execute_with(|| { run_to_block(1 + paras_availability_period, |_| None); @@ -1044,7 +1046,7 @@ fn next_up_on_time_out_reuses_claim_if_nothing_queued() { #[test] fn session_change_requires_reschedule_dropping_removed_paras() { let mut config = default_config(); - config.scheduling_lookahead = 1; + config.scheduler_params.lookahead = 1; let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); @@ -1056,7 +1058,7 @@ fn session_change_requires_reschedule_dropping_removed_paras() { new_test_ext(genesis_config).execute_with(|| { // Setting explicit core count MockAssigner::set_core_count(5); - let assignment_provider_ttl = MockAssigner::get_provider_config(CoreIndex::from(0)).ttl; + let coretime_ttl = >::config().scheduler_params.ttl; schedule_blank_para(para_a); schedule_blank_para(para_b); @@ -1120,7 +1122,7 @@ fn session_change_requires_reschedule_dropping_removed_paras() { vec![ParasEntry::new( Assignment::Bulk(para_a), // At end of block 2 - assignment_provider_ttl + 2 + coretime_ttl + 2 )] .into_iter() .collect() @@ -1169,7 +1171,7 @@ fn session_change_requires_reschedule_dropping_removed_paras() { vec![ParasEntry::new( Assignment::Bulk(para_a), // At block 3 - assignment_provider_ttl + 3 + coretime_ttl + 3 )] .into_iter() .collect() @@ -1179,7 +1181,7 @@ fn session_change_requires_reschedule_dropping_removed_paras() { vec![ParasEntry::new( Assignment::Bulk(para_b), // At block 3 - assignment_provider_ttl + 3 + coretime_ttl + 3 )] .into_iter() .collect() diff --git a/polkadot/runtime/parachains/src/session_info/migration.rs b/polkadot/runtime/parachains/src/session_info/migration.rs index 228c1e3bb2515b14f5fe59a89578b03be065955d..ea6f81834b5db6eb7336521d3d471a6c3df49985 100644 --- a/polkadot/runtime/parachains/src/session_info/migration.rs +++ b/polkadot/runtime/parachains/src/session_info/migration.rs @@ -18,5 +18,5 @@ use frame_support::traits::StorageVersion; -/// The current storage version. +/// The in-code storage version. pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); diff --git a/polkadot/runtime/parachains/src/session_info/tests.rs b/polkadot/runtime/parachains/src/session_info/tests.rs index 92a50575deda8413abb18f892680d693c148d0cb..a5bfeae0745599c00de718684420fc377a9184f1 100644 --- a/polkadot/runtime/parachains/src/session_info/tests.rs +++ b/polkadot/runtime/parachains/src/session_info/tests.rs @@ -25,7 +25,7 @@ use crate::{ util::take_active_subset, }; use keyring::Sr25519Keyring; -use primitives::{BlockNumber, ValidatorId, ValidatorIndex}; +use primitives::{vstaging::SchedulerParams, BlockNumber, ValidatorId, ValidatorIndex}; fn run_to_block( to: BlockNumber, @@ -62,9 +62,9 @@ fn run_to_block( fn default_config() -> HostConfiguration { HostConfiguration { - coretime_cores: 1, dispute_period: 2, needed_approvals: 3, + scheduler_params: SchedulerParams { num_cores: 1, ..Default::default() }, ..Default::default() } } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 11be7a9ffc4396e7deeabf7527bdf72e6c0bf92e..61ca1635ac9567cfdebbb05c4e92c97489387a91 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -13,9 +13,9 @@ workspace = true [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.195", default-features = false } -serde_derive = { version = "1.0.117", optional = true } +log = { workspace = true } +serde = { workspace = true } +serde_derive = { optional = true, workspace = true } static_assertions = "1.1.0" smallvec = "1.8.0" @@ -111,7 +111,7 @@ keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyrin remote-externalities = { package = "frame-remote-externalities", path = "../../../substrate/utils/frame/remote-externalities" } sp-trie = { path = "../../../substrate/primitives/trie" } separator = "0.4.1" -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } tokio = { version = "1.24.2", features = ["macros"] } @@ -246,6 +246,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", diff --git a/polkadot/runtime/rococo/constants/src/weights/block_weights.rs b/polkadot/runtime/rococo/constants/src/weights/block_weights.rs index e2aa4a6cab7febc90418c3222819109e256a18c8..f7dc2f19316d5e6b13deb76044fb0ebf43b25d3b 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 adce840ebbc120a4e7905ad6312b9d27b1e8d3fb..000cee8a237c3ef306e3356f9733422765b67306 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/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 184d0338eb06a2b87c367b3bde96e930ab060b37..ff54c7776701c1ccaa512518e0470655fcd0afde 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -46,9 +46,8 @@ use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; use runtime_parachains::{ assigner_coretime as parachains_assigner_coretime, - assigner_on_demand as parachains_assigner_on_demand, - assigner_parachains as parachains_assigner_parachains, - configuration as parachains_configuration, coretime, disputes as parachains_disputes, + assigner_on_demand as parachains_assigner_on_demand, configuration as parachains_configuration, + coretime, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, inclusion::{AggregateMessageOrigin, UmpQueueId}, @@ -150,7 +149,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("rococo"), impl_name: create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 1_006_002, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 24, @@ -200,6 +199,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 MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -330,6 +330,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! { @@ -592,7 +593,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(), @@ -604,16 +605,17 @@ 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 = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) + Some((call, (address, signature, tx_ext))) } } @@ -634,12 +636,32 @@ parameter_types! { pub Prefix: &'static [u8] = b"Pay ROCs to the Rococo account:"; } +#[cfg(feature = "runtime-benchmarks")] +pub struct ClaimsHelper; + +#[cfg(feature = "runtime-benchmarks")] +use frame_support::dispatch::DispatchInfo; + +#[cfg(feature = "runtime-benchmarks")] +impl claims::BenchmarkHelperTrait for ClaimsHelper { + fn default_call_and_info() -> (RuntimeCall, DispatchInfo) { + use frame_support::dispatch::GetDispatchInfo; + let call = RuntimeCall::Claims(claims::Call::attest { + statement: claims::StatementKind::Regular.to_text().to_vec(), + }); + let info = call.get_dispatch_info(); + (call, info) + } +} + impl claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; type Prefix = Prefix; type MoveClaimOrigin = EnsureRoot; type WeightInfo = weights::runtime_common_claims::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ClaimsHelper; } parameter_types! { @@ -1038,8 +1060,6 @@ impl parachains_assigner_on_demand::Config for Runtime { type WeightInfo = weights::runtime_parachains_assigner_on_demand::WeightInfo; } -impl parachains_assigner_parachains::Config for Runtime {} - impl parachains_assigner_coretime::Config for Runtime {} impl parachains_initializer::Config for Runtime { @@ -1401,7 +1421,6 @@ construct_runtime! { ParasSlashing: parachains_slashing = 63, MessageQueue: pallet_message_queue = 64, OnDemandAssignmentProvider: parachains_assigner_on_demand = 66, - ParachainsAssignmentProvider: parachains_assigner_parachains = 67, CoretimeAssignmentProvider: parachains_assigner_coretime = 68, // Parachain Onboarding Pallets. Start indices at 70 to leave room. @@ -1451,8 +1470,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, @@ -1465,7 +1484,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// All migrations that will run on the next runtime upgrade. /// @@ -1662,6 +1681,7 @@ pub mod migrations { parachains_configuration::migration::v11::MigrateToV11, // This needs to come after the `parachains_configuration` above as we are reading the configuration. coretime::migration::MigrateToCoretime, + parachains_configuration::migration::v12::MigrateToV12, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, @@ -1678,7 +1698,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) @@ -1749,7 +1769,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] @@ -1772,7 +1794,7 @@ sp_api::impl_runtime_apis! { Executive::execute_block(block); } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -1824,6 +1846,12 @@ sp_api::impl_runtime_apis! { impl offchain_primitives::OffchainWorkerApi for Runtime { fn offchain_worker(header: &::Header) { + use sp_runtime::{traits::Header, DigestItem}; + + if header.digest().logs().iter().any(|di| di == &DigestItem::RuntimeEnvironmentUpdated) { + pallet_im_online::migration::clear_offchain_storage(Session::validators().len() as u32); + } + Executive::offchain_worker(header) } } @@ -2237,6 +2265,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; @@ -2257,6 +2286,7 @@ sp_api::impl_runtime_apis! { 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; @@ -2270,12 +2300,30 @@ sp_api::impl_runtime_apis! { TokenLocation::get(), ExistentialDeposit::get() ).into()); - pub ToParachain: ParaId = rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(); + pub AssetHubParaId: ParaId = rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(); + pub const RandomParaId: ParaId = ParaId::new(43211234); } impl frame_system_benchmarking::Config for Runtime {} impl frame_benchmarking::baseline::Config for Runtime {} impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = ( + runtime_common::xcm_sender::ToParachainDeliveryHelper< + XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForChildParachainDelivery, + AssetHubParaId, + (), + >, + runtime_common::xcm_sender::ToParachainDeliveryHelper< + XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForChildParachainDelivery, + RandomParaId, + (), + > + ); + fn reachable_dest() -> Option { Some(crate::xcm_config::AssetHub::get()) } @@ -2284,7 +2332,7 @@ sp_api::impl_runtime_apis! { // Relay/native token can be teleported to/from AH. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Here.into()) }, crate::xcm_config::AssetHub::get(), @@ -2295,10 +2343,10 @@ sp_api::impl_runtime_apis! { // Relay can reserve transfer native token to some random parachain. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Here.into()) }, - Parachain(43211234).into(), + Parachain(RandomParaId::get().into()).into(), )) } @@ -2315,6 +2363,13 @@ sp_api::impl_runtime_apis! { dest ) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::here()), + fun: Fungible(ExistentialDeposit::get()), + } + } } impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = XcmConfig; @@ -2323,7 +2378,7 @@ sp_api::impl_runtime_apis! { XcmConfig, ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, - ToParachain, + AssetHubParaId, (), >; fn valid_destination() -> Result { diff --git a/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs b/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs index dfba0cfc4aa90938c70376796117eea9ff00b676..0f68a5c6fb373b5d7b871aba540aa7210d710a53 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 2e49483dcc62728f3554bb1364efd740f8b03fd2..1742a761ca77baa50c79f51cb4ac854cba0fa274 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 0000000000000000000000000000000000000000..40520591f533f8722b0d3cd9f68847288c28eb38 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,123 @@ +// 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() -> 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 0ba21ccf322d3fcdc63ac83261f5d4c3338de4e2..128a3083a9c7139854fd2c41d75f82422617f1e4 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; @@ -23,7 +24,6 @@ pub mod pallet_bounties; pub mod pallet_child_bounties; pub mod pallet_conviction_voting; pub mod pallet_identity; -pub mod pallet_im_online; pub mod pallet_indices; pub mod pallet_message_queue; pub mod pallet_multisig; @@ -37,6 +37,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 da2d1958cefcfeb41bcdba7ed2dd9c6b4272e873..56b1e2cbc5717fa932d9a5419773ce5fbd246d7f 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 1b0ae1eeece41b10aff0c65181fe757cfdc4dd0e..3fa54f2c36972b90b5304ef3ab3a962d9866ed27 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-20, 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-j8vvqcjr-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_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/ @@ -54,8 +56,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 44_127_000 picoseconds. - Weight::from_parts(45_099_000, 0) + // Minimum execution time: 45_336_000 picoseconds. + Weight::from_parts(46_189_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -66,8 +68,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 34_265_000 picoseconds. - Weight::from_parts(35_083_000, 0) + // Minimum execution time: 34_880_000 picoseconds. + Weight::from_parts(35_770_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -78,8 +80,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 12_189_000 picoseconds. - Weight::from_parts(12_655_000, 0) + // Minimum execution time: 12_904_000 picoseconds. + Weight::from_parts(13_260_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -90,8 +92,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_910_000 picoseconds. - Weight::from_parts(17_474_000, 0) + // Minimum execution time: 17_669_000 picoseconds. + Weight::from_parts(18_228_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -102,8 +104,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 45_212_000 picoseconds. - Weight::from_parts(46_320_000, 0) + // Minimum execution time: 46_492_000 picoseconds. + Weight::from_parts(47_639_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -114,8 +116,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 42_500_000 picoseconds. - Weight::from_parts(43_991_000, 0) + // Minimum execution time: 44_342_000 picoseconds. + Weight::from_parts(45_144_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -126,8 +128,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 15_197_000 picoseconds. - Weight::from_parts(15_749_000, 0) + // Minimum execution time: 15_260_000 picoseconds. + Weight::from_parts(15_775_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -140,11 +142,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_414_000 picoseconds. - Weight::from_parts(14_685_000, 0) + // Minimum execution time: 14_703_000 picoseconds. + Weight::from_parts(14_950_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 7_918 - .saturating_add(Weight::from_parts(13_095_420, 0).saturating_mul(u.into())) + // Standard Error: 7_665 + .saturating_add(Weight::from_parts(13_335_803, 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())) @@ -153,8 +155,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_239_000 picoseconds. - Weight::from_parts(5_617_000, 0) + // Minimum execution time: 5_506_000 picoseconds. + Weight::from_parts(5_753_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } 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 6cca9b9320a6558ae6f1a5192e615d62b4acf8f4..1852ba6c2c4da6c814ca520b4d73a6b4654f84f7 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 @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-20, 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-j8vvqcjr-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_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/ @@ -56,8 +58,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6164` - // Minimum execution time: 41_978_000 picoseconds. - Weight::from_parts(42_989_000, 0) + // Minimum execution time: 42_443_000 picoseconds. + Weight::from_parts(43_250_000, 0) .saturating_add(Weight::from_parts(0, 6164)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -70,8 +72,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6164` - // Minimum execution time: 32_250_000 picoseconds. - Weight::from_parts(33_074_000, 0) + // Minimum execution time: 32_417_000 picoseconds. + Weight::from_parts(33_247_000, 0) .saturating_add(Weight::from_parts(0, 6164)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -82,8 +84,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3577` - // Minimum execution time: 9_906_000 picoseconds. - Weight::from_parts(10_397_000, 0) + // Minimum execution time: 10_091_000 picoseconds. + Weight::from_parts(10_426_000, 0) .saturating_add(Weight::from_parts(0, 3577)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -96,8 +98,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `277` // Estimated: `3593` - // Minimum execution time: 16_298_000 picoseconds. - Weight::from_parts(17_115_000, 0) + // Minimum execution time: 16_546_000 picoseconds. + Weight::from_parts(17_259_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -110,8 +112,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `6196` - // Minimum execution time: 43_283_000 picoseconds. - Weight::from_parts(44_033_000, 0) + // Minimum execution time: 44_322_000 picoseconds. + Weight::from_parts(45_319_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) @@ -124,8 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6164` - // Minimum execution time: 40_564_000 picoseconds. - Weight::from_parts(41_597_000, 0) + // Minimum execution time: 40_852_000 picoseconds. + Weight::from_parts(42_205_000, 0) .saturating_add(Weight::from_parts(0, 6164)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -138,8 +140,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `277` // Estimated: `3593` - // Minimum execution time: 15_018_000 picoseconds. - Weight::from_parts(15_532_000, 0) + // Minimum execution time: 15_050_000 picoseconds. + Weight::from_parts(15_813_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -154,11 +156,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (256 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_470_000 picoseconds. - Weight::from_parts(14_828_000, 0) + // Minimum execution time: 14_830_000 picoseconds. + Weight::from_parts(15_061_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 15_515 - .saturating_add(Weight::from_parts(14_505_553, 0).saturating_mul(u.into())) + // Standard Error: 16_072 + .saturating_add(Weight::from_parts(14_981_430, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -167,8 +169,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_277_000 picoseconds. - Weight::from_parts(5_628_000, 0) + // Minimum execution time: 5_344_000 picoseconds. + Weight::from_parts(5_735_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs index 38d3645316f25faba74fff9d37c66db2ab4f08d9..8f8be5f2386f7983d42dbad355a266ff68cf332a 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs @@ -16,11 +16,11 @@ //! 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-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_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,118 +50,181 @@ 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: 21_772_000 picoseconds. + Weight::from_parts(22_861_341, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 18 - .saturating_add(Weight::from_parts(606, 0).saturating_mul(d.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(721, 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: 11_218_000 picoseconds. + Weight::from_parts(11_796_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: 10_959_000 picoseconds. + Weight::from_parts(11_658_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: `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: 37_419_000 picoseconds. + Weight::from_parts(38_362_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: 27_328_000 picoseconds. + Weight::from_parts(27_661_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: 16_067_000 picoseconds. + Weight::from_parts(16_865_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: 101_153_000 picoseconds. + Weight::from_parts(102_480_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: 38_838_000 picoseconds. + Weight::from_parts(39_549_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: 68_592_000 picoseconds. + Weight::from_parts(70_727_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: 11_272_000 picoseconds. + Weight::from_parts(11_592_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: 2_844_000 picoseconds. + Weight::from_parts(2_900_000, 0) .saturating_add(Weight::from_parts(0, 1887)) + // Standard Error: 9_467 + .saturating_add(Weight::from_parts(32_326_595, 0).saturating_mul(b.into())) + .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 e8c798d45e727618b892e4ebd7e11d7ba81f66ca..47ae3a5c90d1e8524b914bb3b4b5bbaeb71f3c25 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 ba505737f1b070d21931c7e467b4853de1f119d2..5d92c158df44ee17d9e473cc222e4bae76597b67 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 b334e21ea03127a749ff1bf2455f69627f832922..6df16351f2c28f96f807bb197f9059b51e19f703 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,90 +344,93 @@ 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 { // 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`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn remove_expired_approval() -> 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`) + /// 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 { // Proof Size summary in bytes: - // Measured: `126` + // Measured: `98` // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) + // Minimum execution time: 10_829_000 picoseconds. + Weight::from_parts(11_113_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_im_online.rs b/polkadot/runtime/rococo/src/weights/pallet_im_online.rs deleted file mode 100644 index b866426de52a3abc7608f96bb192a1ae4fbb1d90..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_im_online.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_im_online` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `build-host`, CPU: `AMD EPYC 7601 32-Core Processor` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_im_online -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./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_im_online`. -pub struct WeightInfo(PhantomData); -impl pallet_im_online::WeightInfo for WeightInfo { - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ImOnline Keys (r:1 w:0) - /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) - /// Storage: unknown `0x39e295d143ed41353167609a3d816584` (r:1 w:0) - /// Proof Skipped: unknown `0x39e295d143ed41353167609a3d816584` (r:1 w:0) - /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(1028), added: 3503, mode: MaxEncodedLen) - /// Storage: ImOnline AuthoredBlocks (r:1 w:0) - /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// The range of component `k` is `[1, 1000]`. - fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `394 + k * (32 ±0)` - // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 132_910_000 picoseconds. - Weight::from_parts(149_854_501, 0) - .saturating_add(Weight::from_parts(0, 321487)) - // Standard Error: 3_317 - .saturating_add(Weight::from_parts(61_141, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_indices.rs b/polkadot/runtime/rococo/src/weights/pallet_indices.rs index 99ffd3210ed24f04e170a66c57b01ea9232b0475..434db97d4a79faa0d51dcad13c16d6840f357483 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 e1e360d374a0646b4fed8a29f3509565309d89c0..6ebfcd060b642d03c6eebdf7918d032253041e28 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_multisig.rs b/polkadot/runtime/rococo/src/weights/pallet_multisig.rs index a4f33fe198ca167e9b8112a13b1549ba727da354..f1b81759ece6c4c360a4bfb61afafb76836d11b2 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 35dad482129e6c63e0aca0aceb544c66fba78ee7..38b41f3a8e241185e1ccb40332bab8e96a846d2b 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 e051ebd5bbab84cf98d34853666926a0f281e5c1..7a2b77b84d80cad3067f41a63da845af86e16816 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 d9737a85c05ad2b55759c141539f34fc60d3c808..c92025930950e61c3d4d253b2ae33e153ef70ccb 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 ce9d5fcc0c7131b227e205a470532e8042cc93ae..fa2decb16716656c9329050c6a211b30ccf24769 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 0000000000000000000000000000000000000000..ed79aa2b1f175d65d33efad4901d1800fb5cbc28 --- /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 96f172230e13f5aed92b47338b2387f4db79fa27..6dfcea2b8327a853927c45aeef76036752650718 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 b7cc5df28b91cc2cc36cade14784b41d7d34ff71..c35925198f9d0d3c615416aa8dbb3e8e371eecca 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 e4732a2d17dca5180a8e07d5cddd19acd55f1b76..5f6b41d2b54ea95b398877b0ebcaccfbfce313ac 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_scheduler` //! -//! 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_scheduler // --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,30 +50,30 @@ use core::marker::PhantomData; /// Weight functions for `pallet_scheduler`. pub struct WeightInfo(PhantomData); impl pallet_scheduler::WeightInfo for WeightInfo { - /// Storage: Scheduler IncompleteSince (r:1 w:1) - /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Scheduler::IncompleteSince` (r:1 w:1) + /// Proof: `Scheduler::IncompleteSince` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn service_agendas_base() -> Weight { // Proof Size summary in bytes: - // Measured: `69` + // Measured: `68` // Estimated: `1489` - // Minimum execution time: 4_741_000 picoseconds. - Weight::from_parts(4_939_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)) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 50]`. fn service_agenda_base(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` + // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 4_504_000 picoseconds. - Weight::from_parts(7_569_333, 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_818 - .saturating_add(Weight::from_parts(771_180, 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)) } @@ -78,36 +81,38 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_709_000 picoseconds. - Weight::from_parts(5_929_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) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) - /// 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:1 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// 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 `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `251 + s * (1 ±0)` // Estimated: `3716 + s * (1 ±0)` - // Minimum execution time: 20_710_000 picoseconds. - Weight::from_parts(20_918_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_257, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // 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())) } - /// Storage: Scheduler Lookup (r:0 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn service_task_named() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_262_000 picoseconds. - Weight::from_parts(7_412_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)) } @@ -115,90 +120,171 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_774_000 picoseconds. - Weight::from_parts(5_887_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: 2_777_000 picoseconds. - Weight::from_parts(2_865_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: 2_739_000 picoseconds. - Weight::from_parts(2_827_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) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 49]`. fn schedule(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` + // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 14_788_000 picoseconds. - Weight::from_parts(17_705_748, 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_703 - .saturating_add(Weight::from_parts(760_991, 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 Lookup (r:0 w:1) - /// 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`) + /// 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]`. fn cancel(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` + // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 18_716_000 picoseconds. - Weight::from_parts(18_220_022, 0) + // Minimum execution time: 14_649_000 picoseconds. + Weight::from_parts(14_705_132, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_508 - .saturating_add(Weight::from_parts(1_357_835, 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) - /// 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:1 w:1) + /// 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`) /// The range of component `s` is `[0, 49]`. fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `293 + s * (185 ±0)` + // Measured: `292 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 17_719_000 picoseconds. - Weight::from_parts(21_657_806, 0) + // Minimum execution time: 12_335_000 picoseconds. + Weight::from_parts(16_144_217, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_645 - .saturating_add(Weight::from_parts(794_184, 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)) } - /// Storage: Scheduler Lookup (r:1 w:1) - /// 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::Lookup` (r:1 w:1) + /// 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: `319 + s * (185 ±0)` + // Measured: `318 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 20_225_000 picoseconds. - Weight::from_parts(20_494_405, 0) + // Minimum execution time: 16_906_000 picoseconds. + Weight::from_parts(17_846_662, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_890 - .saturating_add(Weight::from_parts(1_379_025, 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(3)) + } + /// 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 schedule_retry(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `155` + // Estimated: `42428` + // Minimum execution time: 8_988_000 picoseconds. + Weight::from_parts(9_527_838, 0) + .saturating_add(Weight::from_parts(0, 42428)) + // 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`) + fn set_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `8965` + // Estimated: `42428` + // 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)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// 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`) + fn set_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `9643` + // Estimated: `42428` + // 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)) + } + /// 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`) + fn cancel_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `8977` + // Estimated: `42428` + // 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)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// 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`) + fn cancel_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `9655` + // Estimated: `42428` + // 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 694174954fc78b1eeb4d93f78e6b26d5bab22b83..ecc31dc3fa9df6c17a5541fcd5a6d957f6ca2e2d 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 1bb2e227ab7d540ba8cfd9e4609e957bf025d57c..7d79621b9e65f959221fe382254db93db6237ff7 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 0000000000000000000000000000000000000000..44dfab289fb2dd22fd6bc81cfaae81769d14313f --- /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 144e9d5b872382b7381e2d77c6fb08a8fbece4fa..acf09989afca1fe41fb5648d3b500116b1acdeed 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,176 +50,168 @@ 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)) } - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, 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::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn propose_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `143` + // Measured: `243` // Estimated: `1489` - // Minimum execution time: 354_000_000 picoseconds. - Weight::from_parts(376_000_000, 0) + // Minimum execution time: 20_714_000 picoseconds. + Weight::from_parts(21_137_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Treasury Proposals (r:1 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Treasury::Proposals` (r:1 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn reject_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `301` + // Measured: `401` // Estimated: `3593` - // Minimum execution time: 547_000_000 picoseconds. - Weight::from_parts(550_000_000, 0) + // Minimum execution time: 31_665_000 picoseconds. + Weight::from_parts(32_442_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Treasury Proposals (r:1 w:0) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, 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:1 w:0) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `470 + p * (8 ±0)` + // Measured: `570 + p * (8 ±0)` // Estimated: `3573` - // Minimum execution time: 104_000_000 picoseconds. - Weight::from_parts(121_184_402, 0) + // Minimum execution time: 6_988_000 picoseconds. + Weight::from_parts(11_464_972, 0) .saturating_add(Weight::from_parts(0, 3573)) - // Standard Error: 42_854 - .saturating_add(Weight::from_parts(153_112, 0).saturating_mul(p.into())) + // Standard Error: 1_722 + .saturating_add(Weight::from_parts(84_536, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// 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: `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 f50f60eaad7fec2c09e9d5620db0551f1c7b1364..6f2a374247f8f28d1deb281b8256393a74294fad 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 2596207d5837df6776177b71480c57af61ac02ce..c21ab0877742019b238adf33bec4a378d4cb82ea 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 7c307deec4c6f8480019b5559117cfc47ee84b40..ec67268d1449952be992bd321154dd676c2a8a4d 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 177407ef7088b5c9bdcc460f36cb7d6485743a71..d5cf33515e6be23e7cde0d892b97c8c1d07d8c2f 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_xcm` //! -//! 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_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/ @@ -48,10 +50,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets() -> Weight { - // TODO: run benchmarks - Weight::zero() - } /// 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) @@ -62,36 +60,80 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3607` - // Minimum execution time: 27_328_000 picoseconds. - Weight::from_parts(27_976_000, 0) - .saturating_add(Weight::from_parts(0, 3607)) + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 25_521_000 picoseconds. + Weight::from_parts(25_922_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(4)) .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: `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 teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 16_280_000 picoseconds. - Weight::from_parts(16_904_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 112_185_000 picoseconds. + Weight::from_parts(115_991_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .saturating_add(T::DbWeight::get().reads(5)) + .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 reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 15_869_000 picoseconds. - Weight::from_parts(16_264_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `232` + // Estimated: `3697` + // Minimum execution time: 108_693_000 picoseconds. + Weight::from_parts(111_853_000, 0) + .saturating_add(Weight::from_parts(0, 3697)) + .saturating_add(T::DbWeight::get().reads(5)) + .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 transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 113_040_000 picoseconds. + Weight::from_parts(115_635_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_923_000 picoseconds. - Weight::from_parts(7_432_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) @@ -100,8 +142,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_333_000 picoseconds. - Weight::from_parts(7_566_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)) } @@ -109,8 +151,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_219_000 picoseconds. - Weight::from_parts(2_375_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) @@ -129,11 +171,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3607` - // Minimum execution time: 30_650_000 picoseconds. - Weight::from_parts(31_683_000, 0) - .saturating_add(Weight::from_parts(0, 3607)) + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 31_238_000 picoseconds. + Weight::from_parts(31_955_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -151,11 +193,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `322` - // Estimated: `3787` - // Minimum execution time: 37_666_000 picoseconds. - Weight::from_parts(38_920_000, 0) - .saturating_add(Weight::from_parts(0, 3787)) + // Measured: `360` + // Estimated: `3825` + // Minimum execution time: 37_237_000 picoseconds. + Weight::from_parts(38_569_000, 0) + .saturating_add(Weight::from_parts(0, 3825)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -165,45 +207,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_244_000 picoseconds. - Weight::from_parts(2_425_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)) } - /// Storage: `XcmPallet::SupportedVersion` (r:4 w:2) + /// Storage: `XcmPallet::SupportedVersion` (r:5 w:2) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `26` - // Estimated: `10916` - // Minimum execution time: 14_710_000 picoseconds. - Weight::from_parts(15_156_000, 0) - .saturating_add(Weight::from_parts(0, 10916)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `22` + // Estimated: `13387` + // Minimum execution time: 16_048_000 picoseconds. + Weight::from_parts(16_617_000, 0) + .saturating_add(Weight::from_parts(0, 13387)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifiers` (r:4 w:2) + /// Storage: `XcmPallet::VersionNotifiers` (r:5 w:2) /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `30` - // Estimated: `10920` - // Minimum execution time: 14_630_000 picoseconds. - Weight::from_parts(15_290_000, 0) - .saturating_add(Weight::from_parts(0, 10920)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `26` + // Estimated: `13391` + // Minimum execution time: 16_073_000 picoseconds. + Weight::from_parts(16_672_000, 0) + .saturating_add(Weight::from_parts(0, 13391)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `40` - // Estimated: `13405` - // Minimum execution time: 16_686_000 picoseconds. - Weight::from_parts(17_332_000, 0) - .saturating_add(Weight::from_parts(0, 13405)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15880` + // Minimum execution time: 18_422_000 picoseconds. + Weight::from_parts(18_900_000, 0) + .saturating_add(Weight::from_parts(0, 15880)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `XcmPallet::VersionNotifyTargets` (r:2 w:1) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -217,38 +259,38 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `178` - // Estimated: `6118` - // Minimum execution time: 30_180_000 picoseconds. - Weight::from_parts(31_351_000, 0) - .saturating_add(Weight::from_parts(0, 6118)) + // Measured: `216` + // Estimated: `6156` + // Minimum execution time: 30_373_000 picoseconds. + Weight::from_parts(30_972_000, 0) + .saturating_add(Weight::from_parts(0, 6156)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:3 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `69` - // Estimated: `8484` - // Minimum execution time: 9_624_000 picoseconds. - Weight::from_parts(10_029_000, 0) - .saturating_add(Weight::from_parts(0, 8484)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `10959` + // Minimum execution time: 11_863_000 picoseconds. + Weight::from_parts(12_270_000, 0) + .saturating_add(Weight::from_parts(0, 10959)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `37` - // Estimated: `10927` - // Minimum execution time: 15_139_000 picoseconds. - Weight::from_parts(15_575_000, 0) - .saturating_add(Weight::from_parts(0, 10927)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `33` + // Estimated: `13398` + // Minimum execution time: 16_733_000 picoseconds. + Weight::from_parts(17_094_000, 0) + .saturating_add(Weight::from_parts(0, 13398)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) /// 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`) @@ -260,12 +302,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `182` - // Estimated: `11072` - // Minimum execution time: 37_871_000 picoseconds. - Weight::from_parts(38_940_000, 0) - .saturating_add(Weight::from_parts(0, 11072)) - .saturating_add(T::DbWeight::get().reads(8)) + // Measured: `216` + // Estimated: `13581` + // Minimum execution time: 39_236_000 picoseconds. + Weight::from_parts(40_587_000, 0) + .saturating_add(Weight::from_parts(0, 13581)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) @@ -276,8 +318,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_732_000 picoseconds. - Weight::from_parts(2_892_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)) @@ -288,10 +330,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 23_813_000 picoseconds. - Weight::from_parts(24_201_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)) } + /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) + /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `23` + // Estimated: `3488` + // Minimum execution time: 34_438_000 picoseconds. + Weight::from_parts(35_514_000, 0) + .saturating_add(Weight::from_parts(0, 3488)) + .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 0000000000000000000000000000000000000000..dc5e5d8ca4b1ca7ba0cceb6fdd8ddedc0d7e3c28 --- /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 0000000000000000000000000000000000000000..b62f36172baf545ac83e55137f11e6bd5e5ad74f --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs @@ -0,0 +1,347 @@ +// 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)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs b/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs index a6beeded428649fdda8530fda4c10492867f11a2..f41a5d4ebf8f080eb7a9a11016296e97e3db3a1a 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -48,7 +50,7 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::assigned_slots`. pub struct WeightInfo(PhantomData); impl runtime_common::assigned_slots::WeightInfo for WeightInfo { - /// 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`) @@ -68,15 +70,15 @@ impl runtime_common::assigned_slots::WeightInfo for Wei /// 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 runtime_common::assigned_slots::WeightInfo for Wei /// 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 runtime_common::assigned_slots::WeightInfo for Wei /// 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 runtime_common::assigned_slots::WeightInfo for Wei // 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 runtime_common::assigned_slots::WeightInfo for Wei // 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/runtime_common_auctions.rs b/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs index 3cd7c7a47e90ee1bf6590d0421faf580c1c776f6..2b756802289488173ce7dbf4cc8e15e4a8ae0f9d 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,92 +50,90 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::auctions`. pub struct WeightInfo(PhantomData); impl runtime_common::auctions::WeightInfo for WeightInfo { - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:1) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Auctions::AuctionInfo` (r:1 w:1) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Auctions::AuctionCounter` (r:1 w:1) + /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn new_auction() -> Weight { // 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/runtime_common_claims.rs b/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs index 52e0dd24afa0aa5e4cd75d53f53ca7d032ca9588..de2bb71933b7a4e94f9b0f31eb417f75228c6602 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,120 +50,133 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::claims`. pub struct WeightInfo(PhantomData); impl runtime_common::claims::WeightInfo for WeightInfo { - /// 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() -> Weight { // 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/runtime_common_coretime.rs b/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs new file mode 100644 index 0000000000000000000000000000000000000000..d068f07e7594a80a9b728e0776649e52f88a7bf5 --- /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/runtime_common_crowdloan.rs b/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs index 0e7420cba2e6c981d4f9c0dd9e3c95c9ce26f1c5..8ebab3d551e69e54832f4da00c302a616cd96354 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,172 +50,168 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::crowdloan`. pub struct WeightInfo(PhantomData); impl runtime_common::crowdloan::WeightInfo for WeightInfo { - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (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: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NextFundIndex (r:1 w:1) - /// Proof Skipped: Crowdloan NextFundIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`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:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::NextFundIndex` (r:1 w:1) + /// Proof: `Crowdloan::NextFundIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn create() -> Weight { // 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/runtime_common_identity_migrator.rs b/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs index cec357453b67be400c0191ac7d5c12e6961a4bee..9b0cb98e6c01f8cb560ea8a99cd42cce9a04fb24 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs +++ b/polkadot/runtime/rococo/src/weights/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 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 runtime_common::identity_migrator::WeightInfo for /// 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/runtime_common_paras_registrar.rs b/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs index 0a56562a1a95f24e9efddc6c26e16c4feeaf37c2..e066106e13450c78159994a808254b44cac43eff 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,175 +50,169 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::paras_registrar`. pub struct WeightInfo(PhantomData); impl runtime_common::paras_registrar::WeightInfo for WeightInfo { - /// Storage: Registrar NextFreeParaId (r:1 w:1) - /// Proof Skipped: Registrar NextFreeParaId (max_values: Some(1), 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: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: `Registrar::NextFreeParaId` (r:1 w:1) + /// Proof: `Registrar::NextFreeParaId` (`max_values`: Some(1), `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:0) + /// Proof: `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/runtime_common_slots.rs b/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs index 23ab1ed3ee0efff9e95fd3526d022c9becad7b93..dd10dbbf1f112d51f0d1270663299baab7af2f59 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,86 +50,82 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::slots`. pub struct WeightInfo(PhantomData); impl runtime_common::slots::WeightInfo for WeightInfo { - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (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: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`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`) 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/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs index ac0f05301b486dbdbb8c0ca004e195ab47171ff3..653e1009f31c3285b7de50fe9b7071d0e4050394 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs @@ -16,26 +16,28 @@ //! Autogenerated weights for `runtime_parachains::assigner_on_demand` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-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-fljshgub-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=runtime_parachains::assigner_on_demand // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=runtime_parachains::assigner_on_demand -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,13 +59,13 @@ impl runtime_parachains::assigner_on_demand::WeightInfo /// The range of component `s` is `[1, 9999]`. fn place_order_keep_alive(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `297 + s * (4 ±0)` - // Estimated: `3762 + s * (4 ±0)` - // Minimum execution time: 33_522_000 picoseconds. - Weight::from_parts(35_436_835, 0) - .saturating_add(Weight::from_parts(0, 3762)) - // Standard Error: 129 - .saturating_add(Weight::from_parts(14_041, 0).saturating_mul(s.into())) + // Measured: `363 + s * (4 ±0)` + // Estimated: `3828 + s * (4 ±0)` + // Minimum execution time: 25_298_000 picoseconds. + Weight::from_parts(21_486_098, 0) + .saturating_add(Weight::from_parts(0, 3828)) + // Standard Error: 136 + .saturating_add(Weight::from_parts(13_943, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -77,13 +79,13 @@ impl runtime_parachains::assigner_on_demand::WeightInfo /// The range of component `s` is `[1, 9999]`. fn place_order_allow_death(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `297 + s * (4 ±0)` - // Estimated: `3762 + s * (4 ±0)` - // Minimum execution time: 33_488_000 picoseconds. - Weight::from_parts(34_848_934, 0) - .saturating_add(Weight::from_parts(0, 3762)) - // Standard Error: 143 - .saturating_add(Weight::from_parts(14_215, 0).saturating_mul(s.into())) + // Measured: `363 + s * (4 ±0)` + // Estimated: `3828 + s * (4 ±0)` + // Minimum execution time: 25_421_000 picoseconds. + Weight::from_parts(21_828_043, 0) + .saturating_add(Weight::from_parts(0, 3828)) + // Standard Error: 133 + .saturating_add(Weight::from_parts(13_831, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs index 34541b83597e6284a401a171e703b200366114a0..caad090ae15bf7d7d79a696d6a178cffeeca1507 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs @@ -16,26 +16,28 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, 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=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 runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_793_000 picoseconds. - Weight::from_parts(8_192_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 runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_819_000 picoseconds. - Weight::from_parts(8_004_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 runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_760_000 picoseconds. - Weight::from_parts(8_174_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 runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_814_000 picoseconds. - Weight::from_parts(8_098_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 runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 10_028_000 picoseconds. - Weight::from_parts(10_386_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 runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_867_000 picoseconds. - Weight::from_parts(8_191_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,24 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 10_158_000 picoseconds. - Weight::from_parts(10_430_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)) + } + /// 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 set_config_with_scheduler_params() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // 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/runtime_parachains_disputes.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs index 63a8c3addc7da4296041627ee8492945945bce7f..cf1aa36e10e704ab0074730896f6b5d2f9a4fedf 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,14 +50,14 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::disputes`. pub struct WeightInfo(PhantomData); impl runtime_parachains::disputes::WeightInfo for WeightInfo { - /// Storage: ParasDisputes Frozen (r:0 w:1) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ParasDisputes::Frozen` (r:0 w:1) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn force_unfreeze() -> Weight { // 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/runtime_parachains_hrmp.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs index 417820e6627f6e39c4107df722f4b83f9cca6a4b..a3b912491e5ec56c340b3dfd3b46e95f39f57e3c 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::hrmp` //! -//! 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::hrmp // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_hrmp.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,105 +50,97 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::hrmp`. pub struct WeightInfo(PhantomData); impl runtime_parachains::hrmp::WeightInfo for WeightInfo { - /// Storage: Paras ParaLifecycles (r:2 w:0) - /// 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: Hrmp HrmpOpenChannelRequests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannels (r:1 w:0) - /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpEgressChannelsIndex (r:1 w:0) - /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestCount (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (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: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:1 w:0) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:1 w:0) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `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 hrmp_init_open_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `704` - // Estimated: `6644` - // Minimum execution time: 41_564_000 picoseconds. - Weight::from_parts(42_048_000, 0) - .saturating_add(Weight::from_parts(0, 6644)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `488` + // Estimated: `3953` + // Minimum execution time: 34_911_000 picoseconds. + Weight::from_parts(35_762_000, 0) + .saturating_add(Weight::from_parts(0, 3953)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Hrmp HrmpOpenChannelRequests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequests (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 ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpIngressChannelsIndex (r:1 w:0) - /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:1 w:1) - /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, 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: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:1 w:0) + /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:1 w:1) + /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`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 hrmp_accept_open_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `936` - // Estimated: `4401` - // Minimum execution time: 43_570_000 picoseconds. - Weight::from_parts(44_089_000, 0) - .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `478` + // Estimated: `3943` + // Minimum execution time: 31_483_000 picoseconds. + Weight::from_parts(32_230_000, 0) + .saturating_add(Weight::from_parts(0, 3943)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Hrmp HrmpChannels (r:1 w:0) - /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpCloseChannelRequests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpCloseChannelRequests (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpCloseChannelRequestsList (r:1 w:1) - /// Proof Skipped: Hrmp HrmpCloseChannelRequestsList (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 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: `Hrmp::HrmpChannels` (r:1 w:0) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpCloseChannelRequests` (r:1 w:1) + /// Proof: `Hrmp::HrmpCloseChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpCloseChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpCloseChannelRequestsList` (`max_values`: Some(1), `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 hrmp_close_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `807` - // Estimated: `4272` - // Minimum execution time: 36_594_000 picoseconds. - Weight::from_parts(37_090_000, 0) - .saturating_add(Weight::from_parts(0, 4272)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `591` + // Estimated: `4056` + // Minimum execution time: 32_153_000 picoseconds. + Weight::from_parts(32_982_000, 0) + .saturating_add(Weight::from_parts(0, 4056)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Hrmp HrmpIngressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpEgressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannels (r:254 w:254) - /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:0 w:1) - /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelContents (r:0 w:254) - /// Proof Skipped: Hrmp HrmpChannelContents (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestCount (r:0 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:128 w:128) + /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:128 w:128) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:254 w:254) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:0 w:1) + /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelContents` (r:0 w:254) + /// Proof: `Hrmp::HrmpChannelContents` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:0 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 127]`. /// The range of component `e` is `[0, 127]`. fn force_clean_hrmp(i: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `264 + e * (100 ±0) + i * (100 ±0)` - // Estimated: `3726 + e * (2575 ±0) + i * (2575 ±0)` - // Minimum execution time: 1_085_140_000 picoseconds. - Weight::from_parts(1_100_901_000, 0) - .saturating_add(Weight::from_parts(0, 3726)) - // Standard Error: 98_982 - .saturating_add(Weight::from_parts(3_229_112, 0).saturating_mul(i.into())) - // Standard Error: 98_982 - .saturating_add(Weight::from_parts(3_210_944, 0).saturating_mul(e.into())) + // Measured: `297 + e * (100 ±0) + i * (100 ±0)` + // Estimated: `3759 + e * (2575 ±0) + i * (2575 ±0)` + // Minimum execution time: 1_240_769_000 picoseconds. + Weight::from_parts(1_249_285_000, 0) + .saturating_add(Weight::from_parts(0, 3759)) + // Standard Error: 112_346 + .saturating_add(Weight::from_parts(3_449_114, 0).saturating_mul(i.into())) + // Standard Error: 112_346 + .saturating_add(Weight::from_parts(3_569_184, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(e.into()))) @@ -155,139 +150,139 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf .saturating_add(Weight::from_parts(0, 2575).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 2575).saturating_mul(i.into())) } - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequests (r:128 w:128) - /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:256 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpIngressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpEgressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestCount (r:128 w:128) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:128 w:128) - /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannels (r:0 w:128) - /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) + /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:128 w:128) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:256 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:128 w:128) + /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:128 w:128) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:128 w:128) + /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:128 w:128) + /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:0 w:128) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 128]`. fn force_process_hrmp_open(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `779 + c * (136 ±0)` - // Estimated: `2234 + c * (5086 ±0)` - // Minimum execution time: 10_497_000 picoseconds. - Weight::from_parts(6_987_455, 0) - .saturating_add(Weight::from_parts(0, 2234)) - // Standard Error: 18_540 - .saturating_add(Weight::from_parts(18_788_534, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `525 + c * (136 ±0)` + // Estimated: `1980 + c * (5086 ±0)` + // Minimum execution time: 6_026_000 picoseconds. + Weight::from_parts(6_257_000, 0) + .saturating_add(Weight::from_parts(0, 1980)) + // Standard Error: 9_732 + .saturating_add(Weight::from_parts(21_049_890, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 5086).saturating_mul(c.into())) } - /// Storage: Hrmp HrmpCloseChannelRequestsList (r:1 w:1) - /// Proof Skipped: Hrmp HrmpCloseChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannels (r:128 w:128) - /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpEgressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpIngressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpCloseChannelRequests (r:0 w:128) - /// Proof Skipped: Hrmp HrmpCloseChannelRequests (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelContents (r:0 w:128) - /// Proof Skipped: Hrmp HrmpChannelContents (max_values: None, max_size: None, mode: Measured) + /// Storage: `Hrmp::HrmpCloseChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpCloseChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:128 w:128) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:128 w:128) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:128 w:128) + /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpCloseChannelRequests` (r:0 w:128) + /// Proof: `Hrmp::HrmpCloseChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelContents` (r:0 w:128) + /// Proof: `Hrmp::HrmpChannelContents` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 128]`. fn force_process_hrmp_close(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `335 + c * (124 ±0)` - // Estimated: `1795 + c * (2600 ±0)` - // Minimum execution time: 6_575_000 picoseconds. - Weight::from_parts(1_228_642, 0) - .saturating_add(Weight::from_parts(0, 1795)) - // Standard Error: 14_826 - .saturating_add(Weight::from_parts(11_604_038, 0).saturating_mul(c.into())) + // Measured: `368 + c * (124 ±0)` + // Estimated: `1828 + c * (2600 ±0)` + // Minimum execution time: 4_991_000 picoseconds. + Weight::from_parts(984_758, 0) + .saturating_add(Weight::from_parts(0, 1828)) + // Standard Error: 11_918 + .saturating_add(Weight::from_parts(13_018_813, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2600).saturating_mul(c.into())) } - /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestCount (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 128]`. fn hrmp_cancel_open_request(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1026 + c * (13 ±0)` - // Estimated: `4295 + c * (15 ±0)` - // Minimum execution time: 22_301_000 picoseconds. - Weight::from_parts(26_131_473, 0) - .saturating_add(Weight::from_parts(0, 4295)) - // Standard Error: 830 - .saturating_add(Weight::from_parts(49_448, 0).saturating_mul(c.into())) + // Measured: `1059 + c * (13 ±0)` + // Estimated: `4328 + c * (15 ±0)` + // Minimum execution time: 17_299_000 picoseconds. + Weight::from_parts(27_621_478, 0) + .saturating_add(Weight::from_parts(0, 4328)) + // Standard Error: 2_527 + .saturating_add(Weight::from_parts(121_149, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(c.into())) } - /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequests (r:128 w:128) - /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:128 w:128) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 128]`. fn clean_open_channel_requests(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `243 + c * (63 ±0)` - // Estimated: `1722 + c * (2538 ±0)` - // Minimum execution time: 5_234_000 picoseconds. - Weight::from_parts(7_350_270, 0) - .saturating_add(Weight::from_parts(0, 1722)) - // Standard Error: 3_105 - .saturating_add(Weight::from_parts(2_981_935, 0).saturating_mul(c.into())) + // Measured: `276 + c * (63 ±0)` + // Estimated: `1755 + c * (2538 ±0)` + // Minimum execution time: 3_764_000 picoseconds. + Weight::from_parts(5_935_301, 0) + .saturating_add(Weight::from_parts(0, 1755)) + // Standard Error: 3_761 + .saturating_add(Weight::from_parts(3_290_277, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2538).saturating_mul(c.into())) } - /// Storage: Paras ParaLifecycles (r:2 w:0) - /// 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: Hrmp HrmpOpenChannelRequests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannels (r:1 w:0) - /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpEgressChannelsIndex (r:1 w:0) - /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestCount (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:2 w:2) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:2 w:2) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpIngressChannelsIndex (r:1 w:0) - /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:1 w:1) - /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) - fn force_open_hrmp_channel(_c: u32, ) -> Weight { + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:1 w:0) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:1 w:0) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:2 w:2) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:2 w:2) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:1 w:0) + /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:1 w:1) + /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 1]`. + fn force_open_hrmp_channel(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `704` - // Estimated: `6644` - // Minimum execution time: 55_611_000 picoseconds. - Weight::from_parts(56_488_000, 0) - .saturating_add(Weight::from_parts(0, 6644)) - .saturating_add(T::DbWeight::get().reads(14)) + // Measured: `488 + c * (235 ±0)` + // Estimated: `6428 + c * (235 ±0)` + // Minimum execution time: 49_506_000 picoseconds. + Weight::from_parts(51_253_075, 0) + .saturating_add(Weight::from_parts(0, 6428)) + // Standard Error: 144_082 + .saturating_add(Weight::from_parts(12_862_224, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) + .saturating_add(Weight::from_parts(0, 235).saturating_mul(c.into())) } /// Storage: `Paras::ParaLifecycles` (r:1 w:0) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -311,11 +306,11 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) fn establish_system_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `417` - // Estimated: `6357` - // Minimum execution time: 629_674_000 picoseconds. - Weight::from_parts(640_174_000, 0) - .saturating_add(Weight::from_parts(0, 6357)) + // Measured: `488` + // Estimated: `6428` + // Minimum execution time: 50_016_000 picoseconds. + Weight::from_parts(50_933_000, 0) + .saturating_add(Weight::from_parts(0, 6428)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -323,11 +318,11 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) fn poke_channel_deposits() -> Weight { // Proof Size summary in bytes: - // Measured: `263` - // Estimated: `3728` - // Minimum execution time: 173_371_000 picoseconds. - Weight::from_parts(175_860_000, 0) - .saturating_add(Weight::from_parts(0, 3728)) + // Measured: `296` + // Estimated: `3761` + // Minimum execution time: 12_280_000 picoseconds. + Weight::from_parts(12_863_000, 0) + .saturating_add(Weight::from_parts(0, 3761)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs index a121ad774cefecf91e57838e03107fde22674f94..b9ec7565bd555d1b5b06fd9db01e7ca2ee765187 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::inclusion` //! -//! 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::inclusion // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_inclusion.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,27 +50,25 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::inclusion`. pub struct WeightInfo(PhantomData); impl runtime_parachains::inclusion::WeightInfo for WeightInfo { - /// 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:999) - /// 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:999) + /// 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) /// The range of component `i` is `[1, 1000]`. fn receive_upward_messages(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33280` + // Measured: `32993` // Estimated: `36283` - // Minimum execution time: 71_094_000 picoseconds. - Weight::from_parts(71_436_000, 0) + // Minimum execution time: 72_675_000 picoseconds. + Weight::from_parts(73_290_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - // Standard Error: 22_149 - .saturating_add(Weight::from_parts(51_495_472, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Standard Error: 16_067 + .saturating_add(Weight::from_parts(57_735_739, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs index 5c627507dfb682a603152fee2155b620773dcd49..e8c554610c999dd93bbc6cb10025933438adc968 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,18 +50,18 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::initializer`. pub struct WeightInfo(PhantomData); impl runtime_parachains::initializer::WeightInfo for WeightInfo { - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (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`) /// The range of component `d` is `[0, 65536]`. fn force_approve(d: u32, ) -> Weight { // 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/runtime_parachains_paras.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs index dfd95006dc7d0a6cedeeab9908d99a2c1c7e561a..af26bfc9ae9b25f5a3a50938ceb1b978646c65eb 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs +++ b/polkadot/runtime/rococo/src/weights/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)] @@ -47,247 +50,248 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::paras`. pub struct WeightInfo(PhantomData); impl runtime_parachains::paras::WeightInfo for WeightInfo { - /// Storage: Paras CurrentCodeHash (r:1 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, 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 PastCodeMeta (r:1 w:1) - /// Proof Skipped: Paras PastCodeMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PastCodePruning (r:1 w:1) - /// Proof Skipped: Paras PastCodePruning (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PastCodeHash (r:0 w:1) - /// Proof Skipped: Paras PastCodeHash (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::CurrentCodeHash` (r:1 w:1) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `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::PastCodeMeta` (r:1 w:1) + /// Proof: `Paras::PastCodeMeta` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PastCodePruning` (r:1 w:1) + /// Proof: `Paras::PastCodePruning` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PastCodeHash` (r:0 w:1) + /// Proof: `Paras::PastCodeHash` (`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`) /// The range of component `c` is `[1, 3145728]`. fn force_set_current_code(c: u32, ) -> Weight { // 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/runtime_parachains_paras_inherent.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs index a102d1903b2f2b4a757edf3bb96809c982f31383..374927f8470de51d6c8c9ab4a0818f03fe849e97 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs @@ -13,161 +13,334 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Autogenerated weights for `runtime_parachains::paras_inherent` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 128 +//! 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/release/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::paras_inherent // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs -// --header=./file_header.txt +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `runtime_parachains::paras_inherent`. pub struct WeightInfo(PhantomData); impl runtime_parachains::paras_inherent::WeightInfo for WeightInfo { - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParaSessionInfo Sessions (r:1 w:0) - // Storage: ParasDisputes Disputes (r:1 w:1) - // Storage: ParasDisputes Included (r:1 w:1) - // Storage: ParasDisputes SpamSlots (r:1 w:1) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// 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: `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: `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) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaSessionInfo::Sessions` (r:1 w:0) + /// Proof: `ParaSessionInfo::Sessions` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:1) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::BackersOnDisputes` (r:1 w:1) + /// Proof: `ParasDisputes::BackersOnDisputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:1 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) + /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) + /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`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::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`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: `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: `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: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`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 `v` is `[10, 200]`. fn enter_variable_disputes(v: u32, ) -> Weight { - Weight::from_parts(352_590_000 as u64, 0) - // Standard Error: 13_000 - .saturating_add(Weight::from_parts(49_254_000 as u64, 0).saturating_mul(v as u64)) - .saturating_add(T::DbWeight::get().reads(24 as u64)) - .saturating_add(T::DbWeight::get().writes(16 as u64)) + // Proof Size summary in bytes: + // Measured: `67819` + // Estimated: `73759 + v * (23 ±0)` + // Minimum execution time: 874_229_000 picoseconds. + Weight::from_parts(486_359_072, 0) + .saturating_add(Weight::from_parts(0, 73759)) + // Standard Error: 19_197 + .saturating_add(Weight::from_parts(41_842_161, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(26)) + .saturating_add(T::DbWeight::get().writes(16)) + .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) } - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParasDisputes Disputes (r:1 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: ParasDisputes Included (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// 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: `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: `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) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) + /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) + /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`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::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`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: `ParasDisputes::Disputes` (r:1 w:0) + /// 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: `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: `ParaInclusion::AvailabilityBitfields` (r:0 w:1) + /// Proof: `ParaInclusion::AvailabilityBitfields` (`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) + /// Proof: `Hrmp::HrmpWatermarks` (`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`) fn enter_bitfields() -> Weight { - Weight::from_parts(299_878_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(21 as u64)) - .saturating_add(T::DbWeight::get().writes(15 as u64)) + // Proof Size summary in bytes: + // Measured: `42791` + // Estimated: `48731` + // Minimum execution time: 428_757_000 picoseconds. + Weight::from_parts(449_681_000, 0) + .saturating_add(Weight::from_parts(0, 48731)) + .saturating_add(T::DbWeight::get().reads(24)) + .saturating_add(T::DbWeight::get().writes(17)) } - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParasDisputes Disputes (r:2 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Paras PastCodeMeta (r:1 w:0) - // Storage: Paras CurrentCodeHash (r:1 w:0) - // Storage: Ump RelayDispatchQueueSize (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: ParasDisputes Included (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) - fn enter_backed_candidates_variable(_v: u32) -> Weight { - Weight::from_parts(442_472_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(25 as u64)) - .saturating_add(T::DbWeight::get().writes(14 as u64)) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// 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: `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: `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) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) + /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) + /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`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::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`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: `ParasDisputes::Disputes` (r:1 w:0) + /// 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: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`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: `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: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`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) + /// 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 `v` is `[101, 200]`. + fn enter_backed_candidates_variable(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42863` + // Estimated: `48803` + // Minimum execution time: 1_276_079_000 picoseconds. + Weight::from_parts(1_313_585_212, 0) + .saturating_add(Weight::from_parts(0, 48803)) + // Standard Error: 18_279 + .saturating_add(Weight::from_parts(43_528, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(27)) + .saturating_add(T::DbWeight::get().writes(16)) } - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParasDisputes Disputes (r:2 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Paras PastCodeMeta (r:1 w:0) - // Storage: Paras CurrentCodeHash (r:1 w:0) - // Storage: Ump RelayDispatchQueueSize (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: ParasDisputes Included (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// 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: `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: `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) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) + /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) + /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`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::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`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: `ParasDisputes::Disputes` (r:1 w:0) + /// 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: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`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: `Paras::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`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: `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: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`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) + /// 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`) fn enter_backed_candidate_code_upgrade() -> Weight { - Weight::from_parts(36_903_411_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(25 as u64)) - .saturating_add(T::DbWeight::get().writes(14 as u64)) + // Proof Size summary in bytes: + // Measured: `42876` + // Estimated: `48816` + // Minimum execution time: 34_352_245_000 picoseconds. + Weight::from_parts(34_587_559_000, 0) + .saturating_add(Weight::from_parts(0, 48816)) + .saturating_add(T::DbWeight::get().reads(29)) + .saturating_add(T::DbWeight::get().writes(16)) } } diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 5fddd749dad3859d13cafa93818aef6d03fd9f03..af8981ddcc146573bdf2179c9baae856269e4b93 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -36,17 +36,15 @@ use runtime_common::{ }; use sp_core::ConstU32; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, DescribeBodyTerminal, DescribeFamily, FixedWeightBounds, - FrameTransactionalProcessor, HashedDescription, IsChildSystemParachain, IsConcrete, - MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsChildSystemParachain, + IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -73,8 +71,7 @@ pub type LocationConverter = ( /// point of view of XCM-only concepts like `Location` and `Asset`. /// /// Ours is only aware of the Balances pallet, which is mapped to `RocLocation`. -#[allow(deprecated)] -pub type LocalAssetTransactor = XcmCurrencyAdapter< +pub type LocalAssetTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 9778ff82439494767b83d5acb6f7f9f57ac89619..bdf688646052133124f58f2ece16672c9e1c64fa 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -13,11 +13,11 @@ workspace = true [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false } -serde_derive = { version = "1.0.117", optional = true } +serde = { workspace = true } +serde_derive = { optional = true, workspace = true } smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", path = "../../../substrate/primitives/authority-discovery", default-features = false } @@ -74,7 +74,7 @@ hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } sp-trie = { path = "../../../substrate/primitives/trie" } -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } [build-dependencies] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } @@ -155,6 +155,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-parachain-primitives/runtime-benchmarks", diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index b74def5de8aadd718df48b27aff1a7ca324389c3..a0617b3108f8135bede66a6e082c41095a2e9704 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -238,6 +238,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = frame_support::weights::ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = (); } parameter_types! { @@ -393,7 +394,7 @@ where 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(), @@ -405,16 +406,17 @@ 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))) + Some((call, (address, signature, tx_ext))) } } @@ -442,12 +444,32 @@ parameter_types! { pub Prefix: &'static [u8] = b"Pay KSMs to the Kusama account:"; } +#[cfg(feature = "runtime-benchmarks")] +pub struct ClaimsHelper; + +#[cfg(feature = "runtime-benchmarks")] +use frame_support::dispatch::DispatchInfo; + +#[cfg(feature = "runtime-benchmarks")] +impl claims::BenchmarkHelperTrait for ClaimsHelper { + fn default_call_and_info() -> (RuntimeCall, DispatchInfo) { + use frame_support::dispatch::GetDispatchInfo; + let call = RuntimeCall::Claims(claims::Call::attest { + statement: claims::StatementKind::Regular.to_text().to_vec(), + }); + let info = call.get_dispatch_info(); + (call, info) + } +} + impl claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; type Prefix = Prefix; type MoveClaimOrigin = frame_system::EnsureRoot; type WeightInfo = claims::TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ClaimsHelper; } parameter_types! { @@ -728,8 +750,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, @@ -741,7 +763,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< @@ -752,7 +774,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; @@ -767,7 +789,7 @@ sp_api::impl_runtime_apis! { Executive::execute_block(block); } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index a81d35f4d788f1628cf20cf5cbd0e366828101ff..a48bca17e9ff988da3d0ca4601003f3f6d96a71d 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -16,14 +16,16 @@ use frame_support::{ parameter_types, - traits::{Everything, Nothing}, + traits::{Everything, Get, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; +use polkadot_runtime_parachains::FeeTracker; +use runtime_common::xcm_sender::{ChildParachainRouter, PriceForMessageDelivery}; use xcm::latest::prelude::*; use xcm_builder::{ AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, - SignedAccountId32AsNative, SignedToAccountId32, + SignedAccountId32AsNative, SignedToAccountId32, WithUniqueTopic, }; use xcm_executor::{ traits::{TransactAsset, WeightTrader}, @@ -36,6 +38,8 @@ parameter_types! { pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 16; pub const UniversalLocation: xcm::latest::InteriorLocation = xcm::latest::Junctions::Here; + pub TokenLocation: Location = Here.into_location(); + pub FeeAssetId: AssetId = AssetId(TokenLocation::get()); } /// Type to convert an `Origin` type value into a `Location` value which represents an interior @@ -45,17 +49,43 @@ pub type LocalOriginToLocation = ( SignedToAccountId32, ); -pub struct DoNothingRouter; -impl SendXcm for DoNothingRouter { - type Ticket = (); - fn validate(_dest: &mut Option, _msg: &mut Option>) -> SendResult<()> { - Ok(((), Assets::new())) - } - fn deliver(_: ()) -> Result { - Ok([0; 32]) +/// Implementation of [`PriceForMessageDelivery`], returning a different price +/// based on whether a message contains a reanchored asset or not. +/// This implementation ensures that messages with non-reanchored assets return higher +/// prices than messages with reanchored assets. +/// Useful for `deposit_reserve_asset_works_for_any_xcm_sender` integration test. +pub struct TestDeliveryPrice(sp_std::marker::PhantomData<(A, F)>); +impl, F: FeeTracker> PriceForMessageDelivery for TestDeliveryPrice { + type Id = F::Id; + + fn price_for_delivery(_: Self::Id, msg: &Xcm<()>) -> Assets { + let base_fee: super::Balance = 1_000_000; + + let parents = msg.iter().find_map(|xcm| match xcm { + ReserveAssetDeposited(assets) => { + let AssetId(location) = &assets.inner().first().unwrap().id; + Some(location.parents) + }, + _ => None, + }); + + // If no asset is found, price defaults to `base_fee`. + let amount = base_fee + .saturating_add(base_fee.saturating_mul(parents.unwrap_or(0) as super::Balance)); + + (A::get(), amount).into() } } +pub type PriceForChildParachainDelivery = TestDeliveryPrice; + +/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our +/// individual routers. +pub type XcmRouter = WithUniqueTopic< + // Only one router so far - use DMP to communicate with child parachains. + ChildParachainRouter, +>; + pub type Barrier = AllowUnpaidExecutionFrom; pub struct DummyAssetTransactor; @@ -99,7 +129,7 @@ type OriginConverter = ( pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = super::RuntimeCall; - type XcmSender = DoNothingRouter; + type XcmSender = XcmRouter; type AssetTransactor = DummyAssetTransactor; type OriginConverter = OriginConverter; type IsReserve = (); @@ -133,7 +163,7 @@ impl pallet_xcm::Config for crate::Runtime { type UniversalLocation = UniversalLocation; type SendXcmOrigin = EnsureXcmOrigin; type Weigher = FixedWeightBounds; - type XcmRouter = DoNothingRouter; + type XcmRouter = XcmRouter; type XcmExecuteFilter = Everything; type XcmExecutor = xcm_executor::XcmExecutor; type XcmTeleportFilter = Everything; diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 0ea2436b6811eb74a4e402eb49c38b176592a869..6899edeeaeb8041f9eeb2cd3391efe89f3e15ed4 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -14,10 +14,10 @@ workspace = true bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -serde = { version = "1.0.195", default-features = false } -serde_derive = { version = "1.0.117", optional = true } +serde = { workspace = true } +serde_derive = { optional = true, workspace = true } smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", path = "../../../substrate/primitives/authority-discovery", default-features = false } @@ -119,7 +119,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", hex-literal = "0.4.1" tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } remote-externalities = { package = "frame-remote-externalities", path = "../../../substrate/utils/frame/remote-externalities" } tokio = { version = "1.24.2", features = ["macros"] } sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } @@ -270,6 +270,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", diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index 848cccd559dc3e50cbd2a50c4df6a643910fe35c..c98f4b114fd88241dea1e2e5ffcf694848448007 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -107,6 +107,8 @@ pub mod system_parachain { pub const COLLECTIVES_ID: u32 = 1001; /// BridgeHub parachain ID. pub const BRIDGE_HUB_ID: u32 = 1002; + /// Encointer parachain ID. + pub const ENCOINTER_ID: u32 = 1003; /// People Chain parachain ID. pub const PEOPLE_ID: u32 = 1004; /// Brokerage parachain ID. @@ -128,6 +130,8 @@ pub mod xcm { const ROOT_INDEX: u32 = 0; // The bodies corresponding to the Polkadot OpenGov Origins. pub const FELLOWSHIP_ADMIN_INDEX: u32 = 1; + #[deprecated = "Will be removed after August 2024; Use `xcm::latest::BodyId::Treasury` \ + instead"] pub const TREASURER_INDEX: u32 = 2; } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 7305684a0d98558e8ddad7c403abd9449d827d6a..45bbd0260e5e6a0f826b030b0452e81c96fc61cb 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -61,12 +61,15 @@ use runtime_common::{ impls::{ LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter, }, - paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BalanceToU256, BlockHashCount, - BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance, + paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, + traits::Leaser, + BalanceToU256, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, + U256ToBalance, }; use runtime_parachains::{ - assigner_parachains as parachains_assigner_parachains, - configuration as parachains_configuration, disputes as parachains_disputes, + assigner_coretime as parachains_assigner_coretime, + assigner_on_demand as parachains_assigner_on_demand, configuration as parachains_configuration, + coretime, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, inclusion::{AggregateMessageOrigin, UmpQueueId}, @@ -147,7 +150,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 1_006_001, + spec_version: 1_008_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 24, @@ -197,6 +200,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 MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -382,6 +386,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! { @@ -817,7 +822,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(), @@ -829,16 +834,17 @@ 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 = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) + Some((call, (address, signature, tx_ext))) } } @@ -1143,7 +1149,7 @@ impl parachains_paras::Config for Runtime { type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; type OnNewHead = (); - type AssignCoretime = (); + type AssignCoretime = CoretimeAssignmentProvider; } parameter_types! { @@ -1212,20 +1218,40 @@ impl parachains_paras_inherent::Config for Runtime { impl parachains_scheduler::Config for Runtime { // If you change this, make sure the `Assignment` type of the new provider is binary compatible, // otherwise provide a migration. - type AssignmentProvider = ParachainsAssignmentProvider; + type AssignmentProvider = CoretimeAssignmentProvider; } parameter_types! { pub const BrokerId: u32 = BROKER_ID; } -impl parachains_assigner_parachains::Config for Runtime {} +impl coretime::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type BrokerId = BrokerId; + type WeightInfo = weights::runtime_parachains_coretime::WeightInfo; + type SendXcm = crate::xcm_config::XcmRouter; +} + +parameter_types! { + pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); +} + +impl parachains_assigner_on_demand::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type TrafficDefaultValue = OnDemandTrafficDefaultValue; + type WeightInfo = weights::runtime_parachains_assigner_on_demand::WeightInfo; +} + +impl parachains_assigner_coretime::Config for Runtime {} impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; type ForceOrigin = EnsureRoot; type WeightInfo = weights::runtime_parachains_initializer::WeightInfo; - type CoretimeOnNewSession = (); + type CoretimeOnNewSession = Coretime; } impl paras_sudo_wrapper::Config for Runtime {} @@ -1479,7 +1505,8 @@ construct_runtime! { ParaSessionInfo: parachains_session_info = 52, ParasDisputes: parachains_disputes = 53, ParasSlashing: parachains_slashing = 54, - ParachainsAssignmentProvider: parachains_assigner_parachains = 55, + OnDemandAssignmentProvider: parachains_assigner_on_demand = 56, + CoretimeAssignmentProvider: parachains_assigner_coretime = 57, // Parachain Onboarding Pallets. Start indices at 60 to leave room. Registrar: paras_registrar = 60, @@ -1488,6 +1515,7 @@ construct_runtime! { Auctions: auctions = 63, Crowdloan: crowdloan = 64, AssignedSlots: assigned_slots = 65, + Coretime: coretime = 66, // Pallet for sending XCM. XcmPallet: pallet_xcm = 99, @@ -1523,8 +1551,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, @@ -1555,6 +1583,24 @@ pub mod migrations { #[cfg(feature = "try-runtime")] use sp_core::crypto::ByteArray; + pub struct GetLegacyLeaseImpl; + impl coretime::migration::GetLegacyLease for GetLegacyLeaseImpl { + fn get_parachain_lease_in_blocks(para: ParaId) -> Option { + let now = frame_system::Pallet::::block_number(); + let lease = slots::Pallet::::lease(para); + if lease.is_empty() { + return None + } + // Lease not yet started, ignore: + if lease.iter().any(Option::is_none) { + return None + } + let (index, _) = + as Leaser>::lease_period_index(now)?; + Some(index.saturating_add(lease.len() as u32).saturating_mul(LeasePeriod::get())) + } + } + parameter_types! { pub const ImOnlinePalletName: &'static str = "ImOnline"; } @@ -1647,7 +1693,7 @@ pub mod migrations { pallet_referenda::migration::v1::MigrateV0ToV1, pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, - pallet_nomination_pools::migration::versioned::V7ToV8, + pallet_nomination_pools::migration::unversioned::TotalValueLockedSync, UpgradeSessionKeys, frame_support::migrations::RemovePallet< ImOnlinePalletName, @@ -1656,14 +1702,21 @@ pub mod migrations { // Migrate Identity pallet for Usernames pallet_identity::migration::versioned::V0ToV1, parachains_configuration::migration::v11::MigrateToV11, + parachains_configuration::migration::v12::MigrateToV12, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, + // Migrate from legacy lease to coretime. Needs to run after configuration v11 + coretime::migration::MigrateToCoretime< + Runtime, + crate::xcm_config::XcmRouter, + GetLegacyLeaseImpl, + >, ); } /// 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, @@ -1674,7 +1727,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 { @@ -1696,6 +1749,8 @@ mod benches { [runtime_parachains::initializer, Initializer] [runtime_parachains::paras, Paras] [runtime_parachains::paras_inherent, ParaInherent] + [runtime_parachains::assigner_on_demand, OnDemandAssignmentProvider] + [runtime_parachains::coretime, Coretime] // Substrate [pallet_bags_list, VoterList] [pallet_balances, Balances] @@ -1718,7 +1773,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] @@ -1742,7 +1799,7 @@ sp_api::impl_runtime_apis! { Executive::execute_block(block); } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -1794,6 +1851,12 @@ sp_api::impl_runtime_apis! { impl offchain_primitives::OffchainWorkerApi for Runtime { fn offchain_worker(header: &::Header) { + use sp_runtime::{traits::Header, DigestItem}; + + if header.digest().logs().iter().any(|di| di == &DigestItem::RuntimeEnvironmentUpdated) { + pallet_im_online::migration::clear_offchain_storage(Session::validators().len() as u32); + } + Executive::offchain_worker(header) } } @@ -2254,6 +2317,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::; @@ -2282,12 +2346,42 @@ 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 {} impl pallet_offences_benchmarking::Config for Runtime {} impl pallet_election_provider_support_benchmarking::Config for Runtime {} + + use xcm_config::{AssetHub, TokenLocation}; + + parameter_types! { + pub ExistentialDepositAsset: Option = Some(( + TokenLocation::get(), + ExistentialDeposit::get() + ).into()); + pub AssetHubParaId: ParaId = westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(); + pub const RandomParaId: ParaId = ParaId::new(43211234); + } + impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = ( + runtime_common::xcm_sender::ToParachainDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForChildParachainDelivery, + AssetHubParaId, + (), + >, + runtime_common::xcm_sender::ToParachainDeliveryHelper< + xcm_config::XcmConfig, + ExistentialDepositAsset, + xcm_config::PriceForChildParachainDelivery, + RandomParaId, + (), + > + ); + fn reachable_dest() -> Option { Some(crate::xcm_config::AssetHub::get()) } @@ -2295,7 +2389,7 @@ sp_api::impl_runtime_apis! { fn teleportable_asset_and_dest() -> Option<(Asset, Location)> { // Relay/native token can be teleported to/from AH. Some(( - Asset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: AssetId(Here.into()) }, + Asset { fun: Fungible(ExistentialDeposit::get()), id: AssetId(Here.into()) }, crate::xcm_config::AssetHub::get(), )) } @@ -2304,10 +2398,10 @@ sp_api::impl_runtime_apis! { // Relay can reserve transfer native token to some random parachain. Some(( Asset { - fun: Fungible(EXISTENTIAL_DEPOSIT), + fun: Fungible(ExistentialDeposit::get()), id: AssetId(Here.into()) }, - crate::Junction::Parachain(43211234).into(), + crate::Junction::Parachain(RandomParaId::get().into()).into(), )) } @@ -2325,6 +2419,13 @@ sp_api::impl_runtime_apis! { dest ) } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::here()), + fun: Fungible(ExistentialDeposit::get()), + } + } } impl frame_system_benchmarking::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {} @@ -2334,15 +2435,6 @@ sp_api::impl_runtime_apis! { AssetId, Fungibility::*, InteriorLocation, Junction, Junctions::*, Asset, Assets, Location, NetworkId, Response, }; - use xcm_config::{AssetHub, TokenLocation}; - - parameter_types! { - pub ExistentialDepositAsset: Option = Some(( - TokenLocation::get(), - ExistentialDeposit::get() - ).into()); - pub ToParachain: ParaId = westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(); - } impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; @@ -2351,7 +2443,7 @@ sp_api::impl_runtime_apis! { xcm_config::XcmConfig, ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, - ToParachain, + AssetHubParaId, (), >; fn valid_destination() -> Result { 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 0000000000000000000000000000000000000000..e4e1a799ec6e6213e2d7613c6a18a25948298a11 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,116 @@ +// 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 4.0.0-dev +//! DATE: 2023-12-20, 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/release/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: 3_356_000 picoseconds. + Weight::from_parts(7_805_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() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_510_000 picoseconds. + Weight::from_parts(10_009_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: 761_000 picoseconds. + Weight::from_parts(4_308_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_396_000 picoseconds. + Weight::from_parts(7_585_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: 521_000 picoseconds. + Weight::from_parts(4_168_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: 541_000 picoseconds. + Weight::from_parts(4_228_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_807_000 picoseconds. + Weight::from_parts(8_025_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 d8a2ae5d2da6fab158898e6cb6548f5f56aa612c..8aeb42165504998c06ea5e73d4e2edc452d05b45 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; @@ -24,7 +25,6 @@ pub mod pallet_conviction_voting; pub mod pallet_election_provider_multi_phase; pub mod pallet_fast_unstake; pub mod pallet_identity; -pub mod pallet_im_online; pub mod pallet_indices; pub mod pallet_message_queue; pub mod pallet_multisig; @@ -38,6 +38,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_im_online.rs b/polkadot/runtime/westend/src/weights/pallet_im_online.rs deleted file mode 100644 index a83cd43804dfdc1ca8827a1988221dd0c6f4ee4d..0000000000000000000000000000000000000000 --- a/polkadot/runtime/westend/src/weights/pallet_im_online.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_im_online` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-30, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `build-host`, CPU: `AMD EPYC 7601 32-Core Processor` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=westend-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_im_online -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/westend/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_im_online`. -pub struct WeightInfo(PhantomData); -impl pallet_im_online::WeightInfo for WeightInfo { - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ImOnline Keys (r:1 w:0) - /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) - /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(1028), added: 3503, mode: MaxEncodedLen) - /// Storage: ImOnline AuthoredBlocks (r:1 w:0) - /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// The range of component `k` is `[1, 1000]`. - fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `361 + k * (32 ±0)` - // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 122_571_000 picoseconds. - Weight::from_parts(162_954_849, 0) - .saturating_add(Weight::from_parts(0, 321487)) - // Standard Error: 8_676 - .saturating_add(Weight::from_parts(11_122, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) - } -} diff --git a/polkadot/runtime/westend/src/weights/pallet_scheduler.rs b/polkadot/runtime/westend/src/weights/pallet_scheduler.rs index 7291b98093300ef887d422051dcf6be7274c0d12..beef3796dea6e5ab3a47a62238422df652f30797 100644 --- a/polkadot/runtime/westend/src/weights/pallet_scheduler.rs +++ b/polkadot/runtime/westend/src/weights/pallet_scheduler.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_scheduler` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner--ss9ysm1-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-grjcggob-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 +// target/production/polkadot // benchmark // pallet -// --chain=westend-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_scheduler // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/westend/src/weights/ +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_scheduler +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,30 +48,30 @@ use core::marker::PhantomData; /// Weight functions for `pallet_scheduler`. pub struct WeightInfo(PhantomData); impl pallet_scheduler::WeightInfo for WeightInfo { - /// Storage: Scheduler IncompleteSince (r:1 w:1) - /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Scheduler::IncompleteSince` (r:1 w:1) + /// Proof: `Scheduler::IncompleteSince` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn service_agendas_base() -> Weight { // Proof Size summary in bytes: // Measured: `69` // Estimated: `1489` - // Minimum execution time: 3_991_000 picoseconds. - Weight::from_parts(4_160_000, 0) + // Minimum execution time: 3_220_000 picoseconds. + Weight::from_parts(3_512_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .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::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 50]`. fn service_agenda_base(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `116 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 3_647_000 picoseconds. - Weight::from_parts(6_608_270, 0) + // Minimum execution time: 3_565_000 picoseconds. + Weight::from_parts(6_102_216, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_516 - .saturating_add(Weight::from_parts(892_866, 0).saturating_mul(s.into())) + // Standard Error: 1_413 + .saturating_add(Weight::from_parts(339_016, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -81,36 +79,38 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_552_000 picoseconds. - Weight::from_parts(5_836_000, 0) + // Minimum execution time: 2_940_000 picoseconds. + Weight::from_parts(3_070_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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: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 `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `217 + s * (1 ±0)` // Estimated: `3682 + s * (1 ±0)` - // Minimum execution time: 20_583_000 picoseconds. - Weight::from_parts(20_771_000, 0) + // Minimum execution time: 16_602_000 picoseconds. + Weight::from_parts(16_834_000, 0) .saturating_add(Weight::from_parts(0, 3682)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(2_250, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Standard Error: 10 + .saturating_add(Weight::from_parts(1_307, 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())) } - /// Storage: Scheduler Lookup (r:0 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn service_task_named() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_271_000 picoseconds. - Weight::from_parts(7_447_000, 0) + // Minimum execution time: 4_202_000 picoseconds. + Weight::from_parts(4_383_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -118,90 +118,169 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_547_000 picoseconds. - Weight::from_parts(5_776_000, 0) + // Minimum execution time: 2_917_000 picoseconds. + Weight::from_parts(3_043_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: 2_480_000 picoseconds. - Weight::from_parts(2_628_000, 0) + // Minimum execution time: 1_707_000 picoseconds. + Weight::from_parts(1_802_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: 2_479_000 picoseconds. - Weight::from_parts(2_626_000, 0) + // Minimum execution time: 1_671_000 picoseconds. + Weight::from_parts(1_796_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 49]`. fn schedule(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `116 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 13_350_000 picoseconds. - Weight::from_parts(15_289_847, 0) + // Minimum execution time: 9_313_000 picoseconds. + Weight::from_parts(12_146_613, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 5_375 - .saturating_add(Weight::from_parts(974_567, 0).saturating_mul(s.into())) + // Standard Error: 1_381 + .saturating_add(Weight::from_parts(360_418, 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 Lookup (r:0 w:1) - /// 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::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]`. fn cancel(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `116 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 17_646_000 picoseconds. - Weight::from_parts(15_858_434, 0) + // Minimum execution time: 13_079_000 picoseconds. + Weight::from_parts(12_921_017, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 5_354 - .saturating_add(Weight::from_parts(1_697_642, 0).saturating_mul(s.into())) + // Standard Error: 1_112 + .saturating_add(Weight::from_parts(538_089, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Scheduler Lookup (r:1 w:1) - /// 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::Lookup` (r:1 w:1) + /// 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`) /// The range of component `s` is `[0, 49]`. fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `293 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 16_419_000 picoseconds. - Weight::from_parts(19_868_760, 0) + // Minimum execution time: 12_458_000 picoseconds. + Weight::from_parts(16_009_539, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 6_915 - .saturating_add(Weight::from_parts(1_010_225, 0).saturating_mul(s.into())) + // Standard Error: 2_260 + .saturating_add(Weight::from_parts(399_245, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Scheduler Lookup (r:1 w:1) - /// 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::Lookup` (r:1 w:1) + /// 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`) /// The range of component `s` is `[1, 50]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `319 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 19_574_000 picoseconds. - Weight::from_parts(18_453_197, 0) + // Minimum execution time: 15_173_000 picoseconds. + Weight::from_parts(15_602_728, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 6_009 - .saturating_add(Weight::from_parts(1_707_130, 0).saturating_mul(s.into())) + // Standard Error: 1_302 + .saturating_add(Weight::from_parts(557_878, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } + /// 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`) + /// The range of component `s` is `[1, 50]`. + fn schedule_retry(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `197` + // Estimated: `42428` + // Minimum execution time: 13_531_000 picoseconds. + Weight::from_parts(13_985_249, 0) + .saturating_add(Weight::from_parts(0, 42428)) + // Standard Error: 619 + .saturating_add(Weight::from_parts(39_068, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// 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`) + fn set_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `116 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 8_050_000 picoseconds. + Weight::from_parts(8_440_627, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// 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`) + fn set_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `325 + s * (185 ±0)` + // Estimated: `42428` + // Minimum execution time: 10_876_000 picoseconds. + Weight::from_parts(11_708_172, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// 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`) + fn cancel_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `116 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 8_050_000 picoseconds. + Weight::from_parts(8_440_627, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// 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`) + fn cancel_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `325 + s * (185 ±0)` + // Estimated: `42428` + // Minimum execution time: 10_876_000 picoseconds. + Weight::from_parts(11_708_172, 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/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 1ecd44747ef5140b0f83f5226d8368a9231085d0..7a641e36a126bada81cecceadd9c22f57e5b88e9 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_staking` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-01-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-8idpd4bs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,8 +62,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `894` // Estimated: `4764` - // Minimum execution time: 38_316_000 picoseconds. - Weight::from_parts(40_022_000, 0) + // Minimum execution time: 37_340_000 picoseconds. + Weight::from_parts(38_930_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) @@ -84,8 +84,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1921` // Estimated: `8877` - // Minimum execution time: 81_027_000 picoseconds. - Weight::from_parts(83_964_000, 0) + // Minimum execution time: 80_630_000 picoseconds. + Weight::from_parts(82_196_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) @@ -112,8 +112,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2128` // Estimated: `8877` - // Minimum execution time: 85_585_000 picoseconds. - Weight::from_parts(87_256_000, 0) + // Minimum execution time: 83_523_000 picoseconds. + Weight::from_parts(86_639_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -133,11 +133,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1075` // Estimated: `4764` - // Minimum execution time: 39_520_000 picoseconds. - Weight::from_parts(41_551_548, 0) + // Minimum execution time: 38_636_000 picoseconds. + Weight::from_parts(40_399_283, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_094 - .saturating_add(Weight::from_parts(50_426, 0).saturating_mul(s.into())) + // Standard Error: 869 + .saturating_add(Weight::from_parts(37_752, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -174,11 +174,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 82_915_000 picoseconds. - Weight::from_parts(89_597_160, 0) + // Minimum execution time: 81_301_000 picoseconds. + Weight::from_parts(88_609_205, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_146 - .saturating_add(Weight::from_parts(1_228_061, 0).saturating_mul(s.into())) + // Standard Error: 3_388 + .saturating_add(Weight::from_parts(1_253_692, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -210,8 +210,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1301` // Estimated: `4556` - // Minimum execution time: 48_070_000 picoseconds. - Weight::from_parts(49_226_000, 0) + // Minimum execution time: 47_292_000 picoseconds. + Weight::from_parts(48_566_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) @@ -225,11 +225,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1243 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_140_000 picoseconds. - Weight::from_parts(30_225_579, 0) + // Minimum execution time: 28_840_000 picoseconds. + Weight::from_parts(27_510_817, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 5_394 - .saturating_add(Weight::from_parts(6_401_367, 0).saturating_mul(k.into())) + // Standard Error: 6_603 + .saturating_add(Weight::from_parts(6_268_853, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -262,11 +262,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1797 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 59_287_000 picoseconds. - Weight::from_parts(58_285_052, 0) + // Minimum execution time: 57_537_000 picoseconds. + Weight::from_parts(55_854_233, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 14_556 - .saturating_add(Weight::from_parts(3_863_008, 0).saturating_mul(n.into())) + // Standard Error: 14_427 + .saturating_add(Weight::from_parts(3_844_957, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -290,8 +290,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1581` // Estimated: `6248` - // Minimum execution time: 51_035_000 picoseconds. - Weight::from_parts(52_163_000, 0) + // Minimum execution time: 49_997_000 picoseconds. + Weight::from_parts(51_266_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) @@ -306,8 +306,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 15_809_000 picoseconds. - Weight::from_parts(16_451_000, 0) + // Minimum execution time: 15_342_000 picoseconds. + Weight::from_parts(15_970_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -322,8 +322,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `932` // Estimated: `4556` - // Minimum execution time: 21_695_000 picoseconds. - Weight::from_parts(22_351_000, 0) + // Minimum execution time: 20_719_000 picoseconds. + Weight::from_parts(21_373_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -336,8 +336,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 18_548_000 picoseconds. - Weight::from_parts(19_205_000, 0) + // Minimum execution time: 18_237_000 picoseconds. + Weight::from_parts(18_896_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -348,8 +348,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_193_000 picoseconds. - Weight::from_parts(2_408_000, 0) + // Minimum execution time: 1_946_000 picoseconds. + Weight::from_parts(2_131_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -359,8 +359,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_475_000 picoseconds. - Weight::from_parts(7_874_000, 0) + // Minimum execution time: 6_840_000 picoseconds. + Weight::from_parts(7_208_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -370,8 +370,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_393_000 picoseconds. - Weight::from_parts(7_643_000, 0) + // Minimum execution time: 6_812_000 picoseconds. + Weight::from_parts(7_254_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -381,8 +381,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_474_000 picoseconds. - Weight::from_parts(7_814_000, 0) + // Minimum execution time: 6_787_000 picoseconds. + Weight::from_parts(7_206_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -393,11 +393,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_358_000 picoseconds. - Weight::from_parts(2_589_423, 0) + // Minimum execution time: 2_045_000 picoseconds. + Weight::from_parts(2_281_841, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 81 - .saturating_add(Weight::from_parts(13_612, 0).saturating_mul(v.into())) + // Standard Error: 70 + .saturating_add(Weight::from_parts(11_592, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Ledger` (r:751 w:1502) @@ -411,11 +411,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `668 + i * (148 ±0)` // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 1_934_000 picoseconds. - Weight::from_parts(2_070_000, 0) + // Minimum execution time: 1_657_000 picoseconds. + Weight::from_parts(1_702_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 19_129 - .saturating_add(Weight::from_parts(13_231_580, 0).saturating_mul(i.into())) + // Standard Error: 20_041 + .saturating_add(Weight::from_parts(13_165_254, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) @@ -453,11 +453,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 80_290_000 picoseconds. - Weight::from_parts(87_901_664, 0) + // Minimum execution time: 78_774_000 picoseconds. + Weight::from_parts(85_770_713, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 2_960 - .saturating_add(Weight::from_parts(1_195_050, 0).saturating_mul(s.into())) + // Standard Error: 2_815 + .saturating_add(Weight::from_parts(1_244_494, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -470,11 +470,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 132_682_000 picoseconds. - Weight::from_parts(932_504_297, 0) + // Minimum execution time: 129_905_000 picoseconds. + Weight::from_parts(932_195_554, 0) .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 57_593 - .saturating_add(Weight::from_parts(4_829_705, 0).saturating_mul(s.into())) + // Standard Error: 57_492 + .saturating_add(Weight::from_parts(4_826_754, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -510,12 +510,12 @@ impl pallet_staking::WeightInfo for WeightInfo { fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `8249 + n * (396 ±0)` - // Estimated: `10779 + n * (3774 ±3)` - // Minimum execution time: 129_091_000 picoseconds. - Weight::from_parts(166_186_167, 0) + // Estimated: `10779 + n * (3774 ±0)` + // Minimum execution time: 127_094_000 picoseconds. + Weight::from_parts(160_088_053, 0) .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 36_242 - .saturating_add(Weight::from_parts(40_467_481, 0).saturating_mul(n.into())) + // Standard Error: 32_978 + .saturating_add(Weight::from_parts(39_845_710, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) @@ -539,11 +539,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1922 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 77_461_000 picoseconds. - Weight::from_parts(80_118_021, 0) + // Minimum execution time: 75_672_000 picoseconds. + Weight::from_parts(78_708_335, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 4_343 - .saturating_add(Weight::from_parts(59_113, 0).saturating_mul(l.into())) + // Standard Error: 3_387 + .saturating_add(Weight::from_parts(37_084, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -578,11 +578,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_366_000 picoseconds. - Weight::from_parts(91_964_557, 0) + // Minimum execution time: 87_991_000 picoseconds. + Weight::from_parts(90_272_005, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 2_799 - .saturating_add(Weight::from_parts(1_206_123, 0).saturating_mul(s.into())) + // Standard Error: 2_815 + .saturating_add(Weight::from_parts(1_232_322, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -627,14 +627,14 @@ impl pallet_staking::WeightInfo for WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` - // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±40)` - // Minimum execution time: 520_430_000 picoseconds. - Weight::from_parts(527_125_000, 0) + // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 528_862_000 picoseconds. + Weight::from_parts(534_620_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 1_974_092 - .saturating_add(Weight::from_parts(64_885_491, 0).saturating_mul(v.into())) - // Standard Error: 196_707 - .saturating_add(Weight::from_parts(18_100_326, 0).saturating_mul(n.into())) + // Standard Error: 2_005_553 + .saturating_add(Weight::from_parts(65_586_008, 0).saturating_mul(v.into())) + // Standard Error: 199_842 + .saturating_add(Weight::from_parts(18_155_389, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(184)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -665,13 +665,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 33_917_323_000 picoseconds. - Weight::from_parts(34_173_565_000, 0) + // Minimum execution time: 33_532_110_000 picoseconds. + Weight::from_parts(33_926_321_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 367_135 - .saturating_add(Weight::from_parts(4_696_840, 0).saturating_mul(v.into())) - // Standard Error: 367_135 - .saturating_add(Weight::from_parts(3_889_075, 0).saturating_mul(n.into())) + // Standard Error: 374_134 + .saturating_add(Weight::from_parts(4_627_629, 0).saturating_mul(v.into())) + // Standard Error: 374_134 + .saturating_add(Weight::from_parts(4_068_168, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -688,11 +688,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `946 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_447_197_000 picoseconds. - Weight::from_parts(13_003_614, 0) + // Minimum execution time: 2_395_956_000 picoseconds. + Weight::from_parts(88_416_870, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 9_738 - .saturating_add(Weight::from_parts(4_953_442, 0).saturating_mul(v.into())) + // Standard Error: 8_731 + .saturating_add(Weight::from_parts(4_750_956, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -703,6 +703,8 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -713,10 +715,10 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_714_000 picoseconds. - Weight::from_parts(3_956_000, 0) + // Minimum execution time: 3_761_000 picoseconds. + Weight::from_parts(4_013_000, 0) .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -724,6 +726,8 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -734,10 +738,10 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_361_000 picoseconds. - Weight::from_parts(3_632_000, 0) + // Minimum execution time: 3_325_000 picoseconds. + Weight::from_parts(3_519_000, 0) .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -765,8 +769,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1870` // Estimated: `6248` - // Minimum execution time: 65_329_000 picoseconds. - Weight::from_parts(67_247_000, 0) + // Minimum execution time: 63_583_000 picoseconds. + Weight::from_parts(65_917_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(6)) @@ -779,8 +783,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `658` // Estimated: `3510` - // Minimum execution time: 11_760_000 picoseconds. - Weight::from_parts(12_095_000, 0) + // Minimum execution time: 10_975_000 picoseconds. + Weight::from_parts(11_328_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -791,8 +795,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_256_000 picoseconds. - Weight::from_parts(2_378_000, 0) + // Minimum execution time: 1_954_000 picoseconds. + Weight::from_parts(2_081_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/westend/src/weights/pallet_sudo.rs b/polkadot/runtime/westend/src/weights/pallet_sudo.rs index e9ab3ad37a4cca6483dc7fdeb98562dd6f1937e6..649c43e031dc4a194bed6564e8e01dc823890c8a 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 0000000000000000000000000000000000000000..001a09f103dafcba1955ef14e70f8bbd8113fcb8 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,65 @@ +// 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 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("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/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: `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: `156` + // Estimated: `1641` + // Minimum execution time: 30_888_000 picoseconds. + Weight::from_parts(41_308_000, 0) + .saturating_add(Weight::from_parts(0, 1641)) + .saturating_add(T::DbWeight::get().reads(3)) + } +} diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 493acd0f9e7bdfbfd1e716b7e82a474643f1050b..10725cecf24995e34b3254baa23535cb91dd9981 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_xcm` //! -//! 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-20, 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("westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=westend-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=westend-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/westend/src/weights/ @@ -50,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets() -> Weight { - // TODO: run benchmarks - Weight::zero() - } /// 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) @@ -64,29 +58,73 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 28_098_000 picoseconds. - Weight::from_parts(28_887_000, 0) - .saturating_add(Weight::from_parts(0, 3574)) + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 25_725_000 picoseconds. + Weight::from_parts(26_174_000, 0) + .saturating_add(Weight::from_parts(0, 3612)) .saturating_add(T::DbWeight::get().reads(4)) .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 teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 17_609_000 picoseconds. - Weight::from_parts(18_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `250` + // Estimated: `6196` + // Minimum execution time: 113_140_000 picoseconds. + Weight::from_parts(116_204_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `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 reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 17_007_000 picoseconds. - Weight::from_parts(17_471_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `302` + // Estimated: `6196` + // Minimum execution time: 108_571_000 picoseconds. + Weight::from_parts(110_650_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `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_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `250` + // Estimated: `6196` + // Minimum execution time: 111_836_000 picoseconds. + Weight::from_parts(114_435_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`) @@ -104,8 +142,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_444_000 picoseconds. - Weight::from_parts(7_671_000, 0) + // Minimum execution time: 7_160_000 picoseconds. + Weight::from_parts(7_477_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -113,8 +151,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_126_000 picoseconds. - Weight::from_parts(2_253_000, 0) + // Minimum execution time: 1_934_000 picoseconds. + Weight::from_parts(2_053_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -133,11 +171,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 31_318_000 picoseconds. - Weight::from_parts(32_413_000, 0) - .saturating_add(Weight::from_parts(0, 3574)) + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 31_123_000 picoseconds. + Weight::from_parts(31_798_000, 0) + .saturating_add(Weight::from_parts(0, 3612)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -155,11 +193,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `289` - // Estimated: `3754` - // Minimum execution time: 35_282_000 picoseconds. - Weight::from_parts(35_969_000, 0) - .saturating_add(Weight::from_parts(0, 3754)) + // Measured: `327` + // Estimated: `3792` + // Minimum execution time: 35_175_000 picoseconds. + Weight::from_parts(36_098_000, 0) + .saturating_add(Weight::from_parts(0, 3792)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -169,45 +207,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_247_000 picoseconds. - Weight::from_parts(2_381_000, 0) + // Minimum execution time: 1_974_000 picoseconds. + Weight::from_parts(2_096_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmPallet::SupportedVersion` (r:4 w:2) + /// Storage: `XcmPallet::SupportedVersion` (r:5 w:2) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `26` - // Estimated: `10916` - // Minimum execution time: 14_512_000 picoseconds. - Weight::from_parts(15_042_000, 0) - .saturating_add(Weight::from_parts(0, 10916)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `22` + // Estimated: `13387` + // Minimum execution time: 16_626_000 picoseconds. + Weight::from_parts(17_170_000, 0) + .saturating_add(Weight::from_parts(0, 13387)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifiers` (r:4 w:2) + /// Storage: `XcmPallet::VersionNotifiers` (r:5 w:2) /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `30` - // Estimated: `10920` - // Minimum execution time: 14_659_000 picoseconds. - Weight::from_parts(15_164_000, 0) - .saturating_add(Weight::from_parts(0, 10920)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `26` + // Estimated: `13391` + // Minimum execution time: 16_937_000 picoseconds. + Weight::from_parts(17_447_000, 0) + .saturating_add(Weight::from_parts(0, 13391)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `40` - // Estimated: `13405` - // Minimum execution time: 16_261_000 picoseconds. - Weight::from_parts(16_986_000, 0) - .saturating_add(Weight::from_parts(0, 13405)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15880` + // Minimum execution time: 19_157_000 picoseconds. + Weight::from_parts(19_659_000, 0) + .saturating_add(Weight::from_parts(0, 15880)) + .saturating_add(T::DbWeight::get().reads(6)) } /// Storage: `XcmPallet::VersionNotifyTargets` (r:2 w:1) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -221,38 +259,38 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `6085` - // Minimum execution time: 30_539_000 picoseconds. - Weight::from_parts(31_117_000, 0) - .saturating_add(Weight::from_parts(0, 6085)) + // Measured: `183` + // Estimated: `6123` + // Minimum execution time: 30_699_000 picoseconds. + Weight::from_parts(31_537_000, 0) + .saturating_add(Weight::from_parts(0, 6123)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:3 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `69` - // Estimated: `8484` - // Minimum execution time: 9_463_000 picoseconds. - Weight::from_parts(9_728_000, 0) - .saturating_add(Weight::from_parts(0, 8484)) - .saturating_add(T::DbWeight::get().reads(3)) + // Estimated: `10959` + // Minimum execution time: 12_303_000 picoseconds. + Weight::from_parts(12_670_000, 0) + .saturating_add(Weight::from_parts(0, 10959)) + .saturating_add(T::DbWeight::get().reads(4)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `37` - // Estimated: `10927` - // Minimum execution time: 15_169_000 picoseconds. - Weight::from_parts(15_694_000, 0) - .saturating_add(Weight::from_parts(0, 10927)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `33` + // Estimated: `13398` + // Minimum execution time: 17_129_000 picoseconds. + Weight::from_parts(17_668_000, 0) + .saturating_add(Weight::from_parts(0, 13398)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) /// 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`) @@ -264,12 +302,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `149` - // Estimated: `11039` - // Minimum execution time: 37_549_000 picoseconds. - Weight::from_parts(38_203_000, 0) - .saturating_add(Weight::from_parts(0, 11039)) - .saturating_add(T::DbWeight::get().reads(8)) + // Measured: `183` + // Estimated: `13548` + // Minimum execution time: 39_960_000 picoseconds. + Weight::from_parts(41_068_000, 0) + .saturating_add(Weight::from_parts(0, 13548)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) @@ -280,8 +318,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_947_000 picoseconds. - Weight::from_parts(3_117_000, 0) + // Minimum execution time: 2_333_000 picoseconds. + Weight::from_parts(2_504_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -292,10 +330,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 24_595_000 picoseconds. - Weight::from_parts(24_907_000, 0) + // Minimum execution time: 22_932_000 picoseconds. + Weight::from_parts(23_307_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) + /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `23` + // Estimated: `3488` + // Minimum execution time: 34_558_000 picoseconds. + Weight::from_parts(35_299_000, 0) + .saturating_add(Weight::from_parts(0, 3488)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs index 3a4813b667c68ea6400c9ad58cea8fd1bfece5d0..8fa3207c6446082a97877f488913d9c063114fca 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, 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-08, 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("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -58,8 +58,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 8_065_000 picoseconds. - Weight::from_parts(8_389_000, 0) + // Minimum execution time: 7_775_000 picoseconds. + Weight::from_parts(8_036_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 +74,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 8_038_000 picoseconds. - Weight::from_parts(8_463_000, 0) + // Minimum execution time: 7_708_000 picoseconds. + Weight::from_parts(7_971_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 +90,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_843_000 picoseconds. - Weight::from_parts(8_216_000, 0) + // Minimum execution time: 7_746_000 picoseconds. + Weight::from_parts(8_028_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 +116,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_969_000 picoseconds. - Weight::from_parts(8_362_000, 0) + // Minimum execution time: 7_729_000 picoseconds. + Weight::from_parts(7_954_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 +132,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 10_084_000 picoseconds. - Weight::from_parts(10_451_000, 0) + // Minimum execution time: 9_871_000 picoseconds. + Weight::from_parts(10_075_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 +148,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_948_000 picoseconds. - Weight::from_parts(8_268_000, 0) + // Minimum execution time: 7_869_000 picoseconds. + Weight::from_parts(8_000_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 +164,24 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 10_257_000 picoseconds. - Weight::from_parts(10_584_000, 0) + // Minimum execution time: 9_797_000 picoseconds. + Weight::from_parts(10_373_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// 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 set_config_with_scheduler_params() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_718_000 picoseconds. + Weight::from_parts(7_984_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/westend/src/weights/runtime_parachains_coretime.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs index d9f2d45207b923e3afe661a6021629cb8441970e..aa65a2e9034a7c9f10a3d596db9cf8d167f561ac 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::coretime` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-01, 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-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! 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("westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot @@ -32,10 +32,10 @@ // --wasm-execution=compiled // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=runtime_common::coretime -// --chain=rococo-dev +// --pallet=runtime_parachains::coretime +// --chain=westend-dev // --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,28 +45,39 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -use runtime_parachains::configuration::{self, WeightInfo as ConfigWeightInfo}; - -/// Weight functions for `runtime_common::coretime`. +/// Weight functions for `runtime_parachains::coretime`. pub struct WeightInfo(PhantomData); -impl runtime_parachains::coretime::WeightInfo for WeightInfo { +impl runtime_parachains::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 { - ::WeightInfo::set_config_with_u32() + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_486_000 picoseconds. + Weight::from_parts(7_889_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`) + /// 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: `76` - // Estimated: `3541` - // Minimum execution time: 6_275_000 picoseconds. - Weight::from_parts(6_883_543, 0) - .saturating_add(Weight::from_parts(0, 3541)) - // Standard Error: 202 - .saturating_add(Weight::from_parts(15_028, 0).saturating_mul(s.into())) + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 9_409_000 picoseconds. + Weight::from_parts(10_177_115, 0) + .saturating_add(Weight::from_parts(0, 3612)) + // Standard Error: 259 + .saturating_add(Weight::from_parts(13_932, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 8c2fea69006089992e7af99658e903b6b01f7942..c57af987ca78050e129ab37736bfb8df7ea46834 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -34,20 +34,16 @@ use runtime_common::{ }; use sp_core::ConstU32; use westend_runtime_constants::{ - currency::CENTS, - system_parachain::*, - xcm::body::{FELLOWSHIP_ADMIN_INDEX, TREASURER_INDEX}, + currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, }; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, DescribeBodyTerminal, DescribeFamily, FrameTransactionalProcessor, - HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + FungibleAdapter, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -75,8 +71,7 @@ pub type LocationConverter = ( HashedDescription>, ); -#[allow(deprecated)] -pub type LocalAssetTransactor = XcmCurrencyAdapter< +pub type LocalAssetTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: @@ -117,12 +112,16 @@ parameter_types! { pub AssetHub: Location = Parachain(ASSET_HUB_ID).into_location(); pub Collectives: Location = Parachain(COLLECTIVES_ID).into_location(); pub BridgeHub: Location = Parachain(BRIDGE_HUB_ID).into_location(); + pub Encointer: Location = Parachain(ENCOINTER_ID).into_location(); pub People: Location = Parachain(PEOPLE_ID).into_location(); + pub Broker: Location = Parachain(BROKER_ID).into_location(); pub Wnd: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(TokenLocation::get()) }); pub WndForAssetHub: (AssetFilter, Location) = (Wnd::get(), AssetHub::get()); pub WndForCollectives: (AssetFilter, Location) = (Wnd::get(), Collectives::get()); pub WndForBridgeHub: (AssetFilter, Location) = (Wnd::get(), BridgeHub::get()); + pub WndForEncointer: (AssetFilter, Location) = (Wnd::get(), Encointer::get()); pub WndForPeople: (AssetFilter, Location) = (Wnd::get(), People::get()); + pub WndForBroker: (AssetFilter, Location) = (Wnd::get(), Broker::get()); pub MaxInstructions: u32 = 100; pub MaxAssetsIntoHolding: u32 = 64; } @@ -131,7 +130,9 @@ pub type TrustedTeleporters = ( xcm_builder::Case, xcm_builder::Case, xcm_builder::Case, + xcm_builder::Case, xcm_builder::Case, + xcm_builder::Case, ); pub struct OnlyParachains; @@ -228,7 +229,7 @@ parameter_types! { // FellowshipAdmin pluralistic body. pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); // `Treasurer` pluralistic body. - pub const TreasurerBodyId: BodyId = BodyId::Index(TREASURER_INDEX); + pub const TreasurerBodyId: BodyId = BodyId::Treasury; } /// Type to convert the `GeneralAdmin` origin to a Plurality `Location` value. @@ -262,7 +263,7 @@ pub type LocalPalletOriginToLocation = ( StakingAdminToPlurality, // FellowshipAdmin origin to be used in XCM as a corresponding Plurality `Location` value. FellowshipAdminToPlurality, - // `Treasurer` origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + // `Treasurer` origin to be used in XCM as a corresponding Plurality `Location` value. TreasurerToPlurality, ); diff --git a/polkadot/scripts/build-only-wasm.sh b/polkadot/scripts/build-only-wasm.sh index b6da3319c8214aeca3ca54b76fda87d83077eec5..50b786dab41014dd53cd3e4dea3e02f66fd8b42d 100755 --- a/polkadot/scripts/build-only-wasm.sh +++ b/polkadot/scripts/build-only-wasm.sh @@ -13,6 +13,14 @@ fi WASM_BUILDER_RUNNER="$PROJECT_ROOT/target/release/wbuild-runner/$1" +fl_cargo () { + if command -v forklift >/dev/null 2>&1; then + forklift cargo "$@"; + else + cargo "$@"; + fi +} + if [ -z "$2" ]; then export WASM_TARGET_DIRECTORY=$(pwd) else @@ -22,8 +30,8 @@ fi if [ -d $WASM_BUILDER_RUNNER ]; then export DEBUG=false export OUT_DIR="$PROJECT_ROOT/target/release/build" - cargo run --release --manifest-path="$WASM_BUILDER_RUNNER/Cargo.toml" \ + fl_cargo run --release --manifest-path="$WASM_BUILDER_RUNNER/Cargo.toml" \ | grep -vE "cargo:rerun-if-|Executing build command" else - cargo build --release -p $1 + fl_cargo build --release -p $1 fi diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 6403b822ed9b1ad6879698b3909f0f48daf1e765..37b8a99d640a2d23e0d7a532adc0c43b04bba1f2 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -13,3 +13,4 @@ workspace = true parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-core = { path = "../../substrate/primitives/core" } primitives = { package = "polkadot-primitives", path = "../primitives" } +gum = { package = "tracing-gum", path = "../node/gum" } diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs index 22bffde5acc11b8fdbea565d054949caf40d788f..2ee6f6a4f781842866728e2105d6c23e2fa1cd70 100644 --- a/polkadot/statement-table/src/generic.rs +++ b/polkadot/statement-table/src/generic.rs @@ -36,6 +36,7 @@ use primitives::{ }; use parity_scale_codec::{Decode, Encode}; +const LOG_TARGET: &str = "parachain::statement-table"; /// Context for the statement table. pub trait Context { @@ -53,9 +54,6 @@ pub trait Context { /// get the digest of a candidate. fn candidate_digest(candidate: &Self::Candidate) -> Self::Digest; - /// get the group of a candidate. - fn candidate_group(candidate: &Self::Candidate) -> Self::GroupId; - /// Whether a authority is a member of a group. /// Members are meant to submit candidates and vote on validity. fn is_member_of(&self, authority: &Self::AuthorityId, group: &Self::GroupId) -> bool; @@ -342,13 +340,13 @@ impl Table { pub fn import_statement( &mut self, context: &Ctx, + group_id: Ctx::GroupId, statement: SignedStatement, ) -> Option> { let SignedStatement { statement, signature, sender: signer } = statement; - let res = match statement { Statement::Seconded(candidate) => - self.import_candidate(context, signer.clone(), candidate, signature), + self.import_candidate(context, signer.clone(), candidate, signature, group_id), Statement::Valid(digest) => self.validity_vote(context, signer.clone(), digest, ValidityVote::Valid(signature)), }; @@ -387,9 +385,10 @@ impl Table { authority: Ctx::AuthorityId, candidate: Ctx::Candidate, signature: Ctx::Signature, + group: Ctx::GroupId, ) -> ImportResult { - let group = Ctx::candidate_group(&candidate); if !context.is_member_of(&authority, &group) { + gum::debug!(target: LOG_TARGET, authority = ?authority, group = ?group, "New `Misbehavior::UnauthorizedStatement`, candidate backed by validator that doesn't belong to expected group" ); return Err(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { statement: SignedStatement { signature, @@ -634,10 +633,6 @@ mod tests { Digest(candidate.1) } - fn candidate_group(candidate: &Candidate) -> GroupId { - GroupId(candidate.0) - } - fn is_member_of(&self, authority: &AuthorityId, group: &GroupId) -> bool { self.authorities.get(authority).map(|v| v == group).unwrap_or(false) } @@ -675,10 +670,10 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, statement_a); + table.import_statement(&context, GroupId(2), statement_a); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); - table.import_statement(&context, statement_b); + table.import_statement(&context, GroupId(2), statement_b); assert_eq!( table.detected_misbehavior[&AuthorityId(1)][0], Misbehavior::MultipleCandidates(MultipleCandidates { @@ -711,10 +706,10 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, statement_a); + table.import_statement(&context, GroupId(2), statement_a); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); - table.import_statement(&context, statement_b); + table.import_statement(&context, GroupId(2), statement_b); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); } @@ -735,7 +730,7 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, statement); + table.import_statement(&context, GroupId(2), statement); assert_eq!( table.detected_misbehavior[&AuthorityId(1)][0], @@ -769,7 +764,7 @@ mod tests { }; let candidate_a_digest = Digest(100); - table.import_statement(&context, candidate_a); + table.import_statement(&context, GroupId(2), candidate_a); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); @@ -779,7 +774,7 @@ mod tests { signature: Signature(2), sender: AuthorityId(2), }; - table.import_statement(&context, bad_validity_vote); + table.import_statement(&context, GroupId(3), bad_validity_vote); assert_eq!( table.detected_misbehavior[&AuthorityId(2)][0], @@ -811,7 +806,7 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, statement); + table.import_statement(&context, GroupId(2), statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let invalid_statement = SignedStatement { @@ -820,7 +815,7 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, invalid_statement); + table.import_statement(&context, GroupId(2), invalid_statement); assert!(table.detected_misbehavior.contains_key(&AuthorityId(1))); } @@ -842,7 +837,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement); + table.import_statement(&context, GroupId(2), statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let extra_vote = SignedStatement { @@ -851,7 +846,7 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, extra_vote); + table.import_statement(&context, GroupId(2), extra_vote); assert_eq!( table.detected_misbehavior[&AuthorityId(1)][0], Misbehavior::ValidityDoubleVote(ValidityDoubleVote::IssuedAndValidity( @@ -910,7 +905,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement); + table.import_statement(&context, GroupId(2), statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); assert!(table.attested_candidate(&candidate_digest, &context, 2).is_none()); @@ -921,7 +916,7 @@ mod tests { sender: AuthorityId(2), }; - table.import_statement(&context, vote); + table.import_statement(&context, GroupId(2), vote); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); assert!(table.attested_candidate(&candidate_digest, &context, 2).is_some()); } @@ -944,7 +939,7 @@ mod tests { }; let summary = table - .import_statement(&context, statement) + .import_statement(&context, GroupId(2), statement) .expect("candidate import to give summary"); assert_eq!(summary.candidate, Digest(100)); @@ -971,7 +966,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement); + table.import_statement(&context, GroupId(2), statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let vote = SignedStatement { @@ -980,8 +975,9 @@ mod tests { sender: AuthorityId(2), }; - let summary = - table.import_statement(&context, vote).expect("candidate vote to give summary"); + let summary = table + .import_statement(&context, GroupId(2), vote) + .expect("candidate vote to give summary"); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); diff --git a/polkadot/statement-table/src/lib.rs b/polkadot/statement-table/src/lib.rs index d4629330ac01512e2dc2b0f441d2302f0fd38624..3740d15cc4f326962b962557e61ca14e9163de7d 100644 --- a/polkadot/statement-table/src/lib.rs +++ b/polkadot/statement-table/src/lib.rs @@ -35,8 +35,8 @@ pub use generic::{Config, Context, Table}; pub mod v2 { use crate::generic; use primitives::{ - CandidateHash, CommittedCandidateReceipt, CompactStatement as PrimitiveStatement, Id, - ValidatorIndex, ValidatorSignature, + CandidateHash, CommittedCandidateReceipt, CompactStatement as PrimitiveStatement, + CoreIndex, ValidatorIndex, ValidatorSignature, }; /// Statements about candidates on the network. @@ -59,7 +59,7 @@ pub mod v2 { >; /// A summary of import of a statement. - pub type Summary = generic::Summary; + pub type Summary = generic::Summary; impl<'a> From<&'a Statement> for PrimitiveStatement { fn from(s: &'a Statement) -> PrimitiveStatement { diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index b255b7ab64d05790d5e278ea9e74664d9236a5fc..c0e9bd332df7ccca511bd199221405ce4d43d025 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -10,7 +10,7 @@ description = "CLI to generate voter bags for Polkadot runtimes" workspace = true [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index f8190e6aefa941f328a31c46b21bda7d8f089872..ddc5af97a166af253e660d0523b7ac6e357c367c 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -18,6 +18,6 @@ sp-tracing = { path = "../../../../substrate/primitives/tracing" } frame-system = { path = "../../../../substrate/frame/system" } sp-core = { path = "../../../../substrate/primitives/core" } -clap = { version = "4.4.18", features = ["derive"] } -log = "0.4.17" +clap = { version = "4.5.1", features = ["derive"] } +log = { workspace = true, default-features = true } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 41b79051bbf01d5af62bd0646e77e146a8498d93..f9ccfb9833a6b276f001491ff29daa183f0f8e22 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -14,11 +14,11 @@ array-bytes = "6.1" bounded-collections = { version = "0.2.0", default-features = false, features = ["serde"] } derivative = { version = "2.2.0", default-features = false, features = ["use_core"] } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.17", default-features = false } +log = { workspace = true } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive", "rc"] } +serde = { features = ["alloc", "derive", "rc"], workspace = true } schemars = { version = "0.8.13", default-features = true, optional = true } xcm-procedural = { path = "procedural" } environmental = { version = "1.1.4", default-features = false } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index adeacddf90c1522a9505b7126365e2791fbc88e9..80f2d1deedf724c28ca71508a2b21411b57096ee 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -24,7 +24,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", def frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false } xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } -log = "0.4.17" +log = { workspace = true, default-features = true } [dev-dependencies] pallet-balances = { path = "../../../substrate/frame/balances" } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index e96ec48fcba46f2aaf668445ad25ecc5888a7d7a..4b77199069d341320a67f196719604cedcc35157 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -64,13 +64,16 @@ benchmarks_instance_pallet! { transfer_asset { let (sender_account, sender_location) = account_and_location::(1); let asset = T::get_asset(); - let assets: Assets = vec![ asset.clone() ].into(); + let assets: Assets = vec![asset.clone()].into(); // this xcm doesn't use holding let dest_location = T::valid_destination()?; let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap(); >::deposit_asset(&asset, &sender_location, None).unwrap(); + // We deposit the asset twice so we have enough for ED after transferring + >::deposit_asset(&asset, &sender_location, None).unwrap(); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); assert!(T::TransactAsset::balance(&dest_account).is_zero()); let mut executor = new_executor::(sender_location); @@ -79,7 +82,7 @@ benchmarks_instance_pallet! { }: { executor.bench_process(xcm)?; } verify { - assert!(T::TransactAsset::balance(&sender_account).is_zero()); + assert!(T::TransactAsset::balance(&sender_account) < sender_account_balance_before); assert!(!T::TransactAsset::balance(&dest_account).is_zero()); } @@ -93,11 +96,12 @@ benchmarks_instance_pallet! { &dest_location, FeeReason::TransferReserveAsset ); - let sender_account_balance_before = T::TransactAsset::balance(&sender_account); let asset = T::get_asset(); >::deposit_asset(&asset, &sender_location, None).unwrap(); - assert!(T::TransactAsset::balance(&sender_account) > sender_account_balance_before); + // We deposit the asset twice so we have enough for ED after transferring + >::deposit_asset(&asset, &sender_location, None).unwrap(); + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); let assets: Assets = vec![asset].into(); assert!(T::TransactAsset::balance(&dest_account).is_zero()); diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index fe3ee81f9d44c1a3717b07670ee71cd6f967c8ca..637446832fdca7d836f4df6b8565a46682f96213 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -103,8 +103,7 @@ impl xcm_executor::traits::MatchesFungible for MatchAnyFungible { } // Use balances as the asset transactor. -#[allow(deprecated)] -pub type AssetTransactor = xcm_builder::CurrencyAdapter< +pub type AssetTransactor = xcm_builder::FungibleAdapter< Balances, MatchAnyFungible, AccountIdConverter, @@ -192,8 +191,7 @@ impl xcm_balances_benchmark::Config for Test { type TrustedReserve = TrustedReserve; fn get_asset() -> Asset { - let amount = - >::minimum_balance() as u128; + let amount = 1_000_000_000_000; Asset { id: AssetId(Here.into()), fun: Fungible(amount) } } } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs index 6ce8d3e99e8e54114048ff35d2c2a7c38b01b9c4..63ed0ac0ca736450077a4677d29d65a81e9eaf3b 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -22,10 +22,8 @@ use codec::Encode; use frame_benchmarking::{account, BenchmarkError}; use sp_std::prelude::*; use xcm::latest::prelude::*; -use xcm_executor::{ - traits::{ConvertLocation, FeeReason}, - Config as XcmConfig, FeesMode, -}; +use xcm_builder::EnsureDelivery; +use xcm_executor::{traits::ConvertLocation, Config as XcmConfig}; pub mod fungible; pub mod generic; @@ -114,29 +112,3 @@ pub fn account_and_location(index: u32) -> (T::AccountId, Location) { (account, location) } - -/// Trait for a type which ensures all requirements for successful delivery with XCM transport -/// layers. -pub trait EnsureDelivery { - /// Prepare all requirements for successful `XcmSender: SendXcm` passing (accounts, balances, - /// channels ...). Returns: - /// - possible `FeesMode` which is expected to be set to executor - /// - possible `Assets` which are expected to be subsume to the Holding Register - fn ensure_successful_delivery( - origin_ref: &Location, - dest: &Location, - fee_reason: FeeReason, - ) -> (Option, Option); -} - -/// `()` implementation does nothing which means no special requirements for environment. -impl EnsureDelivery for () { - fn ensure_successful_delivery( - _origin_ref: &Location, - _dest: &Location, - _fee_reason: FeeReason, - ) -> (Option, Option) { - // doing nothing - (None, None) - } -} diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index dc9b3c0e20d352bd3240f9e002919be39e6e4464..4840b6127f55425de91eea85099649d4dfda0881 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -13,8 +13,8 @@ workspace = true bounded-collections = { version = "0.2.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +log = { workspace = true } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index c7d8fb24e9df320f8439616591c467f3f6d7aa1e..ed42f93692b406ea07b2edbda0fbdb315c2b4071 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -17,21 +17,26 @@ use super::*; use bounded_collections::{ConstU32, WeakBoundedVec}; use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; -use frame_support::{traits::Currency, weights::Weight}; +use frame_support::{ + traits::fungible::{Inspect, Mutate}, + weights::Weight, +}; use frame_system::RawOrigin; use sp_std::prelude::*; use xcm::{latest::prelude::*, v2}; +use xcm_builder::EnsureDelivery; +use xcm_executor::traits::FeeReason; type RuntimeOrigin = ::RuntimeOrigin; -// existential deposit multiplier -const ED_MULTIPLIER: u32 = 100; - /// Pallet we're benchmarking here. pub struct Pallet(crate::Pallet); /// Trait that must be implemented by runtime to be able to benchmark pallet properly. pub trait Config: crate::Config { + /// Helper that ensures successful delivery for extrinsics/benchmarks which need `SendXcm`. + type DeliveryHelper: EnsureDelivery; + /// A `Location` that can be reached via `XcmRouter`. Used only in benchmarks. /// /// If `None`, the benchmarks that depend on a reachable destination will be skipped. @@ -74,6 +79,13 @@ pub trait Config: crate::Config { fn set_up_complex_asset_transfer() -> Option<(Assets, u32, Location, Box)> { None } + + /// Gets an asset that can be handled by the AssetTransactor. + /// + /// Used only in benchmarks. + /// + /// Used, for example, in the benchmark for `claim_assets`. + fn get_asset() -> Asset; } benchmarks! { @@ -107,23 +119,29 @@ benchmarks! { }.into(); let assets: Assets = asset.into(); - let existential_deposit = T::ExistentialDeposit::get(); - let caller = whitelisted_caller(); - - // Give some multiple of the existential deposit - let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); - assert!(balance >= transferred_amount); - let _ = as Currency<_>>::make_free_balance_be(&caller, balance); - // verify initial balance - assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance); - + let caller: T::AccountId = whitelisted_caller(); let send_origin = RawOrigin::Signed(caller.clone()); let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmTeleportFilter::contains(&(origin_location, assets.clone().into_inner())) { + if !T::XcmTeleportFilter::contains(&(origin_location.clone(), assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } + // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + let (_, _) = T::DeliveryHelper::ensure_successful_delivery( + &origin_location, + &destination, + FeeReason::ChargeFees, + ); + + // Actual balance (e.g. `ensure_successful_delivery` could drip delivery fees, ...) + let balance = as Inspect<_>>::balance(&caller); + // Add transferred_amount to origin + as Mutate<_>>::mint_into(&caller, transferred_amount)?; + // verify initial balance + let balance = balance + transferred_amount; + assert_eq!( as Inspect<_>>::balance(&caller), balance); + let recipient = [0u8; 32]; let versioned_dest: VersionedLocation = destination.into(); let versioned_beneficiary: VersionedLocation = @@ -132,7 +150,7 @@ benchmarks! { }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) verify { // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) - assert!(pallet_balances::Pallet::::free_balance(&caller) <= balance - transferred_amount); + assert!( as Inspect<_>>::balance(&caller) <= balance - transferred_amount); } reserve_transfer_assets { @@ -146,23 +164,29 @@ benchmarks! { }.into(); let assets: Assets = asset.into(); - let existential_deposit = T::ExistentialDeposit::get(); - let caller = whitelisted_caller(); - - // Give some multiple of the existential deposit - let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); - assert!(balance >= transferred_amount); - let _ = as Currency<_>>::make_free_balance_be(&caller, balance); - // verify initial balance - assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance); - + let caller: T::AccountId = whitelisted_caller(); let send_origin = RawOrigin::Signed(caller.clone()); let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmReserveTransferFilter::contains(&(origin_location, assets.clone().into_inner())) { + if !T::XcmReserveTransferFilter::contains(&(origin_location.clone(), assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } + // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + let (_, _) = T::DeliveryHelper::ensure_successful_delivery( + &origin_location, + &destination, + FeeReason::ChargeFees, + ); + + // Actual balance (e.g. `ensure_successful_delivery` could drip delivery fees, ...) + let balance = as Inspect<_>>::balance(&caller); + // Add transferred_amount to origin + as Mutate<_>>::mint_into(&caller, transferred_amount)?; + // verify initial balance + let balance = balance + transferred_amount; + assert_eq!( as Inspect<_>>::balance(&caller), balance); + let recipient = [0u8; 32]; let versioned_dest: VersionedLocation = destination.into(); let versioned_beneficiary: VersionedLocation = @@ -171,7 +195,7 @@ benchmarks! { }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) verify { // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) - assert!(pallet_balances::Pallet::::free_balance(&caller) <= balance - transferred_amount); + assert!( as Inspect<_>>::balance(&caller) <= balance - transferred_amount); } transfer_assets { @@ -324,11 +348,23 @@ benchmarks! { u32::MAX, ).unwrap()).collect::>(); crate::Pallet::::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); - }: { as QueryHandler>::take_response(query_id); } + claim_assets { + let claim_origin = RawOrigin::Signed(whitelisted_caller()); + let claim_location = T::ExecuteXcmOrigin::try_origin(claim_origin.clone().into()).map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let asset: Asset = T::get_asset(); + // Trap assets for claiming later + crate::Pallet::::drop_assets( + &claim_location, + asset.clone().into(), + &XcmContext { origin: None, message_id: [0u8; 32], topic: None } + ); + let versioned_assets = VersionedAssets::V4(asset.into()); + }: _>(claim_origin.into(), Box::new(versioned_assets), Box::new(VersionedLocation::V4(claim_location))) + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext_with_balances(Vec::new()), diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 586c275ae980ff551f5e96c2cb04c9207b1c23fa..1a1f8b402a39041ffb5852dd56e9725a550afc7c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -29,7 +29,7 @@ pub mod migration; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use frame_support::{ - dispatch::GetDispatchInfo, + dispatch::{DispatchErrorWithPostInfo, GetDispatchInfo, WithPostDispatchInfo}, pallet_prelude::*, traits::{ Contains, ContainsPair, Currency, Defensive, EnsureOrigin, Get, LockableCurrency, @@ -85,6 +85,7 @@ pub trait WeightInfo { fn migrate_and_notify_old_targets() -> Weight; fn new_query() -> Weight; fn take_response() -> Weight; + fn claim_assets() -> Weight; } /// fallback implementation @@ -165,6 +166,10 @@ impl WeightInfo for TestWeightInfo { fn take_response() -> Weight { Weight::from_parts(100_000_000, 0) } + + fn claim_assets() -> Weight { + Weight::from_parts(100_000_000, 0) + } } #[frame_support::pallet] @@ -291,22 +296,38 @@ pub mod pallet { origin: OriginFor, message: Box::RuntimeCall>>, max_weight: Weight, - ) -> Result { - let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let mut hash = message.using_encoded(sp_io::hashing::blake2_256); - let message = (*message).try_into().map_err(|()| Error::::BadVersion)?; - let value = (origin_location, message); - ensure!(T::XcmExecuteFilter::contains(&value), Error::::Filtered); - let (origin_location, message) = value; - let outcome = T::XcmExecutor::prepare_and_execute( - origin_location, - message, - &mut hash, - max_weight, - max_weight, - ); + ) -> Result { + log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); + let outcome = (|| { + let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let mut hash = message.using_encoded(sp_io::hashing::blake2_256); + let message = (*message).try_into().map_err(|()| Error::::BadVersion)?; + let value = (origin_location, message); + ensure!(T::XcmExecuteFilter::contains(&value), Error::::Filtered); + let (origin_location, message) = value; + Ok(T::XcmExecutor::prepare_and_execute( + origin_location, + message, + &mut hash, + max_weight, + max_weight, + )) + })() + .map_err(|e: DispatchError| { + e.with_weight(::execute()) + })?; + Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); - Ok(outcome) + 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); + Error::::LocalExecutionIncomplete.with_weight( + weight_used.saturating_add( + ::execute(), + ), + ) + })?; + Ok(weight_used) } } @@ -1009,9 +1030,6 @@ pub mod pallet { /// No more than `max_weight` will be used in its attempted execution. If this is less than /// the maximum amount of weight that the message could take to be executed, then no /// execution attempt will be made. - /// - /// NOTE: A successful return to this does *not* imply that the `msg` was executed - /// successfully to completion; only that it was attempted. #[pallet::call_index(3)] #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( @@ -1019,13 +1037,8 @@ pub mod pallet { message: Box::RuntimeCall>>, max_weight: Weight, ) -> DispatchResultWithPostInfo { - log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); - let outcome = >::execute(origin, message, max_weight)?; - 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); - Error::::LocalExecutionIncomplete - })?; + let weight_used = + >::execute(origin, message, max_weight)?; Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into()) } @@ -1378,6 +1391,64 @@ pub mod pallet { weight_limit, ) } + + /// Claims assets trapped on this pallet because of leftover assets during XCM execution. + /// + /// - `origin`: Anyone can call this extrinsic. + /// - `assets`: The exact assets that were trapped. Use the version to specify what version + /// was the latest when they were trapped. + /// - `beneficiary`: The location/account where the claimed assets will be deposited. + #[pallet::call_index(12)] + #[pallet::weight({ + let assets_version = assets.identify_version(); + let maybe_assets: Result = (*assets.clone()).try_into(); + let maybe_beneficiary: Result = (*beneficiary.clone()).try_into(); + match (maybe_assets, maybe_beneficiary) { + (Ok(assets), Ok(beneficiary)) => { + let ticket: Location = GeneralIndex(assets_version as u128).into(); + let mut message = Xcm(vec![ + ClaimAsset { assets: assets.clone(), ticket }, + DepositAsset { assets: AllCounted(assets.len() as u32).into(), beneficiary }, + ]); + T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::claim_assets().saturating_add(w)) + } + _ => Weight::MAX + } + })] + pub fn claim_assets( + origin: OriginFor, + assets: Box, + 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); + // Extract version from `assets`. + let assets_version = assets.identify_version(); + let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; + let number_of_assets = assets.len() as u32; + let beneficiary: Location = + (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; + let ticket: Location = GeneralIndex(assets_version as u128).into(); + let mut message = Xcm(vec![ + ClaimAsset { assets, ticket }, + DepositAsset { assets: AllCounted(number_of_assets).into(), beneficiary }, + ]); + let weight = + T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; + let mut hash = message.using_encoded(sp_io::hashing::blake2_256); + let outcome = T::XcmExecutor::prepare_and_execute( + origin_location, + message, + &mut hash, + weight, + weight, + ); + outcome.ensure_complete().map_err(|error| { + log::error!(target: "xcm::pallet_xcm::claim_assets", "XCM execution failed with error: {:?}", error); + Error::::LocalExecutionIncomplete + })?; + Ok(()) + } } } diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 434dac1659b50085f4e4f863e77c0cbe1b38af68..d5ba7312a3a55dcddbc24c64e613985fca0c7bb9 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -30,13 +30,11 @@ use sp_core::H256; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; pub use sp_std::cell::RefCell; use xcm::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, DescribeAllTerminal, FixedRateOfFungible, FixedWeightBounds, - FrameTransactionalProcessor, FungiblesAdapter, HashedDescription, IsConcrete, + FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete, MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount, }; @@ -174,7 +172,7 @@ impl SendXcm for TestSendXcm { msg: &mut Option>, ) -> SendResult<(Location, Xcm<()>)> { if FAIL_SEND_XCM.with(|q| *q.borrow()) { - return Err(SendError::Transport("Intentional send failure used in tests")) + return Err(SendError::Transport("Intentional send failure used in tests")); } let pair = (dest.take().unwrap(), msg.take().unwrap()); Ok((pair, Assets::new())) @@ -424,9 +422,8 @@ pub type ForeignAssetsConvertedConcreteId = MatchedConvertedConcreteId< JustTry, >; -#[allow(deprecated)] pub type AssetTransactors = ( - XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>, + FungibleAdapter, SovereignAccountOf, AccountId, ()>, FungiblesAdapter< AssetsPallet, ForeignAssetsConvertedConcreteId, @@ -566,8 +563,30 @@ impl pallet_test_notifier::Config for Test { type RuntimeCall = RuntimeCall; } +#[cfg(feature = "runtime-benchmarks")] +pub struct TestDeliveryHelper; +#[cfg(feature = "runtime-benchmarks")] +impl xcm_builder::EnsureDelivery for TestDeliveryHelper { + fn ensure_successful_delivery( + origin_ref: &Location, + _dest: &Location, + _fee_reason: xcm_executor::traits::FeeReason, + ) -> (Option, Option) { + use xcm_executor::traits::ConvertLocation; + let account = SovereignAccountOf::convert_location(origin_ref).expect("Valid location"); + // Give the existential deposit at least + let balance = ExistentialDeposit::get(); + let _ = >::make_free_balance_be( + &account, balance, + ); + (None, None) + } +} + #[cfg(feature = "runtime-benchmarks")] impl super::benchmarking::Config for Test { + type DeliveryHelper = TestDeliveryHelper; + fn reachable_dest() -> Option { Some(Parachain(1000).into()) } @@ -635,6 +654,10 @@ impl super::benchmarking::Config for Test { }); Some((assets, fee_index as u32, dest, verify)) } + + fn get_asset() -> Asset { + Asset { id: AssetId(Location::here()), fun: Fungible(ExistentialDeposit::get()) } + } } pub(crate) fn last_event() -> RuntimeEvent { diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index e5ac80c3a14274923cd6b2e5f81a5c354a77717f..13022d9a8b1f69f528393ee8ac16e3d62151bae9 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -20,11 +20,12 @@ pub(crate) mod assets_transfer; use crate::{ mock::*, pallet::SupportedVersion, AssetTraps, Config, CurrentMigration, Error, - LatestVersionedLocation, Pallet, Queries, QueryStatus, VersionDiscoveryQueue, - VersionMigrationStage, VersionNotifiers, VersionNotifyTargets, WeightInfo, + ExecuteControllerWeightInfo, LatestVersionedLocation, Pallet, Queries, QueryStatus, + VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, VersionNotifyTargets, + WeightInfo, }; use frame_support::{ - assert_noop, assert_ok, + assert_err_ignore_postinfo, assert_noop, assert_ok, traits::{Currency, Hooks}, weights::Weight, }; @@ -450,19 +451,70 @@ fn trapped_assets_can_be_claimed() { assert_eq!(Balances::total_balance(&BOB), INITIAL_BALANCE + SEND_AMOUNT); assert_eq!(AssetTraps::::iter().collect::>(), vec![]); - let weight = BaseXcmWeight::get() * 3; - assert_ok!(>::execute( + // Can't claim twice. + assert_err_ignore_postinfo!( + XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(Xcm(vec![ + ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, + buy_execution((Here, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + ]))), + weight + ), + Error::::LocalExecutionIncomplete + ); + }); +} + +// Like `trapped_assets_can_be_claimed` but using the `claim_assets` extrinsic. +#[test] +fn claim_assets_works() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + new_test_ext_with_balances(balances).execute_with(|| { + // First trap some assets. + let trapping_program = + Xcm::builder_unsafe().withdraw_asset((Here, SEND_AMOUNT).into()).build(); + // Even though assets are trapped, the extrinsic returns success. + assert_ok!(XcmPallet::execute( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ - ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, - buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]))), - weight + Box::new(VersionedXcm::V4(trapping_program)), + BaseXcmWeight::get() * 2, )); - let outcome = - Outcome::Incomplete { used: BaseXcmWeight::get(), error: XcmError::UnknownClaim }; - assert_eq!(last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome })); + 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 hash = BlakeTwo256::hash_of(&(source.clone(), versioned_assets.clone())); + + // Assets were indeed trapped. + assert_eq!( + last_events(2), + vec![ + RuntimeEvent::XcmPallet(crate::Event::AssetsTrapped { + hash, + origin: source, + assets: versioned_assets + }), + RuntimeEvent::XcmPallet(crate::Event::Attempted { + outcome: Outcome::Complete { used: BaseXcmWeight::get() * 1 } + }) + ], + ); + let trapped = AssetTraps::::iter().collect::>(); + assert_eq!(trapped, vec![(hash, 1)]); + + // 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() + )), + )); + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); + assert_eq!(AssetTraps::::iter().collect::>(), vec![]); }); } @@ -495,11 +547,14 @@ fn incomplete_execute_reverts_side_effects() { // all effects are reverted and balances unchanged for either sender or receiver assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); assert_eq!(Balances::total_balance(&BOB), INITIAL_BALANCE); + assert_eq!( result, Err(sp_runtime::DispatchErrorWithPostInfo { post_info: frame_support::dispatch::PostDispatchInfo { - actual_weight: None, + actual_weight: Some( + as ExecuteControllerWeightInfo>::execute() + weight + ), pays_fee: frame_support::dispatch::Pays::Yes, }, error: sp_runtime::DispatchError::Module(sp_runtime::ModuleError { diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index f87347f12dc29161bfe2ab71f5cce69530b94cfe..ca9fb351bd3cad1f805106e405cfdcc496c9d8a8 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -15,8 +15,8 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = "2.0.48" +quote = { workspace = true } +syn = { workspace = true } Inflector = "0.11.4" [dev-dependencies] diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index 561d5175b419376449759a92e61e0a2f12ae0294..ba8d726aecff4989417373fc9e14c174d5a5277f 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -165,6 +165,15 @@ macro_rules! versioned_type { <$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 { @@ -287,6 +296,16 @@ macro_rules! versioned_type { <$v3>::max_encoded_len() } } + impl IdentifyVersion for $n { + fn identify_version(&self) -> Version { + use $n::*; + match self { + V2(_) => v2::VERSION, + V3(_) => v3::VERSION, + V4(_) => v4::VERSION, + } + } + } }; } @@ -493,8 +512,14 @@ pub trait WrapVersion { ) -> Result, ()>; } +/// Used to get the version out of a versioned type. +// TODO(XCMv5): This could be `GetVersion` and we change the current one to `GetVersionFor`. +pub trait IdentifyVersion { + fn identify_version(&self) -> Version; +} + /// Check and return the `Version` that should be used for the `Xcm` datum for the destination -/// `MultiLocation`, which will interpret it. +/// `Location`, which will interpret it. pub trait GetVersion { fn get_version_for(dest: &latest::Location) -> Option; } @@ -572,9 +597,9 @@ pub type AlwaysLts = AlwaysV4; pub mod prelude { pub use super::{ latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, AlwaysV4, GetVersion, - IntoVersion, Unsupported, Version as XcmVersion, VersionedAsset, VersionedAssetId, - VersionedAssets, VersionedInteriorLocation, VersionedLocation, VersionedResponse, - VersionedXcm, WrapVersion, + IdentifyVersion, IntoVersion, Unsupported, Version as XcmVersion, VersionedAsset, + VersionedAssetId, VersionedAssets, VersionedInteriorLocation, VersionedLocation, + VersionedResponse, VersionedXcm, WrapVersion, }; } diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs index 188b7f0b5c9384b7395ed08b27c4c8378719be8f..347f3f2c29206222ca546b7d543409da83cbedcf 100644 --- a/polkadot/xcm/src/v2/mod.rs +++ b/polkadot/xcm/src/v2/mod.rs @@ -1134,7 +1134,10 @@ impl TryFrom> for Instruction Self::UnsubscribeVersion, - _ => return Err(()), + i => { + log::debug!(target: "xcm::v3tov2", "`{i:?}` not supported by v2"); + return Err(()); + }, }) } } diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 30010fc2105b8f47a9a943dbd72ec9490cd49f7a..660a30605e53afcabc76d43335d131297a1fa23c 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -23,7 +23,7 @@ sp-weights = { path = "../../../substrate/primitives/weights", default-features frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } # Polkadot dependencies polkadot-parachain-primitives = { path = "../../parachain", default-features = false } @@ -47,6 +47,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-runtime-parachains/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs index 8ead18b5bd7fb4d64967123c13246ce60f46e437..ba2b1fb44b8eeb0916fdec24d97e36121bc18c8a 100644 --- a/polkadot/xcm/xcm-builder/src/controller.rs +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -18,7 +18,10 @@ //! Controller traits defined in this module are high-level traits that will rely on other traits //! from `xcm-executor` to perform their tasks. -use frame_support::pallet_prelude::DispatchError; +use frame_support::{ + dispatch::{DispatchErrorWithPostInfo, WithPostDispatchInfo}, + pallet_prelude::DispatchError, +}; use sp_std::boxed::Box; use xcm::prelude::*; pub use xcm_executor::traits::QueryHandler; @@ -52,7 +55,8 @@ pub trait ExecuteController { /// Weight information for ExecuteController functions. type WeightInfo: ExecuteControllerWeightInfo; - /// Attempt to execute an XCM locally, and return the outcome. + /// Attempt to execute an XCM locally, returns Ok with the weight consumed if the execution + /// complete successfully, Err otherwise. /// /// # Parameters /// @@ -63,7 +67,7 @@ pub trait ExecuteController { origin: Origin, message: Box>, max_weight: Weight, - ) -> Result; + ) -> Result; } /// Weight functions needed for [`SendController`]. @@ -137,8 +141,9 @@ impl ExecuteController for () { _origin: Origin, _message: Box>, _max_weight: Weight, - ) -> Result { - Ok(Outcome::Error { error: XcmError::Unimplemented }) + ) -> Result { + Err(DispatchError::Other("ExecuteController::execute not implemented") + .with_weight(Weight::zero())) } } diff --git a/polkadot/xcm/xcm-builder/src/currency_adapter.rs b/polkadot/xcm/xcm-builder/src/currency_adapter.rs index fe26b7319bb18b2d4ad33774d389afd0f834eb50..24261ac06583c4ca284f52071a4ee80afae2a6ec 100644 --- a/polkadot/xcm/xcm-builder/src/currency_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/currency_adapter.rs @@ -170,7 +170,7 @@ impl< } fn can_check_out(_dest: &Location, what: &Asset, _context: &XcmContext) -> Result { - log::trace!(target: "xcm::currency_adapter", "check_out dest: {:?}, what: {:?}", _dest, what); + log::trace!(target: "xcm::currency_adapter", "can_check_out dest: {:?}, what: {:?}", _dest, what); let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotHandled)?; match CheckedAccount::get() { Some((checked_account, MintLocation::Local)) => diff --git a/polkadot/xcm/xcm-builder/src/fungible_adapter.rs b/polkadot/xcm/xcm-builder/src/fungible_adapter.rs index 7bea8cdf957e169585c182d3a3489519ee2a14ed..21c828922b333e85e9332d16c768aef0d34cbd9f 100644 --- a/polkadot/xcm/xcm-builder/src/fungible_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungible_adapter.rs @@ -151,7 +151,7 @@ impl< fn can_check_out(_dest: &Location, what: &Asset, _context: &XcmContext) -> XcmResult { log::trace!( target: "xcm::fungible_adapter", - "check_out dest: {:?}, what: {:?}", + "can_check_out dest: {:?}, what: {:?}", _dest, what ); @@ -204,7 +204,7 @@ impl< ) -> result::Result { log::trace!( target: "xcm::fungible_adapter", - "deposit_asset what: {:?}, who: {:?}", + "withdraw_asset what: {:?}, who: {:?}", what, who, ); let amount = Matcher::matches_fungible(what).ok_or(MatchError::AssetNotHandled)?; diff --git a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs index 4574d5ed4c682c7bb62b6f20b6f9397dc37e4098..b4c418ebf1c9cf7d9d26540e998f966665993585 100644 --- a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs @@ -235,7 +235,7 @@ impl< fn can_check_out(_origin: &Location, what: &Asset, _context: &XcmContext) -> XcmResult { log::trace!( target: "xcm::fungibles_adapter", - "can_check_in origin: {:?}, what: {:?}", + "can_check_out origin: {:?}, what: {:?}", _origin, what ); // Check we handle this asset. diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 42522c64d8a4da77cc676e6a338d9f019ef707a5..e2af8187136e8eba2b42d7d4a667a69830556032 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -117,7 +117,7 @@ mod process_xcm_message; pub use process_xcm_message::ProcessXcmMessage; mod routing; -pub use routing::{WithTopicSource, WithUniqueTopic}; +pub use routing::{EnsureDelivery, WithTopicSource, WithUniqueTopic}; mod transactional; pub use transactional::FrameTransactionalProcessor; diff --git a/polkadot/xcm/xcm-builder/src/routing.rs b/polkadot/xcm/xcm-builder/src/routing.rs index 9c0302baee06b81ec662bc3a0e25eb9308fc0a3a..529ef80c15ff11d3c0d2629aeb4fa9506cb37a28 100644 --- a/polkadot/xcm/xcm-builder/src/routing.rs +++ b/polkadot/xcm/xcm-builder/src/routing.rs @@ -20,6 +20,7 @@ use frame_system::unique; use parity_scale_codec::Encode; use sp_std::{marker::PhantomData, result::Result}; use xcm::prelude::*; +use xcm_executor::{traits::FeeReason, FeesMode}; /// Wrapper router which, if the message does not already end with a `SetTopic` instruction, /// appends one to the message filled with a universally unique ID. This ID is returned from a @@ -104,3 +105,37 @@ impl SendXcm for WithTopicSource (Option, Option); +} + +/// Tuple implementation for `EnsureDelivery`. +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl EnsureDelivery for Tuple { + fn ensure_successful_delivery( + origin_ref: &Location, + dest: &Location, + fee_reason: FeeReason, + ) -> (Option, Option) { + for_tuples!( #( + // If the implementation returns something, we're done; if not, let others try. + match Tuple::ensure_successful_delivery(origin_ref, dest, fee_reason.clone()) { + r @ (Some(_), Some(_)) | r @ (Some(_), None) | r @ (None, Some(_)) => return r, + (None, None) => (), + } + )* ); + // doing nothing + (None, None) + } +} diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 9892c500f2eebb7cd4a3cfd88f86c6669cca4111..3bd2fa4b4f5309eac6bd2ac54ece79851c134613 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -25,14 +25,22 @@ use frame_support::{ traits::{ConstU32, Everything}, }; use frame_system::{EnsureRoot, EnsureSigned}; -use polkadot_test_runtime::SignedExtra; use primitives::{AccountIndex, BlakeTwo256, Signature}; 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; diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 34508d7622c5f8a3e703cefa833ea6dafd900e56..06cedb9c35775898e264a58e175ebe81e06d10a4 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -32,14 +32,12 @@ use xcm_executor::XcmExecutor; use staging_xcm_builder as xcm_builder; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - FixedRateOfFungible, FixedWeightBounds, IsChildSystemParachain, IsConcrete, MintLocation, - RespectSuspension, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, - TakeWeightCredit, + FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, IsChildSystemParachain, IsConcrete, + MintLocation, RespectSuspension, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, }; pub type AccountId = AccountId32; @@ -146,14 +144,8 @@ parameter_types! { pub type SovereignAccountOf = (ChildParachainConvertsVia, AccountId32Aliases); -#[allow(deprecated)] -pub type LocalCurrencyAdapter = XcmCurrencyAdapter< - Balances, - IsConcrete, - SovereignAccountOf, - AccountId, - CheckAccount, ->; +pub type LocalCurrencyAdapter = + FungibleAdapter, SovereignAccountOf, AccountId, CheckAccount>; pub type LocalAssetTransactor = (LocalCurrencyAdapter,); diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 7ce4a1cc171ded3eba5ab6711d9dc307a0a2cc05..71bd58073db6d7247cf5048d4a684aa19ea79bfd 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -22,7 +22,7 @@ sp-core = { path = "../../../substrate/primitives/core", default-features = fals sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-weights = { path = "../../../substrate/primitives/weights", default-features = false } frame-support = { path = "../../../substrate/frame/support", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } [features] diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index cafe12dc587f883a31ac3539aced38e8de29a89e..1e572e6210a27a7469f827bbe5d076c01c84f032 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -20,6 +20,7 @@ pallet-xcm = { path = "../../pallet-xcm" } polkadot-test-client = { path = "../../../node/test/client" } polkadot-test-runtime = { path = "../../../runtime/test-runtime" } polkadot-test-service = { path = "../../../node/test/service" } +polkadot-service = { path = "../../../node/service" } sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } @@ -27,6 +28,7 @@ sp-state-machine = { path = "../../../../substrate/primitives/state-machine" } xcm = { package = "staging-xcm", path = "../..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = ".." } sp-tracing = { path = "../../../../substrate/primitives/tracing" } +sp-core = { path = "../../../../substrate/primitives/core" } [features] default = ["std"] diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index 79d6cb1c411b12da2a9f6b81a01b93a44c97ebe9..da7fc0d97825f24e1eea91e441cecef11a136e5f 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -19,12 +19,14 @@ use codec::Encode; use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; +use polkadot_service::chain_spec::get_account_id_from_seed; use polkadot_test_client::{ BlockBuilderExt, ClientBlockImportExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder, TestClientBuilder, TestClientBuilderExt, }; use polkadot_test_runtime::{pallet_test_notifier, xcm_config::XcmConfig}; use polkadot_test_service::construct_extrinsic; +use sp_core::sr25519; use sp_runtime::traits::Block; use sp_state_machine::InspectState; use xcm::{latest::prelude::*, VersionedResponse, VersionedXcm}; @@ -323,3 +325,84 @@ fn query_response_elicits_handler() { ))); }); } + +/// Simulates a cross-chain message from Parachain to Parachain through Relay Chain +/// that deposits assets into the reserve of the destination. +/// Regression test for `DepostiReserveAsset` changes in +/// +#[test] +fn deposit_reserve_asset_works_for_any_xcm_sender() { + sp_tracing::try_init_simple(); + let mut client = TestClientBuilder::new().build(); + + // Init values for the simulated origin Parachain + let amount_to_send: u128 = 1_000_000_000_000; + let assets: Assets = (Parent, amount_to_send).into(); + let fee_asset_item = 0; + let max_assets = assets.len() as u32; + let fees = assets.get(fee_asset_item as usize).unwrap().clone(); + 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 = 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 + // destination + let fee1 = amount_to_send.saturating_div(2); + let fee2 = amount_to_send.saturating_sub(fee1); + let fees_half_1 = Asset::from((fees.id.clone(), Fungible(fee1))); + let fees_half_2 = Asset::from((fees.id.clone(), Fungible(fee2))); + + let reserve_context = ::UniversalLocation::get(); + // identifies fee item as seen by `reserve` - to be used at reserve chain + let reserve_fees = fees_half_1.reanchored(&reserve, &reserve_context).unwrap(); + // identifies fee item as seen by `dest` - to be used at destination chain + let dest_fees = fees_half_2.reanchored(&dest, &reserve_context).unwrap(); + // identifies assets as seen by `reserve` - to be used at reserve chain + let assets_reanchored = assets.reanchored(&reserve, &reserve_context).unwrap(); + // identifies `dest` as seen by `reserve` + let dest = dest.reanchored(&reserve, &reserve_context).unwrap(); + // xcm to be executed at dest + let xcm_on_dest = Xcm(vec![ + BuyExecution { fees: dest_fees, weight_limit: weight_limit.clone() }, + DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + ]); + // xcm to be executed at reserve + let msg = Xcm(vec![ + WithdrawAsset(assets_reanchored), + ClearOrigin, + BuyExecution { fees: reserve_fees, weight_limit }, + DepositReserveAsset { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest }, + ]); + + let mut block_builder = client.init_polkadot_block_builder(); + + // Simulate execution of an incoming XCM message at the reserve chain + let execute = construct_extrinsic( + &client, + polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { + message: Box::new(VersionedXcm::from(msg)), + max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), + }), + sp_keyring::Sr25519Keyring::Alice, + 0, + ); + + block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic"); + + let block = block_builder.build().expect("Finalizes the block").block; + let block_hash = block.hash(); + + futures::executor::block_on(client.import(sp_consensus::BlockOrigin::Own, block)) + .expect("imports the block"); + + client.state_at(block_hash).expect("state should exist").inspect_state(|| { + assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!( + r.event, + polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::Attempted { + outcome: Outcome::Complete { .. } + }), + ))); + }); +} diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index b26779f3ae9da206d76823027dc193dc771cc215..c61e1e1d15bcd8fd78ffe47c415abeaf8c1cb4cd 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -826,9 +826,9 @@ impl XcmExecutor { // 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.into()), ClearOrigin]; + 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))?; diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index 9cb5b6b7eeb92e7cf6095d2e86ed9b05185165c4..af471df60aba4dbc4d03692e7bfb84d99eb16420 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.10.0", features = ["derive"] } -log = { version = "0.4.14", default-features = false } +log = { workspace = true } frame-system = { path = "../../../../substrate/frame/system" } frame-support = { path = "../../../../substrate/frame/support" } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index 13b6e7b8652fbbb178071f429b286b6c5b8d64ac..30644dc0e0a53fe485261f9d0e52533ba0641603 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -18,6 +18,8 @@ scale-info = { version = "2.10.0", features = ["derive"] } frame-system = { path = "../../../../substrate/frame/system" } frame-support = { path = "../../../../substrate/frame/support" } +frame-executive = { path = "../../../../substrate/frame/executive" } +frame-try-runtime = { path = "../../../../substrate/frame/try-runtime" } pallet-balances = { path = "../../../../substrate/frame/balances" } pallet-message-queue = { path = "../../../../substrate/frame/message-queue" } sp-std = { path = "../../../../substrate/primitives/std" } @@ -35,6 +37,17 @@ polkadot-runtime-parachains = { path = "../../../runtime/parachains" } polkadot-parachain-primitives = { path = "../../../parachain" } [features] +try-runtime = [ + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-balances/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-xcm/try-runtime", + "polkadot-runtime-parachains/try-runtime", + "sp-runtime/try-runtime", +] runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-simulator/fuzzer/README.md b/polkadot/xcm/xcm-simulator/fuzzer/README.md index 0b3fdd8ec776d5e78d37aa5b57e6c0762af21320..9c15ee881c1b6f5f9a1c30215a16e74abdda2b62 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/README.md +++ b/polkadot/xcm/xcm-simulator/fuzzer/README.md @@ -14,7 +14,7 @@ cargo install honggfuzz In this directory, run this command: ``` -cargo hfuzz run xcm-fuzzer +HFUZZ_BUILD_ARGS="--features=try-runtime" cargo hfuzz run xcm-fuzzer ``` ## Run a single input @@ -22,7 +22,7 @@ cargo hfuzz run xcm-fuzzer In this directory, run this command: ``` -cargo hfuzz run-debug xcm-fuzzer hfuzz_workspace/xcm-fuzzer/fuzzer_input_file +cargo run --features=try-runtime -- hfuzz_workspace/xcm-fuzzer/fuzzer_input_file ``` ## Generate coverage @@ -31,7 +31,7 @@ In this directory, run these four commands: ``` RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" \ -CARGO_INCREMENTAL=0 SKIP_WASM_BUILD=1 CARGO_HOME=./cargo cargo build +CARGO_INCREMENTAL=0 SKIP_WASM_BUILD=1 CARGO_HOME=./cargo cargo build --features=try-runtime ../../../target/debug/xcm-fuzzer hfuzz_workspace/xcm-fuzzer/input/ zip -0 ccov.zip `find ../../../target/ \( -name "*.gc*" -o -name "test-*.gc*" \) -print` grcov ccov.zip -s ../../../ -t html --llvm --branch --ignore-not-existing -o ./coverage diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs index 7026d5467c8b9049eaa86f94e9cd927321d10d68..adf6cacd278b9f25a02f9199fbdabc0af3434414 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs @@ -23,7 +23,9 @@ use polkadot_parachain_primitives::primitives::Id as ParaId; use sp_runtime::{traits::AccountIdConversion, BuildStorage}; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; -use frame_support::assert_ok; +#[cfg(feature = "try-runtime")] +use frame_support::traits::{TryState, TryStateSelect::All}; +use frame_support::{assert_ok, traits::IntegrityTest}; use xcm::{latest::prelude::*, MAX_XCM_DECODE_DEPTH}; use arbitrary::{Arbitrary, Error, Unstructured}; @@ -98,7 +100,7 @@ impl<'a> Arbitrary<'a> for XcmMessage { if let Ok(message) = DecodeLimit::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut encoded_message) { - return Ok(XcmMessage { source, destination, message }) + return Ok(XcmMessage { source, destination, message }); } Err(Error::IncorrectFormat) } @@ -148,6 +150,21 @@ pub fn relay_ext() -> sp_io::TestExternalities { pub type RelayChainPalletXcm = pallet_xcm::Pallet; pub type ParachainPalletXcm = pallet_xcm::Pallet; +// We check XCM messages recursively for blocklisted messages +fn recursively_matches_blocklisted_messages(message: &Instruction<()>) -> bool { + match message { + DepositReserveAsset { xcm, .. } | + ExportMessage { xcm, .. } | + InitiateReserveWithdraw { xcm, .. } | + InitiateTeleport { xcm, .. } | + TransferReserveAsset { xcm, .. } | + SetErrorHandler(xcm) | + SetAppendix(xcm) => xcm.iter().any(recursively_matches_blocklisted_messages), + // The blocklisted message is the Transact instruction. + m => matches!(m, Transact { .. }), + } +} + fn run_input(xcm_messages: [XcmMessage; 5]) { MockNet::reset(); @@ -155,6 +172,11 @@ fn run_input(xcm_messages: [XcmMessage; 5]) { println!(); for xcm_message in xcm_messages { + if xcm_message.message.iter().any(recursively_matches_blocklisted_messages) { + println!(" skipping message\n"); + continue; + } + if xcm_message.source % 4 == 0 { // We get the destination for the message let parachain_id = (xcm_message.destination % 3) + 1; @@ -197,8 +219,22 @@ fn run_input(xcm_messages: [XcmMessage; 5]) { } #[cfg(not(fuzzing))] println!(); + // We run integrity tests and try_runtime invariants + [ParaA::execute_with, ParaB::execute_with, ParaC::execute_with].iter().for_each( + |execute_with| { + execute_with(|| { + #[cfg(feature = "try-runtime")] + parachain::AllPalletsWithSystem::try_state(Default::default(), All).unwrap(); + parachain::AllPalletsWithSystem::integrity_test(); + }); + }, + ); + Relay::execute_with(|| { + #[cfg(feature = "try-runtime")] + relay_chain::AllPalletsWithSystem::try_state(Default::default(), All).unwrap(); + relay_chain::AllPalletsWithSystem::integrity_test(); + }); } - Relay::execute_with(|| {}); } fn main() { diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index d8327c9b401d0ba67ec6cccb12e16ea70ee1ba3e..f953e54111c2e4cae5058b6a201b1a15e4ceb5f4 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -24,10 +24,11 @@ use frame_support::{ }; use frame_system::EnsureRoot; -use sp_core::{ConstU32, H256}; +use sp_core::ConstU32; use sp_runtime::{ - traits::{Hash, IdentityLookup}, - AccountId32, + generic, + traits::{AccountIdLookup, BlakeTwo256, Hash, IdentifyAccount, Verify}, + MultiAddress, MultiSignature, }; use sp_std::prelude::*; @@ -37,48 +38,37 @@ use polkadot_parachain_primitives::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; use xcm::{latest::prelude::*, VersionedXcm}; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedRateOfFungible, - FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, + ParentIsPreset, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; use xcm_executor::{Config, XcmExecutor}; -pub type AccountId = AccountId32; +pub type TxExtension = (frame_system::CheckNonZeroSender,); + +pub type BlockNumber = u64; +pub type Address = MultiAddress; +pub type Header = generic::Header; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +pub type Block = generic::Block; + +pub type Signature = MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; pub type Balance = u128; parameter_types! { - pub const BlockHashCount: u64 = 250; + pub const BlockHashCount: u32 = 250; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; - type Lookup = IdentityLookup; + type Lookup = AccountIdLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = Everything; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -133,9 +123,8 @@ parameter_types! { pub const MaxAssetsIntoHolding: u32 = 64; } -#[allow(deprecated)] pub type LocalAssetTransactor = - XcmCurrencyAdapter, LocationToAccountId, AccountId, ()>; + FungibleAdapter, LocationToAccountId, AccountId, ()>; pub type XcmRouter = super::ParachainXcmRouter; pub type Barrier = AllowUnpaidExecutionFrom; @@ -356,8 +345,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; } -type Block = frame_system::mocking::MockBlock; - construct_runtime!( pub enum Runtime { diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 7e42f558dd6e89cbac2e5f378e16d75fd07ffa78..a11e535492cb696c47981de5b5d3a81e297b8762 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -23,8 +23,12 @@ use frame_support::{ }; use frame_system::EnsureRoot; -use sp_core::{ConstU32, H256}; -use sp_runtime::{traits::IdentityLookup, AccountId32}; +use sp_core::ConstU32; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiAddress, MultiSignature, +}; use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{ @@ -33,48 +37,37 @@ use polkadot_runtime_parachains::{ origin, shared, }; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, FixedRateOfFungible, - FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, + FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; use xcm_executor::{Config, XcmExecutor}; -pub type AccountId = AccountId32; +pub type TxExtension = (frame_system::CheckNonZeroSender,); + +pub type BlockNumber = u64; +pub type Address = MultiAddress; +pub type Header = generic::Header; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +pub type Block = generic::Block; + +pub type Signature = MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; pub type Balance = u128; parameter_types! { - pub const BlockHashCount: u64 = 250; + pub const BlockHashCount: u32 = 250; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; - type Lookup = IdentityLookup; + type Lookup = sp_runtime::traits::AccountIdLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = Everything; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } parameter_types! { @@ -117,9 +110,8 @@ parameter_types! { pub type SovereignAccountOf = (ChildParachainConvertsVia, AccountId32Aliases); -#[allow(deprecated)] pub type LocalAssetTransactor = - XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + FungibleAdapter, SovereignAccountOf, AccountId, ()>; type LocalOriginConverter = ( SovereignSignedViaLocation, @@ -202,8 +194,6 @@ parameter_types! { impl origin::Config for Runtime {} -type Block = frame_system::mocking::MockBlock; - parameter_types! { /// Amount of weight that can be spent per block to service messages. pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); diff --git a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml index f6bdfeb4877e1dbd5f293f8c0ec864f4f7f1b80d..2561661de1f8408b2ed2808f1f5e41b4286ce97e 100644 --- a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml +++ b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml @@ -2,9 +2,11 @@ timeout = 1000 [relaychain.genesis.runtimeGenesis.patch.configuration.config] - max_validators_per_core = 5 needed_approvals = 8 +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 5 + [relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] max_approval_coalesce_count = 5 diff --git a/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml index 5d6f299d46133e52c645bd128fbdcc8171490d4e..a2a2621f8426d2e8deb32f524d23e666ab1b5c00 100644 --- a/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml +++ b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml @@ -2,8 +2,10 @@ timeout = 1000 bootnode = true -[relaychain.genesis.runtimeGenesis.patch.configuration.config] +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] max_validators_per_core = 1 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] needed_approvals = 2 [relaychain] diff --git a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml index e2fbec079b1a81ec50054a30ef89d049bb717482..a3bbc82e74ba6d9d5c442742afc2dd18f31c7305 100644 --- a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml +++ b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml @@ -3,8 +3,10 @@ timeout = 1000 bootnode = true [relaychain.genesis.runtimeGenesis.patch.configuration.config] - max_validators_per_core = 1 needed_approvals = 2 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 group_rotation_frequency = 2 [relaychain] diff --git a/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml index bef54cb8ca416fb3210849fb9801c44a31e846a4..858f87b9cfe52c10c9cff9885dbeb57b0dcba2f5 100644 --- a/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml +++ b/polkadot/zombienet_tests/functional/0006-parachains-max-tranche0.toml @@ -3,10 +3,12 @@ timeout = 1000 bootnode = true [relaychain.genesis.runtimeGenesis.patch.configuration.config] - max_validators_per_core = 1 needed_approvals = 7 relay_vrf_modulo_samples = 5 +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 + [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" diff --git a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml index 69eb0804d8cb70c58fbc70abdb091af3a197d2fb..573ccf961385fa2c721caa0bb67ed97b94deb5a1 100644 --- a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml +++ b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.toml @@ -2,9 +2,11 @@ timeout = 1000 [relaychain.genesis.runtimeGenesis.patch.configuration.config] - max_validators_per_core = 1 needed_approvals = 1 +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 + [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" diff --git a/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml b/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml index 1ea385c3a42ee8fdf89b7595151a98c26d9b011b..ea1c93a1403fb837b45a6da01d0920c516e43ae6 100644 --- a/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml +++ b/polkadot/zombienet_tests/functional/0008-dispute-old-finalized.toml @@ -2,9 +2,11 @@ timeout = 1000 [relaychain.genesis.runtimeGenesis.patch.configuration.config] - max_validators_per_core = 1 needed_approvals = 1 +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 + [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" diff --git a/polkadot/zombienet_tests/functional/0010-validator-disabling.toml b/polkadot/zombienet_tests/functional/0010-validator-disabling.toml index 6701d60d74d147d517fc55dd3f1253171f6b807f..c9d79c5f8f236918cf409fd684b7d0b8d9792d33 100644 --- a/polkadot/zombienet_tests/functional/0010-validator-disabling.toml +++ b/polkadot/zombienet_tests/functional/0010-validator-disabling.toml @@ -3,8 +3,10 @@ timeout = 1000 bootnode = true [relaychain.genesis.runtimeGenesis.patch.configuration.config] - max_validators_per_core = 1 needed_approvals = 2 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 group_rotation_frequency = 10 [relaychain] diff --git a/polkadot/zombienet_tests/functional/0011-async-backing-6-seconds-rate.toml b/polkadot/zombienet_tests/functional/0011-async-backing-6-seconds-rate.toml index 5a6832b149be21a48ca17fe6e84f75cfc3324ed0..b776622fdce33df2e9a78debc31ee3e62ae4805d 100644 --- a/polkadot/zombienet_tests/functional/0011-async-backing-6-seconds-rate.toml +++ b/polkadot/zombienet_tests/functional/0011-async-backing-6-seconds-rate.toml @@ -8,13 +8,16 @@ chain = "rococo-local" [relaychain.genesis.runtimeGenesis.patch.configuration.config] needed_approvals = 4 relay_vrf_modulo_samples = 6 - scheduling_lookahead = 2 - group_rotation_frequency = 4 [relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] max_candidate_depth = 3 allowed_ancestry_len = 2 +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + lookahead = 2 + group_rotation_frequency = 4 + + [relaychain.default_resources] limits = { memory = "4G", cpu = "2" } requests = { memory = "2G", cpu = "1" } diff --git a/polkadot/zombienet_tests/functional/0012-elastic-scaling-mvp.toml b/polkadot/zombienet_tests/functional/0012-elastic-scaling-mvp.toml new file mode 100644 index 0000000000000000000000000000000000000000..9b3576eaa3c212bd9490095c12ae4bca65f6fa54 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0012-elastic-scaling-mvp.toml @@ -0,0 +1,40 @@ +[settings] +timeout = 1000 +bootnode = true + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] + needed_approvals = 4 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 2 + num_cores = 2 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +default_command = "polkadot" + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.nodes]] + name = "alice" + validator = "true" + + [[relaychain.node_groups]] + name = "validator" + count = 3 + args = [ "-lparachain=debug,runtime=debug"] + +[[parachains]] +id = 2000 +default_command = "polkadot-parachain" +add_to_genesis = false +register_para = true +onboard_as_parachain = false + + [parachains.collator] + name = "collator2000" + command = "polkadot-parachain" + args = [ "-lparachain=debug" ] diff --git a/polkadot/zombienet_tests/functional/0012-elastic-scaling-mvp.zndsl b/polkadot/zombienet_tests/functional/0012-elastic-scaling-mvp.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..edc87c802a0965b6fd685db44ccbf50e807f1ed3 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0012-elastic-scaling-mvp.zndsl @@ -0,0 +1,19 @@ +Description: Test that a paraid acquiring multiple cores does not brick itself if ElasticScalingMVP feature is enabled in genesis +Network: ./0012-elastic-scaling-mvp.toml +Creds: config + +# Check authority status. +validator: reports node_roles is 4 + +validator: reports substrate_block_height{status="finalized"} is at least 10 within 100 seconds + +# Ensure parachain was able to make progress. +validator: parachain 2000 block height is at least 10 within 200 seconds + +# Register the second core assigned to this parachain. +alice: js-script ./0012-register-para.js return is 0 within 600 seconds + +validator: reports substrate_block_height{status="finalized"} is at least 35 within 100 seconds + +# Ensure parachain is now making progress. +validator: parachain 2000 block height is at least 30 within 200 seconds diff --git a/polkadot/zombienet_tests/functional/0012-register-para.js b/polkadot/zombienet_tests/functional/0012-register-para.js new file mode 100644 index 0000000000000000000000000000000000000000..25c7e4f5ffddcf087edab4df37e696af92fe6d3f --- /dev/null +++ b/polkadot/zombienet_tests/functional/0012-register-para.js @@ -0,0 +1,37 @@ +async function run(nodeName, networkInfo, _jsArgs) { + const { wsUri, userDefinedTypes } = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + await zombie.util.cryptoWaitReady(); + + // account to submit tx + const keyring = new zombie.Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + await new Promise(async (resolve, reject) => { + const unsub = await api.tx.sudo + .sudo(api.tx.coretime.assignCore(0, 35, [[{ task: 2000 }, 57600]], null)) + .signAndSend(alice, ({ status, isError }) => { + if (status.isInBlock) { + console.log( + `Transaction included at blockhash ${status.asInBlock}`, + ); + } else if (status.isFinalized) { + console.log( + `Transaction finalized at blockHash ${status.asFinalized}`, + ); + unsub(); + return resolve(); + } else if (isError) { + console.log(`Transaction error`); + reject(`Transaction error`); + } + }); + }); + + + + return 0; +} + +module.exports = { run }; diff --git a/polkadot/zombienet_tests/misc/0001-paritydb.toml b/polkadot/zombienet_tests/misc/0001-paritydb.toml index 399f848d3ac49e7e9950617c170c13d5c63593dd..b3ce2081b1119ec237c1b3d6e14e1e4aed8322c5 100644 --- a/polkadot/zombienet_tests/misc/0001-paritydb.toml +++ b/polkadot/zombienet_tests/misc/0001-paritydb.toml @@ -3,9 +3,11 @@ timeout = 1000 bootnode = true [relaychain.genesis.runtimeGenesis.patch.configuration.config] - max_validators_per_core = 1 needed_approvals = 3 +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 + [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" diff --git a/polkadot/zombienet_tests/misc/0001-paritydb.zndsl b/polkadot/zombienet_tests/misc/0001-paritydb.zndsl index 4a22311de764c1936be2f5812ffb32a7471b5f8e..e0260cb9fdde18882bd9e1cb1ec88a12cdb7a3b9 100644 --- a/polkadot/zombienet_tests/misc/0001-paritydb.zndsl +++ b/polkadot/zombienet_tests/misc/0001-paritydb.zndsl @@ -31,28 +31,28 @@ validator-0: parachain 2008 is registered validator-0: parachain 2009 is registered # Ensure parachains made some progress. -validator-0: parachain 2000 block height is at least 3 within 30 seconds -validator-0: parachain 2001 block height is at least 3 within 30 seconds -validator-0: parachain 2002 block height is at least 3 within 30 seconds -validator-0: parachain 2003 block height is at least 3 within 30 seconds -validator-0: parachain 2004 block height is at least 3 within 30 seconds -validator-0: parachain 2005 block height is at least 3 within 30 seconds -validator-0: parachain 2006 block height is at least 3 within 30 seconds -validator-0: parachain 2007 block height is at least 3 within 30 seconds -validator-0: parachain 2008 block height is at least 3 within 30 seconds -validator-0: parachain 2009 block height is at least 3 within 30 seconds +validator-0: parachain 2000 block height is at least 3 within 60 seconds +validator-0: parachain 2001 block height is at least 3 within 60 seconds +validator-0: parachain 2002 block height is at least 3 within 60 seconds +validator-0: parachain 2003 block height is at least 3 within 60 seconds +validator-0: parachain 2004 block height is at least 3 within 60 seconds +validator-0: parachain 2005 block height is at least 3 within 60 seconds +validator-0: parachain 2006 block height is at least 3 within 60 seconds +validator-0: parachain 2007 block height is at least 3 within 60 seconds +validator-0: parachain 2008 block height is at least 3 within 60 seconds +validator-0: parachain 2009 block height is at least 3 within 60 seconds # Check lag - approval -validator-0: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-1: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-2: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-3: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-4: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-5: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-6: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-7: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-8: reports polkadot_parachain_approval_checking_finality_lag is 0 -validator-9: reports polkadot_parachain_approval_checking_finality_lag is 0 +validator-0: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-1: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-2: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-3: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-4: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-5: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-6: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-7: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-8: reports polkadot_parachain_approval_checking_finality_lag <= 1 +validator-9: reports polkadot_parachain_approval_checking_finality_lag <= 1 # Check lag - dispute conclusion validator-0: reports polkadot_parachain_candidate_disputes_total is 0 diff --git a/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl b/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl index db0a60ac1df617e5c89dc6a1385c4c106c1ead05..5fe1b2ad2f1a7589a28f8b1b8da05d6f35d3d59b 100644 --- a/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl +++ b/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl @@ -10,9 +10,8 @@ dave: parachain 2001 block height is at least 10 within 200 seconds # POLKADOT_PR_ARTIFACTS_URL=https://gitlab.parity.io/parity/mirrors/polkadot/-/jobs/1842869/artifacts/raw/artifacts # with the version of polkadot you want to download. -# avg 30s in our infra -alice: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 60 seconds -bob: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 60 seconds +alice: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 240 seconds +bob: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 240 seconds # update the cmd to add the flag '--insecure-validator-i-know-what-i-do' # once the base image include the version with this flag we can remove this logic. alice: run ./0002-update-cmd.sh within 60 seconds diff --git a/prdoc/1.4.0/pr_1246.prdoc b/prdoc/1.4.0/pr_1246.prdoc index a4d270c45cb5915760ddfbd60e5e4b3b7c08cd4a..3b5c2017f22acfba25471595c50015ae14c3e5cd 100644 --- a/prdoc/1.4.0/pr_1246.prdoc +++ b/prdoc/1.4.0/pr_1246.prdoc @@ -11,7 +11,7 @@ migrations: description: "Messages from the DMP dispatch queue will be moved over to the MQ pallet via `on_initialize`. This happens over multiple blocks and emits a `Completed` event at the end. The pallet can be un-deployed and deleted afterwards. Note that the migration reverses the order of messages, which should be acceptable as a one-off." crates: - - name: cumulus_pallet_xcmp_queue + - name: cumulus-pallet-xcmp-queue note: Pallet config must be altered according to the MR description. host_functions: [] diff --git a/prdoc/1.6.0/pr_2689.prdoc b/prdoc/1.6.0/pr_2689.prdoc index 847c3e8026cef9dfdf63f044a1b773be85b12921..5d3081e3a4ce71d872c8eb8a96fda5b2e273b684 100644 --- a/prdoc/1.6.0/pr_2689.prdoc +++ b/prdoc/1.6.0/pr_2689.prdoc @@ -1,7 +1,7 @@ # Schema: Parity PR Documentation Schema (prdoc) # See doc at https://github.com/paritytech/prdoc -title: BEEFY: Support compatibility with Warp Sync - Allow Warp Sync for Validators +title: "BEEFY: Support compatibility with Warp Sync - Allow Warp Sync for Validators" doc: - audience: Node Operator diff --git a/prdoc/1.6.0/pr_2771.prdoc b/prdoc/1.6.0/pr_2771.prdoc index 1b49162e4392ba1ad1a77d61e5b2289474b0ffbe..50fb99556ecddf39adbcece77d9b83e5d98651b4 100644 --- a/prdoc/1.6.0/pr_2771.prdoc +++ b/prdoc/1.6.0/pr_2771.prdoc @@ -6,4 +6,4 @@ doc: Enable better req-response protocol versioning, by allowing for fallback requests on different protocols. crates: - - name: sc_network + - name: sc-network diff --git a/prdoc/pr_1222.prdoc b/prdoc/1.7.0/pr_1222.prdoc similarity index 100% rename from prdoc/pr_1222.prdoc rename to prdoc/1.7.0/pr_1222.prdoc diff --git a/prdoc/pr_1230.prdoc b/prdoc/1.7.0/pr_1230.prdoc similarity index 100% rename from prdoc/pr_1230.prdoc rename to prdoc/1.7.0/pr_1230.prdoc diff --git a/prdoc/pr_1296.prdoc b/prdoc/1.7.0/pr_1296.prdoc similarity index 100% rename from prdoc/pr_1296.prdoc rename to prdoc/1.7.0/pr_1296.prdoc diff --git a/prdoc/pr_1313.prdoc b/prdoc/1.7.0/pr_1313.prdoc similarity index 100% rename from prdoc/pr_1313.prdoc rename to prdoc/1.7.0/pr_1313.prdoc diff --git a/prdoc/pr_1845.prdoc b/prdoc/1.7.0/pr_1845.prdoc similarity index 100% rename from prdoc/pr_1845.prdoc rename to prdoc/1.7.0/pr_1845.prdoc diff --git a/prdoc/pr_1871.prdoc b/prdoc/1.7.0/pr_1871.prdoc similarity index 100% rename from prdoc/pr_1871.prdoc rename to prdoc/1.7.0/pr_1871.prdoc diff --git a/prdoc/pr_2125.prdoc b/prdoc/1.7.0/pr_2125.prdoc similarity index 100% rename from prdoc/pr_2125.prdoc rename to prdoc/1.7.0/pr_2125.prdoc diff --git a/prdoc/pr_2467.prdoc b/prdoc/1.7.0/pr_2467.prdoc similarity index 100% rename from prdoc/pr_2467.prdoc rename to prdoc/1.7.0/pr_2467.prdoc diff --git a/prdoc/pr_2477-use-clone-instead-of-fork-on-pvf.prdoc b/prdoc/1.7.0/pr_2477-use-clone-instead-of-fork-on-pvf.prdoc similarity index 100% rename from prdoc/pr_2477-use-clone-instead-of-fork-on-pvf.prdoc rename to prdoc/1.7.0/pr_2477-use-clone-instead-of-fork-on-pvf.prdoc diff --git a/prdoc/pr_2587.prdoc b/prdoc/1.7.0/pr_2587.prdoc similarity index 100% rename from prdoc/pr_2587.prdoc rename to prdoc/1.7.0/pr_2587.prdoc diff --git a/prdoc/pr_2657.prdoc b/prdoc/1.7.0/pr_2657.prdoc similarity index 100% rename from prdoc/pr_2657.prdoc rename to prdoc/1.7.0/pr_2657.prdoc diff --git a/prdoc/pr_2796.prdoc b/prdoc/1.7.0/pr_2796.prdoc similarity index 100% rename from prdoc/pr_2796.prdoc rename to prdoc/1.7.0/pr_2796.prdoc diff --git a/prdoc/pr_2826.prdoc b/prdoc/1.7.0/pr_2826.prdoc similarity index 100% rename from prdoc/pr_2826.prdoc rename to prdoc/1.7.0/pr_2826.prdoc diff --git a/prdoc/pr_2889.prdoc b/prdoc/1.7.0/pr_2889.prdoc similarity index 100% rename from prdoc/pr_2889.prdoc rename to prdoc/1.7.0/pr_2889.prdoc diff --git a/prdoc/pr_2920.prdoc b/prdoc/1.7.0/pr_2920.prdoc similarity index 100% rename from prdoc/pr_2920.prdoc rename to prdoc/1.7.0/pr_2920.prdoc diff --git a/prdoc/pr_2924.prdoc b/prdoc/1.7.0/pr_2924.prdoc similarity index 100% rename from prdoc/pr_2924.prdoc rename to prdoc/1.7.0/pr_2924.prdoc diff --git a/prdoc/pr_2942.prdoc b/prdoc/1.7.0/pr_2942.prdoc similarity index 100% rename from prdoc/pr_2942.prdoc rename to prdoc/1.7.0/pr_2942.prdoc diff --git a/prdoc/pr_2970.prdoc b/prdoc/1.7.0/pr_2970.prdoc similarity index 100% rename from prdoc/pr_2970.prdoc rename to prdoc/1.7.0/pr_2970.prdoc diff --git a/prdoc/pr_3001.prdoc b/prdoc/1.7.0/pr_3001.prdoc similarity index 100% rename from prdoc/pr_3001.prdoc rename to prdoc/1.7.0/pr_3001.prdoc diff --git a/prdoc/pr_3009.prdoc b/prdoc/1.7.0/pr_3009.prdoc similarity index 100% rename from prdoc/pr_3009.prdoc rename to prdoc/1.7.0/pr_3009.prdoc diff --git a/prdoc/pr_3020.prdoc b/prdoc/1.7.0/pr_3020.prdoc similarity index 100% rename from prdoc/pr_3020.prdoc rename to prdoc/1.7.0/pr_3020.prdoc diff --git a/prdoc/pr_3029.prdoc b/prdoc/1.7.0/pr_3029.prdoc similarity index 100% rename from prdoc/pr_3029.prdoc rename to prdoc/1.7.0/pr_3029.prdoc diff --git a/prdoc/pr_3040.prdoc b/prdoc/1.7.0/pr_3040.prdoc similarity index 100% rename from prdoc/pr_3040.prdoc rename to prdoc/1.7.0/pr_3040.prdoc diff --git a/prdoc/pr_3057.prdoc b/prdoc/1.7.0/pr_3057.prdoc similarity index 100% rename from prdoc/pr_3057.prdoc rename to prdoc/1.7.0/pr_3057.prdoc diff --git a/prdoc/pr_3061.prdoc b/prdoc/1.7.0/pr_3061.prdoc similarity index 100% rename from prdoc/pr_3061.prdoc rename to prdoc/1.7.0/pr_3061.prdoc diff --git a/prdoc/pr_3077.prdoc b/prdoc/1.7.0/pr_3077.prdoc similarity index 100% rename from prdoc/pr_3077.prdoc rename to prdoc/1.7.0/pr_3077.prdoc diff --git a/prdoc/pr_3108.prdoc b/prdoc/1.7.0/pr_3108.prdoc similarity index 100% rename from prdoc/pr_3108.prdoc rename to prdoc/1.7.0/pr_3108.prdoc diff --git a/prdoc/pr_3110.prdoc b/prdoc/1.7.0/pr_3110.prdoc similarity index 100% rename from prdoc/pr_3110.prdoc rename to prdoc/1.7.0/pr_3110.prdoc diff --git a/prdoc/pr_3156.prdoc b/prdoc/1.7.0/pr_3156.prdoc similarity index 100% rename from prdoc/pr_3156.prdoc rename to prdoc/1.7.0/pr_3156.prdoc diff --git a/prdoc/pr_3228.prdoc b/prdoc/1.7.0/pr_3228.prdoc similarity index 100% rename from prdoc/pr_3228.prdoc rename to prdoc/1.7.0/pr_3228.prdoc diff --git a/prdoc/1.8.0/pr_1660.prdoc b/prdoc/1.8.0/pr_1660.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..dda38c9549595526bb438e9358ed792c6bc1406c --- /dev/null +++ b/prdoc/1.8.0/pr_1660.prdoc @@ -0,0 +1,12 @@ +title: Implements a percentage cap on staking rewards from era inflation + +doc: + - audience: Runtime Dev + description: | + The `pallet-staking` exposes a new perbill configuration, `MaxStakersRewards`, which caps the + amount of era inflation that is distributed to the stakers. The remainder of the era + inflation is minted directly into `T::RewardRemainder` account. This allows the runtime to be + configured to assign a minimum inflation value per era to a specific account (e.g. treasury). + +crates: + - name: pallet-staking diff --git a/prdoc/1.8.0/pr_2061.prdoc b/prdoc/1.8.0/pr_2061.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..07df11ca0543a5c90a60996f73e96b059a7e8fe4 --- /dev/null +++ b/prdoc/1.8.0/pr_2061.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 Parameters Pallet + +doc: + - audience: Runtime Dev + description: | + Adds `pallet-parameters` that allows to have parameters for pallet configs that dynamically change at runtime. Allows to be permissioned on a per-key basis and is compatible with ORML macros. + +crates: + - name: "pallet-parameters" + - name: "frame-support" + - name: "frame-support-procedural" diff --git a/prdoc/1.8.0/pr_2290.prdoc b/prdoc/1.8.0/pr_2290.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9f0476e9152641fa0bacd3e71af77ca92bcd142f --- /dev/null +++ b/prdoc/1.8.0/pr_2290.prdoc @@ -0,0 +1,10 @@ +title: im-online pallet offcain storage cleanup + +doc: + - audience: Runtime Dev + description: | + Adds a function `clear_offchain_storage` to `pallet-im-online`. This function can be used + after the pallet was removed to clear its offchain storage. + +crates: + - name: pallet-im-online diff --git a/prdoc/1.8.0/pr_2903.prdoc b/prdoc/1.8.0/pr_2903.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..dd22fa0eea3754436e1dca0a9657eb1be8fb8151 --- /dev/null +++ b/prdoc/1.8.0/pr_2903.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: "Implement `ConversionToAssetBalance` in asset-rate" + +doc: + - audience: Runtime Dev + description: | + Implements the `ConversionToAssetBalance` trait to the asset-rate pallet. + + Previously only the `ConversionFromAssetBalance` trait was implemented, which would allow to convert an asset balance into the corresponding native balance. + + The `ConversionToAssetBalance` allows to use pallet-asset-rate, e.g., as a mechanism to charge XCM fees in an asset that is not the native. +crates: [ ] + diff --git a/prdoc/pr_2949-async-backing-on-all-testnet-system-chains.prdoc b/prdoc/1.8.0/pr_2949-async-backing-on-all-testnet-system-chains.prdoc similarity index 100% rename from prdoc/pr_2949-async-backing-on-all-testnet-system-chains.prdoc rename to prdoc/1.8.0/pr_2949-async-backing-on-all-testnet-system-chains.prdoc diff --git a/prdoc/1.8.0/pr_3007.prdoc b/prdoc/1.8.0/pr_3007.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..17870469a21988f46a8338599f53562e4cd9acff --- /dev/null +++ b/prdoc/1.8.0/pr_3007.prdoc @@ -0,0 +1,16 @@ +title: Try State Hook for Ranked Collective. + +doc: + - audience: Runtime User + description: | + Invariants for storage items in the ranked collective pallet. Enforces the following Invariants: + 1. Total number of `Members` in storage should be >= [`MemberIndex`] of a [`Rank`] in `MemberCount`. + 2. `Rank` in Members should be in `MemberCount`. + 3.`Sum` of `MemberCount` index should be the same as the sum of all the index attained for + rank possessed by `Members` + 4. `Member` in storage of `IdToIndex` should be the same as `Member` in `IndexToId`. + 5. `Rank` in `IdToIndex` should be the same as the the `Rank` in `IndexToId`. + 6. `Rank` of the member `who` in `IdToIndex` should be the same as the `Rank` of + the member `who` in `Members` +crates: +- name: pallet-ranked-collective diff --git a/prdoc/1.8.0/pr_3052.prdoc b/prdoc/1.8.0/pr_3052.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..09f3cf59e4da467e277aeb3d36c737cd8e6a2a85 --- /dev/null +++ b/prdoc/1.8.0/pr_3052.prdoc @@ -0,0 +1,15 @@ +title: "Fixes a scenario where a nomination pool's `TotalValueLocked` is out of sync due to staking's implicit withdraw" + +doc: + - audience: Runtime Dev + description: | + The nomination pools pallet `TotalValueLocked` may get out of sync if the staking pallet + does implicit withdrawal of unlocking chunks belonging to a bonded pool stash. This fix + is based on a new method on the `OnStakingUpdate` traits, `on_withdraw`, which allows the + nomination pools pallet to adjust the `TotalValueLocked` every time there is an implicit or + explicit withdrawal from a bonded pool's stash. + +crates: + - name: "pallet-nomination-pools" + - name: "pallet-staking" + - name: "sp-staking" diff --git a/prdoc/1.8.0/pr_3060.prdoc b/prdoc/1.8.0/pr_3060.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..4cd6674ebb2e91b03ed0f4c5d1626bae58c82286 --- /dev/null +++ b/prdoc/1.8.0/pr_3060.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: Add retry mechanics to `pallet-scheduler` + +doc: + - audience: Runtime Dev + description: | + This PR adds retry mechanics to pallet-scheduler, as described in the issue above. + Users can now set a retry configuration for a task so that, in case its scheduled run fails, it will be retried after a number of blocks, for a specified number of times or until it succeeds. + If a retried task runs successfully before running out of retries, its remaining retry counter will be reset to the initial value. If a retried task runs out of retries, it will be removed from the schedule. + Tasks which need to be scheduled for a retry are still subject to weight metering and agenda space, same as a regular task. Periodic tasks will have their periodic schedule put on hold while the task is retrying. + +crates: + - name: pallet-scheduler diff --git a/prdoc/1.8.0/pr_3079.prdoc b/prdoc/1.8.0/pr_3079.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c745c1ffbfe5775f205dc5510a637dbfd4e6f56c --- /dev/null +++ b/prdoc/1.8.0/pr_3079.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: Implement transaction_unstable_broadcast and transaction_unstable_stop + +doc: + - audience: Node Dev + description: | + A new RPC class is added to handle transactions. The `transaction_unstable_broadcast` broadcasts + the provided transaction to the peers of the node, until the `transaction_unstable_stop` is called. + The APIs are marked as unstable and subject to change in the future. + To know if the transaction was added to the chain, users can decode the bodies of announced finalized blocks. + This is a low-level approach for `transactionWatch_unstable_submitAndWatch`. + +crates: [ ] diff --git a/prdoc/pr_3154.prdoc b/prdoc/1.8.0/pr_3154.prdoc similarity index 100% rename from prdoc/pr_3154.prdoc rename to prdoc/1.8.0/pr_3154.prdoc diff --git a/prdoc/pr_3160.prdoc b/prdoc/1.8.0/pr_3160.prdoc similarity index 100% rename from prdoc/pr_3160.prdoc rename to prdoc/1.8.0/pr_3160.prdoc diff --git a/prdoc/pr_3166.prdoc b/prdoc/1.8.0/pr_3166.prdoc similarity index 100% rename from prdoc/pr_3166.prdoc rename to prdoc/1.8.0/pr_3166.prdoc diff --git a/prdoc/1.8.0/pr_3184.prdoc b/prdoc/1.8.0/pr_3184.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..36ba92bcf5a79ac75934f4fa08e1e02d78b6175e --- /dev/null +++ b/prdoc/1.8.0/pr_3184.prdoc @@ -0,0 +1,10 @@ +title: "Contracts: Remove no longer enforced limits from the Schedule" + +doc: + - audience: Runtime Dev + description: | + The limits are no longer in use and do nothing. Every builder overwritting them + can just adapt their code to remove them without any consequence. + +crates: + - name: pallet-contracts diff --git a/prdoc/pr_3212.prdoc b/prdoc/1.8.0/pr_3212.prdoc similarity index 100% rename from prdoc/pr_3212.prdoc rename to prdoc/1.8.0/pr_3212.prdoc diff --git a/prdoc/pr_3225.prdoc b/prdoc/1.8.0/pr_3225.prdoc similarity index 100% rename from prdoc/pr_3225.prdoc rename to prdoc/1.8.0/pr_3225.prdoc diff --git a/prdoc/1.8.0/pr_3230.prdoc b/prdoc/1.8.0/pr_3230.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e6d32f918d3911d691e90ff83fd6bc6695da4c25 --- /dev/null +++ b/prdoc/1.8.0/pr_3230.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: rpc server remove prometheus metrics `substrate_rpc_requests_started/finished` and refactor WS ping/pongs. + +doc: + - audience: Node Operator + description: | + This PR updates the rpc server library to `jsonrpsee v0.22` to utilize new APIs. + + Breaking changes: + - Remove prometheus RPC metrics `substrate_rpc_requests_started` and `substrate_rpc_requests_finished`. + - The RPC server now disconnects inactive peers that didn't acknowledge WebSocket + pings more than three times in time. + + Added: + - Add prometheus RPC `substrate_rpc_sessions_time` to collect the duration for each WebSocket + session. +crates: [ ] diff --git a/prdoc/1.8.0/pr_3232.prdoc b/prdoc/1.8.0/pr_3232.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c6a339931c6f56772e0fbaa3a4a8992e7b3050c9 --- /dev/null +++ b/prdoc/1.8.0/pr_3232.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: Validate code when scheduling uprades + +doc: + - audience: Runtime User + description: | + Adds checks to ensure that the validation code is valid before scheduling + a code upgrade. + +crates: + - name: polkadot-runtime-parachains diff --git a/prdoc/1.8.0/pr_3243.prdoc b/prdoc/1.8.0/pr_3243.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..5bad985a2672453b56ee3828483d7035b71d4b79 --- /dev/null +++ b/prdoc/1.8.0/pr_3243.prdoc @@ -0,0 +1,13 @@ +title: Don't fail fast if the weight limit of a cross contract call is too big + +doc: + - audience: Runtime Dev + description: | + Cross contracts calls will now be executed even if the supplied weight + limit is bigger than the reamining weight. If the **actual** weight is too low + they will fail in the cross contract call and roll back. This is different from the + old behaviour where the limit for the cross contract call must be smaller than + the remaining weight. + +crates: + - name: pallet-contracts diff --git a/prdoc/1.8.0/pr_3244.prdoc b/prdoc/1.8.0/pr_3244.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3d851c8afe0d2453a943caa1f0342d7ec76fe53c --- /dev/null +++ b/prdoc/1.8.0/pr_3244.prdoc @@ -0,0 +1,18 @@ +title: "Make the `benchmark pallet` command only require a Hasher" + +doc: + - audience: Node Dev + description: | + Currently the `benchmark pallet` command requires a `Block` type, while only using its hasher. + Now this is changed to only require the hasher. This means to use `HashingFor` in the + place where `Block` was required. + Example patch for your node with `cmd` being `BenchmarkCmd::Pallet(cmd)`: + + ```patch + - cmd.run::(config) + + cmd.run::, ()>(config) + ``` + +crates: + - name: sc-client-db + - name: frame-benchmarking-cli diff --git a/prdoc/1.8.0/pr_3272.prdoc b/prdoc/1.8.0/pr_3272.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a03113cf9739b741a37c5d8b4fb41dd59ede0d9f --- /dev/null +++ b/prdoc/1.8.0/pr_3272.prdoc @@ -0,0 +1,11 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Westend Coretime Runtime + +doc: + - audience: Runtime User + description: | + Add the Broker pallet to the Westend Coretime Chain runtime for the main functionality and sales to start. + +crates: [ ] diff --git a/prdoc/1.8.0/pr_3301.prdoc b/prdoc/1.8.0/pr_3301.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..19d1c5f1c18907cd1996603aade66990c358efeb --- /dev/null +++ b/prdoc/1.8.0/pr_3301.prdoc @@ -0,0 +1,11 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: rpc server add rate limiting. + +doc: + - audience: Node Operator + description: | + Add rate limiting for RPC server which can be utilized by the CLI `--rpc-rate-limit ` + The rate-limiting is disabled by default. +crates: [ ] diff --git a/prdoc/1.8.0/pr_3308.prdoc b/prdoc/1.8.0/pr_3308.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..386cbd6230b42144741f9a85490cddb009221ab2 --- /dev/null +++ b/prdoc/1.8.0/pr_3308.prdoc @@ -0,0 +1,14 @@ +title: "Parachains-Aura: Only produce once per slot" + +doc: + - audience: Node Dev + description: | + With the introduction of asynchronous backing the relay chain allows parachain to include blocks every 6 seconds. + The Cumulus Aura implementations, besides the lookahead collator, are building blocks when there is a free slot for + the parachain in the relay chain. Most parachains are still running with a 12s slot duration and not allowing + to build multiple blocks per slot. But, the block production logic will be triggered every 6s, resulting in error + logs like: "no space left for the block in the unincluded segment". This is solved by ensuring that we don't build + multiple blocks per slot. + +crates: + - name: "cumulus-client-consensus-aura" diff --git a/prdoc/1.8.0/pr_3319.prdoc b/prdoc/1.8.0/pr_3319.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b84ec25a22eda2a561fb44eb1e732a3c36921418 --- /dev/null +++ b/prdoc/1.8.0/pr_3319.prdoc @@ -0,0 +1,11 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add Coretime to Westend + +doc: + - audience: Runtime User + description: | + Add the on demand and coretime assigners and migrate from legacy parachain auctions to coretime. + +crates: [ ] diff --git a/prdoc/1.8.0/pr_3325.prdoc b/prdoc/1.8.0/pr_3325.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..eb8126dc912520c049f44fb760bb759caf6336f9 --- /dev/null +++ b/prdoc/1.8.0/pr_3325.prdoc @@ -0,0 +1,10 @@ +title: "Ensure `TracksInfo` tracks are sorted by ID." + +doc: + - audience: Runtime Dev + description: | + Add a `integrity_check` function to trait `TracksInfo` and explicitly state that tracks must + always be sorted by ID. The referenda pallet now also uses this check in its `integrity_test`. + +crates: + - name: pallet-referenda diff --git a/prdoc/1.8.0/pr_3358.prdoc b/prdoc/1.8.0/pr_3358.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b6a03b3872f4e7d24305dfd924ccb8424f6e39b2 --- /dev/null +++ b/prdoc/1.8.0/pr_3358.prdoc @@ -0,0 +1,11 @@ +title: Do not stall finality on spam disputes + +doc: + - audience: Node Operator + description: | + This PR fixes the issue that periodically caused + finality stalls on Kusama due to disputes happening + there in combination with disputes spam protection mechanism. + See: https://github.com/paritytech/polkadot-sdk/issues/3345 + +crates: [ ] diff --git a/prdoc/1.8.0/pr_3361.prdoc b/prdoc/1.8.0/pr_3361.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..65baa9e94a0e38a4af16bf6f69aab7526c4ad920 --- /dev/null +++ b/prdoc/1.8.0/pr_3361.prdoc @@ -0,0 +1,10 @@ +title: Fix double charge of host function weight + +doc: + - audience: Runtime Dev + description: | + Fixed a double charge which can lead to quadratic gas consumption of + the `call` and `instantiate` host functions. + +crates: + - name: pallet-contracts diff --git a/prdoc/1.8.0/pr_3364.prdoc b/prdoc/1.8.0/pr_3364.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1e7a6a5278d730a71a0bf5a928815812d8576386 --- /dev/null +++ b/prdoc/1.8.0/pr_3364.prdoc @@ -0,0 +1,12 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: rpc server expose batch request configuration + +doc: + - audience: Node Operator + description: | + Add functionality to limit RPC batch requests by two new CLI options: + --rpc-disable-batch-request - disable batch requests on the server + --rpc-max-batch-request-len - limit batches to LEN on the server +crates: [ ] diff --git a/prdoc/1.8.0/pr_3370.prdoc b/prdoc/1.8.0/pr_3370.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..f40d3821b9fed3eae49803128a9ff61058cd5d02 --- /dev/null +++ b/prdoc/1.8.0/pr_3370.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Remove `key` getter from pallet-sudo" + +doc: + - audience: Runtime Dev + description: | + Removed the `key` getter function from the sudo pallet. There is no replacement for getting + the key currently. + +crates: + - name: pallet-sudo diff --git a/prdoc/1.8.0/pr_3384.prdoc b/prdoc/1.8.0/pr_3384.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c19464977582a37b11760c81491a7ea7cf3ebced --- /dev/null +++ b/prdoc/1.8.0/pr_3384.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: "[pallet_contracts] stabilize `call_v2`, `instantiate_v2`, `lock_dependency` and `unlock_dependency`" + +doc: + - audience: Runtime Dev + description: | + These APIs are currently unstable and are being stabilized in this PR. + Note: `add_delegate_dependency` and `remove_delegate_dependency` have been renamed to `lock_dependency` and `unlock_dependency` respectively. + +crates: + - name: pallet-contracts-uapi + - name: pallet-contracts diff --git a/prdoc/1.8.0/pr_3395.prdoc b/prdoc/1.8.0/pr_3395.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..a10fb84fd7f56211602fadaf656a25ea5d382255 --- /dev/null +++ b/prdoc/1.8.0/pr_3395.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: "`benchmarking-cli` `pallet` subcommand: refactor `--list` and add `--all` option" + +doc: + - audience: Node Dev + description: | + `pallet` subcommand's `--list` now accepts two values: "all" and "pallets". The former will list all available benchmarks, the latter will list only pallets. + Also adds `--all` to run all the available benchmarks and `--no-csv-header` to omit the csv-style header in the output. + NOTE: changes are backward compatible. + +crates: + - name: frame-benchmarking-cli diff --git a/prdoc/1.8.0/pr_3415.prdoc b/prdoc/1.8.0/pr_3415.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c56a5d3ffaa129d4aba36e1e11905e9d72b936cb --- /dev/null +++ b/prdoc/1.8.0/pr_3415.prdoc @@ -0,0 +1,9 @@ +title: "[pallet-contracts] Add APIVersion to the config." + +doc: + - audience: Runtime Dev + description: | + Add `APIVersion` to the config to communicate the state of the Host functions exposed by the pallet. + +crates: + - name: pallet-contracts diff --git a/prdoc/1.8.0/pr_3435.prdoc b/prdoc/1.8.0/pr_3435.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..7d7896bff7d405a0a1dd34f09bc2aff0834b9ff2 --- /dev/null +++ b/prdoc/1.8.0/pr_3435.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: Fix BEEFY-related gossip messages error logs + +doc: + - audience: Node Operator + description: | + Added logic to pump the gossip engine while waiting for other things + to make sure gossiped messages get consumed (practically discarded + until worker is fully initialized). + This fixes an issue where node operators saw error logs, and fixes + potential RAM bloat when BEEFY initialization takes a long time + (i.e. during clean sync). +crates: + - name: sc-consensus-beefy diff --git a/prdoc/1.8.0/pr_3477.prdoc b/prdoc/1.8.0/pr_3477.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..26e96d3635b14634ca523797d741ddaf224aa9ae --- /dev/null +++ b/prdoc/1.8.0/pr_3477.prdoc @@ -0,0 +1,11 @@ +title: Allow parachain which acquires multiple coretime cores to make progress + +doc: + - audience: Node Operator + description: | + Adds the needed changes so that parachains which acquire multiple coretime cores can still make progress. + Only one of the cores will be able to be occupied at a time. + Only works if the ElasticScalingMVP node feature is enabled in the runtime and the block author validator is + updated to include this change. + +crates: [ ] diff --git a/prdoc/pr_1378.prdoc b/prdoc/pr_1378.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..6533dcb663030718fdcd3ffc353b2ae8b2a92407 --- /dev/null +++ b/prdoc/pr_1378.prdoc @@ -0,0 +1,27 @@ +title: Construct Runtime V2 - An outer macro approach to define the runtime + +doc: + - audience: Runtime Dev + description: | + Introduces `#[frame_support::runtime]` that can be attached to a mod to define a runtime. The items + in this mod can be attached to the following attributes to define the key components of the runtime. + 1. `#[runtime::runtime]` attached to a struct defines the main runtime + 2. `#[runtime::derive]` attached to the runtime struct defines the types generated by the runtime + 3. `#[runtime::pallet_index]` must be attached to a pallet to define its index + 4. `#[runtime::disable_call]` can be optionally attached to a pallet to disable its calls + 5. `#[runtime::disable_unsigned]` can be optionally attached to a pallet to disable unsigned calls + 6. A pallet instance can be defined as `TemplateModule: pallet_template` + An optional attribute can be defined as `#[frame_support::runtime(legacy_ordering)]` to ensure that + the order of hooks is same as the order of pallets (and not based on the pallet_index). This is to support + legacy runtimes and should be avoided for new ones. + +migrations: + db: [] + + runtime: [] + +crates: + - name: frame-support + - name: frame-support-procedural + +host_functions: [] diff --git a/prdoc/pr_1554.prdoc b/prdoc/pr_1554.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..bfce7c5edafd9df39ff9235f18536591b1d47158 --- /dev/null +++ b/prdoc/pr_1554.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: Runtime Upgrade ref docs and Single Block Migration example pallet + +doc: + - audience: Runtime Dev + description: | + `frame_support::traits::GetStorageVersion::current_storage_version` has been renamed `frame_support::traits::GetStorageVersion::in_code_storage_version`. + A simple find-replace is sufficient to handle this change. + +crates: + - name: "frame-support" + diff --git a/prdoc/pr_1781.prdoc b/prdoc/pr_1781.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e3560842d15ab249539ac2de172dc5914e92cc19 --- /dev/null +++ b/prdoc/pr_1781.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: "Multi-Block-Migrations, `poll` hook and new System Callbacks" + +doc: + - audience: Runtime Dev + description: | + The major things that this MR touches are: + + **Multi-Block-Migrations**: `pallet-migrations` is introduced that can be configured in the + `System` of a runtime to act as multi-block migrator. The `migrations` pallet then in turn + receives the list of MBMs as config parameter. The list of migrations can be an aggregated + tuple of `SteppedMigration` trait implementation. + It is paramount that the `migrations` pallet is configured in `System` once it is deployed. A + test is in place to double check this. + + To integrate this into your runtime, it is only necessary to change the return type of + `initialize_block` to `RuntimeExecutiveMode`. For extended info please see + https://github.com/paritytech/polkadot-sdk/pull/1781. + + **poll**: a new pallet hook named `poll` is added. This can be used for places where the code + that should be executed is not deadline critical. Runtime devs are advised to skim their usage + of `on_initialize` and `on_finalize` to see whether they can be replace with `poll`. `poll` is + not guaranteed to be called each block. In fact it will not be called when MBMs are ongoing. + + **System Callbacks**: The `system` pallet gets five new config items - all of which can be + safely set to `()` as default. They are: + - `SingleBlockMigrations`: replaces the `Executive` now for configuring migrations. + - `MultiBlockMigrator`: the `pallet-migrations` would be set here, if deployed. + - `PreInherents`: a hook that runs before any inherent. + - `PostInherents`: a hook to run between inherents and `poll`/MBM logic. + - `PostTransactions`: a hook to run after all transactions but before `on_idle`. + +crates: + - name: frame-executive + - name: frame-system + - name: frame-support + - name: frame-support-procedural + - name: pallet-migrations + - name: sc-basic-authorship + - name: sc-block-builder + - name: sp-api + - name: sp-api-proc-macro + - name: sp-runtime diff --git a/prdoc/pr_2280.prdoc b/prdoc/pr_2280.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3026dc254e64b4e97f847f010afab2b42e9647c5 --- /dev/null +++ b/prdoc/pr_2280.prdoc @@ -0,0 +1,144 @@ +# 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 Create `TransactionExtension` as a replacement for `SignedExtension` + +doc: + - audience: Runtime User + 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 passsed in to `prepare` using + the new user-specifiable type `Val`. + - Unsigned logic should be migrated from the old `*_unsigned` functions into the regular + versions of the new functions where the `Origin` is `None`. + - The `Call` type defining the runtime call is now a type parameter. + - `TransactionExtension` now takes a `Context` type parameter. This defines some arbitrary + contextual data that is injected into the transaction extension logic. It is unused in + instances migrated from `SignedExtension`. + - Extensions now track the weight they consume during valdiation, 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 + - name: bp-bridge-hub-cumulus + - name: bp-kusama + - name: bp-polkadot-bulletin + - name: bp-polkadot + - name: bp-rococo + - name: bp-westend + - name: bp-polkadot-core + - name: bp-runtime + - name: snowbridge-pallet-inbound-queue + - name: snowbridge-pallet-outbound-queue + - name: snowbridge-pallet-system + - name: snowbridge-runtime-test-common + - name: parachain-template-runtime + - name: asset-hub-rococo-runtime + - name: asset-hub-westend-runtime + - name: bridge-hub-rococo-runtime + - name: bridge-hub-westend-runtime + - name: collectives-westend-runtime + - name: contracts-rococo-runtime + - name: coretime-rococo-runtime + - name: coretime-westend-runtime + - name: glutton-westend-runtime + - name: people-rococo-runtime + - name: people-westend-runtime + - name: seedling-runtime + - name: shell-runtime + - name: penpal-runtime + - name: rococo-parachain-runtime + - name: polkadot-parachain-bin + - name: cumulus-primitives-storage-weight-reclaim + - name: cumulus-test-client + - name: cumulus-test-runtime + - name: cumulus-test-service + - name: polkadot-sdk-docs + - name: polkadot-service + - name: polkadot-test-service + - name: polkadot-runtime-common + - name: rococo-runtime + - name: polkadot-test-runtime + - name: westend-runtime + - name: staging-xcm-builder + - name: minimal-runtime + - name: node-template + - name: node-template-runtime + - name: staging-node-cli + - name: kitchensink-runtime + - name: node-testing + - name: sc-client-api + - name: sc-client-db + - name: sc-network-gossip + - name: sc-network-sync + - name: sc-transaction-pool + - name: frame + - name: pallet-babe + - name: pallet-balances + - name: pallet-beefy + - name: pallet-collective + - name: pallet-election-provider-multi-phase + - name: pallet-elections-phragmen + - name: pallet-example-basic + - name: pallet-example-offchain-worker + - name: frame-executive + - name: pallet-grandpa + - name: pallet-im-online + - name: pallet-offences + - name: pallet-sassafras + - name: pallet-state-trie-migration + - name: pallet-sudo + - name: frame-support-procedural + - name: frame-support + - name: frame-system + - name: frame-system-benchmarking + - name: pallet-transaction-payment + - name: pallet-asset-conversion-tx-payment + - name: pallet-asset-tx-payment + - name: pallet-skip-feeless-payment + - name: sp-inherents + - name: sp-metadata-ir + - name: sp-runtime + - name: substrate-test-runtime + - name: frame-benchmarking-cli + - name: frame-remote-externalities + - name: substrate-rpc-client diff --git a/prdoc/pr_2393.prdoc b/prdoc/pr_2393.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..708d017fafd50d103c0470997c3a7571e0ff30c1 --- /dev/null +++ b/prdoc/pr_2393.prdoc @@ -0,0 +1,16 @@ +title: "[XCMP] Use the number of 'ready' pages in XCMP suspend logic" + +doc: + - audience: Runtime Dev + description: | + Semantics of the suspension logic in the XCMP queue pallet change from using the number of + total pages to the number of 'ready' pages. The number of ready pages is now also exposed by + the `MessageQueue` pallet to downstream via the queue `footprint`. + +crates: + - name: cumulus-pallet-xcmp-queue + bump: patch + - name: pallet-message-queue + bump: patch + - name: frame-support + bump: major diff --git a/prdoc/pr_3002.prdoc b/prdoc/pr_3002.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..511a07e39c47d5055bd161fda0e748f96e4a9997 --- /dev/null +++ b/prdoc/pr_3002.prdoc @@ -0,0 +1,29 @@ +# 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: PoV Reclaim Runtime Side +author: skunert +topic: runtime +doc: + - audience: Runtime Dev + description: | + Adds a mechanism to reclaim proof size weight. + 1. Introduces a new `SignedExtension` that reclaims the difference + between benchmarked proof size weight and actual consumed proof size weight. + 2. Introduces a manual mechanism, `StorageWeightReclaimer`, to reclaim excess storage weight for situations + that require manual weight management. The most prominent case is the `on_idle` hook. + 3. Adds the `storage_proof_size` host function to the PVF. Parachain nodes should add it to ensure compatibility. + + To enable proof size reclaiming, add the host `storage_proof_size` host function to the parachain node. Add the + `StorageWeightReclaim` `SignedExtension` to your runtime and enable proof recording during block import. + + +crates: + - name: "cumulus-primitives-storage-weight-reclaim" +host_functions: + - name: "storage_proof_size" + description: | + This host function is used to pass the current size of the storage proof to the runtime. + It was introduced before but becomes relevant now. + Note: This host function is intended to be used through `cumulus_primitives_storage_weight_reclaim::get_proof_size`. + Direct usage is not recommended. diff --git a/prdoc/pr_3187.prdoc b/prdoc/pr_3187.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..bda41142d86c8f9c1af8398e0cf21cdfeebebfa7 --- /dev/null +++ b/prdoc/pr_3187.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: Retrying an execution on failed runtime construction + +doc: + - audience: Node Dev + description: | + If a runtime construction error happened during the execution request, then the artifact is re-prepared + and the execution request is retried at most once. See also the related issue. + +crates: + - name: polkadot-node-core-candidate-validation + - name: polkadot-node-core-pvf + - name: polkadot-node-core-pvf-execute-worker + - name: polkadot-node-core-pvf-common diff --git a/prdoc/pr_3231.prdoc b/prdoc/pr_3231.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..26e96d3635b14634ca523797d741ddaf224aa9ae --- /dev/null +++ b/prdoc/pr_3231.prdoc @@ -0,0 +1,11 @@ +title: Allow parachain which acquires multiple coretime cores to make progress + +doc: + - audience: Node Operator + description: | + Adds the needed changes so that parachains which acquire multiple coretime cores can still make progress. + Only one of the cores will be able to be occupied at a time. + Only works if the ElasticScalingMVP node feature is enabled in the runtime and the block author validator is + updated to include this change. + +crates: [ ] diff --git a/prdoc/pr_3233.prdoc b/prdoc/pr_3233.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..ed4e8cce31f75b4bd98f91f7d15ec3fae0761354 --- /dev/null +++ b/prdoc/pr_3233.prdoc @@ -0,0 +1,12 @@ +title: "provisioner: allow multiple cores assigned to the same para" + +topic: Node + +doc: + - audience: Node Dev + description: | + Enable supplying multiple backable candidates to the paras_inherent pallet for the same paraid. + +crates: + - name: polkadot-node-core-prospective-parachains + - name: polkadot-node-core-provisioner diff --git a/prdoc/pr_3324.prdoc b/prdoc/pr_3324.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..0425fbf317c8620125e9fe64f96a0eb99e4595f0 --- /dev/null +++ b/prdoc/pr_3324.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: "Fix weight calculation and event emission in pallet-membership" + +doc: + - audience: Runtime Dev + description: | + Bug fix for the membership pallet to use correct weights. Also no event will be emitted + anymore when `change_key` is called with identical accounts. + +crates: + - name: pallet-membership diff --git a/prdoc/pr_3371.prdoc b/prdoc/pr_3371.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..605d540772f0b249962088463237dda2e6690d6c --- /dev/null +++ b/prdoc/pr_3371.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: removed `pallet::getter` from example pallets + +doc: + - audience: Runtime Dev + description: | + This PR removes all the `pallet::getter` usages from the template pallets found in the Substrate and Cumulus template nodes, and from the Substrate example pallets. + The purpose is to discourage developers to use this macro, that is currently being removed and soon will be deprecated. + +crates: + - name: pallet-template + - name: pallet-parachain-template + - name: pallet-example-basic + - name: pallet-example-kitchensink + - name: pallet-example-offchain-worker + - name: pallet-example-split + diff --git a/prdoc/pr_3377.prdoc b/prdoc/pr_3377.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..8e5b3935512b1b2dd12836e940a5d95040df8cf2 --- /dev/null +++ b/prdoc/pr_3377.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: Permissioned contract deployment + +doc: + - audience: Runtime Dev + description: | + This PR introduces two new config types that specify the origins allowed to + upload and instantiate contract code. However, this check is not enforced when + a contract instantiates another contract. + +crates: +- name: pallet-contracts diff --git a/prdoc/pr_3378.prdoc b/prdoc/pr_3378.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2470fc158519e31e297a7cbefcae3bc54eb8f708 --- /dev/null +++ b/prdoc/pr_3378.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove deprecated GenesisConfig + +doc: + - audience: Runtime Dev + description: | + Removes deprecated type `GenesisConfig`, it was replaced by `RuntimeGenesisConfig` on May 24 of 2023. + The type `GenesisConfig` was deprecated on May 24 of 2023 [#14210](https://github.com/paritytech/substrate/pull/14210) + +crates: + - name: frame-support-procedural \ No newline at end of file diff --git a/prdoc/pr_3403.prdoc b/prdoc/pr_3403.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..086e769da3c39c4d3def42791c18a82948676386 --- /dev/null +++ b/prdoc/pr_3403.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: "Add `claim_assets` extrinsic to `pallet-xcm`" + +doc: + - audience: Runtime User + description: | + There's a new extrinsic in `pallet-xcm` for claiming assets. + This means that if your assets ever get trapped while teleporting or doing reserve asset transfers, + you can easily claim them by calling this new extrinsic. + - audience: Runtime Dev + description: | + There's a new extrinsic in `pallet-xcm` that needs a new configuration item for its benchmarks. + It's a simple function in `pallet_xcm::benchmarking::Config`, `get_asset`, that returns a valid asset + handled by the AssetTransactor of the chain. + If you're already using `pallet-xcm-benchmarks`, then you already have this function there and can + just copy and paste it. + +crates: + - name: pallet-xcm + - name: staging-xcm diff --git a/prdoc/pr_3411.prdoc b/prdoc/pr_3411.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d847d6756ac7f019cf12e4d9e7993ebeda1273ab --- /dev/null +++ b/prdoc/pr_3411.prdoc @@ -0,0 +1,11 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: add Encointer as trusted teleporter for Westend + +doc: + - audience: Runtime Dev + description: | + add Encointer as trusted teleporter for Westend with ParaId 1003 + +crates: [ ] diff --git a/prdoc/pr_3412.prdoc b/prdoc/pr_3412.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1ee6edfeb837f81646d32633ed009d2cded4dcfe --- /dev/null +++ b/prdoc/pr_3412.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: "[FRAME] Add genesis test and remove some checks" + +doc: + - audience: Runtime Dev + description: | + The construct_runtime macro now generates a test to assert that all `GenesisConfig`s of all + pallets can be build within the runtime. This ensures that the `BuildGenesisConfig` runtime + API works. + Further, some checks from a few pallets were removed to make this pass. + +crates: + - name: pallet-babe + - name: cumulus-pallet-aura-ext + - name: pallet-session diff --git a/prdoc/pr_3447.prdoc b/prdoc/pr_3447.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1d8d4f409f77cf29247d35d196bccff390896881 --- /dev/null +++ b/prdoc/pr_3447.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: Use generic hash for runtime wasm in resolve_state_version_from_wasm + +doc: + - audience: Node Dev + description: | + Changes the runtime hash algorithm used in resolve_state_version_from_wasm from DefaultHasher to a caller-provided + one (usually HashingFor). Fixes a bug where the runtime wasm was being compiled again when it was not + needed, because the hash did not match +crates: + - name: sc-chain-spec diff --git a/prdoc/pr_3453.prdoc b/prdoc/pr_3453.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1f01440f722fb9984231f690a20c517b9d4bf0a1 --- /dev/null +++ b/prdoc/pr_3453.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: "[pallet-nomination-pools]: `chill` is permissionless if depositor's stake is less than `min_nominator_bond`" + +doc: + - audience: Runtime Dev + description: | + Nomination pools currently have an issue whereby member funds cannot be unbonded if the depositor bonded amount is less than `MinNominatorBond`. + This PR makes the `chill` function permissionless if this condition is met. + Consequently, `nominate` function also checks for `depositor` to have at least `MinNominatorBond`, and returns `MinimumBondNotMet` error if not. +crates: + - name: pallet-nomination-pools diff --git a/prdoc/pr_3454.prdoc b/prdoc/pr_3454.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..7f564258f23a57f3784c2ee055176153f006734f --- /dev/null +++ b/prdoc/pr_3454.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: "Introduce storage attr macro #[disable_try_decode_storage] and set it on System::Events and ParachainSystem::HostConfiguration" + +doc: + - audience: Runtime Dev + description: | + Allows marking storage items with \#[disable_try_decode_storage], which disables that storage item from being decoded + during try_decode_entire_state calls. + + Applied the attribute to System::Events to close https://github.com/paritytech/polkadot-sdk/issues/2560. + Applied the attribute to ParachainSystem::HostConfiguration to resolve periodic issues with it. + +crates: + - name: frame-support-procedural + - name: frame-system + - name: cumulus-pallet-parachain-system + diff --git a/prdoc/pr_3456.prdoc b/prdoc/pr_3456.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c7327e17e57d74614fd1b593cc222faf4a87192d --- /dev/null +++ b/prdoc/pr_3456.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: Removed `pallet::getter` usage from `pallet-collective` + +doc: + - audience: Runtime Dev + description: | + This PR removes `pallet::getter` usage from `pallet-collective`, and updates dependant code accordingly. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-collective + - name: kitchensink-runtime + - name: collectives-westend-runtime diff --git a/prdoc/pr_3460.prdoc b/prdoc/pr_3460.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1f16fe0890836dd25bfcaa75d5fc647688230dd8 --- /dev/null +++ b/prdoc/pr_3460.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: Repot all templates + +doc: + - audience: Runtime Dev + description: | + This PR moves all templates into a single folder in the polkadot-sdk repo (`/templates`) and + unifies their crate names as well. Most notably, the crate name for what was formerly known + as `node-template` is no `solochain-template-node`. The other two crates in the template are + consequently called: `solochain-runtime-template` and `pallet-solochain-template`. + The other two template crate names follow a similar patter, just replacing `solochain` with + `parachain` or `minimal`. + + This PR is part of a bigger step toward automating the template repositories, see the + following: https://github.com/paritytech/polkadot-sdk/issues/3155 + +# the following crates are removed and renamed, although none are released. +crates: + - name: minimal-template-runtime # formerly called minimal-runtime + - name: minimal-template-node # formerly called minimal-node + - name: solochain-template-node # formerly called node-template + - name: solochain-template-runtime # formerly called node-template-runtime + - name: parachain-template-runtime # formerly called parachain-runtime + - name: parachain-template-runtime # formerly called parachain-node diff --git a/prdoc/pr_3491.prdoc b/prdoc/pr_3491.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e36afb916a6226c3609b1e2eb8aacf6af8127d32 --- /dev/null +++ b/prdoc/pr_3491.prdoc @@ -0,0 +1,12 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove Deprecated OldWeight + +doc: + - audience: Runtime Dev + description: | + Removed deprecated sp_weights::OldWeight type. Use [`weight_v2::Weight`] instead. + +crates: + - name: frame-support diff --git a/prdoc/pr_3504.prdoc b/prdoc/pr_3504.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..90a8ddd38b8f7f8159199ac6423ffee3dc645291 --- /dev/null +++ b/prdoc/pr_3504.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 prometheus label "is_rate_limited" to rpc calls + +doc: + - audience: Node Operator + description: | + This PR adds a label "is_rate_limited" to the prometheus metrics "substrate_rpc_calls_time" and "substrate_rpc_calls_finished" + than can be used to distinguish rate-limited RPC calls from other RPC calls. Because rate-limited RPC calls may take + tens of seconds. + +crates: [ ] diff --git a/prdoc/pr_3505.prdoc b/prdoc/pr_3505.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..08ad909739c7d761371e0e1e40d575794fc4e217 --- /dev/null +++ b/prdoc/pr_3505.prdoc @@ -0,0 +1,36 @@ +# 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: Removes `as [disambiguation_path]` from the required syntax in `derive_impl` + +doc: + - audience: Runtime Dev + description: | + This PR removes the need to specify `as [disambiguation_path]` for cases where the trait + definition resides within the same scope as default impl path. + + For example, in the following macro invocation + ```rust + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + ... + } + ``` + the trait `DefaultConfig` lies within the `frame_system` scope and `TestDefaultConfig` impls + the `DefaultConfig` trait. + + Using this information, we can compute the disambiguation path internally, thus removing the + need of an explicit specification: + ```rust + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] + impl frame_system::Config for Runtime { + ... + } + ``` + + In cases where the trait lies outside this scope, we would still need to specify it explicitly, + but this should take care of most (if not all) uses of `derive_impl` within FRAME's context. + +crates: + - name: frame-support-procedural + - name: pallet-default-config-example diff --git a/prdoc/pr_3510.prdoc b/prdoc/pr_3510.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..6ee2f9a81f750ef0c64a2b8d8197e1e44d7e9f0c --- /dev/null +++ b/prdoc/pr_3510.prdoc @@ -0,0 +1,13 @@ +title: "Fix multi-collator parachain transition to async backing" + +doc: + - audience: Node Operator + description: | + The dynamic Aura slot duration, introduced in PR#3211, didn't take the block import pipeline + into account. The result was the parachain backed by multiple collators not being able to + keep producing blocks after its runtime was upgraded to support async backing, requiring to + restart all the collator nodes. This change fixes the issue, introducing the dynamic Aura + slot duration into the block import pipeline. + +crates: + - name: "polkadot-parachain-bin" diff --git a/prdoc/pr_3513.prdoc b/prdoc/pr_3513.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e1f2afe280a5bc2e8d341f9ab5ac73315f1676e8 --- /dev/null +++ b/prdoc/pr_3513.prdoc @@ -0,0 +1,18 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Fix call enum's metadata regression + +doc: + - audience: Runtime Dev + - audience: Runtime User + description: | + This PR fixes an issue where in the metadata of all FRAME-based chains, the documentation for + all extrinsic/call/transactions has been replaced by a single line saying "see Pallet::name". + + Many wallets display the metadata of transactions to the user before signing, and this bug + might have affected this process. + +crates: + - name: frame + - name: frame-support diff --git a/prdoc/pr_3523.prdoc b/prdoc/pr_3523.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c31d9d096dc00797254f7946fd44984636cb1547 --- /dev/null +++ b/prdoc/pr_3523.prdoc @@ -0,0 +1,19 @@ +title: Fix crash of synced parachain node run with `--sync=warp` + +doc: + - audience: Node Operator + description: | + Fix crash of `SyncingEngine` when an already synced parachain node is run with `--sync=warp` + (issue https://github.com/paritytech/polkadot-sdk/issues/3496). + The issue manifests itself by errors in the logs: + ``` + [Parachain] Cannot set warp sync target block: no warp sync strategy is active. + [Parachain] Failed to set warp sync target block header, terminating `SyncingEngine`. + ``` + Followed by a stream of messages: + ``` + [Parachain] Protocol command streams have been shut down + ``` + +crates: + - name: sc-network-sync diff --git a/prdoc/pr_3532.prdoc b/prdoc/pr_3532.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d47c8d1d49156aca4ac1b7683ee7fbd9d8e9e690 --- /dev/null +++ b/prdoc/pr_3532.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove deprecated `trait Store` + +doc: + - audience: Runtime Dev + description: | + The deprecated `trait Store` feature has been removed from the codebase. Please remove usages of `generate_store` + macro from your pallets and access the storage through generics. For example, + `::StoredRange::mutate` will need to be updated to `StoredRange::::mutate`. + +crates: + - name: frame-support + - name: frame \ No newline at end of file diff --git a/prdoc/pr_3540.prdoc b/prdoc/pr_3540.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d0a91882b6bf4e357fde899c2d939ddb7de62f34 --- /dev/null +++ b/prdoc/pr_3540.prdoc @@ -0,0 +1,10 @@ +title: "[pallet-contracts] Only allow non-deterministic code to be uploaded with Determinism::Relaxed" + +doc: + - audience: Runtime Dev + description: | + The `upload_code` extrinsic, will now only allow non-deterministic code to be uploaded with the `Determinism::Relaxed` flag. + This prevent an attacker from uploading "deterministic" code with the `Determinism::Relaxed` flag, preventing the code to be instantiated for on-chain execution. + +crates: + - name: pallet-contracts diff --git a/prdoc/pr_3574.prdoc b/prdoc/pr_3574.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..99868ea8a132a6440b9daff0d9f7deaa329ca4b3 --- /dev/null +++ b/prdoc/pr_3574.prdoc @@ -0,0 +1,23 @@ +title: Generate test functions for each benchmark with benchmarking v2 + +doc: + - audience: Runtime Dev + description: | + This PR fixes an issue where using `impl_benchmark_test_suite` macro + within modules that use the benchmarking v2 macros (`#[benchmarks]` + and `#[instance_benchmarks]`) always produced a single test called + `test_benchmarks` instead of a separate benchmark test for every + benchmark (noted with the `#[benchmark]` macro). + + By using this macro from now on, new tests will be created named + `test_benchmark_{name}` where `name` is the name of the benchmark + function. Those tests will be nested inside the module intended for + benchmark functions. + + Also, when using `impl_benchmark_test_suite` inside the module, + the import of such marco will not be necessary, so any explicit + import of it will be marked as unused, the same way it works for + v1 macros so far. + +crates: + - name: frame-support-procedural diff --git a/prdoc/pr_3589.prdoc b/prdoc/pr_3589.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..98b9b1039ab49f1dc62580d56327bf7944ed3372 --- /dev/null +++ b/prdoc/pr_3589.prdoc @@ -0,0 +1,10 @@ +title: Removed `pallet::getter` usage from `pallet-im-online` + +doc: + - audience: Runtime Dev + description: | + This PR removes `pallet::getter` usage from `pallet-im-online`, and updates dependant code accordingly. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-im-online diff --git a/prdoc/pr_3606.prdoc b/prdoc/pr_3606.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..18b71de9477ea516de2bcd5ecfab52a6a5479afb --- /dev/null +++ b/prdoc/pr_3606.prdoc @@ -0,0 +1,9 @@ +title: "[pallet_contracts] mark lock/unlock_delegate_dependency as stable" + +doc: + - audience: Runtime Dev + description: | + Lock and unlock delegate dependency are stable now, so we can mark them as such. + +crates: + - name: pallet-contracts diff --git a/prdoc/pr_3636.prdoc b/prdoc/pr_3636.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..934158ac1022dc14309696bea43492db8f7a0e88 --- /dev/null +++ b/prdoc/pr_3636.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: "[pallet_broker] Fix `Linear::adapt_price` behavior at zero" + +doc: + - audience: Runtime Dev + description: | + This fixes the behaviour of `Linear` which is the default implementation of the `AdaptPrice` + trait in the broker pallet. Previously if cores were offered but not sold in only one sale, + the price would be set to zero and due to the logic being purely multiplicative, the price + would stay at 0 indefinitely. + +crates: + - name: pallet-broker diff --git a/prdoc/pr_3643.prdoc b/prdoc/pr_3643.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..6e85af8d99a07f397ce03d4b7c936f7560f36c8f --- /dev/null +++ b/prdoc/pr_3643.prdoc @@ -0,0 +1,12 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Fix weight refund for `pallet_collator_selection::set_candidacy_bond` + +doc: + - audience: Runtime Dev + description: | + This PR implements the weight refund of `pallet_collator_selection::set_candidacy_bond` to + account for no iterations over the candidate list when the candidacy bond is decreased. +crates: + - name: pallet-collator-selection diff --git a/prdoc/schema_user.json b/prdoc/schema_user.json index 82215d51866b35895b5e840a8f3a900b161a9cf6..1bd0b3b93ee45ea75d9781ef1485898dd86c7ff3 100644 --- a/prdoc/schema_user.json +++ b/prdoc/schema_user.json @@ -3,9 +3,8 @@ "$id": "https://raw.githubusercontent.com/paritytech/prdoc/master/prdoc_schema_user.json", "version": { "major": 1, - "minor": 0, - "patch": 0, - "timestamp": 20230817152351 + "minor": 1, + "patch": 0 }, "title": "Polkadot SDK PRDoc Schema", "description": "JSON Schema definition for the Polkadot SDK PR documentation", @@ -125,10 +124,16 @@ "name": { "type": "string" }, + "bump": { + "$ref": "#/$defs/semver_bump" + }, "note": { "type": "string" } - } + }, + "required": [ + "name" + ] }, "migration_db": { "type": "object", @@ -165,6 +170,26 @@ "description" ] }, + "semver_bump": { + "description": "The type of bump to apply to the crate version according to Cargo SemVer: https://doc.rust-lang.org/cargo/reference/semver.html. Please check docs/RELEASE.md for more information.", + "oneOf": [ + { + "const": "major", + "title": "Major", + "description": "A bump to the leftmost non-zero digit of the version number." + }, + { + "const": "minor", + "title": "Minor", + "description": "A bump to the second leftmost non-zero digit of the version number." + }, + { + "const": "patch", + "title": "Patch", + "description": "A bump to the third leftmost non-zero digit of the version number." + } + ] + }, "doc": { "type": "object", "description": "You have the the option to provide different description of your PR for different audiences.", diff --git a/substrate/.maintain/frame-weight-template.hbs b/substrate/.maintain/frame-weight-template.hbs index ecd384a514563cfb4ecb0e9f364cdf473f5b5cec..ec9eee205cee37b534eca5187ece031daa54dd99 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/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml deleted file mode 100644 index 34476a72954dd31e98cbb56f266ebba447a46513..0000000000000000000000000000000000000000 --- a/substrate/bin/minimal/node/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "minimal-node" -version = "4.0.0-dev" -description = "A fresh FRAME-based Substrate node, ready for hacking." -authors = ["Substrate DevHub "] -homepage = "https://substrate.io/" -edition = "2021" -license = "MIT-0" -publish = false -repository = "https://github.com/substrate-developer-hub/substrate-node-template/" -build = "build.rs" - -[lints] -workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[[bin]] -name = "minimal-node" - -[dependencies] -clap = { version = "4.4.18", features = ["derive"] } -futures = { version = "0.3.21", features = ["thread-pool"] } -futures-timer = "3.0.1" -jsonrpsee = { version = "0.20.3", features = ["server"] } -serde_json = "1.0.111" - -sc-cli = { path = "../../../client/cli" } -sc-executor = { path = "../../../client/executor" } -sc-network = { path = "../../../client/network" } -sc-service = { path = "../../../client/service" } -sc-telemetry = { path = "../../../client/telemetry" } -sc-transaction-pool = { path = "../../../client/transaction-pool" } -sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } -sc-consensus = { path = "../../../client/consensus/common" } -sc-consensus-manual-seal = { path = "../../../client/consensus/manual-seal" } -sc-rpc-api = { path = "../../../client/rpc-api" } -sc-basic-authorship = { path = "../../../client/basic-authorship" } -sc-offchain = { path = "../../../client/offchain" } -sc-client-api = { path = "../../../client/api" } - -sp-timestamp = { path = "../../../primitives/timestamp" } -sp-keyring = { path = "../../../primitives/keyring" } -sp-api = { path = "../../../primitives/api" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-block-builder = { path = "../../../primitives/block-builder" } -sp-io = { path = "../../../primitives/io" } -sp-runtime = { path = "../../../primitives/runtime" } - -substrate-frame-rpc-system = { path = "../../../utils/frame/rpc/system" } - -frame = { path = "../../../frame", features = ["experimental", "runtime"] } -runtime = { package = "minimal-runtime", path = "../runtime" } - -[build-dependencies] -substrate-build-script-utils = { path = "../../../utils/build-script-utils" } - -[features] -default = [] diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml deleted file mode 100644 index 296106544bbfdbbb1f7f76b86d5c8ddefb54f917..0000000000000000000000000000000000000000 --- a/substrate/bin/minimal/runtime/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -[package] -name = "minimal-runtime" -version = "0.1.0" -authors.workspace = true -description = "A minimal Substrate example runtime" -edition.workspace = true -repository.workspace = true -license.workspace = true -publish = false - -[lints] -workspace = true - -[dependencies] -parity-scale-codec = { version = "3.0.0", default-features = false } -scale-info = { version = "2.6.0", default-features = false } - -# this is a frame-based runtime, thus importing `frame` with runtime feature enabled. -frame = { path = "../../../frame", default-features = false, features = ["experimental", "runtime"] } -frame-support = { path = "../../../frame/support", default-features = false } - -# pallets that we want to use -pallet-balances = { path = "../../../frame/balances", default-features = false } -pallet-sudo = { path = "../../../frame/sudo", default-features = false } -pallet-timestamp = { path = "../../../frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false } - -# genesis builder that allows us to interacto with runtime genesis config -sp-genesis-builder = { path = "../../../primitives/genesis-builder", default-features = false } - - -[build-dependencies] -substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } - -[features] -default = ["std"] -std = [ - "frame-support/std", - "frame/std", - "pallet-balances/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "parity-scale-codec/std", - "scale-info/std", - "sp-genesis-builder/std", - "substrate-wasm-builder", -] diff --git a/substrate/bin/node-template/.editorconfig b/substrate/bin/node-template/.editorconfig deleted file mode 100644 index 5adac74ca24b3422222b2cb886b2a50cd22b6d1b..0000000000000000000000000000000000000000 --- a/substrate/bin/node-template/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -root = true - -[*] -indent_style=space -indent_size=2 -tab_width=2 -end_of_line=lf -charset=utf-8 -trim_trailing_whitespace=true -insert_final_newline = true - -[*.{rs,toml}] -indent_style=tab -indent_size=tab -tab_width=4 -max_line_length=100 diff --git a/substrate/bin/node-template/.envrc b/substrate/bin/node-template/.envrc deleted file mode 100644 index 3550a30f2de389e537ee40ca5e64a77dc185c79b..0000000000000000000000000000000000000000 --- a/substrate/bin/node-template/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml deleted file mode 100644 index da601a665e9c33bf923bf1f3b32e630a5daeef39..0000000000000000000000000000000000000000 --- a/substrate/bin/node-template/node/Cargo.toml +++ /dev/null @@ -1,92 +0,0 @@ -[package] -name = "node-template" -version = "4.0.0-dev" -description = "A fresh FRAME-based Substrate node, ready for hacking." -authors = ["Substrate DevHub "] -homepage = "https://substrate.io/" -edition.workspace = true -license = "MIT-0" -publish = false -repository = "https://github.com/substrate-developer-hub/substrate-node-template/" -build = "build.rs" - -[lints] -workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[[bin]] -name = "node-template" - -[dependencies] -clap = { version = "4.4.18", features = ["derive"] } -futures = { version = "0.3.21", features = ["thread-pool"] } -serde_json = "1.0.111" - -sc-cli = { path = "../../../client/cli" } -sp-core = { path = "../../../primitives/core" } -sc-executor = { path = "../../../client/executor" } -sc-network = { path = "../../../client/network" } -sc-service = { path = "../../../client/service" } -sc-telemetry = { path = "../../../client/telemetry" } -sc-transaction-pool = { path = "../../../client/transaction-pool" } -sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } -sc-offchain = { path = "../../../client/offchain" } -sc-consensus-aura = { path = "../../../client/consensus/aura" } -sp-consensus-aura = { path = "../../../primitives/consensus/aura" } -sc-consensus = { path = "../../../client/consensus/common" } -sc-consensus-grandpa = { path = "../../../client/consensus/grandpa" } -sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa" } -sc-client-api = { path = "../../../client/api" } -sp-runtime = { path = "../../../primitives/runtime" } -sp-io = { path = "../../../primitives/io" } -sp-timestamp = { path = "../../../primitives/timestamp" } -sp-inherents = { path = "../../../primitives/inherents" } -sp-keyring = { path = "../../../primitives/keyring" } -frame-system = { path = "../../../frame/system" } -pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } - -# These dependencies are used for the node template's RPCs -jsonrpsee = { version = "0.20.3", features = ["server"] } -sp-api = { path = "../../../primitives/api" } -sc-rpc-api = { path = "../../../client/rpc-api" } -sp-blockchain = { path = "../../../primitives/blockchain" } -sp-block-builder = { path = "../../../primitives/block-builder" } -sc-basic-authorship = { path = "../../../client/basic-authorship" } -substrate-frame-rpc-system = { path = "../../../utils/frame/rpc/system" } -pallet-transaction-payment-rpc = { path = "../../../frame/transaction-payment/rpc" } - -# These dependencies are used for runtime benchmarking -frame-benchmarking = { path = "../../../frame/benchmarking" } -frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli" } - -# Local Dependencies -node-template-runtime = { path = "../runtime" } - -# CLI-specific dependencies -try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true } - -[build-dependencies] -substrate-build-script-utils = { path = "../../../utils/build-script-utils" } - -[features] -default = [] -# Dependencies that are only required if runtime benchmarking should be build. -runtime-benchmarks = [ - "frame-benchmarking-cli/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "node-template-runtime/runtime-benchmarks", - "sc-service/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] -# Enable features that allow the runtime to be tried and debugged. Name might be subject to change -# in the near future. -try-runtime = [ - "frame-system/try-runtime", - "node-template-runtime/try-runtime", - "pallet-transaction-payment/try-runtime", - "sp-runtime/try-runtime", - "try-runtime-cli/try-runtime", -] diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml deleted file mode 100644 index a7b93a230ca85dd0b400884b4788a50d24db0402..0000000000000000000000000000000000000000 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ /dev/null @@ -1,125 +0,0 @@ -[package] -name = "node-template-runtime" -version = "4.0.0-dev" -description = "A fresh FRAME-based Substrate node, ready for hacking." -authors = ["Substrate DevHub "] -homepage = "https://substrate.io/" -edition.workspace = true -license = "MIT-0" -publish = false -repository = "https://github.com/substrate-developer-hub/substrate-node-template/" - -[lints] -workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } - -pallet-aura = { path = "../../../frame/aura", default-features = false } -pallet-balances = { path = "../../../frame/balances", default-features = false } -frame-support = { path = "../../../frame/support", default-features = false } -pallet-grandpa = { path = "../../../frame/grandpa", default-features = false } -pallet-sudo = { path = "../../../frame/sudo", default-features = false } -frame-system = { path = "../../../frame/system", default-features = false } -frame-try-runtime = { path = "../../../frame/try-runtime", default-features = false, optional = true } -pallet-timestamp = { path = "../../../frame/timestamp", default-features = false } -pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false } -frame-executive = { path = "../../../frame/executive", default-features = false } -sp-api = { path = "../../../primitives/api", default-features = false } -sp-block-builder = { path = "../../../primitives/block-builder", default-features = false } -sp-consensus-aura = { path = "../../../primitives/consensus/aura", default-features = false, features = ["serde"] } -sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features = ["serde"] } -sp-core = { path = "../../../primitives/core", default-features = false, features = ["serde"] } -sp-inherents = { path = "../../../primitives/inherents", default-features = false } -sp-offchain = { path = "../../../primitives/offchain", default-features = false } -sp-runtime = { path = "../../../primitives/runtime", default-features = false, features = ["serde"] } -sp-session = { path = "../../../primitives/session", default-features = false } -sp-std = { path = "../../../primitives/std", default-features = false } -sp-storage = { path = "../../../primitives/storage", default-features = false } -sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false } -sp-version = { path = "../../../primitives/version", default-features = false, features = ["serde"] } -serde_json = { version = "1.0.111", default-features = false, features = ["alloc"] } -sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" } - -# Used for the node template's RPCs -frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false } - -# Used for runtime benchmarking -frame-benchmarking = { path = "../../../frame/benchmarking", default-features = false, optional = true } -frame-system-benchmarking = { path = "../../../frame/system/benchmarking", default-features = false, optional = true } - -# Local Dependencies -pallet-template = { path = "../pallets/template", default-features = false } - -[build-dependencies] -substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-benchmarking?/std", - "frame-executive/std", - "frame-support/std", - "frame-system-benchmarking?/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - "frame-try-runtime?/std", - "pallet-aura/std", - "pallet-balances/std", - "pallet-grandpa/std", - "pallet-sudo/std", - "pallet-template/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", - "sp-consensus-grandpa/std", - "sp-core/std", - "sp-genesis-builder/std", - "sp-inherents/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-std/std", - "sp-storage/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-grandpa/runtime-benchmarks", - "pallet-sudo/runtime-benchmarks", - "pallet-template/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] -try-runtime = [ - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime/try-runtime", - "pallet-aura/try-runtime", - "pallet-balances/try-runtime", - "pallet-grandpa/try-runtime", - "pallet-sudo/try-runtime", - "pallet-template/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "sp-runtime/try-runtime", -] -experimental = ["pallet-aura/experimental"] diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 42af802d716b7181b91310318137928896c6bd66..8e0f7fb93b3904ac20902662326a7cba067fbf21 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -16,16 +16,16 @@ workspace = true [dependencies] array-bytes = "6.1" -clap = { version = "4.4.18", features = ["derive"] } -log = "0.4.17" +clap = { version = "4.5.1", features = ["derive"] } +log = { workspace = true, default-features = true } node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } kitchensink-runtime = { path = "../runtime" } sc-client-api = { path = "../../../client/api" } sp-runtime = { path = "../../../primitives/runtime" } sp-state-machine = { path = "../../../primitives/state-machine" } -serde = "1.0.195" -serde_json = "1.0.111" +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.13.0" kvdb-rocksdb = "0.19.0" diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 5dfe915b789d5e2e22b56d786513214e9c4e26a6..c91a83e6d6eab210a7a54a0eb4cc156c1ad79e23 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -41,12 +41,12 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies array-bytes = "6.1" -clap = { version = "4.4.18", features = ["derive"], optional = true } +clap = { version = "4.5.1", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } -serde = { version = "1.0.195", features = ["derive"] } -jsonrpsee = { version = "0.20.3", features = ["server"] } +serde = { features = ["derive"], workspace = true, default-features = true } +jsonrpsee = { version = "0.22", features = ["server"] } futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } rand = "0.8" # primitives @@ -116,7 +116,7 @@ sc-cli = { path = "../../../client/cli", optional = true } frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true } node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } try-runtime-cli = { path = "../../../utils/frame/try-runtime/cli", optional = true } -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } [dev-dependencies] sc-keystore = { path = "../../../client/keystore" } @@ -159,13 +159,13 @@ sp-consensus-babe = { path = "../../../primitives/consensus/babe" } sp-externalities = { path = "../../../primitives/externalities" } sp-keyring = { path = "../../../primitives/keyring" } sp-runtime = { path = "../../../primitives/runtime" } -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } scale-info = { version = "2.10.0", features = ["derive", "serde"] } sp-trie = { path = "../../../primitives/trie" } sp-state-machine = { path = "../../../primitives/state-machine" } [build-dependencies] -clap = { version = "4.4.18", optional = true } +clap = { version = "4.5.1", optional = true } clap_complete = { version = "4.0.2", optional = true } node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true } @@ -196,6 +196,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "kitchensink-runtime/runtime-benchmarks", "node-inspect?/runtime-benchmarks", + "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -205,6 +206,7 @@ runtime-benchmarks = [ "pallet-skip-feeless-payment/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index c17c12dfef13e49662fe1ed8c73a9499e00535ec..b98a321c338e93e6fb773cecf67d13a978d1a7bd 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -28,7 +28,7 @@ use sc_consensus::{ use sc_service::{ config::{ BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, - PruningMode, WasmExecutionMethod, WasmtimeInstantiationStrategy, + PruningMode, RpcBatchRequestConfig, WasmExecutionMethod, WasmtimeInstantiationStrategy, }, BasePath, Configuration, Role, }; @@ -84,6 +84,8 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, rpc_message_buffer_capacity: Default::default(), + rpc_batch_config: RpcBatchRequestConfig::Unlimited, + rpc_rate_limit: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, @@ -108,7 +110,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { kitchensink_runtime::UncheckedExtrinsic { - signature: None, + preamble: sp_runtime::generic::Preamble::Bare, function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), } .into() diff --git a/substrate/bin/node/cli/benches/executor.rs b/substrate/bin/node/cli/benches/executor.rs index a326e1a79ea347f169e372581d07dc4f43848e24..e13d34f9657acea48f0b53aa021296e9897f4780 100644 --- a/substrate/bin/node/cli/benches/executor.rs +++ b/substrate/bin/node/cli/benches/executor.rs @@ -29,7 +29,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; @@ -144,11 +144,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 0d0d3a072d89dd18ddf0362bc4b73dab54f8df51..de4eef1944d41bc6f37d06819ad70ca0a6dad109 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -26,7 +26,7 @@ use node_primitives::AccountId; use sc_service::{ config::{ BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, - PruningMode, TransactionPoolOptions, + PruningMode, RpcBatchRequestConfig, TransactionPoolOptions, }, BasePath, Configuration, Role, }; @@ -80,6 +80,8 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, rpc_message_buffer_capacity: Default::default(), + rpc_batch_config: RpcBatchRequestConfig::Unlimited, + rpc_rate_limit: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs index f3c0435fd32dcaa71f9f94b78dcae01ff07c8b81..3345afae4fd2b181f147fd6fb6d5597d36db7885 100644 --- a/substrate/bin/node/cli/src/cli.rs +++ b/substrate/bin/node/cli/src/cli.rs @@ -63,7 +63,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone CLI /// (). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, /// Key management cli utilities diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index dc28705c2aea9323d0ce84ae901d0206fe513efe..9645173202866a7334ab3eaacd948132d9b3c9d7 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -28,6 +28,7 @@ use node_primitives::Block; use sc_cli::{Result, SubstrateCli}; use sc_service::PartialComponents; use sp_keyring::Sr25519Keyring; +use sp_runtime::traits::HashingFor; use std::sync::Arc; @@ -106,7 +107,7 @@ pub fn run() -> Result<()> { ) } - cmd.run::(config) + cmd.run::, sp_statement_store::runtime_api::HostFunctions>(config) }, BenchmarkCmd::Block(cmd) => { // ensure that we keep the task manager alive diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 8f2aba6b44cd0a980771ec7d84eb383421551a6b..157f278fb5345526727f812b3bc5efec5d782000 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -107,18 +107,21 @@ 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(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(generic::Era::mortal( - period, - best_block.saturated_into(), - )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(generic::Era::mortal( + period, + best_block.saturated_into(), + )), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + ) + .into(), pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::< kitchensink_runtime::Runtime, @@ -128,15 +131,17 @@ pub fn create_extrinsic( let raw_payload = kitchensink_runtime::SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ( - (), - kitchensink_runtime::VERSION.spec_version, - kitchensink_runtime::VERSION.transaction_version, - genesis_hash, - best_hash, - (), - (), + ( + (), + kitchensink_runtime::VERSION.spec_version, + kitchensink_runtime::VERSION.transaction_version, + genesis_hash, + best_hash, + (), + (), + ), (), ), ); @@ -146,7 +151,7 @@ pub fn create_extrinsic( function, sp_runtime::AccountId32::from(sender.public()).into(), kitchensink_runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) } @@ -791,7 +796,7 @@ mod tests { use codec::Encode; use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, - Address, BalancesCall, RuntimeCall, UncheckedExtrinsic, + Address, BalancesCall, RuntimeCall, TxExtension, UncheckedExtrinsic, }; use node_primitives::{Block, DigestItem, Signature}; use sc_client_api::BlockBackend; @@ -993,25 +998,31 @@ mod tests { let tx_payment = pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None), ); - let extra = ( - check_non_zero_sender, - check_spec_version, - check_tx_version, - check_genesis, - check_era, - check_nonce, - check_weight, + let tx_ext: TxExtension = ( + ( + check_non_zero_sender, + check_spec_version, + check_tx_version, + check_genesis, + check_era, + check_nonce, + check_weight, + ) + .into(), tx_payment, ); let raw_payload = SignedPayload::from_raw( function, - extra, - ((), spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()), + tx_ext, + ( + ((), spec_version, transaction_version, genesis_hash, genesis_hash, (), ()), + (), + ), ); 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) + UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), tx_ext) .into() }, ); diff --git a/substrate/bin/node/cli/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs index 525ab2e39c1287edcf235fe3ac6381e3f0fc8e10..5fcb2295ef009adaeb84017534cf2965917405b9 100644 --- a/substrate/bin/node/cli/tests/basic.rs +++ b/substrate/bin/node/cli/tests/basic.rs @@ -67,7 +67,7 @@ fn transfer_fee(extrinsic: &E) -> Balance { 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()), }) } @@ -84,11 +84,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, @@ -111,11 +111,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, @@ -131,18 +131,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, @@ -166,11 +166,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] }), }, ], @@ -677,11 +677,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, > { @@ -694,7 +694,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, diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index 8c7b3c873157770a8f156a019aa7e43e66460bae..9d6407067a37a51791a9d74ed987d1928926442e 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -54,11 +54,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) }, @@ -77,11 +77,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] }), }, ], @@ -147,7 +147,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()), }); @@ -211,7 +211,10 @@ fn block_weight_capacity_report() { let num_transfers = block_number * factor; let mut xts = (0..num_transfers) .map(|i| CheckedExtrinsic { - signed: Some((charlie(), signed_extra(nonce + i as Nonce, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed( + charlie(), + tx_ext(nonce + i as Nonce, 0), + ), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 0, @@ -222,7 +225,7 @@ fn block_weight_capacity_report() { xts.insert( 0, CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, ); @@ -285,13 +288,16 @@ fn block_length_capacity_report() { previous_hash, vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000, }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(nonce, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed( + charlie(), + tx_ext(nonce, 0), + ), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0u8; (block_number * factor) as usize], }), diff --git a/substrate/bin/node/cli/tests/res/default_genesis_config.json b/substrate/bin/node/cli/tests/res/default_genesis_config.json index 1465a6497cadb3d79f75910dc2e084c168559c62..e21fbb47da8c4619e0923c85bf3470828cd80b23 100644 --- a/substrate/bin/node/cli/tests/res/default_genesis_config.json +++ b/substrate/bin/node/cli/tests/res/default_genesis_config.json @@ -2,7 +2,13 @@ "system": {}, "babe": { "authorities": [], - "epochConfig": null + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } }, "indices": { "indices": [] diff --git a/substrate/bin/node/cli/tests/submit_transaction.rs b/substrate/bin/node/cli/tests/submit_transaction.rs index 5cbb0103d471b96902bb341bcd796e6cf09eac76..f3a5bac8fb52bd06d49703faeeaa18ff724a977b 100644 --- a/substrate/bin/node/cli/tests/submit_transaction.rs +++ b/substrate/bin/node/cli/tests/submit_transaction.rs @@ -130,8 +130,8 @@ 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; - extra.5 + let extra = tx.preamble.to_signed().unwrap().2; + (extra.0).5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); @@ -179,8 +179,8 @@ 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; - extra.5 + let extra = tx.preamble.to_signed().unwrap().2; + (extra.0).5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); @@ -236,7 +236,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.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/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index e703e312b51bb144cc1c2dd18b927d7d40908b3c..7db6e3efd3a0fccc7ddd624e6ecb029c82637c03 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -15,9 +15,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } -thiserror = "1.0" +thiserror = { workspace = true } sc-cli = { path = "../../../client/cli" } sc-client-api = { path = "../../../client/api" } sc-service = { path = "../../../client/service", default-features = false } diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index 63a30965a160603094a1058b30dcd026ec18b6a0..894dbf0da85ca56d412087adf01fa12c7983ae7a 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["server"] } +jsonrpsee = { version = "0.22", features = ["server"] } node-primitives = { path = "../primitives" } pallet-transaction-payment-rpc = { path = "../../../frame/transaction-payment/rpc" } mmr-rpc = { path = "../../../client/merkle-mountain-range/rpc" } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 4bb5fed2b09a210ff4915609b1b825746ed4f514..09c8fb4ed3d49d150a063dc22a1990d0b02a0f48 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -25,8 +25,8 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } static_assertions = "1.1.0" -log = { version = "0.4.17", default-features = false } -serde_json = { version = "1.0.111", default-features = false, features = ["alloc", "arbitrary_precision"] } +log = { workspace = true } +serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "num-traits", "scale-info"] } @@ -58,7 +58,7 @@ sp-io = { path = "../../../primitives/io", default-features = false } frame-executive = { path = "../../../frame/executive", default-features = false } frame-benchmarking = { path = "../../../frame/benchmarking", default-features = false } frame-benchmarking-pallet-pov = { path = "../../../frame/benchmarking/pov", default-features = false } -frame-support = { path = "../../../frame/support", default-features = false, features = ["tuples-96"] } +frame-support = { path = "../../../frame/support", default-features = false, features = ["experimental", "tuples-96"] } frame-system = { path = "../../../frame/system", default-features = false } frame-system-benchmarking = { path = "../../../frame/system/benchmarking", default-features = false, optional = true } frame-election-provider-support = { path = "../../../frame/election-provider-support", default-features = false } @@ -88,6 +88,7 @@ pallet-election-provider-support-benchmarking = { path = "../../../frame/electio pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", default-features = false } pallet-example-tasks = { path = "../../../frame/examples/tasks", default-features = false } pallet-fast-unstake = { path = "../../../frame/fast-unstake", default-features = false } +pallet-migrations = { path = "../../../frame/migrations", default-features = false } pallet-nis = { path = "../../../frame/nis", default-features = false } pallet-grandpa = { path = "../../../frame/grandpa", default-features = false } pallet-im-online = { path = "../../../frame/im-online", default-features = false } @@ -142,6 +143,7 @@ pallet-vesting = { path = "../../../frame/vesting", default-features = false } pallet-whitelist = { path = "../../../frame/whitelist", default-features = false } pallet-tx-pause = { path = "../../../frame/tx-pause", default-features = false } pallet-safe-mode = { path = "../../../frame/safe-mode", default-features = false } +pallet-parameters = { path = "../../../frame/parameters", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true } @@ -197,6 +199,7 @@ std = [ "pallet-lottery/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-mixnet/std", "pallet-mmr/std", "pallet-multisig/std", @@ -209,6 +212,7 @@ std = [ "pallet-nomination-pools/std", "pallet-offences-benchmarking?/std", "pallet-offences/std", + "pallet-parameters/std", "pallet-preimage/std", "pallet-proxy/std", "pallet-ranked-collective/std", @@ -272,6 +276,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-alliance/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", @@ -300,6 +305,7 @@ runtime-benchmarks = [ "pallet-lottery/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-mixnet/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", @@ -310,6 +316,7 @@ runtime-benchmarks = [ "pallet-nomination-pools/runtime-benchmarks", "pallet-offences-benchmarking/runtime-benchmarks", "pallet-offences/runtime-benchmarks", + "pallet-parameters/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-ranked-collective/runtime-benchmarks", @@ -327,6 +334,7 @@ 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", @@ -378,6 +386,7 @@ try-runtime = [ "pallet-lottery/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-mixnet/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", @@ -386,6 +395,7 @@ try-runtime = [ "pallet-nis/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-offences/try-runtime", + "pallet-parameters/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-ranked-collective/try-runtime", diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 7ff52a758b3dd756dc4536df5928d3b2bb68a148..34f043b33a4edfe2d8cdbe154896e937826110ca 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -30,8 +30,8 @@ use pallet_identity::legacy::IdentityField; use sp_std::prelude::*; use crate::{ - AccountId, AllianceMotion, Assets, Authorship, Balances, Hash, NegativeImbalance, Runtime, - RuntimeCall, + AccountId, AllianceCollective, AllianceMotion, Assets, Authorship, Balances, Hash, + NegativeImbalance, Runtime, RuntimeCall, }; pub struct Author; @@ -107,7 +107,7 @@ impl ProposalProvider for AllianceProposalProvider } fn proposal_of(proposal_hash: Hash) -> Option { - AllianceMotion::proposal_of(proposal_hash) + pallet_collective::ProposalOf::::get(proposal_hash) } } @@ -276,7 +276,7 @@ mod multiplier_tests { let next = runtime_multiplier_update(fm); fm = next; if fm == min_multiplier() { - break + break; } iterations += 1; } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 515272cd99ab46e0ae64ecd62c26e053df13cde3..96611f5a144d4b957dc598a4c12acb8d7d9c3bb1 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -28,8 +28,9 @@ use frame_election_provider_support::{ onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight, }; use frame_support::{ - construct_runtime, derive_impl, + derive_impl, dispatch::DispatchClass, + dynamic_params::{dynamic_pallet_params, dynamic_params}, genesis_builder_helper::{build_config, create_default_config}, instances::{Instance1, Instance2}, ord_parameter_types, @@ -44,9 +45,9 @@ use frame_support::{ GetSalary, PayFromAccount, }, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Contains, Currency, - EitherOfDiverse, EqualPrivilegeOnly, Imbalance, InsideBoth, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, OnUnbalanced, - WithdrawReasons, + EitherOfDiverse, EnsureOriginWithArg, EqualPrivilegeOnly, Imbalance, InsideBoth, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, + OnUnbalanced, WithdrawReasons, }, weights::{ constants::{ @@ -309,6 +310,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = frame_system::weights::SubstrateWeight; type SS58Prefix = ConstU16<42>; type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } impl pallet_insecure_randomness_collective_flip::Config for Runtime {} @@ -457,9 +459,6 @@ impl pallet_glutton::Config for Runtime { } parameter_types! { - pub const PreimageBaseDeposit: Balance = 1 * DOLLARS; - // One cent: $10,000 / MB - pub const PreimageByteDeposit: Balance = 1 * CENTS; pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); } @@ -472,7 +471,11 @@ impl pallet_preimage::Config for Runtime { AccountId, Balances, PreimageHoldReason, - LinearStoragePrice, + LinearStoragePrice< + dynamic_params::storage::BaseDeposit, + dynamic_params::storage::ByteDeposit, + Balance, + >, >; } @@ -557,6 +560,7 @@ impl pallet_transaction_payment::Config for Runtime { MinimumMultiplier, MaximumMultiplier, >; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_asset_tx_payment::Config for Runtime { @@ -566,6 +570,9 @@ impl pallet_asset_tx_payment::Config for Runtime { pallet_assets::BalanceToAssetBalance, CreditToBlockAuthor, >; + type WeightInfo = pallet_asset_tx_payment::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetTxHelper; } impl pallet_asset_conversion_tx_payment::Config for Runtime { @@ -576,6 +583,9 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { AssetConversion, Native, >; + type WeightInfo = pallet_asset_conversion_tx_payment::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } impl pallet_skip_feeless_payment::Config for Runtime { @@ -1326,9 +1336,6 @@ impl pallet_tips::Config for Runtime { } parameter_types! { - pub const DepositPerItem: Balance = deposit(1, 0); - pub const DepositPerByte: Balance = deposit(0, 1); - pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024); pub Schedule: pallet_contracts::Schedule = Default::default(); pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(30); } @@ -1346,9 +1353,9 @@ impl pallet_contracts::Config for Runtime { /// change because that would break already deployed contracts. The `Call` structure itself /// is not allowed to change the indices of existing pallets, too. type CallFilter = Nothing; - type DepositPerItem = DepositPerItem; - type DepositPerByte = DepositPerByte; - type DefaultDepositLimit = DefaultDepositLimit; + type DepositPerItem = dynamic_params::contracts::DepositPerItem; + type DepositPerByte = dynamic_params::contracts::DepositPerByte; + type DefaultDepositLimit = dynamic_params::contracts::DefaultDepositLimit; type CallStack = [pallet_contracts::Frame; 5]; type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_contracts::weights::SubstrateWeight; @@ -1358,6 +1365,8 @@ impl pallet_contracts::Config for Runtime { type MaxCodeLen = ConstU32<{ 123 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; type UnsafeUnstableInterface = ConstBool; + type UploadOrigin = EnsureSigned; + type InstantiateOrigin = EnsureSigned; type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; type RuntimeHoldReason = RuntimeHoldReason; #[cfg(not(feature = "runtime-benchmarks"))] @@ -1368,6 +1377,7 @@ impl pallet_contracts::Config for Runtime { type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; type Debug = (); type Environment = (); + type ApiVersion = (); type Xcm = (); } @@ -1406,29 +1416,33 @@ where // so the actual block number is `n`. .saturating_sub(1); let era = Era::mortal(period, current_block); - let extra = ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(era), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), + let tx_ext: TxExtension = ( + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(era), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + ) + .into(), pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from( tip, None, ), ), ); - 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(); + Some((call, (address, signature, tx_ext))) } } @@ -2007,6 +2021,25 @@ impl pallet_statement::Config for Runtime { type MaxAllowedBytes = MaxAllowedBytes; } +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 = (); + // 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 = pallet_migrations::weights::SubstrateWeight; +} + parameter_types! { pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); } @@ -2028,7 +2061,7 @@ pub struct CoretimeProvider; impl CoretimeInterface for CoretimeProvider { type AccountId = AccountId; type Balance = Balance; - type RealyChainBlockNumberProvider = System; + type RelayChainBlockNumberProvider = System; fn request_core_count(_count: CoreIndex) {} fn request_revenue_info_at(_when: u32) {} fn credit_account(_who: Self::AccountId, _amount: Self::Balance) {} @@ -2088,90 +2121,335 @@ impl pallet_mixnet::Config for Runtime { type MinMixnodes = ConstU32<7>; // Low to allow small testing networks } -construct_runtime!( - pub enum Runtime { - System: frame_system, - Utility: pallet_utility, - Babe: pallet_babe, - Timestamp: pallet_timestamp, - // Authorship must be before session in order to note author in the correct session and era - // for im-online and staking. - Authorship: pallet_authorship, - Indices: pallet_indices, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - AssetTxPayment: pallet_asset_tx_payment, - AssetConversionTxPayment: pallet_asset_conversion_tx_payment, - ElectionProviderMultiPhase: pallet_election_provider_multi_phase, - Staking: pallet_staking, - Session: pallet_session, - Democracy: pallet_democracy, - Council: pallet_collective::, - TechnicalCommittee: pallet_collective::, - Elections: pallet_elections_phragmen, - TechnicalMembership: pallet_membership::, - Grandpa: pallet_grandpa, - Treasury: pallet_treasury, - AssetRate: pallet_asset_rate, - Contracts: pallet_contracts, - Sudo: pallet_sudo, - ImOnline: pallet_im_online, - AuthorityDiscovery: pallet_authority_discovery, - Offences: pallet_offences, - Historical: pallet_session_historical, - RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, - Identity: pallet_identity, - Society: pallet_society, - Recovery: pallet_recovery, - Vesting: pallet_vesting, - Scheduler: pallet_scheduler, - Glutton: pallet_glutton, - Preimage: pallet_preimage, - Proxy: pallet_proxy, - Multisig: pallet_multisig, - Bounties: pallet_bounties, - Tips: pallet_tips, - Assets: pallet_assets::, - PoolAssets: pallet_assets::, - Beefy: pallet_beefy, - // MMR leaf construction must be after session in order to have a leaf's next_auth_set - // refer to block. See issue polkadot-fellows/runtimes#160 for details. - Mmr: pallet_mmr, - MmrLeaf: pallet_beefy_mmr, - Lottery: pallet_lottery, - Nis: pallet_nis, - Uniques: pallet_uniques, - Nfts: pallet_nfts, - NftFractionalization: pallet_nft_fractionalization, - Salary: pallet_salary, - CoreFellowship: pallet_core_fellowship, - TransactionStorage: pallet_transaction_storage, - VoterList: pallet_bags_list::, - StateTrieMigration: pallet_state_trie_migration, - ChildBounties: pallet_child_bounties, - Referenda: pallet_referenda, - Remark: pallet_remark, - RootTesting: pallet_root_testing, - ConvictionVoting: pallet_conviction_voting, - Whitelist: pallet_whitelist, - AllianceMotion: pallet_collective::, - Alliance: pallet_alliance, - NominationPools: pallet_nomination_pools, - RankedPolls: pallet_referenda::, - RankedCollective: pallet_ranked_collective, - AssetConversion: pallet_asset_conversion, - FastUnstake: pallet_fast_unstake, - MessageQueue: pallet_message_queue, - Pov: frame_benchmarking_pallet_pov, - TxPause: pallet_tx_pause, - SafeMode: pallet_safe_mode, - Statement: pallet_statement, - Broker: pallet_broker, - TasksExample: pallet_example_tasks, - Mixnet: pallet_mixnet, - SkipFeelessPayment: pallet_skip_feeless_payment, +/// Dynamic parameters that can be changed at runtime through the +/// `pallet_parameters::set_parameter`. +#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::)] +pub mod dynamic_params { + use super::*; + + #[dynamic_pallet_params] + #[codec(index = 0)] + pub mod storage { + /// Configures the base deposit of storing some data. + #[codec(index = 0)] + pub static BaseDeposit: Balance = 1 * DOLLARS; + + /// Configures the per-byte deposit of storing some data. + #[codec(index = 1)] + pub static ByteDeposit: Balance = 1 * CENTS; } -); + + #[dynamic_pallet_params] + #[codec(index = 1)] + pub mod contracts { + #[codec(index = 0)] + pub static DepositPerItem: Balance = deposit(1, 0); + + #[codec(index = 1)] + pub static DepositPerByte: Balance = deposit(0, 1); + + #[codec(index = 2)] + pub static DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024); + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl Default for RuntimeParameters { + fn default() -> Self { + RuntimeParameters::Storage(dynamic_params::storage::Parameters::BaseDeposit( + dynamic_params::storage::BaseDeposit, + Some(1 * DOLLARS), + )) + } +} + +pub struct DynamicParametersManagerOrigin; +impl EnsureOriginWithArg for DynamicParametersManagerOrigin { + type Success = (); + + fn try_origin( + origin: RuntimeOrigin, + key: &RuntimeParametersKey, + ) -> Result { + match key { + RuntimeParametersKey::Storage(_) => { + frame_system::ensure_root(origin.clone()).map_err(|_| origin)?; + return Ok(()) + }, + RuntimeParametersKey::Contract(_) => { + frame_system::ensure_root(origin.clone()).map_err(|_| origin)?; + return Ok(()) + }, + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(_key: &RuntimeParametersKey) -> Result { + Ok(RuntimeOrigin::root()) + } +} + +impl pallet_parameters::Config for Runtime { + type RuntimeParameters = RuntimeParameters; + type RuntimeEvent = RuntimeEvent; + type AdminOrigin = DynamicParametersManagerOrigin; + type WeightInfo = (); +} + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + + #[runtime::pallet_index(1)] + pub type Utility = pallet_utility; + + #[runtime::pallet_index(2)] + pub type Babe = pallet_babe; + + #[runtime::pallet_index(3)] + pub type Timestamp = pallet_timestamp; + + // Authorship must be before session in order to note author in the correct session and era + // for im-online and staking. + #[runtime::pallet_index(4)] + pub type Authorship = pallet_authorship; + + #[runtime::pallet_index(5)] + pub type Indices = pallet_indices; + + #[runtime::pallet_index(6)] + pub type Balances = pallet_balances; + + #[runtime::pallet_index(7)] + pub type TransactionPayment = pallet_transaction_payment; + + #[runtime::pallet_index(8)] + pub type AssetTxPayment = pallet_asset_tx_payment; + + #[runtime::pallet_index(9)] + pub type AssetConversionTxPayment = pallet_asset_conversion_tx_payment; + + #[runtime::pallet_index(10)] + pub type ElectionProviderMultiPhase = pallet_election_provider_multi_phase; + + #[runtime::pallet_index(11)] + pub type Staking = pallet_staking; + + #[runtime::pallet_index(12)] + pub type Session = pallet_session; + + #[runtime::pallet_index(13)] + pub type Democracy = pallet_democracy; + + #[runtime::pallet_index(14)] + pub type Council = pallet_collective; + + #[runtime::pallet_index(15)] + pub type TechnicalCommittee = pallet_collective; + + #[runtime::pallet_index(16)] + pub type Elections = pallet_elections_phragmen; + + #[runtime::pallet_index(17)] + pub type TechnicalMembership = pallet_membership; + + #[runtime::pallet_index(18)] + pub type Grandpa = pallet_grandpa; + + #[runtime::pallet_index(19)] + pub type Treasury = pallet_treasury; + + #[runtime::pallet_index(20)] + pub type AssetRate = pallet_asset_rate; + + #[runtime::pallet_index(21)] + pub type Contracts = pallet_contracts; + + #[runtime::pallet_index(22)] + pub type Sudo = pallet_sudo; + + #[runtime::pallet_index(23)] + pub type ImOnline = pallet_im_online; + + #[runtime::pallet_index(24)] + pub type AuthorityDiscovery = pallet_authority_discovery; + + #[runtime::pallet_index(25)] + pub type Offences = pallet_offences; + + #[runtime::pallet_index(26)] + pub type Historical = pallet_session_historical; + + #[runtime::pallet_index(27)] + pub type RandomnessCollectiveFlip = pallet_insecure_randomness_collective_flip; + + #[runtime::pallet_index(28)] + pub type Identity = pallet_identity; + + #[runtime::pallet_index(29)] + pub type Society = pallet_society; + + #[runtime::pallet_index(30)] + pub type Recovery = pallet_recovery; + + #[runtime::pallet_index(31)] + pub type Vesting = pallet_vesting; + + #[runtime::pallet_index(32)] + pub type Scheduler = pallet_scheduler; + + #[runtime::pallet_index(33)] + pub type Glutton = pallet_glutton; + + #[runtime::pallet_index(34)] + pub type Preimage = pallet_preimage; + + #[runtime::pallet_index(35)] + pub type Proxy = pallet_proxy; + + #[runtime::pallet_index(36)] + pub type Multisig = pallet_multisig; + + #[runtime::pallet_index(37)] + pub type Bounties = pallet_bounties; + + #[runtime::pallet_index(38)] + pub type Tips = pallet_tips; + + #[runtime::pallet_index(39)] + pub type Assets = pallet_assets; + + #[runtime::pallet_index(40)] + pub type PoolAssets = pallet_assets; + + #[runtime::pallet_index(41)] + pub type Beefy = pallet_beefy; + + // MMR leaf construction must be after session in order to have a leaf's next_auth_set + // refer to block. See issue polkadot-fellows/runtimes#160 for details. + #[runtime::pallet_index(42)] + pub type Mmr = pallet_mmr; + + #[runtime::pallet_index(43)] + pub type MmrLeaf = pallet_beefy_mmr; + + #[runtime::pallet_index(44)] + pub type Lottery = pallet_lottery; + + #[runtime::pallet_index(45)] + pub type Nis = pallet_nis; + + #[runtime::pallet_index(46)] + pub type Uniques = pallet_uniques; + + #[runtime::pallet_index(47)] + pub type Nfts = pallet_nfts; + + #[runtime::pallet_index(48)] + pub type NftFractionalization = pallet_nft_fractionalization; + + #[runtime::pallet_index(49)] + pub type Salary = pallet_salary; + + #[runtime::pallet_index(50)] + pub type CoreFellowship = pallet_core_fellowship; + + #[runtime::pallet_index(51)] + pub type TransactionStorage = pallet_transaction_storage; + + #[runtime::pallet_index(52)] + pub type VoterList = pallet_bags_list; + + #[runtime::pallet_index(53)] + pub type StateTrieMigration = pallet_state_trie_migration; + + #[runtime::pallet_index(54)] + pub type ChildBounties = pallet_child_bounties; + + #[runtime::pallet_index(55)] + pub type Referenda = pallet_referenda; + + #[runtime::pallet_index(56)] + pub type Remark = pallet_remark; + + #[runtime::pallet_index(57)] + pub type RootTesting = pallet_root_testing; + + #[runtime::pallet_index(58)] + pub type ConvictionVoting = pallet_conviction_voting; + + #[runtime::pallet_index(59)] + pub type Whitelist = pallet_whitelist; + + #[runtime::pallet_index(60)] + pub type AllianceMotion = pallet_collective; + + #[runtime::pallet_index(61)] + pub type Alliance = pallet_alliance; + + #[runtime::pallet_index(62)] + pub type NominationPools = pallet_nomination_pools; + + #[runtime::pallet_index(63)] + pub type RankedPolls = pallet_referenda; + + #[runtime::pallet_index(64)] + pub type RankedCollective = pallet_ranked_collective; + + #[runtime::pallet_index(65)] + pub type AssetConversion = pallet_asset_conversion; + + #[runtime::pallet_index(66)] + pub type FastUnstake = pallet_fast_unstake; + + #[runtime::pallet_index(67)] + pub type MessageQueue = pallet_message_queue; + + #[runtime::pallet_index(68)] + pub type Pov = frame_benchmarking_pallet_pov; + + #[runtime::pallet_index(69)] + pub type TxPause = pallet_tx_pause; + + #[runtime::pallet_index(70)] + pub type SafeMode = pallet_safe_mode; + + #[runtime::pallet_index(71)] + pub type Statement = pallet_statement; + + #[runtime::pallet_index(72)] + pub type MultiBlockMigrations = pallet_migrations; + + #[runtime::pallet_index(73)] + pub type Broker = pallet_broker; + + #[runtime::pallet_index(74)] + pub type TasksExample = pallet_example_tasks; + + #[runtime::pallet_index(75)] + pub type Mixnet = pallet_mixnet; + + #[runtime::pallet_index(76)] + pub type Parameters = pallet_parameters; + + #[runtime::pallet_index(77)] + pub type SkipFeelessPayment = pallet_skip_feeless_payment; +} /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; @@ -2183,19 +2461,21 @@ 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 = ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, +pub type TxExtension = ( + ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + ), pallet_skip_feeless_payment::SkipCheckIfFeeless< Runtime, pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, @@ -2204,11 +2484,11 @@ 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; /// 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, @@ -2263,6 +2543,106 @@ mod mmr { pub type Hashing = ::Hashing; } +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetConversionTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_asset_conversion_tx_payment::BenchmarkHelperTrait + for AssetConversionTxHelper +{ + fn create_asset_id_parameter(seed: u32) -> (u32, u32) { + (seed, seed) + } + + fn setup_balances_and_pool(asset_id: u32, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_id.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_id.into(), + &lp_provider, + ((u64::MAX as u128) * 100).into() + )); + + let token_native = Box::new(NativeOrWithId::Native); + let token_second = Box::new(NativeOrWithId::WithId(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")] +pub struct AssetTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_asset_tx_payment::BenchmarkHelperTrait for AssetTxHelper { + fn create_asset_id_parameter(seed: u32) -> (u32, u32) { + (seed, seed) + } + + fn setup_balances_and_pool(asset_id: u32, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_id.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_id.into(), + &lp_provider, + ((u64::MAX as u128) * 100).into() + )); + + let token_native = Box::new(NativeOrWithId::Native); + let token_second = Box::new(NativeOrWithId::WithId(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 { frame_benchmarking::define_benchmarks!( @@ -2283,11 +2663,15 @@ mod benches { [tasks_example, TasksExample] [pallet_democracy, Democracy] [pallet_asset_conversion, AssetConversion] + [pallet_asset_conversion_tx_payment, AssetConversionTxPayment] + [pallet_asset_tx_payment, AssetTxPayment] + [pallet_transaction_payment, TransactionPayment] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] [pallet_fast_unstake, FastUnstake] [pallet_nis, Nis] + [pallet_parameters, Parameters] [pallet_grandpa, Grandpa] [pallet_identity, Identity] [pallet_im_online, ImOnline] @@ -2295,6 +2679,7 @@ mod benches { [pallet_lottery, Lottery] [pallet_membership, TechnicalMembership] [pallet_message_queue, MessageQueue] + [pallet_migrations, MultiBlockMigrations] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] @@ -2314,6 +2699,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] @@ -2340,7 +2726,7 @@ impl_runtime_apis! { Executive::execute_block(block); } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -2861,6 +3247,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; @@ -2885,6 +3272,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 9ca8b8ef7265e362de2ec8b2f482efe389d71dff..31f8689d46ca30546482d438938c09457a433bf5 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } fs_extra = "1" futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } tempfile = "3.1.0" frame-system = { path = "../../../frame/system" } node-cli = { package = "staging-node-cli", path = "../cli" } diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index df302a6453b9ffbef603afc36fc860a1535a7ca2..ccf79eed8847d8a2acdb4b5f96c15d021f750b65 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -51,6 +51,7 @@ use sp_core::{ed25519, sr25519, traits::SpawnNamed, Pair, Public}; use sp_crypto_hashing::blake2_256; use sp_inherents::InherentData; use sp_runtime::{ + generic::{ExtrinsicFormat, Preamble}, traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; @@ -295,10 +296,10 @@ impl<'a> Iterator for BlockContentIterator<'a> { 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 +563,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, @@ -581,11 +582,20 @@ impl BenchKeyring { } }); UncheckedExtrinsic { - signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), + preamble: Preamble::Signed( + sp_runtime::MultiAddress::Id(signed), + signature, + tx_ext, + ), function: payload.0, } }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + ExtrinsicFormat::Bare => + UncheckedExtrinsic { preamble: Preamble::Bare, function: xt.function }, + ExtrinsicFormat::General(tx_ext) => UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(tx_ext), + function: xt.function, + }, } } diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index 6ec21fbe09342d1f704a4ed1a6f79b6160c27a01..c79612d68444c8bd64ad18c3b0a74ceed176eff8 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -20,9 +20,8 @@ use crate::keyring::*; use kitchensink_runtime::{ - constants::currency::*, AccountId, AssetsConfig, BabeConfig, BalancesConfig, GluttonConfig, - GrandpaConfig, IndicesConfig, RuntimeGenesisConfig, SessionConfig, SocietyConfig, StakerStatus, - StakingConfig, BABE_GENESIS_EPOCH_CONFIG, + constants::currency::*, AccountId, AssetsConfig, BalancesConfig, IndicesConfig, + RuntimeGenesisConfig, SessionConfig, SocietyConfig, StakerStatus, StakingConfig, }; use sp_keyring::Ed25519Keyring; use sp_runtime::Perbill; @@ -47,7 +46,6 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS))); RuntimeGenesisConfig { - system: Default::default(), indices: IndicesConfig { indices: vec![] }, balances: BalancesConfig { balances: endowed }, session: SessionConfig { @@ -69,39 +67,8 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { invulnerables: vec![alice(), bob(), charlie()], ..Default::default() }, - babe: BabeConfig { - authorities: vec![], - epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - grandpa: GrandpaConfig { authorities: vec![], _config: Default::default() }, - beefy: Default::default(), - im_online: Default::default(), - authority_discovery: Default::default(), - democracy: Default::default(), - council: Default::default(), - technical_committee: Default::default(), - technical_membership: Default::default(), - elections: Default::default(), - sudo: Default::default(), - treasury: Default::default(), society: SocietyConfig { pot: 0 }, - vesting: Default::default(), assets: AssetsConfig { assets: vec![(9, alice(), true, 1)], ..Default::default() }, - pool_assets: Default::default(), - transaction_storage: Default::default(), - transaction_payment: Default::default(), - alliance: Default::default(), - alliance_motion: Default::default(), - nomination_pools: Default::default(), - safe_mode: Default::default(), - tx_pause: Default::default(), - glutton: GluttonConfig { - compute: Default::default(), - storage: Default::default(), - trash_data_count: Default::default(), - ..Default::default() - }, - mixnet: Default::default(), + ..Default::default() } } diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index f712191bed695031275cfb11c5e22c8fa2a26f78..13daf915325db370698e563e8a23140136e84a44 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -19,13 +19,13 @@ //! Test accounts. use codec::Encode; -use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic}; +use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, TxExtension, UncheckedExtrinsic}; use node_cli::chain_spec::get_from_seed; use node_primitives::{AccountId, Balance, Nonce}; use sp_core::{ecdsa, ed25519, sr25519}; use sp_crypto_hashing::blake2_256; use sp_keyring::AccountKeyring; -use sp_runtime::generic::Era; +use sp_runtime::generic::{Era, ExtrinsicFormat}; /// Alice's account id. pub fn alice() -> AccountId { @@ -70,15 +70,18 @@ pub fn session_keys_from_seed(seed: &str) -> SessionKeys { } /// 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(), - frame_system::CheckTxVersion::new(), - frame_system::CheckGenesis::new(), - frame_system::CheckEra::from(Era::mortal(256, 0)), - frame_system::CheckNonce::from(nonce), - frame_system::CheckWeight::new(), + ( + frame_system::CheckNonZeroSender::new(), + frame_system::CheckSpecVersion::new(), + frame_system::CheckTxVersion::new(), + frame_system::CheckGenesis::new(), + frame_system::CheckEra::from(Era::mortal(256, 0)), + frame_system::CheckNonce::from(nonce), + frame_system::CheckWeight::new(), + ) + .into(), pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None), ), @@ -92,10 +95,10 @@ pub fn sign( 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(), spec_version, tx_version, genesis_hash, genesis_hash); + (xt.function, tx_ext.clone(), spec_version, tx_version, genesis_hash, genesis_hash); let key = AccountKeyring::from_account_id(&signed).unwrap(); let signature = payload @@ -108,10 +111,21 @@ pub fn sign( }) .into(); UncheckedExtrinsic { - signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), + preamble: sp_runtime::generic::Preamble::Signed( + sp_runtime::MultiAddress::Id(signed), + signature, + tx_ext, + ), function: payload.0, } }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + ExtrinsicFormat::Bare => UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::Bare, + function: xt.function, + }, + ExtrinsicFormat::General(tx_ext) => UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(tx_ext), + function: xt.function, + }, } } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index e39c98983800a72ed24ab64a0af07f70c2d7d48d..996372c8a0f8638ad4420dc8e21c8f1d418bb60e 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -23,8 +23,8 @@ name = "chain-spec-builder" crate-type = ["rlib"] [dependencies] -clap = { version = "4.4.18", features = ["derive"] } -log = "0.4.17" +clap = { version = "4.5.1", features = ["derive"] } +log = { workspace = true, default-features = true } sc-chain-spec = { path = "../../../client/chain-spec" } -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } sp-tracing = { path = "../../../primitives/tracing" } diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index ac97428a7dfdb9cb9edad671cdf9698000091eca..93b1368ca757ad8f383a4c0945c69d0055a8c1ff 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -20,5 +20,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/subkey/README.md b/substrate/bin/utils/subkey/README.md index 3232c82958727555a44168351309b6039a708d89..a5f27cfd3707d6278ac9f78b727021a305a18457 100644 --- a/substrate/bin/utils/subkey/README.md +++ b/substrate/bin/utils/subkey/README.md @@ -91,7 +91,7 @@ SS58 addresses are: ### Json output -`subkey` can calso generate the output as *json*. This is useful for automation. +`subkey` can also generate the output as *json*. This is useful for automation. command: diff --git a/substrate/client/allocator/Cargo.toml b/substrate/client/allocator/Cargo.toml index f882cda9081fd27c57f41e2b75b57ff8018e7f54..2c268b548ea9c32fabdc82226c77e82a7ef59cea 100644 --- a/substrate/client/allocator/Cargo.toml +++ b/substrate/client/allocator/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.17" -thiserror = "1.0.48" +log = { workspace = true, default-features = true } +thiserror = { workspace = true } sp-core = { path = "../../primitives/core" } sp-wasm-interface = { path = "../../primitives/wasm-interface" } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index 14aca6d9a2ee1631483df3e10a4dd1549670e0d0..cd7b613e277f3952304d70c3bf63c36d09432bc2 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } fnv = "1.0.6" futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-executor = { path = "../executor" } @@ -41,6 +41,6 @@ sp-storage = { path = "../../primitives/storage" } sp-trie = { path = "../../primitives/trie" } [dev-dependencies] -thiserror = "1.0.48" +thiserror = { workspace = true } sp-test-primitives = { path = "../../primitives/test-primitives" } substrate-test-runtime = { path = "../../test-utils/runtime" } diff --git a/substrate/client/api/src/client.rs b/substrate/client/api/src/client.rs index 46232c74539c6c230652a753b5fcd4b6761600d8..2de09840e4dfdc15e1f1d1acaa5f3e438de0caca 100644 --- a/substrate/client/api/src/client.rs +++ b/substrate/client/api/src/client.rs @@ -278,7 +278,7 @@ impl fmt::Display for UsageInfo { pub struct UnpinHandleInner { /// Hash of the block pinned by this handle hash: Block::Hash, - unpin_worker_sender: TracingUnboundedSender, + unpin_worker_sender: TracingUnboundedSender>, } impl Debug for UnpinHandleInner { @@ -291,7 +291,7 @@ impl UnpinHandleInner { /// Create a new [`UnpinHandleInner`] pub fn new( hash: Block::Hash, - unpin_worker_sender: TracingUnboundedSender, + unpin_worker_sender: TracingUnboundedSender>, ) -> Self { Self { hash, unpin_worker_sender } } @@ -299,12 +299,25 @@ impl UnpinHandleInner { impl Drop for UnpinHandleInner { fn drop(&mut self) { - if let Err(err) = self.unpin_worker_sender.unbounded_send(self.hash) { + if let Err(err) = + self.unpin_worker_sender.unbounded_send(UnpinWorkerMessage::Unpin(self.hash)) + { log::debug!(target: "db", "Unable to unpin block with hash: {}, error: {:?}", self.hash, err); }; } } +/// Message that signals notification-based pinning actions to the pinning-worker. +/// +/// When the notification is dropped, an `Unpin` message should be sent to the worker. +#[derive(Debug)] +pub enum UnpinWorkerMessage { + /// Should be sent when a import or finality notification is created. + AnnouncePin(Block::Hash), + /// Should be sent when a import or finality notification is dropped. + Unpin(Block::Hash), +} + /// Keeps a specific block pinned while the handle is alive. /// Once the last handle instance for a given block is dropped, the /// block is unpinned in the [`Backend`](crate::backend::Backend::unpin_block). @@ -315,7 +328,7 @@ impl UnpinHandle { /// Create a new [`UnpinHandle`] pub fn new( hash: Block::Hash, - unpin_worker_sender: TracingUnboundedSender, + unpin_worker_sender: TracingUnboundedSender>, ) -> UnpinHandle { UnpinHandle(Arc::new(UnpinHandleInner::new(hash, unpin_worker_sender))) } @@ -353,7 +366,7 @@ impl BlockImportNotification { header: Block::Header, is_new_best: bool, tree_route: Option>>, - unpin_worker_sender: TracingUnboundedSender, + unpin_worker_sender: TracingUnboundedSender>, ) -> Self { Self { hash, @@ -412,7 +425,7 @@ impl FinalityNotification { /// Create finality notification from finality summary. pub fn from_summary( mut summary: FinalizeSummary, - unpin_worker_sender: TracingUnboundedSender, + unpin_worker_sender: TracingUnboundedSender>, ) -> FinalityNotification { let hash = summary.finalized.pop().unwrap_or_default(); FinalityNotification { @@ -436,7 +449,7 @@ impl BlockImportNotification { /// Create finality notification from finality summary. pub fn from_summary( summary: ImportSummary, - unpin_worker_sender: TracingUnboundedSender, + unpin_worker_sender: TracingUnboundedSender>, ) -> BlockImportNotification { let hash = summary.hash; BlockImportNotification { diff --git a/substrate/client/api/src/notifications/tests.rs b/substrate/client/api/src/notifications/tests.rs index fba829b1cf9020034529b034f52015fb423608d8..7afdcbd95438f54a8a19eb03c29113288488eb54 100644 --- a/substrate/client/api/src/notifications/tests.rs +++ b/substrate/client/api/src/notifications/tests.rs @@ -18,7 +18,10 @@ use super::*; -use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; +use sp_runtime::{ + generic::UncheckedExtrinsic, + testing::{Block as RawBlock, H256 as Hash}, +}; use std::iter::{empty, Empty}; type TestChangeSet = ( @@ -50,7 +53,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 4c8370233e9413d7a2c6476e58ca61dfc8f3dce6..cdd4052f0b0998f283ede885f7e7de7509ecd169 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -29,10 +29,10 @@ multihash = { version = "0.18.1", default-features = false, features = [ "sha2", "std", ] } -log = "0.4.17" +log = { workspace = true, default-features = true } prost = "0.12" rand = "0.8.5" -thiserror = "1.0" +thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-client-api = { path = "../api" } sc-network = { path = "../network" } diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index 6db25416dee78323a1531f5868be2601af3eaee0..9bccb96ff378f262e9b66b4268d2ed95befe2bdb 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -306,29 +306,30 @@ where fn addresses_to_publish(&self) -> impl Iterator { let peer_id: Multihash = self.network.local_peer_id().into(); let publish_non_global_ips = self.publish_non_global_ips; - self.network - .external_addresses() - .into_iter() - .filter(move |a| { - if publish_non_global_ips { - return true - } + let addresses = self.network.external_addresses().into_iter().filter(move |a| { + if publish_non_global_ips { + return true + } - a.iter().all(|p| match p { - // 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, - }) - }) - .map(move |a| { - if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) { - a - } else { - a.with(multiaddr::Protocol::P2p(peer_id)) - } + a.iter().all(|p| match p { + // 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, }) + }); + + debug!(target: LOG_TARGET, "Authority DHT record peer_id='{:?}' addresses='{:?}'", peer_id, addresses.clone().collect::>()); + + // The address must include the peer id if not already set. + addresses.map(move |a| { + if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) { + a + } else { + a.with(multiaddr::Protocol::P2p(peer_id)) + } + }) } /// Publish own public addresses. diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index 370f4a4adf5c17f57e4c036a7aaeed81e559a1da..51a06464d0d6d5df0ccf960509f4df46d8b12207 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.17" +log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-block-builder = { path = "../block-builder" } sc-proposer-metrics = { path = "../proposer-metrics" } diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index c07f3e639c3e15b572dbb470c1518b9ddfddae32..932287ac86577b0e1a9b2c057320aeda9d12319a 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -38,7 +38,7 @@ use sp_core::traits::SpawnNamed; use sp_inherents::InherentData; use sp_runtime::{ traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as HeaderT}, - Digest, Percent, SaturatedConversion, + Digest, ExtrinsicInclusionMode, Percent, SaturatedConversion, }; use std::{marker::PhantomData, pin::Pin, sync::Arc, time}; @@ -87,6 +87,22 @@ pub struct ProposerFactory { _phantom: PhantomData, } +impl Clone for ProposerFactory { + fn clone(&self) -> Self { + Self { + spawn_handle: self.spawn_handle.clone(), + client: self.client.clone(), + transaction_pool: self.transaction_pool.clone(), + metrics: self.metrics.clone(), + default_block_size_limit: self.default_block_size_limit, + soft_deadline_percent: self.soft_deadline_percent, + telemetry: self.telemetry.clone(), + include_proof_in_block_size_estimation: self.include_proof_in_block_size_estimation, + _phantom: self._phantom, + } + } +} + impl ProposerFactory { /// Create a new proposer factory. /// @@ -319,11 +335,12 @@ where self.apply_inherents(&mut block_builder, inherent_data)?; - // TODO call `after_inherents` and check if we should apply extrinsincs here - // - - let end_reason = - self.apply_extrinsics(&mut block_builder, deadline, block_size_limit).await?; + let mode = block_builder.extrinsic_inclusion_mode(); + let end_reason = match mode { + ExtrinsicInclusionMode::AllExtrinsics => + self.apply_extrinsics(&mut block_builder, deadline, block_size_limit).await?, + ExtrinsicInclusionMode::OnlyInherents => EndProposingReason::TransactionForbidden, + }; let (block, storage_changes, proof) = block_builder.build()?.into_inner(); let block_took = block_timer.elapsed(); diff --git a/substrate/client/block-builder/src/lib.rs b/substrate/client/block-builder/src/lib.rs index 258e39d962b2de2397d85a54223c155e821ddfa3..2f22cd42591fc60bf1665d00a1c5b2b548ad3aea 100644 --- a/substrate/client/block-builder/src/lib.rs +++ b/substrate/client/block-builder/src/lib.rs @@ -37,7 +37,7 @@ use sp_core::traits::CallContext; use sp_runtime::{ legacy, traits::{Block as BlockT, Hash, HashingFor, Header as HeaderT, NumberFor, One}, - Digest, + Digest, ExtrinsicInclusionMode, }; use std::marker::PhantomData; @@ -198,10 +198,12 @@ pub struct BlockBuilder<'a, Block: BlockT, C: ProvideRuntimeApi + 'a> { extrinsics: Vec, api: ApiRef<'a, C::Api>, call_api_at: &'a C, + /// Version of the [`BlockBuilderApi`] runtime API. version: u32, parent_hash: Block::Hash, /// The estimated size of the block header. estimated_header_size: usize, + extrinsic_inclusion_mode: ExtrinsicInclusionMode, } impl<'a, Block, C> BlockBuilder<'a, Block, C> @@ -244,9 +246,19 @@ where api.set_call_context(CallContext::Onchain); - api.initialize_block(parent_hash, &header)?; + let core_version = api + .api_version::>(parent_hash)? + .ok_or_else(|| Error::VersionInvalid("Core".to_string()))?; - let version = api + let extrinsic_inclusion_mode = if core_version >= 5 { + api.initialize_block(parent_hash, &header)? + } else { + #[allow(deprecated)] + api.initialize_block_before_version_5(parent_hash, &header)?; + ExtrinsicInclusionMode::AllExtrinsics + }; + + let bb_version = api .api_version::>(parent_hash)? .ok_or_else(|| Error::VersionInvalid("BlockBuilderApi".to_string()))?; @@ -254,12 +266,18 @@ where parent_hash, extrinsics: Vec::new(), api, - version, + version: bb_version, estimated_header_size, call_api_at, + extrinsic_inclusion_mode, }) } + /// The extrinsic inclusion mode of the runtime for this block. + pub fn extrinsic_inclusion_mode(&self) -> ExtrinsicInclusionMode { + self.extrinsic_inclusion_mode + } + /// Push onto the block's list of extrinsics. /// /// This will ensure the extrinsic can be validly executed (by executing it). diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 9ab12dc2ad55878714327e4c51c049c8d8da5396..f2138c07d71ad4c524e12d33ffb73d453d707fbb 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -18,8 +18,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } memmap2 = "0.9.3" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sc-client-api = { path = "../api" } sc-chain-spec-derive = { path = "derive" } sc-executor = { path = "../executor" } @@ -32,7 +32,7 @@ sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } sp-genesis-builder = { path = "../../primitives/genesis-builder" } sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } array-bytes = { version = "6.1" } docify = "0.2.7" diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 5e8e64e55513350d001e69755816e68536ac4592..521eee578ecae3b03cf86a3b4e3630bb7cd22f02 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -20,5 +20,5 @@ proc-macro = true [dependencies] proc-macro-crate = "3.0.0" proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = "2.0.48" +quote = { workspace = true } +syn = { workspace = true } diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs index fe8fcfda216e1fa86215daf93add2aa6adc78bd9..78e81e10d2b613d83c98e8b689cba2fd1356287c 100644 --- a/substrate/client/chain-spec/src/chain_spec.rs +++ b/substrate/client/chain-spec/src/chain_spec.rs @@ -1237,15 +1237,7 @@ mod tests { "TestName", "test", ChainType::Local, - move || substrate_test_runtime::RuntimeGenesisConfig { - babe: substrate_test_runtime::BabeConfig { - epoch_config: Some( - substrate_test_runtime::TEST_RUNTIME_BABE_EPOCH_CONFIGURATION, - ), - ..Default::default() - }, - ..Default::default() - }, + || Default::default(), Vec::new(), None, None, diff --git a/substrate/client/chain-spec/src/genesis_block.rs b/substrate/client/chain-spec/src/genesis_block.rs index 6aa156a620a7933034643f8a7bdbf8e0d617ad97..3c7b9f64dcd6bc0babff662747571f9d31853eec 100644 --- a/substrate/client/chain-spec/src/genesis_block.rs +++ b/substrate/client/chain-spec/src/genesis_block.rs @@ -18,23 +18,25 @@ //! Tool for creating the genesis block. -use std::{collections::hash_map::DefaultHasher, marker::PhantomData, sync::Arc}; +use std::{marker::PhantomData, sync::Arc}; +use codec::Encode; use sc_client_api::{backend::Backend, BlockImportOperation}; use sc_executor::RuntimeVersionOf; use sp_core::storage::{well_known_keys, StateVersion, Storage}; use sp_runtime::{ - traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero}, + traits::{Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, Zero}, BuildStorage, }; /// Return the state version given the genesis storage and executor. -pub fn resolve_state_version_from_wasm( +pub fn resolve_state_version_from_wasm( storage: &Storage, executor: &E, ) -> sp_blockchain::Result where E: RuntimeVersionOf, + H: HashT, { if let Some(wasm) = storage.top.get(well_known_keys::CODE) { let mut ext = sp_state_machine::BasicExternalities::new_empty(); // just to read runtime version. @@ -43,12 +45,7 @@ where let runtime_code = sp_core::traits::RuntimeCode { code_fetcher: &code_fetcher, heap_pages: None, - hash: { - use std::hash::{Hash, Hasher}; - let mut state = DefaultHasher::new(); - wasm.hash(&mut state); - state.finish().to_le_bytes().to_vec() - }, + hash: ::hash(wasm).encode(), }; let runtime_version = RuntimeVersionOf::runtime_version(executor, &mut ext, &runtime_code) .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()))?; @@ -129,7 +126,8 @@ impl, E: RuntimeVersionOf> BuildGenesisBlock sp_blockchain::Result<(Block, Self::BlockImportOperation)> { let Self { genesis_storage, commit_genesis_state, backend, executor, _phantom } = self; - let genesis_state_version = resolve_state_version_from_wasm(&genesis_storage, &executor)?; + let genesis_state_version = + resolve_state_version_from_wasm::<_, HashingFor>(&genesis_storage, &executor)?; let mut op = backend.begin_operation()?; let state_root = op.set_genesis_state(genesis_storage, commit_genesis_state, genesis_state_version)?; diff --git a/substrate/client/chain-spec/src/genesis_config_builder.rs b/substrate/client/chain-spec/src/genesis_config_builder.rs index 8766dd5c5ad28c9263f7538d255e03a898244026..c8b54f66be6f52ffb6900fafd2e8ec1652030976 100644 --- a/substrate/client/chain-spec/src/genesis_config_builder.rs +++ b/substrate/client/chain-spec/src/genesis_config_builder.rs @@ -81,7 +81,8 @@ where .0 } - /// Returns the default `GenesisConfig` provided by the `runtime`. + /// Returns a json representation of the default `RuntimeGenesisConfig` provided by the + /// `runtime`. /// /// Calls [`GenesisBuilder::create_default_config`](sp_genesis_builder::GenesisBuilder::create_default_config) in the `runtime`. pub fn get_default_config(&self) -> core::result::Result { @@ -94,7 +95,7 @@ where Ok(from_slice(&default_config[..]).expect("returned value is json. qed.")) } - /// Build the given `GenesisConfig` and returns the genesis state. + /// Builds `RuntimeGenesisConfig` from given json blob and returns the genesis state. /// /// Calls [`GenesisBuilder::build_config`](sp_genesis_builder::GenesisBuilder::build_config) /// provided by the `runtime`. @@ -111,25 +112,26 @@ where Ok(ext.into_storages()) } - /// Creates the genesis state by patching the default `GenesisConfig` and applying it. + /// Creates the genesis state by patching the default `RuntimeGenesisConfig`. /// - /// This function generates the `GenesisConfig` for the runtime by applying a provided JSON - /// patch. The patch modifies the default `GenesisConfig` allowing customization of the specific - /// keys. The resulting `GenesisConfig` is then deserialized from the patched JSON - /// representation and stored in the storage. + /// This function generates the `RuntimeGenesisConfig` for the runtime by applying a provided + /// JSON patch. The patch modifies the default `RuntimeGenesisConfig` allowing customization of + /// the specific keys. The resulting `RuntimeGenesisConfig` is then deserialized from the + /// patched JSON representation and stored in the storage. /// /// If the provided JSON patch is incorrect or the deserialization fails the error will be /// returned. /// - /// The patching process modifies the default `GenesisConfig` according to the following rules: + /// 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. /// 2. If a key exists in the patch but not in the default configuration, it will be added to - /// the resulting `GenesisConfig`. + /// the resulting `RuntimeGenesisConfig`. /// 3. Keys in the default configuration that have null values in the patch will be removed from - /// the resulting `GenesisConfig`. This is helpful for changing enum variant value. + /// the resulting `RuntimeGenesisConfig`. This is helpful for changing enum variant value. /// - /// Please note that the patch may contain full `GenesisConfig`. + /// Please note that the patch may contain full `RuntimeGenesisConfig`. pub fn get_storage_for_patch(&self, patch: Value) -> core::result::Result { let mut config = self.get_default_config()?; crate::json_patch::merge(&mut config, patch); @@ -149,7 +151,7 @@ mod tests { ::new(substrate_test_runtime::wasm_binary_unwrap()) .get_default_config() .unwrap(); - let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; + let expected = r#"{"babe": {"authorities": [], "epochConfig": {"allowed_slots": "PrimaryAndSecondaryVRFSlots", "c": [1, 4]}}, "balances": {"balances": []}, "substrateTest": {"authorities": []}, "system": {}}"#; assert_eq!(from_str::(expected).unwrap(), config); } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 2d9c2fa5ffbdd97e53bb2a246ceee69c013ea7c7..c70a0893c72505ce37d659225a93569ce98a025c 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -18,21 +18,22 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4.31" -clap = { version = "4.4.18", features = ["derive", "string", "wrap_help"] } +clap = { version = "4.5.1", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" futures = "0.3.21" itertools = "0.10.3" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } -log = "0.4.17" +log = { workspace = true, default-features = true } names = { version = "0.14.0", default-features = false } parity-scale-codec = "3.6.1" rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" -serde = "1.0.195" -serde_json = "1.0.111" -thiserror = "1.0.48" -bip39 = "2.0.0" +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } +# personal fork here as workaround for: https://github.com/rust-bitcoin/rust-bip39/pull/64 +bip39 = { package = "parity-bip39", version = "2.0.1", features = ["rand"] } tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "signal"] } sc-client-api = { path = "../api" } sc-client-db = { path = "../db", default-features = false } diff --git a/substrate/client/cli/src/commands/generate.rs b/substrate/client/cli/src/commands/generate.rs index c465bcc85a47be16a5217677311499ce42573895..94769279e21940993785b2a4eeb6fed5d08ddeb6 100644 --- a/substrate/client/cli/src/commands/generate.rs +++ b/substrate/client/cli/src/commands/generate.rs @@ -64,7 +64,7 @@ impl GenerateCmd { let password = self.keystore_params.read_password()?; let output = self.output_scheme.output_type; - let phrase = mnemonic.word_iter().join(" "); + let phrase = mnemonic.words().join(" "); with_crypto_scheme!( self.crypto_scheme.scheme, diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index f7b0fc51049106306ccff6d0d8fedc4db48868a6..221c32affd5a91d680f23ed11eb5f7a9a4051da2 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -30,11 +30,14 @@ use crate::{ use clap::Parser; use regex::Regex; use sc_service::{ - config::{BasePath, PrometheusConfig, TransactionPoolOptions}, + config::{BasePath, PrometheusConfig, RpcBatchRequestConfig, TransactionPoolOptions}, ChainSpec, Role, }; use sc_telemetry::TelemetryEndpoints; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + num::NonZeroU32, +}; /// The `run` command used to run a node. #[derive(Debug, Clone, Parser)] @@ -59,7 +62,7 @@ pub struct RunCmd { /// Not all RPC methods are safe to be exposed publicly. /// /// Use an RPC proxy server to filter out dangerous methods. More details: - /// . + /// . /// /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. #[arg(long)] @@ -82,6 +85,15 @@ pub struct RunCmd { )] pub rpc_methods: RpcMethods, + /// RPC rate limiting (calls/minute) for each connection. + /// + /// This is disabled by default. + /// + /// For example `--rpc-rate-limit 10` will maximum allow + /// 10 calls per minute per connection. + #[arg(long)] + pub rpc_rate_limit: Option, + /// Set the maximum RPC request payload size for both HTTP and WS in megabytes. #[arg(long, default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB)] pub rpc_max_request_size: u32, @@ -113,6 +125,14 @@ pub struct RunCmd { #[arg(long, default_value_t = RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN)] pub rpc_message_buffer_capacity_per_connection: u32, + /// Disable RPC batch requests + #[arg(long, alias = "rpc_no_batch_requests", conflicts_with_all = &["rpc_max_batch_request_len"])] + pub rpc_disable_batch_requests: bool, + + /// Limit the max length per RPC batch request + #[arg(long, conflicts_with_all = &["rpc_disable_batch_requests"], value_name = "LEN")] + pub rpc_max_batch_request_len: Option, + /// Specify browser *origins* allowed to access the HTTP & WS RPC servers. /// /// A comma-separated list of origins (protocol://domain or special `null` @@ -399,6 +419,26 @@ impl CliConfiguration for RunCmd { Ok(self.rpc_max_subscriptions_per_connection) } + fn rpc_buffer_capacity_per_connection(&self) -> Result { + Ok(self.rpc_message_buffer_capacity_per_connection) + } + + fn rpc_batch_config(&self) -> Result { + let cfg = if self.rpc_disable_batch_requests { + RpcBatchRequestConfig::Disabled + } else if let Some(l) = self.rpc_max_batch_request_len { + RpcBatchRequestConfig::Limit(l) + } else { + RpcBatchRequestConfig::Unlimited + }; + + Ok(cfg) + } + + fn rpc_rate_limit(&self) -> Result> { + Ok(self.rpc_rate_limit) + } + fn transaction_pool(&self, is_dev: bool) -> Result { Ok(self.pool_config.transaction_pool(is_dev)) } diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index defcc4a8a69078513ffacf667e6de7a7dd67f6dd..5def9ce9b72620eb7942ac6ee68b16493f6b8053 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -28,12 +28,13 @@ use sc_service::{ config::{ BasePath, Configuration, DatabaseSource, KeystoreConfig, NetworkConfiguration, NodeKeyConfig, OffchainWorkerConfig, OutputFormat, PrometheusConfig, PruningMode, Role, - RpcMethods, TelemetryEndpoints, TransactionPoolOptions, WasmExecutionMethod, + RpcBatchRequestConfig, RpcMethods, TelemetryEndpoints, TransactionPoolOptions, + WasmExecutionMethod, }, BlocksPruning, ChainSpec, TracingReceiver, }; use sc_tracing::logging::LoggerBuilder; -use std::{net::SocketAddr, path::PathBuf}; +use std::{net::SocketAddr, num::NonZeroU32, path::PathBuf}; /// The maximum number of characters for a node name. pub(crate) const NODE_NAME_MAX_LENGTH: usize = 64; @@ -338,6 +339,16 @@ pub trait CliConfiguration: Sized { Ok(RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN) } + /// RPC server batch request configuration. + fn rpc_batch_config(&self) -> Result { + Ok(RpcBatchRequestConfig::Unlimited) + } + + /// RPC rate limit configuration. + fn rpc_rate_limit(&self) -> Result> { + Ok(None) + } + /// Get the prometheus configuration (`None` if disabled) /// /// By default this is `None`. @@ -510,6 +521,8 @@ pub trait CliConfiguration: Sized { rpc_max_subs_per_conn: self.rpc_max_subscriptions_per_connection()?, rpc_port: DCV::rpc_listen_port(), rpc_message_buffer_capacity: self.rpc_buffer_capacity_per_connection()?, + rpc_batch_config: self.rpc_batch_config()?, + rpc_rate_limit: self.rpc_rate_limit()?, prometheus_config: self .prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?, telemetry_endpoints, diff --git a/substrate/client/cli/src/runner.rs b/substrate/client/cli/src/runner.rs index e37c8ab0e55163f72a4ec79dbc3c8c221205ac84..4201a0f4062fb0063621d85dd02feb0deade24bc 100644 --- a/substrate/client/cli/src/runner.rs +++ b/substrate/client/cli/src/runner.rs @@ -271,6 +271,8 @@ mod tests { rpc_max_subs_per_conn: Default::default(), rpc_message_buffer_capacity: Default::default(), rpc_port: 9944, + rpc_batch_config: sc_service::config::RpcBatchRequestConfig::Unlimited, + rpc_rate_limit: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index 33f7d160d8131f2b7eaadd679c8f32c112c1646f..213f75974da0c99cc5c39248a8a789c4989d8047 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -19,8 +19,8 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" -log = "0.4.17" -thiserror = "1.0" +log = { workspace = true, default-features = true } +thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-block-builder = { path = "../../block-builder" } sc-client-api = { path = "../../api" } diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index 01c5d062d61db800bc2fbdc727aa6349963505a8..c98fb7112b7c25bd39d980cab20c188f30b42eff 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -20,12 +20,12 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } num-bigint = "0.4.3" num-rational = "0.4.1" num-traits = "0.2.17" parking_lot = "0.12.1" -thiserror = "1.0" +thiserror = { workspace = true } fork-tree = { path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-client-api = { path = "../../api" } diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 2ca029444d078754bdd954386d2104b02cc09e34..043b566673e7bd5aa581e3043dfa1280aa04d53f 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -16,10 +16,10 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } futures = "0.3.21" -serde = { version = "1.0.195", features = ["derive"] } -thiserror = "1.0" +serde = { features = ["derive"], workspace = true, default-features = true } +thiserror = { workspace = true } sc-consensus-babe = { path = ".." } sc-consensus-epochs = { path = "../../epochs" } sc-rpc-api = { path = "../../../rpc-api" } @@ -33,7 +33,7 @@ sp-keystore = { path = "../../../../primitives/keystore" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } tokio = "1.22.0" sc-consensus = { path = "../../common" } sc-keystore = { path = "../../../keystore" } diff --git a/substrate/client/consensus/babe/rpc/src/lib.rs b/substrate/client/consensus/babe/rpc/src/lib.rs index 307b1f955ba2efa3a51302225d3d74e00e800538..a3e811baecffd6de1b9f94952be40d00d8b61de3 100644 --- a/substrate/client/consensus/babe/rpc/src/lib.rs +++ b/substrate/client/consensus/babe/rpc/src/lib.rs @@ -258,9 +258,9 @@ mod tests { let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params": [],"id":1}"#; let (response, _) = api.raw_json_request(request, 1).await.unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4],"secondary_vrf":[]}},"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[],"secondary_vrf":[1,2,4]}},"id":1}"#; - assert_eq!(&response.result, expected); + assert_eq!(response, expected); } #[tokio::test] @@ -272,6 +272,6 @@ mod tests { let (response, _) = api.raw_json_request(request, 1).await.unwrap(); let expected = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"#; - assert_eq!(&response.result, expected); + assert_eq!(response, expected); } } diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 3522697427875034ec330d31b80b22085c1f042b..8552a49002239aaeaf232c0aebf4180cec207337 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -18,9 +18,9 @@ async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } fnv = "1.0.6" futures = "0.3" -log = "0.4" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" -thiserror = "1.0" +thiserror = { workspace = true } wasm-timer = "0.2.5" prometheus = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-client-api = { path = "../../api" } @@ -44,7 +44,7 @@ tokio = "1.22.0" [dev-dependencies] -serde = "1.0.195" +serde = { workspace = true, default-features = true } tempfile = "3.1.0" sc-block-builder = { path = "../../block-builder" } sc-network-test = { path = "../../network/test" } @@ -52,3 +52,12 @@ sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa" } sp-keyring = { path = "../../../primitives/keyring" } sp-tracing = { path = "../../../primitives/tracing" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } + +[features] +# This feature adds BLS crypto primitives. It should not be used in production since +# the BLS implementation and interface may still be subject to significant change. +bls-experimental = [ + "sp-application-crypto/bls-experimental", + "sp-consensus-beefy/bls-experimental", + "sp-core/bls-experimental", +] diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 496aefac113aeffbdc9ad361c2df9a8fc2c99856..bb2ae4a08966707fd93afd48b625ccc4f760762b 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -14,11 +14,11 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } -log = "0.4" +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +log = { workspace = true, default-features = true } parking_lot = "0.12.1" -serde = { version = "1.0.195", features = ["derive"] } -thiserror = "1.0" +serde = { features = ["derive"], workspace = true, default-features = true } +thiserror = { workspace = true } sc-consensus-beefy = { path = ".." } sp-consensus-beefy = { path = "../../../../primitives/consensus/beefy" } sc-rpc = { path = "../../../rpc" } @@ -26,7 +26,7 @@ sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } sc-rpc = { path = "../../../rpc", features = ["test-helpers"] } substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } tokio = { version = "1.22.0", features = ["macros"] } diff --git a/substrate/client/consensus/beefy/rpc/src/lib.rs b/substrate/client/consensus/beefy/rpc/src/lib.rs index 03c83e92716c7d860760af40a578f651b962d23d..f01baee2d6ece9a9d1dd36e1524a1d004e9b0401 100644 --- a/substrate/client/consensus/beefy/rpc/src/lib.rs +++ b/substrate/client/consensus/beefy/rpc/src/lib.rs @@ -184,10 +184,10 @@ mod tests { async fn uninitialized_rpc_handler() { let (rpc, _) = setup_io_handler(); let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; - let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#.to_string(); + let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); - assert_eq!(expected_response, response.result); + assert_eq!(expected_response, response); } #[tokio::test] @@ -205,20 +205,18 @@ mod tests { \"jsonrpc\":\"2.0\",\ \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\",\ \"id\":1\ - }" - .to_string(); + }"; let not_ready = "{\ \"jsonrpc\":\"2.0\",\ \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"},\ \"id\":1\ - }" - .to_string(); + }"; let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); while std::time::Instant::now() < deadline { let (response, _) = io.raw_json_request(request, 1).await.expect("RPC requests work"); - if response.result != not_ready { - assert_eq!(response.result, expected); + if response != not_ready { + assert_eq!(response, expected); // Success return } @@ -249,7 +247,7 @@ mod tests { .unwrap(); let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - assert_eq!(response.result, expected); + assert_eq!(response, expected); } fn create_finality_proof() -> BeefyVersionedFinalityProof { diff --git a/substrate/client/consensus/beefy/src/aux_schema.rs b/substrate/client/consensus/beefy/src/aux_schema.rs index 944a00f8372fa8b0643dd4ddff8f8ce684e9f325..534f668ae69c2996064bef086e2958b23f48caf0 100644 --- a/substrate/client/consensus/beefy/src/aux_schema.rs +++ b/substrate/client/consensus/beefy/src/aux_schema.rs @@ -20,7 +20,7 @@ use crate::{error::Error, worker::PersistedState, LOG_TARGET}; use codec::{Decode, Encode}; -use log::{info, trace}; +use log::{debug, trace}; use sc_client_api::{backend::AuxStore, Backend}; use sp_runtime::traits::Block as BlockT; @@ -30,7 +30,7 @@ const WORKER_STATE_KEY: &[u8] = b"beefy_voter_state"; const CURRENT_VERSION: u32 = 4; pub(crate) fn write_current_version(backend: &BE) -> Result<(), Error> { - info!(target: LOG_TARGET, "🥩 write aux schema version {:?}", CURRENT_VERSION); + debug!(target: LOG_TARGET, "🥩 write aux schema version {:?}", CURRENT_VERSION); AuxStore::insert_aux(backend, &[(VERSION_KEY, CURRENT_VERSION.encode().as_slice())], &[]) .map_err(|e| Error::Backend(e.to_string())) } diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 645a10b2a1d43f9bb879a799ac9625b2f623506c..eb43c9173d751bf75bc4973aca248d80fb68ca48 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -56,6 +56,8 @@ pub(super) enum Action { Keep(H, ReputationChange), // discard, applying cost/benefit to originator. Discard(ReputationChange), + // ignore, no cost/benefit applied to originator. + DiscardNoReport, } /// An outcome of examining a message. @@ -68,7 +70,7 @@ enum Consider { /// Message is from the future. Reject. RejectFuture, /// Message cannot be evaluated. Reject. - RejectOutOfScope, + CannotEvaluate, } /// BEEFY gossip message type that gets encoded and sent on the network. @@ -168,18 +170,14 @@ impl Filter { .as_ref() .map(|f| // only from current set and only [filter.start, filter.end] - if set_id < f.validator_set.id() { + if set_id < f.validator_set.id() || round < f.start { Consider::RejectPast - } else if set_id > f.validator_set.id() { - Consider::RejectFuture - } else if round < f.start { - Consider::RejectPast - } else if round > f.end { + } else if set_id > f.validator_set.id() || round > f.end { Consider::RejectFuture } else { Consider::Accept }) - .unwrap_or(Consider::RejectOutOfScope) + .unwrap_or(Consider::CannotEvaluate) } /// Return true if `round` is >= than `max(session_start, best_beefy)`, @@ -199,7 +197,7 @@ impl Filter { Consider::Accept } ) - .unwrap_or(Consider::RejectOutOfScope) + .unwrap_or(Consider::CannotEvaluate) } /// Add new _known_ `round` to the set of seen valid justifications. @@ -244,7 +242,7 @@ where pub(crate) fn new( known_peers: Arc>>, ) -> (GossipValidator, TracingUnboundedReceiver) { - let (tx, rx) = tracing_unbounded("mpsc_beefy_gossip_validator", 10_000); + let (tx, rx) = tracing_unbounded("mpsc_beefy_gossip_validator", 100_000); let val = GossipValidator { votes_topic: votes_topic::(), justifs_topic: proofs_topic::(), @@ -289,7 +287,9 @@ where match filter.consider_vote(round, set_id) { Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), - Consider::RejectOutOfScope => return Action::Discard(cost::OUT_OF_SCOPE_MESSAGE), + // When we can't evaluate, it's our fault (e.g. filter not initialized yet), we + // discard the vote without punishing or rewarding the sending peer. + Consider::CannotEvaluate => return Action::DiscardNoReport, Consider::Accept => {}, } @@ -330,7 +330,9 @@ where match guard.consider_finality_proof(round, set_id) { Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), - Consider::RejectOutOfScope => return Action::Discard(cost::OUT_OF_SCOPE_MESSAGE), + // When we can't evaluate, it's our fault (e.g. filter not initialized yet), we + // discard the proof without punishing or rewarding the sending peer. + Consider::CannotEvaluate => return Action::DiscardNoReport, Consider::Accept => {}, } @@ -357,7 +359,9 @@ where Action::Keep(self.justifs_topic, benefit::VALIDATED_PROOF) } }) - .unwrap_or(Action::Discard(cost::OUT_OF_SCOPE_MESSAGE)) + // When we can't evaluate, it's our fault (e.g. filter not initialized yet), we + // discard the proof without punishing or rewarding the sending peer. + .unwrap_or(Action::DiscardNoReport) }; if matches!(action, Action::Keep(_, _)) { self.gossip_filter.write().mark_round_as_proven(round); @@ -404,6 +408,7 @@ where self.report(*sender, cb); ValidationResult::Discard }, + Action::DiscardNoReport => ValidationResult::Discard, } } @@ -485,8 +490,8 @@ pub(crate) mod tests { use sc_network_test::Block; use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus_beefy::{ - ecdsa_crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, - SignedCommitment, VoteMessage, + ecdsa_crypto::Signature, known_payloads, test_utils::Keyring, Commitment, MmrRootHash, + Payload, SignedCommitment, VoteMessage, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; @@ -507,10 +512,13 @@ pub(crate) mod tests { } } - pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { + pub fn sign_commitment( + who: &Keyring, + commitment: &Commitment, + ) -> Signature { let store = MemoryKeystore::new(); store.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap(); - let beefy_keystore: BeefyKeystore = Some(store.into()).into(); + let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } @@ -538,7 +546,10 @@ pub(crate) mod tests { .validators() .iter() .map(|validator: &AuthorityId| { - Some(sign_commitment(&Keyring::from_public(validator).unwrap(), &commitment)) + Some(sign_commitment( + &Keyring::::from_public(validator).unwrap(), + &commitment, + )) }) .collect(); @@ -547,7 +558,7 @@ pub(crate) mod tests { #[test] fn should_validate_messages() { - let keys = vec![Keyring::Alice.public()]; + let keys = vec![Keyring::::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); let (gv, mut report_stream) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); @@ -573,8 +584,8 @@ pub(crate) mod tests { // filter not initialized let res = gv.validate(&mut context, &sender, &encoded); assert!(matches!(res, ValidationResult::Discard)); - expected_report.cost_benefit = cost::OUT_OF_SCOPE_MESSAGE; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); + // nothing reported + assert!(report_stream.try_recv().is_err()); gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); // nothing in cache first time diff --git a/substrate/client/consensus/beefy/src/communication/mod.rs b/substrate/client/consensus/beefy/src/communication/mod.rs index 3827559057dde856d201ebb9c9ff71a1d7d11f47..6fda63688e6952839c18e1bbc9ff50ff0c5f7c21 100644 --- a/substrate/client/consensus/beefy/src/communication/mod.rs +++ b/substrate/client/consensus/beefy/src/communication/mod.rs @@ -90,8 +90,6 @@ mod cost { pub(super) const BAD_SIGNATURE: Rep = Rep::new(-100, "BEEFY: Bad signature"); // Message received with vote from voter not in validator set. pub(super) const UNKNOWN_VOTER: Rep = Rep::new(-150, "BEEFY: Unknown voter"); - // A message received that cannot be evaluated relative to our current state. - pub(super) const OUT_OF_SCOPE_MESSAGE: Rep = Rep::new(-500, "BEEFY: Out-of-scope message"); // Message containing invalid proof. pub(super) const INVALID_PROOF: Rep = Rep::new(-5000, "BEEFY: Invalid commit"); // Reputation cost per signature checked for invalid proof. diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index fc19ecc301422d74d5da5a289ed641810b1022f1..ed8ed68c4e8d0d378728ba87d1ffe726f6c4c11a 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -159,7 +159,7 @@ where // The proof is valid and the block is imported and final, we can import. debug!( target: LOG_TARGET, - "🥩 import justif {:?} for block number {:?}.", proof, number + "🥩 import justif {} for block number {:?}.", proof, number ); // Send the justification to the BEEFY voter for processing. self.justification_sender diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 483184e2374a2b9239554e4ce2709cd7a294cb8c..7f1b9e5237c3970eb8cba4936debd18c77117288 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -76,7 +76,7 @@ pub(crate) fn verify_with_validator_set( .as_ref() .map(|sig| { signatures_checked += 1; - BeefyKeystore::verify(id, sig, &message[..]) + BeefyKeystore::verify(*id, sig, &message[..]) }) .unwrap_or(false) }) @@ -93,7 +93,8 @@ pub(crate) fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use sp_consensus_beefy::{ - known_payloads, Commitment, Keyring, Payload, SignedCommitment, VersionedFinalityProof, + known_payloads, test_utils::Keyring, Commitment, Payload, SignedCommitment, + VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; @@ -103,7 +104,7 @@ pub(crate) mod tests { pub(crate) fn new_finality_proof( block_num: NumberFor, validator_set: &ValidatorSet, - keys: &[Keyring], + keys: &[Keyring], ) -> BeefyVersionedFinalityProof { let commitment = Commitment { payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), @@ -174,7 +175,7 @@ pub(crate) mod tests { }; // change a signature to a different key *bad_signed_commitment.signatures.first_mut().unwrap() = - Some(Keyring::Dave.sign(&bad_signed_commitment.commitment.encode())); + Some(Keyring::::Dave.sign(&bad_signed_commitment.commitment.encode())); match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { Err((ConsensusError::InvalidJustification, 3)) => (), e => assert!(false, "Got unexpected {:?}", e), diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 75c44de3324cee7b4f0cc4a08335640708952157..2ddc938fbc6ce33aa74c62d051cf77a519c634ee 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -16,41 +16,45 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, RuntimeAppPublic}; +use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, RuntimeAppPublic}; +use sp_consensus_beefy::{AuthorityIdBound, BeefyAuthorityId, BeefySignatureHasher}; +use sp_core::ecdsa; +#[cfg(feature = "bls-experimental")] +use sp_core::ecdsa_bls377; use sp_crypto_hashing::keccak_256; use sp_keystore::KeystorePtr; +use codec::Decode; use log::warn; - -use sp_consensus_beefy::{ - ecdsa_crypto::{Public, Signature}, - BeefyAuthorityId, -}; +use std::marker::PhantomData; use crate::{error, LOG_TARGET}; -/// Hasher used for BEEFY signatures. -pub(crate) type BeefySignatureHasher = sp_runtime::traits::Keccak256; - /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a /// wrapper around [`sp_keystore::Keystore`] and allows to customize /// common cryptographic functionality. -pub(crate) struct BeefyKeystore(Option); +pub(crate) struct BeefyKeystore( + Option, + PhantomData AuthorityId>, +); -impl BeefyKeystore { +impl BeefyKeystore { /// Check if the keystore contains a private key for one of the public keys /// contained in `keys`. A public key with a matching private key is known /// as a local authority id. /// /// Return the public key for which we also do have a private key. If no /// matching private key is found, `None` will be returned. - pub fn authority_id(&self, keys: &[Public]) -> Option { + pub fn authority_id(&self, keys: &[AuthorityId]) -> Option { let store = self.0.clone()?; // we do check for multiple private keys as a key store sanity check. - let public: Vec = keys + let public: Vec = keys .iter() - .filter(|k| store.has_keys(&[(k.to_raw_vec(), BEEFY_KEY_TYPE)])) + .filter(|k| { + store + .has_keys(&[(::to_raw_vec(k), BEEFY_KEY_TYPE)]) + }) .cloned() .collect(); @@ -71,55 +75,125 @@ impl BeefyKeystore { /// Note that `message` usually will be pre-hashed before being signed. /// /// Return the message signature or an error in case of failure. - pub fn sign(&self, public: &Public, message: &[u8]) -> Result { + pub fn sign( + &self, + public: &AuthorityId, + message: &[u8], + ) -> Result<::Signature, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - let msg = keccak_256(message); - let public = public.as_ref(); - - let sig = store - .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, public, &msg) - .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()))?; - - // check that `sig` has the expected result type - let sig = sig.clone().try_into().map_err(|_| { - error::Error::Signature(format!("invalid signature {:?} for key {:?}", sig, public)) + // ECDSA should use ecdsa_sign_prehashed since it needs to be hashed by keccak_256 instead + // of blake2. As such we need to deal with producing the signatures case-by-case + let signature_byte_array: Vec = match ::CRYPTO_ID { + ecdsa::CRYPTO_ID => { + let msg_hash = keccak_256(message); + let public: ecdsa::Public = ecdsa::Public::try_from(public.as_slice()).unwrap(); + + let sig = store + .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, &public, &msg_hash) + .map_err(|e| error::Error::Keystore(e.to_string()))? + .ok_or_else(|| { + error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()) + })?; + let sig_ref: &[u8] = sig.as_ref(); + sig_ref.to_vec() + }, + + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => { + let public: ecdsa_bls377::Public = + ecdsa_bls377::Public::try_from(public.as_slice()).unwrap(); + let sig = store + .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) + .map_err(|e| error::Error::Keystore(e.to_string()))? + .ok_or_else(|| error::Error::Signature("bls377_sign() failed".to_string()))?; + let sig_ref: &[u8] = sig.as_ref(); + sig_ref.to_vec() + }, + + _ => Err(error::Error::Keystore("key type is not supported by BEEFY Keystore".into()))?, + }; + + //check that `sig` has the expected result type + let signature = ::Signature::decode( + &mut signature_byte_array.as_slice(), + ) + .map_err(|_| { + error::Error::Signature(format!( + "invalid signature {:?} for key {:?}", + signature_byte_array, public + )) })?; - Ok(sig) + Ok(signature) } /// Returns a vector of [`sp_consensus_beefy::crypto::Public`] keys which are currently /// supported (i.e. found in the keystore). - pub fn public_keys(&self) -> Result, error::Error> { + pub fn public_keys(&self) -> Result, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - let pk: Vec = - store.ecdsa_public_keys(BEEFY_KEY_TYPE).drain(..).map(Public::from).collect(); - - Ok(pk) + let pk = match ::CRYPTO_ID { + ecdsa::CRYPTO_ID => store + .ecdsa_public_keys(BEEFY_KEY_TYPE) + .drain(..) + .map(|pk| AuthorityId::try_from(pk.as_ref())) + .collect::, _>>() + .or_else(|_| { + Err(error::Error::Keystore( + "unable to convert public key into authority id".into(), + )) + }), + + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => store + .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) + .drain(..) + .map(|pk| AuthorityId::try_from(pk.as_ref())) + .collect::, _>>() + .or_else(|_| { + Err(error::Error::Keystore( + "unable to convert public key into authority id".into(), + )) + }), + + _ => Err(error::Error::Keystore("key type is not supported by BEEFY Keystore".into())), + }; + + pk } /// Use the `public` key to verify that `sig` is a valid signature for `message`. /// /// Return `true` if the signature is authentic, `false` otherwise. - pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { + pub fn verify( + public: &AuthorityId, + sig: &::Signature, + message: &[u8], + ) -> bool { BeefyAuthorityId::::verify(public, sig, message) } } -impl From> for BeefyKeystore { - fn from(store: Option) -> BeefyKeystore { - BeefyKeystore(store) +impl From> for BeefyKeystore +where + ::Signature: Send + Sync, +{ + fn from(store: Option) -> BeefyKeystore { + BeefyKeystore(store, PhantomData) } } #[cfg(test)] pub mod tests { - use sp_consensus_beefy::{ecdsa_crypto, Keyring}; - use sp_core::{ecdsa, Pair}; - use sp_keystore::testing::MemoryKeystore; + #[cfg(feature = "bls-experimental")] + use sp_consensus_beefy::ecdsa_bls_crypto; + use sp_consensus_beefy::{ + ecdsa_crypto, + test_utils::{BeefySignerAuthority, Keyring}, + }; + use sp_core::Pair as PairT; + use sp_keystore::{testing::MemoryKeystore, Keystore}; use super::*; use crate::error::Error; @@ -128,152 +202,265 @@ pub mod tests { MemoryKeystore::new().into() } - #[test] - fn verify_should_work() { - let msg = keccak_256(b"I am Alice!"); - let sig = Keyring::Alice.sign(b"I am Alice!"); - - assert!(ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Alice.public().into(), + fn pair_verify_should_work< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { + let msg = b"I am Alice!"; + let sig = Keyring::::Alice.sign(b"I am Alice!"); + + assert!(>::verify( + &Keyring::Alice.public(), + &sig, + &msg.as_slice(), )); // different public key -> fail - assert!(!ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Bob.public().into(), + assert!(!>::verify( + &Keyring::Bob.public(), + &sig, + &msg.as_slice(), )); - let msg = keccak_256(b"I am not Alice!"); + let msg = b"I am not Alice!"; // different msg -> fail - assert!( - !ecdsa::Pair::verify_prehashed(&sig.into(), &msg, &Keyring::Alice.public().into(),) - ); + assert!(!>::verify( + &Keyring::Alice.public(), + &sig, + &msg.as_slice(), + )); + } + + /// Generate key pair in the given store using the provided seed + fn generate_in_store( + store: KeystorePtr, + key_type: sp_application_crypto::KeyTypeId, + owner: Option>, + ) -> AuthorityId + where + AuthorityId: + AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + ::Pair: BeefySignerAuthority, + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + { + let optional_seed: Option = owner.map(|owner| owner.to_seed()); + + match ::CRYPTO_ID { + ecdsa::CRYPTO_ID => { + let pk = store.ecdsa_generate_new(key_type, optional_seed.as_deref()).ok().unwrap(); + AuthorityId::decode(&mut pk.as_ref()).unwrap() + }, + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => { + let pk = store + .ecdsa_bls377_generate_new(key_type, optional_seed.as_deref()) + .ok() + .unwrap(); + AuthorityId::decode(&mut pk.as_ref()).unwrap() + }, + _ => panic!("Requested CRYPTO_ID is not supported by the BEEFY Keyring"), + } } #[test] - fn pair_works() { - let want = ecdsa_crypto::Pair::from_string("//Alice", None) + fn pair_verify_should_work_ecdsa() { + pair_verify_should_work::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn pair_verify_should_work_ecdsa_n_bls() { + pair_verify_should_work::(); + } + + fn pair_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { + let want = ::Pair::from_string("//Alice", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Alice.pair().to_raw_vec(); + let got = Keyring::::Alice.pair().to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Bob", None) + let want = ::Pair::from_string("//Bob", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Bob.pair().to_raw_vec(); + let got = Keyring::::Bob.pair().to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Charlie", None) + let want = ::Pair::from_string("//Charlie", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Charlie.pair().to_raw_vec(); + let got = Keyring::::Charlie.pair().to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Dave", None) + let want = ::Pair::from_string("//Dave", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Dave.pair().to_raw_vec(); + let got = Keyring::::Dave.pair().to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Eve", None) + let want = ::Pair::from_string("//Eve", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Eve.pair().to_raw_vec(); + let got = Keyring::::Eve.pair().to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Ferdie", None) + let want = ::Pair::from_string("//Ferdie", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Ferdie.pair().to_raw_vec(); + let got = Keyring::::Ferdie.pair().to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//One", None) + let want = ::Pair::from_string("//One", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::One.pair().to_raw_vec(); + let got = Keyring::::One.pair().to_raw_vec(); assert_eq!(want, got); - let want = ecdsa_crypto::Pair::from_string("//Two", None) + let want = ::Pair::from_string("//Two", None) .expect("Pair failed") .to_raw_vec(); - let got = Keyring::Two.pair().to_raw_vec(); + let got = Keyring::::Two.pair().to_raw_vec(); assert_eq!(want, got); } #[test] - fn authority_id_works() { + fn ecdsa_pair_works() { + pair_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn ecdsa_n_bls_pair_works() { + pair_works::(); + } + + fn authority_id_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - let alice: ecdsa_crypto::Public = store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice)); + + let alice = Keyring::::Alice.public(); let bob = Keyring::Bob.public(); let charlie = Keyring::Charlie.public(); - let store: BeefyKeystore = Some(store).into(); + let beefy_store: BeefyKeystore = Some(store).into(); let mut keys = vec![bob, charlie]; - let id = store.authority_id(keys.as_slice()); + let id = beefy_store.authority_id(keys.as_slice()); assert!(id.is_none()); keys.push(alice.clone()); - let id = store.authority_id(keys.as_slice()).unwrap(); + let id = beefy_store.authority_id(keys.as_slice()).unwrap(); assert_eq!(id, alice); } #[test] - fn sign_works() { + fn authority_id_works_for_ecdsa() { + authority_id_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn authority_id_works_for_ecdsa_n_bls() { + authority_id_works::(); + } + + fn sign_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - let alice: ecdsa_crypto::Public = store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice)); - let store: BeefyKeystore = Some(store).into(); + let alice = Keyring::Alice.public(); + + let store: BeefyKeystore = Some(store).into(); let msg = b"are you involved or commited?"; let sig1 = store.sign(&alice, msg).unwrap(); - let sig2 = Keyring::Alice.sign(msg); + let sig2 = Keyring::::Alice.sign(msg); assert_eq!(sig1, sig2); } #[test] - fn sign_error() { + fn sign_works_for_ecdsa() { + sign_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn sign_works_for_ecdsa_n_bls() { + sign_works::(); + } + + fn sign_error< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >( + expected_error_message: &str, + ) where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Bob.to_seed())) - .ok() - .unwrap(); + generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Bob)); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let alice = Keyring::Alice.public(); let msg = b"are you involved or commited?"; let sig = store.sign(&alice, msg).err().unwrap(); - let err = Error::Signature("ecdsa_sign_prehashed() failed".to_string()); + let err = Error::Signature(expected_error_message.to_string()); assert_eq!(sig, err); } + #[test] + fn sign_error_for_ecdsa() { + sign_error::("ecdsa_sign_prehashed() failed"); + } + + #[cfg(feature = "bls-experimental")] + #[test] + fn sign_error_for_ecdsa_n_bls() { + sign_error::("bls377_sign() failed"); + } + #[test] fn sign_no_keystore() { - let store: BeefyKeystore = None.into(); + let store: BeefyKeystore = None.into(); let alice = Keyring::Alice.public(); let msg = b"are you involved or commited"; @@ -283,17 +470,21 @@ pub mod tests { assert_eq!(sig, err); } - #[test] - fn verify_works() { + fn verify_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { let store = keystore(); - let alice: ecdsa_crypto::Public = store - .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice)); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); + + let alice = Keyring::Alice.public(); // `msg` and `sig` match let msg = b"are you involved or commited?"; @@ -305,32 +496,48 @@ pub mod tests { assert!(!BeefyKeystore::verify(&alice, &sig, msg)); } - // Note that we use keys with and without a seed for this test. #[test] - fn public_keys_works() { + fn verify_works_for_ecdsa() { + verify_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + + fn verify_works_for_ecdsa_n_bls() { + verify_works::(); + } + + // Note that we use keys with and without a seed for this test. + fn public_keys_works< + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + >() + where + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, + ::Pair: BeefySignerAuthority, + { const TEST_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"test"); let store = keystore(); - let add_key = - |key_type, seed: Option<&str>| store.ecdsa_generate_new(key_type, seed).unwrap(); - // test keys - let _ = add_key(TEST_TYPE, Some(Keyring::Alice.to_seed().as_str())); - let _ = add_key(TEST_TYPE, Some(Keyring::Bob.to_seed().as_str())); - - let _ = add_key(TEST_TYPE, None); - let _ = add_key(TEST_TYPE, None); + let _ = generate_in_store::(store.clone(), TEST_TYPE, Some(Keyring::Alice)); + let _ = generate_in_store::(store.clone(), TEST_TYPE, Some(Keyring::Bob)); // BEEFY keys - let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); - let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); + let _ = + generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Dave)); + let _ = generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Eve)); + + let _ = generate_in_store::(store.clone(), TEST_TYPE, None); + let _ = generate_in_store::(store.clone(), TEST_TYPE, None); - let key1: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); - let key2: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); + let key1 = generate_in_store::(store.clone(), BEEFY_KEY_TYPE, None); + let key2 = generate_in_store::(store.clone(), BEEFY_KEY_TYPE, None); - let store: BeefyKeystore = Some(store).into(); + let store: BeefyKeystore = Some(store).into(); let keys = store.public_keys().ok().unwrap(); @@ -340,4 +547,16 @@ pub mod tests { assert!(keys.contains(&key1)); assert!(keys.contains(&key2)); } + + #[test] + fn public_keys_works_for_ecdsa_keystore() { + public_keys_works::(); + } + + #[cfg(feature = "bls-experimental")] + #[test] + + fn public_keys_works_for_ecdsa_n_bls() { + public_keys_works::(); + } } diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 1f10d8099d836b55fab2b13a60dcc2faf0f37320..323af1bc8305c38bf7a34b4690b212954b7b0864 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -31,7 +31,7 @@ use crate::{ import::BeefyBlockImport, metrics::register_metrics, }; -use futures::{stream::Fuse, StreamExt}; +use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, warn}; use parking_lot::Mutex; use prometheus::Registry; @@ -40,17 +40,21 @@ use sc_consensus::BlockImport; use sc_network::{NetworkRequest, NotificationService, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::ProvideRuntimeApi; -use sp_blockchain::{ - Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, -}; +use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_consensus_beefy::{ - ecdsa_crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, + ecdsa_crypto::AuthorityId, BeefyApi, ConsensusLog, MmrRootHash, PayloadProvider, ValidatorSet, + BEEFY_ENGINE_ID, }; use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::{Block, Header as HeaderT, NumberFor, Zero}; -use std::{collections::BTreeMap, marker::PhantomData, sync::Arc, time::Duration}; +use std::{ + collections::{BTreeMap, VecDeque}, + marker::PhantomData, + sync::Arc, + time::Duration, +}; mod aux_schema; mod error; @@ -63,9 +67,19 @@ pub mod communication; pub mod import; pub mod justification; +use crate::{ + communication::{gossip::GossipValidator, peers::PeerReport}, + justification::BeefyVersionedFinalityProof, + keystore::BeefyKeystore, + metrics::VoterMetrics, + round::Rounds, + worker::{BeefyWorker, PersistedState}, +}; pub use communication::beefy_protocol_name::{ gossip_protocol_name, justifications_protocol_name as justifs_protocol_name, }; +use sc_utils::mpsc::TracingUnboundedReceiver; +use sp_runtime::generic::OpaqueDigestItemId; #[cfg(test)] mod tests; @@ -209,6 +223,247 @@ pub struct BeefyParams { /// Handler for incoming BEEFY justifications requests from a remote peer. pub on_demand_justifications_handler: BeefyJustifsRequestHandler, } +/// Helper object holding BEEFY worker communication/gossip components. +/// +/// These are created once, but will be reused if worker is restarted/reinitialized. +pub(crate) struct BeefyComms { + pub gossip_engine: GossipEngine, + pub gossip_validator: Arc>, + pub gossip_report_stream: TracingUnboundedReceiver, + pub on_demand_justifications: OnDemandJustificationsEngine, +} + +/// Helper builder object for building [worker::BeefyWorker]. +/// +/// It has to do it in two steps: initialization and build, because the first step can sleep waiting +/// for certain chain and backend conditions, and while sleeping we still need to pump the +/// GossipEngine. Once initialization is done, the GossipEngine (and other pieces) are added to get +/// the complete [worker::BeefyWorker] object. +pub(crate) struct BeefyWorkerBuilder { + // utilities + backend: Arc, + runtime: Arc, + key_store: BeefyKeystore, + // voter metrics + metrics: Option, + persisted_state: PersistedState, +} + +impl BeefyWorkerBuilder +where + B: Block + codec::Codec, + BE: Backend, + R: ProvideRuntimeApi, + R::Api: BeefyApi, +{ + /// This will wait for the chain to enable BEEFY (if not yet enabled) and also wait for the + /// backend to sync all headers required by the voter to build a contiguous chain of mandatory + /// justifications. Then it builds the initial voter state using a combination of previously + /// persisted state in AUX DB and latest chain information/progress. + /// + /// Returns a sane `BeefyWorkerBuilder` that can build the `BeefyWorker`. + pub async fn async_initialize( + backend: Arc, + runtime: Arc, + key_store: BeefyKeystore, + metrics: Option, + min_block_delta: u32, + gossip_validator: Arc>, + finality_notifications: &mut Fuse>, + ) -> Result { + // Wait for BEEFY pallet to be active before starting voter. + let (beefy_genesis, best_grandpa) = + wait_for_runtime_pallet(&*runtime, finality_notifications).await?; + + let persisted_state = Self::load_or_init_state( + beefy_genesis, + best_grandpa, + min_block_delta, + backend.clone(), + runtime.clone(), + &key_store, + &metrics, + ) + .await?; + // Update the gossip validator with the right starting round and set id. + persisted_state + .gossip_filter_config() + .map(|f| gossip_validator.update_filter(f))?; + + Ok(BeefyWorkerBuilder { backend, runtime, key_store, metrics, persisted_state }) + } + + /// Takes rest of missing pieces as params and builds the `BeefyWorker`. + pub fn build( + self, + payload_provider: P, + sync: Arc, + comms: BeefyComms, + links: BeefyVoterLinks, + pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + ) -> BeefyWorker { + BeefyWorker { + backend: self.backend, + runtime: self.runtime, + key_store: self.key_store, + metrics: self.metrics, + persisted_state: self.persisted_state, + payload_provider, + sync, + comms, + links, + pending_justifications, + } + } + + // If no persisted state present, walk back the chain from first GRANDPA notification to either: + // - latest BEEFY finalized block, or if none found on the way, + // - BEEFY pallet genesis; + // Enqueue any BEEFY mandatory blocks (session boundaries) found on the way, for voter to + // finalize. + async fn init_state( + beefy_genesis: NumberFor, + best_grandpa: ::Header, + min_block_delta: u32, + backend: Arc, + runtime: Arc, + ) -> Result, Error> { + let blockchain = backend.blockchain(); + + let beefy_genesis = runtime + .runtime_api() + .beefy_genesis(best_grandpa.hash()) + .ok() + .flatten() + .filter(|genesis| *genesis == beefy_genesis) + .ok_or_else(|| Error::Backend("BEEFY pallet expected to be active.".into()))?; + // Walk back the imported blocks and initialize voter either, at the last block with + // a BEEFY justification, or at pallet genesis block; voter will resume from there. + let mut sessions = VecDeque::new(); + let mut header = best_grandpa.clone(); + let state = loop { + if let Some(true) = blockchain + .justifications(header.hash()) + .ok() + .flatten() + .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) + { + debug!( + target: LOG_TARGET, + "🥩 Initialize BEEFY voter at last BEEFY finalized block: {:?}.", + *header.number() + ); + let best_beefy = *header.number(); + // If no session boundaries detected so far, just initialize new rounds here. + if sessions.is_empty() { + let active_set = + expect_validator_set(runtime.as_ref(), backend.as_ref(), &header).await?; + let mut rounds = Rounds::new(best_beefy, active_set); + // Mark the round as already finalized. + rounds.conclude(best_beefy); + sessions.push_front(rounds); + } + let state = PersistedState::checked_new( + best_grandpa, + best_beefy, + sessions, + min_block_delta, + beefy_genesis, + ) + .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))?; + break state + } + + if *header.number() == beefy_genesis { + // We've reached BEEFY genesis, initialize voter here. + let genesis_set = + expect_validator_set(runtime.as_ref(), backend.as_ref(), &header).await?; + info!( + target: LOG_TARGET, + "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ + Starting voting rounds at block {:?}, genesis validator set {:?}.", + beefy_genesis, + genesis_set, + ); + + sessions.push_front(Rounds::new(beefy_genesis, genesis_set)); + break PersistedState::checked_new( + best_grandpa, + Zero::zero(), + sessions, + min_block_delta, + beefy_genesis, + ) + .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))? + } + + if let Some(active) = find_authorities_change::(&header) { + debug!( + target: LOG_TARGET, + "🥩 Marking block {:?} as BEEFY Mandatory.", + *header.number() + ); + sessions.push_front(Rounds::new(*header.number(), active)); + } + + // Move up the chain. + header = wait_for_parent_header(blockchain, header, HEADER_SYNC_DELAY).await?; + }; + + aux_schema::write_current_version(backend.as_ref())?; + aux_schema::write_voter_state(backend.as_ref(), &state)?; + Ok(state) + } + + async fn load_or_init_state( + beefy_genesis: NumberFor, + best_grandpa: ::Header, + min_block_delta: u32, + backend: Arc, + runtime: Arc, + key_store: &BeefyKeystore, + metrics: &Option, + ) -> Result, Error> { + // Initialize voter state from AUX DB if compatible. + if let Some(mut state) = crate::aux_schema::load_persistent(backend.as_ref())? + // Verify state pallet genesis matches runtime. + .filter(|state| state.pallet_genesis() == beefy_genesis) + { + // Overwrite persisted state with current best GRANDPA block. + state.set_best_grandpa(best_grandpa.clone()); + // Overwrite persisted data with newly provided `min_block_delta`. + state.set_min_block_delta(min_block_delta); + debug!(target: LOG_TARGET, "🥩 Loading BEEFY voter state from db: {:?}.", state); + + // Make sure that all the headers that we need have been synced. + let mut new_sessions = vec![]; + let mut header = best_grandpa.clone(); + while *header.number() > state.best_beefy() { + if state.voting_oracle().can_add_session(*header.number()) { + if let Some(active) = find_authorities_change::(&header) { + new_sessions.push((active, *header.number())); + } + } + header = + wait_for_parent_header(backend.blockchain(), header, HEADER_SYNC_DELAY).await?; + } + + // Make sure we didn't miss any sessions during node restart. + for (validator_set, new_session_start) in new_sessions.drain(..).rev() { + debug!( + target: LOG_TARGET, + "🥩 Handling missed BEEFY session after node restart: {:?}.", + new_session_start + ); + state.init_session_at(new_session_start, validator_set, key_store, metrics); + } + return Ok(state) + } + + // No valid voter-state persisted, re-initialize from pallet genesis. + Self::init_state(beefy_genesis, best_grandpa, min_block_delta, backend, runtime).await + } +} /// Start the BEEFY gadget. /// @@ -277,7 +532,7 @@ pub async fn start_beefy_gadget( known_peers, prometheus_registry.clone(), ); - let mut beefy_comms = worker::BeefyComms { + let mut beefy_comms = BeefyComms { gossip_engine, gossip_validator, gossip_report_stream, @@ -287,57 +542,45 @@ pub async fn start_beefy_gadget( // We re-create and re-run the worker in this loop in order to quickly reinit and resume after // select recoverable errors. loop { - // Wait for BEEFY pallet to be active before starting voter. - let (beefy_genesis, best_grandpa) = match wait_for_runtime_pallet( - &*runtime, - &mut beefy_comms.gossip_engine, - &mut finality_notifications, - ) - .await - { - Ok(res) => res, - Err(e) => { - error!(target: LOG_TARGET, "Error: {:?}. Terminating.", e); - return - }, - }; - - let mut worker_base = worker::BeefyWorkerBase { - backend: backend.clone(), - runtime: runtime.clone(), - key_store: key_store.clone().into(), - metrics: metrics.clone(), - _phantom: Default::default(), - }; - - let persisted_state = match worker_base - .load_or_init_state(beefy_genesis, best_grandpa, min_block_delta) - .await - { - Ok(state) => state, - Err(e) => { - error!(target: LOG_TARGET, "Error: {:?}. Terminating.", e); - return - }, + // Make sure to pump gossip engine while waiting for initialization conditions. + let worker_builder = loop { + futures::select! { + builder_init_result = BeefyWorkerBuilder::async_initialize( + backend.clone(), + runtime.clone(), + key_store.clone().into(), + metrics.clone(), + min_block_delta, + beefy_comms.gossip_validator.clone(), + &mut finality_notifications, + ).fuse() => { + match builder_init_result { + Ok(builder) => break builder, + Err(e) => { + error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", e); + return + }, + } + }, + // Pump peer reports + _ = &mut beefy_comms.gossip_report_stream.next() => { + continue + }, + // Pump gossip engine. + _ = &mut beefy_comms.gossip_engine => { + error!(target: LOG_TARGET, "🥩 Gossip engine has unexpectedly terminated."); + return + } + } }; - // Update the gossip validator with the right starting round and set id. - if let Err(e) = persisted_state - .gossip_filter_config() - .map(|f| beefy_comms.gossip_validator.update_filter(f)) - { - error!(target: LOG_TARGET, "Error: {:?}. Terminating.", e); - return - } - let worker = worker::BeefyWorker { - base: worker_base, - payload_provider: payload_provider.clone(), - sync: sync.clone(), - comms: beefy_comms, - links: links.clone(), - pending_justifications: BTreeMap::new(), - persisted_state, - }; + let worker = worker_builder.build( + payload_provider.clone(), + sync.clone(), + beefy_comms, + links.clone(), + BTreeMap::new(), + ); match futures::future::select( Box::pin(worker.run(&mut block_import_justif, &mut finality_notifications)), @@ -404,9 +647,8 @@ where /// Should be called only once during worker initialization. async fn wait_for_runtime_pallet( runtime: &R, - mut gossip_engine: &mut GossipEngine, finality: &mut Fuse>, -) -> ClientResult<(NumberFor, ::Header)> +) -> Result<(NumberFor, ::Header), Error> where B: Block, R: ProvideRuntimeApi, @@ -414,33 +656,24 @@ where { info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); loop { - futures::select! { - notif = finality.next() => { - let notif = match notif { - Some(notif) => notif, - None => break - }; - let at = notif.header.hash(); - if let Some(start) = runtime.runtime_api().beefy_genesis(at).ok().flatten() { - if *notif.header.number() >= start { - // Beefy pallet available, return header for best grandpa at the time. - info!( - target: LOG_TARGET, - "🥩 BEEFY pallet available: block {:?} beefy genesis {:?}", - notif.header.number(), start - ); - return Ok((start, notif.header)) - } - } - }, - _ = gossip_engine => { - break + let notif = finality.next().await.ok_or_else(|| { + let err_msg = "🥩 Finality stream has unexpectedly terminated.".into(); + error!(target: LOG_TARGET, "{}", err_msg); + Error::Backend(err_msg) + })?; + let at = notif.header.hash(); + if let Some(start) = runtime.runtime_api().beefy_genesis(at).ok().flatten() { + if *notif.header.number() >= start { + // Beefy pallet available, return header for best grandpa at the time. + info!( + target: LOG_TARGET, + "🥩 BEEFY pallet available: block {:?} beefy genesis {:?}", + notif.header.number(), start + ); + return Ok((start, notif.header)) } } } - let err_msg = "🥩 Gossip engine has unexpectedly terminated.".into(); - error!(target: LOG_TARGET, "{}", err_msg); - Err(ClientError::Backend(err_msg)) } /// Provides validator set active `at_header`. It tries to get it from state, otherwise falls @@ -460,17 +693,21 @@ where R::Api: BeefyApi, { let blockchain = backend.blockchain(); - // Walk up the chain looking for the validator set active at 'at_header'. Process both state and // header digests. - debug!(target: LOG_TARGET, "🥩 Trying to find validator set active at header: {:?}", at_header); + debug!( + target: LOG_TARGET, + "🥩 Trying to find validator set active at header(number {:?}, hash {:?})", + at_header.number(), + at_header.hash() + ); let mut header = at_header.clone(); loop { debug!(target: LOG_TARGET, "🥩 Looking for auth set change at block number: {:?}", *header.number()); if let Ok(Some(active)) = runtime.runtime_api().validator_set(header.hash()) { return Ok(active) } else { - match worker::find_authorities_change::(&header) { + match find_authorities_change::(&header) { Some(active) => return Ok(active), // Move up the chain. Ultimately we'll get it from chain genesis state, or error out // there. @@ -482,3 +719,18 @@ where } } } + +/// Scan the `header` digest log for a BEEFY validator set change. Return either the new +/// validator set or `None` in case no validator set change has been signaled. +pub(crate) fn find_authorities_change(header: &B::Header) -> Option> +where + B: Block, +{ + let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); + + let filter = |log: ConsensusLog| match log { + ConsensusLog::AuthoritiesChange(validator_set) => Some(validator_set), + _ => None, + }; + header.digest().convert_first(|l| l.try_to(id).and_then(filter)) +} diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 47414c60fdb5fc8fc94e60136481ebaefd4d7560..0045dc70c260ee43ca1137d7d7f92b097220aeaf 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -207,7 +207,7 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, Keyring, Payload, + known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, EquivocationProof, Payload, SignedCommitment, ValidatorSet, VoteMessage, }; @@ -226,7 +226,7 @@ mod tests { #[test] fn round_tracker() { let mut rt = RoundTracker::default(); - let bob_vote = (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")); + let bob_vote = (Keyring::Bob.public(), Keyring::::Bob.sign(b"I am committed")); let threshold = 2; // adding new vote allowed @@ -237,7 +237,8 @@ mod tests { // vote is not done assert!(!rt.is_done(threshold)); - let alice_vote = (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")); + let alice_vote = + (Keyring::Alice.public(), Keyring::::Alice.sign(b"I am committed")); // adding new vote (self vote this time) allowed assert!(rt.add_vote(alice_vote)); @@ -271,7 +272,11 @@ mod tests { assert_eq!(42, rounds.validator_set_id()); assert_eq!(1, rounds.session_start()); assert_eq!( - &vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + &vec![ + Keyring::::Alice.public(), + Keyring::::Bob.public(), + Keyring::::Charlie.public() + ], rounds.validators() ); } @@ -301,7 +306,7 @@ mod tests { let mut vote = VoteMessage { id: Keyring::Alice.public(), commitment: commitment.clone(), - signature: Keyring::Alice.sign(b"I am committed"), + signature: Keyring::::Alice.sign(b"I am committed"), }; // add 1st good vote assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); @@ -310,26 +315,26 @@ mod tests { assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); vote.id = Keyring::Dave.public(); - vote.signature = Keyring::Dave.sign(b"I am committed"); + vote.signature = Keyring::::Dave.sign(b"I am committed"); // invalid vote (Dave is not a validator) assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Invalid); vote.id = Keyring::Bob.public(); - vote.signature = Keyring::Bob.sign(b"I am committed"); + vote.signature = Keyring::::Bob.sign(b"I am committed"); // add 2nd good vote assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); vote.id = Keyring::Charlie.public(); - vote.signature = Keyring::Charlie.sign(b"I am committed"); + vote.signature = Keyring::::Charlie.sign(b"I am committed"); // add 3rd good vote -> round concluded -> signatures present assert_eq!( rounds.add_vote(vote.clone()), VoteImportResult::RoundConcluded(SignedCommitment { commitment, signatures: vec![ - Some(Keyring::Alice.sign(b"I am committed")), - Some(Keyring::Bob.sign(b"I am committed")), - Some(Keyring::Charlie.sign(b"I am committed")), + Some(Keyring::::Alice.sign(b"I am committed")), + Some(Keyring::::Bob.sign(b"I am committed")), + Some(Keyring::::Charlie.sign(b"I am committed")), None, ] }) @@ -337,7 +342,7 @@ mod tests { rounds.conclude(block_number); vote.id = Keyring::Eve.public(); - vote.signature = Keyring::Eve.sign(b"I am committed"); + vote.signature = Keyring::::Eve.sign(b"I am committed"); // Eve is a validator, but round was concluded, adding vote disallowed assert_eq!(rounds.add_vote(vote), VoteImportResult::Stale); } @@ -364,7 +369,7 @@ mod tests { let mut vote = VoteMessage { id: Keyring::Alice.public(), commitment, - signature: Keyring::Alice.sign(b"I am committed"), + signature: Keyring::::Alice.sign(b"I am committed"), }; // add vote for previous session, should fail assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); @@ -407,22 +412,22 @@ mod tests { let mut alice_vote = VoteMessage { id: Keyring::Alice.public(), commitment: commitment.clone(), - signature: Keyring::Alice.sign(b"I am committed"), + signature: Keyring::::Alice.sign(b"I am committed"), }; let mut bob_vote = VoteMessage { id: Keyring::Bob.public(), commitment: commitment.clone(), - signature: Keyring::Bob.sign(b"I am committed"), + signature: Keyring::::Bob.sign(b"I am committed"), }; let mut charlie_vote = VoteMessage { id: Keyring::Charlie.public(), commitment, - signature: Keyring::Charlie.sign(b"I am committed"), + signature: Keyring::::Charlie.sign(b"I am committed"), }; let expected_signatures = vec![ - Some(Keyring::Alice.sign(b"I am committed")), - Some(Keyring::Bob.sign(b"I am committed")), - Some(Keyring::Charlie.sign(b"I am committed")), + Some(Keyring::::Alice.sign(b"I am committed")), + Some(Keyring::::Bob.sign(b"I am committed")), + Some(Keyring::::Charlie.sign(b"I am committed")), ]; // round 1 - only 2 out of 3 vote @@ -484,7 +489,7 @@ mod tests { let alice_vote1 = VoteMessage { id: Keyring::Alice.public(), commitment: commitment1, - signature: Keyring::Alice.sign(b"I am committed"), + signature: Keyring::::Alice.sign(b"I am committed"), }; let mut alice_vote2 = alice_vote1.clone(); alice_vote2.commitment = commitment2; diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 7e61e877c1ddac692c6ae5f7199cf5ff35752ff7..d106c9dcd88165f929085972483e090dbf78c559 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -32,8 +32,8 @@ use crate::{ gossip_protocol_name, justification::*, wait_for_runtime_pallet, - worker::{BeefyWorkerBase, PersistedState}, - BeefyRPCLinks, BeefyVoterLinks, KnownPeers, + worker::PersistedState, + BeefyRPCLinks, BeefyVoterLinks, BeefyWorkerBuilder, KnownPeers, }; use futures::{future, stream::FuturesUnordered, Future, FutureExt, StreamExt}; use parking_lot::Mutex; @@ -57,9 +57,10 @@ use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId, Signature}, known_payloads, mmr::{find_mmr_root_digest, MmrRootProvider}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash, - OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + test_utils::Keyring as BeefyKeyring, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, MmrRootHash, OpaqueKeyOwnershipProof, + Payload, SignedCommitment, ValidatorSet, ValidatorSetId, VersionedFinalityProof, VoteMessage, + BEEFY_ENGINE_ID, }; use sp_core::H256; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; @@ -349,11 +350,11 @@ fn add_auth_change_digest(builder: &mut impl BlockBuilderExt, new_auth_set: Beef .unwrap(); } -pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { - keys.iter().map(|&key| key.public().into()).collect() +pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { + keys.iter().map(|key| key.public().into()).collect() } -pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> KeystorePtr { +pub(crate) fn create_beefy_keystore(authority: &BeefyKeyring) -> KeystorePtr { let keystore = MemoryKeystore::new(); keystore .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&authority.to_seed())) @@ -367,33 +368,25 @@ async fn voter_init_setup( api: &TestApi, ) -> Result, Error> { let backend = net.peer(0).client().as_backend(); - let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let (gossip_validator, _) = GossipValidator::new(known_peers); - let gossip_validator = Arc::new(gossip_validator); - let mut gossip_engine = sc_network_gossip::GossipEngine::new( - net.peer(0).network_service().clone(), - net.peer(0).sync_service().clone(), - net.peer(0).take_notification_service(&beefy_gossip_proto_name()).unwrap(), - "/beefy/whatever", - gossip_validator, - None, - ); - let (beefy_genesis, best_grandpa) = - wait_for_runtime_pallet(api, &mut gossip_engine, finality).await.unwrap(); - let mut worker_base = BeefyWorkerBase { + let (beefy_genesis, best_grandpa) = wait_for_runtime_pallet(api, finality).await.unwrap(); + let key_store = None.into(); + let metrics = None; + BeefyWorkerBuilder::load_or_init_state( + beefy_genesis, + best_grandpa, + 1, backend, - runtime: Arc::new(api.clone()), - key_store: None.into(), - metrics: None, - _phantom: Default::default(), - }; - worker_base.load_or_init_state(beefy_genesis, best_grandpa, 1).await + Arc::new(api.clone()), + &key_store, + &metrics, + ) + .await } // Spawns beefy voters. Returns a future to spawn on the runtime. fn initialize_beefy( net: &mut BeefyTestNet, - peers: Vec<(usize, &BeefyKeyring, Arc)>, + peers: Vec<(usize, &BeefyKeyring, Arc)>, min_block_delta: u32, ) -> impl Future where @@ -413,7 +406,7 @@ where for (peer_id, key, api) in peers.into_iter() { let peer = &net.peers[peer_id]; - let keystore = create_beefy_keystore(*key); + let keystore = create_beefy_keystore(key); let (_, _, peer_data) = net.make_block_import(peer.client().clone()); let PeerData { beefy_rpc_links, beefy_voter_links, .. } = peer_data; @@ -471,7 +464,7 @@ async fn run_for(duration: Duration, net: &Arc>) { pub(crate) fn get_beefy_streams( net: &mut BeefyTestNet, // peer index and key - peers: impl Iterator, + peers: impl Iterator)>, ) -> (Vec>, Vec>>) { let mut best_block_streams = Vec::new(); @@ -569,7 +562,7 @@ async fn streams_empty_after_timeout( async fn finalize_block_and_wait_for_beefy( net: &Arc>, // peer index and key - peers: impl Iterator + Clone, + peers: impl Iterator)> + Clone, finalize_target: &H256, expected_beefy: &[u64], ) { @@ -1064,32 +1057,7 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); // load persistent state - nothing in DB, should init at genesis - // - // NOTE: code from `voter_init_setup()` is moved here because the new network event system - // doesn't allow creating a new `GossipEngine` as the notification handle is consumed by the - // first `GossipEngine` - let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let (gossip_validator, _) = GossipValidator::new(known_peers); - let gossip_validator = Arc::new(gossip_validator); - let mut gossip_engine = sc_network_gossip::GossipEngine::new( - net.peer(0).network_service().clone(), - net.peer(0).sync_service().clone(), - net.peer(0).take_notification_service(&beefy_gossip_proto_name()).unwrap(), - "/beefy/whatever", - gossip_validator, - None, - ); - let (beefy_genesis, best_grandpa) = - wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); - let mut worker_base = BeefyWorkerBase { - backend: backend.clone(), - runtime: Arc::new(api), - key_store: None.into(), - metrics: None, - _phantom: Default::default(), - }; - let persisted_state = - worker_base.load_or_init_state(beefy_genesis, best_grandpa, 1).await.unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) @@ -1119,18 +1087,7 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[10], None).unwrap(); // load persistent state - state preset in DB, but with different pallet genesis - // the network state persists and uses the old `GossipEngine` initialized for `peer(0)` - let (beefy_genesis, best_grandpa) = - wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); - let mut worker_base = BeefyWorkerBase { - backend: backend.clone(), - runtime: Arc::new(api), - key_store: None.into(), - metrics: None, - _phantom: Default::default(), - }; - let new_persisted_state = - worker_base.load_or_init_state(beefy_genesis, best_grandpa, 1).await.unwrap(); + let new_persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // verify voter initialized with single session starting at block `new_pallet_genesis` (10) let sessions = new_persisted_state.voting_oracle().sessions(); @@ -1321,32 +1278,7 @@ async fn should_catch_up_when_loading_saved_voter_state() { let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at genesis - // - // NOTE: code from `voter_init_setup()` is moved here because the new network event system - // doesn't allow creating a new `GossipEngine` as the notification handle is consumed by the - // first `GossipEngine` - let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let (gossip_validator, _) = GossipValidator::new(known_peers); - let gossip_validator = Arc::new(gossip_validator); - let mut gossip_engine = sc_network_gossip::GossipEngine::new( - net.peer(0).network_service().clone(), - net.peer(0).sync_service().clone(), - net.peer(0).take_notification_service(&beefy_gossip_proto_name()).unwrap(), - "/beefy/whatever", - gossip_validator, - None, - ); - let (beefy_genesis, best_grandpa) = - wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); - let mut worker_base = BeefyWorkerBase { - backend: backend.clone(), - runtime: Arc::new(api.clone()), - key_store: None.into(), - metrics: None, - _phantom: Default::default(), - }; - let persisted_state = - worker_base.load_or_init_state(beefy_genesis, best_grandpa, 1).await.unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with two sessions starting at blocks 1 and 10 @@ -1373,18 +1305,7 @@ async fn should_catch_up_when_loading_saved_voter_state() { // finalize 25 without justifications net.peer(0).client().as_client().finalize_block(hashes[25], None).unwrap(); // load persistent state - state preset in DB - // the network state persists and uses the old `GossipEngine` initialized for `peer(0)` - let (beefy_genesis, best_grandpa) = - wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); - let mut worker_base = BeefyWorkerBase { - backend: backend.clone(), - runtime: Arc::new(api), - key_store: None.into(), - metrics: None, - _phantom: Default::default(), - }; - let persisted_state = - worker_base.load_or_init_state(beefy_genesis, best_grandpa, 1).await.unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // Verify voter initialized with old sessions plus a new one starting at block 20. // There shouldn't be any duplicates. diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index e67e3e0f76ad996c4666142bf28fead1aed200b6..c8eb19621ba5a6e45ea2be93e1e2e830492a9b81 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -17,46 +17,42 @@ // along with this program. If not, see . use crate::{ - aux_schema, communication::{ - gossip::{proofs_topic, votes_topic, GossipFilterCfg, GossipMessage, GossipValidator}, + gossip::{proofs_topic, votes_topic, GossipFilterCfg, GossipMessage}, peers::PeerReport, - request_response::outgoing_requests_engine::{OnDemandJustificationsEngine, ResponseInfo}, + request_response::outgoing_requests_engine::ResponseInfo, }, error::Error, - expect_validator_set, + find_authorities_change, justification::BeefyVersionedFinalityProof, - keystore::{BeefyKeystore, BeefySignatureHasher}, + keystore::BeefyKeystore, metric_inc, metric_set, metrics::VoterMetrics, round::{Rounds, VoteImportResult}, - wait_for_parent_header, BeefyVoterLinks, HEADER_SYNC_DELAY, LOG_TARGET, + BeefyComms, BeefyVoterLinks, LOG_TARGET, }; use codec::{Codec, Decode, DecodeAll, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; -use sc_network_gossip::GossipEngine; -use sc_utils::{mpsc::TracingUnboundedReceiver, notification::NotificationReceiver}; +use sc_utils::notification::NotificationReceiver; use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; -use sp_blockchain::Backend as BlockchainBackend; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ check_equivocation_proof, ecdsa_crypto::{AuthorityId, Signature}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, + BeefyApi, BeefySignatureHasher, Commitment, EquivocationProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ - generic::{BlockId, OpaqueDigestItemId}, + generic::BlockId, traits::{Block, Header, NumberFor, Zero}, SaturatedConversion, }; use std::{ collections::{BTreeMap, BTreeSet, VecDeque}, fmt::Debug, - marker::PhantomData, sync::Arc, }; @@ -180,8 +176,8 @@ impl VoterOracle { } } - // Check if an observed session can be added to the Oracle. - fn can_add_session(&self, session_start: NumberFor) -> bool { + /// Check if an observed session can be added to the Oracle. + pub fn can_add_session(&self, session_start: NumberFor) -> bool { let latest_known_session_start = self.sessions.back().map(|session| session.session_start()); Some(session_start) > latest_known_session_start @@ -319,229 +315,28 @@ impl PersistedState { self.voting_oracle.best_grandpa_block_header = best_grandpa; } + pub fn voting_oracle(&self) -> &VoterOracle { + &self.voting_oracle + } + pub(crate) fn gossip_filter_config(&self) -> Result, Error> { let (start, end) = self.voting_oracle.accepted_interval()?; let validator_set = self.voting_oracle.current_validator_set()?; Ok(GossipFilterCfg { start, end, validator_set }) } -} - -/// Helper object holding BEEFY worker communication/gossip components. -/// -/// These are created once, but will be reused if worker is restarted/reinitialized. -pub(crate) struct BeefyComms { - pub gossip_engine: GossipEngine, - pub gossip_validator: Arc>, - pub gossip_report_stream: TracingUnboundedReceiver, - pub on_demand_justifications: OnDemandJustificationsEngine, -} - -pub(crate) struct BeefyWorkerBase { - // utilities - pub backend: Arc, - pub runtime: Arc, - pub key_store: BeefyKeystore, - - /// BEEFY client metrics. - pub metrics: Option, - - pub _phantom: PhantomData, -} - -impl BeefyWorkerBase -where - B: Block + Codec, - BE: Backend, - R: ProvideRuntimeApi, - R::Api: BeefyApi, -{ - // If no persisted state present, walk back the chain from first GRANDPA notification to either: - // - latest BEEFY finalized block, or if none found on the way, - // - BEEFY pallet genesis; - // Enqueue any BEEFY mandatory blocks (session boundaries) found on the way, for voter to - // finalize. - async fn init_state( - &self, - beefy_genesis: NumberFor, - best_grandpa: ::Header, - min_block_delta: u32, - ) -> Result, Error> { - let blockchain = self.backend.blockchain(); - - let beefy_genesis = self - .runtime - .runtime_api() - .beefy_genesis(best_grandpa.hash()) - .ok() - .flatten() - .filter(|genesis| *genesis == beefy_genesis) - .ok_or_else(|| Error::Backend("BEEFY pallet expected to be active.".into()))?; - // Walk back the imported blocks and initialize voter either, at the last block with - // a BEEFY justification, or at pallet genesis block; voter will resume from there. - let mut sessions = VecDeque::new(); - let mut header = best_grandpa.clone(); - let state = loop { - if let Some(true) = blockchain - .justifications(header.hash()) - .ok() - .flatten() - .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) - { - info!( - target: LOG_TARGET, - "🥩 Initialize BEEFY voter at last BEEFY finalized block: {:?}.", - *header.number() - ); - let best_beefy = *header.number(); - // If no session boundaries detected so far, just initialize new rounds here. - if sessions.is_empty() { - let active_set = - expect_validator_set(self.runtime.as_ref(), self.backend.as_ref(), &header) - .await?; - let mut rounds = Rounds::new(best_beefy, active_set); - // Mark the round as already finalized. - rounds.conclude(best_beefy); - sessions.push_front(rounds); - } - let state = PersistedState::checked_new( - best_grandpa, - best_beefy, - sessions, - min_block_delta, - beefy_genesis, - ) - .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))?; - break state - } - - if *header.number() == beefy_genesis { - // We've reached BEEFY genesis, initialize voter here. - let genesis_set = - expect_validator_set(self.runtime.as_ref(), self.backend.as_ref(), &header) - .await?; - info!( - target: LOG_TARGET, - "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ - Starting voting rounds at block {:?}, genesis validator set {:?}.", - beefy_genesis, - genesis_set, - ); - - sessions.push_front(Rounds::new(beefy_genesis, genesis_set)); - break PersistedState::checked_new( - best_grandpa, - Zero::zero(), - sessions, - min_block_delta, - beefy_genesis, - ) - .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))? - } - - if let Some(active) = find_authorities_change::(&header) { - info!( - target: LOG_TARGET, - "🥩 Marking block {:?} as BEEFY Mandatory.", - *header.number() - ); - sessions.push_front(Rounds::new(*header.number(), active)); - } - - // Move up the chain. - header = wait_for_parent_header(blockchain, header, HEADER_SYNC_DELAY).await?; - }; - - aux_schema::write_current_version(self.backend.as_ref())?; - aux_schema::write_voter_state(self.backend.as_ref(), &state)?; - Ok(state) - } - - pub async fn load_or_init_state( - &mut self, - beefy_genesis: NumberFor, - best_grandpa: ::Header, - min_block_delta: u32, - ) -> Result, Error> { - // Initialize voter state from AUX DB if compatible. - if let Some(mut state) = crate::aux_schema::load_persistent(self.backend.as_ref())? - // Verify state pallet genesis matches runtime. - .filter(|state| state.pallet_genesis() == beefy_genesis) - { - // Overwrite persisted state with current best GRANDPA block. - state.set_best_grandpa(best_grandpa.clone()); - // Overwrite persisted data with newly provided `min_block_delta`. - state.set_min_block_delta(min_block_delta); - info!(target: LOG_TARGET, "🥩 Loading BEEFY voter state from db: {:?}.", state); - - // Make sure that all the headers that we need have been synced. - let mut new_sessions = vec![]; - let mut header = best_grandpa.clone(); - while *header.number() > state.best_beefy() { - if state.voting_oracle.can_add_session(*header.number()) { - if let Some(active) = find_authorities_change::(&header) { - new_sessions.push((active, *header.number())); - } - } - header = - wait_for_parent_header(self.backend.blockchain(), header, HEADER_SYNC_DELAY) - .await?; - } - - // Make sure we didn't miss any sessions during node restart. - for (validator_set, new_session_start) in new_sessions.drain(..).rev() { - info!( - target: LOG_TARGET, - "🥩 Handling missed BEEFY session after node restart: {:?}.", - new_session_start - ); - self.init_session_at(&mut state, validator_set, new_session_start); - } - return Ok(state) - } - - // No valid voter-state persisted, re-initialize from pallet genesis. - self.init_state(beefy_genesis, best_grandpa, min_block_delta).await - } - - /// Verify `active` validator set for `block` against the key store - /// - /// We want to make sure that we have _at least one_ key in our keystore that - /// is part of the validator set, that's because if there are no local keys - /// then we can't perform our job as a validator. - /// - /// Note that for a non-authority node there will be no keystore, and we will - /// return an error and don't check. The error can usually be ignored. - fn verify_validator_set( - &self, - block: &NumberFor, - active: &ValidatorSet, - ) -> Result<(), Error> { - let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); - - let public_keys = self.key_store.public_keys()?; - let store: BTreeSet<&AuthorityId> = public_keys.iter().collect(); - - if store.intersection(&active).count() == 0 { - let msg = "no authority public key found in store".to_string(); - debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); - metric_inc!(self.metrics, beefy_no_authority_found_in_store); - Err(Error::Keystore(msg)) - } else { - Ok(()) - } - } /// Handle session changes by starting new voting round for mandatory blocks. - fn init_session_at( + pub fn init_session_at( &mut self, - persisted_state: &mut PersistedState, - validator_set: ValidatorSet, new_session_start: NumberFor, + validator_set: ValidatorSet, + key_store: &BeefyKeystore, + metrics: &Option, ) { debug!(target: LOG_TARGET, "🥩 New active validator set: {:?}", validator_set); // BEEFY should finalize a mandatory block during each session. - if let Ok(active_session) = persisted_state.voting_oracle.active_rounds() { + if let Ok(active_session) = self.voting_oracle.active_rounds() { if !active_session.mandatory_done() { debug!( target: LOG_TARGET, @@ -549,20 +344,20 @@ where validator_set.id(), active_session.validator_set_id(), ); - metric_inc!(self.metrics, beefy_lagging_sessions); + metric_inc!(metrics, beefy_lagging_sessions); } } if log_enabled!(target: LOG_TARGET, log::Level::Debug) { // verify the new validator set - only do it if we're also logging the warning - let _ = self.verify_validator_set(&new_session_start, &validator_set); + if verify_validator_set::(&new_session_start, &validator_set, key_store).is_err() { + metric_inc!(metrics, beefy_no_authority_found_in_store); + } } let id = validator_set.id(); - persisted_state - .voting_oracle - .add_session(Rounds::new(new_session_start, validator_set)); - metric_set!(self.metrics, beefy_validator_set_id, id); + self.voting_oracle.add_session(Rounds::new(new_session_start, validator_set)); + metric_set!(metrics, beefy_validator_set_id, id); info!( target: LOG_TARGET, "🥩 New Rounds for validator set id: {:?} with session_start {:?}", @@ -574,9 +369,10 @@ where /// A BEEFY worker/voter that follows the BEEFY protocol pub(crate) struct BeefyWorker { - pub base: BeefyWorkerBase, - - // utils + // utilities + pub backend: Arc, + pub runtime: Arc, + pub key_store: BeefyKeystore, pub payload_provider: P, pub sync: Arc, @@ -592,6 +388,8 @@ pub(crate) struct BeefyWorker { pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. pub persisted_state: PersistedState, + /// BEEFY voter metrics + pub metrics: Option, } impl BeefyWorker @@ -622,24 +420,28 @@ where validator_set: ValidatorSet, new_session_start: NumberFor, ) { - self.base - .init_session_at(&mut self.persisted_state, validator_set, new_session_start); + self.persisted_state.init_session_at( + new_session_start, + validator_set, + &self.key_store, + &self.metrics, + ); } fn handle_finality_notification( &mut self, notification: &FinalityNotification, ) -> Result<(), Error> { + let header = ¬ification.header; debug!( target: LOG_TARGET, - "🥩 Finality notification: header {:?} tree_route {:?}", - notification.header, + "🥩 Finality notification: header(number {:?}, hash {:?}) tree_route {:?}", + header.number(), + header.hash(), notification.tree_route, ); - let header = ¬ification.header; - self.base - .runtime + self.runtime .runtime_api() .beefy_genesis(header.hash()) .ok() @@ -653,7 +455,7 @@ where self.persisted_state.set_best_grandpa(header.clone()); // Check all (newly) finalized blocks for new session(s). - let backend = self.base.backend.clone(); + let backend = self.backend.clone(); for header in notification .tree_route .iter() @@ -672,7 +474,7 @@ where } if new_session_added { - crate::aux_schema::write_voter_state(&*self.base.backend, &self.persisted_state) + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) .map_err(|e| Error::Backend(e.to_string()))?; } @@ -706,7 +508,7 @@ where true, ); }, - RoundAction::Drop => metric_inc!(self.base.metrics, beefy_stale_votes), + RoundAction::Drop => metric_inc!(self.metrics, beefy_stale_votes), RoundAction::Enqueue => error!(target: LOG_TARGET, "🥩 unexpected vote: {:?}.", vote), }; Ok(()) @@ -726,23 +528,23 @@ where match self.voting_oracle().triage_round(block_num)? { RoundAction::Process => { debug!(target: LOG_TARGET, "🥩 Process justification for round: {:?}.", block_num); - metric_inc!(self.base.metrics, beefy_imported_justifications); + metric_inc!(self.metrics, beefy_imported_justifications); self.finalize(justification)? }, RoundAction::Enqueue => { debug!(target: LOG_TARGET, "🥩 Buffer justification for round: {:?}.", block_num); if self.pending_justifications.len() < MAX_BUFFERED_JUSTIFICATIONS { self.pending_justifications.entry(block_num).or_insert(justification); - metric_inc!(self.base.metrics, beefy_buffered_justifications); + metric_inc!(self.metrics, beefy_buffered_justifications); } else { - metric_inc!(self.base.metrics, beefy_buffered_justifications_dropped); + metric_inc!(self.metrics, beefy_buffered_justifications_dropped); warn!( target: LOG_TARGET, "🥩 Buffer justification dropped for round: {:?}.", block_num ); } }, - RoundAction::Drop => metric_inc!(self.base.metrics, beefy_stale_justifications), + RoundAction::Drop => metric_inc!(self.metrics, beefy_stale_justifications), }; Ok(()) } @@ -757,14 +559,14 @@ where match rounds.add_vote(vote) { VoteImportResult::RoundConcluded(signed_commitment) => { let finality_proof = VersionedFinalityProof::V1(signed_commitment); - info!( + debug!( target: LOG_TARGET, "🥩 Round #{} concluded, finality_proof: {:?}.", block_number, finality_proof ); // We created the `finality_proof` and know to be valid. // New state is persisted after finalization. self.finalize(finality_proof.clone())?; - metric_inc!(self.base.metrics, beefy_good_votes_processed); + metric_inc!(self.metrics, beefy_good_votes_processed); return Ok(Some(finality_proof)) }, VoteImportResult::Ok => { @@ -775,20 +577,17 @@ where .map(|(mandatory_num, _)| mandatory_num == block_number) .unwrap_or(false) { - crate::aux_schema::write_voter_state( - &*self.base.backend, - &self.persisted_state, - ) - .map_err(|e| Error::Backend(e.to_string()))?; + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) + .map_err(|e| Error::Backend(e.to_string()))?; } - metric_inc!(self.base.metrics, beefy_good_votes_processed); + metric_inc!(self.metrics, beefy_good_votes_processed); }, VoteImportResult::Equivocation(proof) => { - metric_inc!(self.base.metrics, beefy_equivocation_votes); + metric_inc!(self.metrics, beefy_equivocation_votes); self.report_equivocation(proof)?; }, - VoteImportResult::Invalid => metric_inc!(self.base.metrics, beefy_invalid_votes), - VoteImportResult::Stale => metric_inc!(self.base.metrics, beefy_stale_votes), + VoteImportResult::Invalid => metric_inc!(self.metrics, beefy_invalid_votes), + VoteImportResult::Stale => metric_inc!(self.metrics, beefy_stale_votes), }; Ok(None) } @@ -815,15 +614,14 @@ where // Set new best BEEFY block number. self.persisted_state.set_best_beefy(block_num); - crate::aux_schema::write_voter_state(&*self.base.backend, &self.persisted_state) + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) .map_err(|e| Error::Backend(e.to_string()))?; - metric_set!(self.base.metrics, beefy_best_block, block_num); + metric_set!(self.metrics, beefy_best_block, block_num); self.comms.on_demand_justifications.cancel_requests_older_than(block_num); if let Err(e) = self - .base .backend .blockchain() .expect_block_hash_from_id(&BlockId::Number(block_num)) @@ -833,8 +631,7 @@ where .notify(|| Ok::<_, ()>(hash)) .expect("forwards closure result; the closure always returns Ok; qed."); - self.base - .backend + self.backend .append_justification(hash, (BEEFY_ENGINE_ID, finality_proof.encode())) }) { debug!( @@ -871,13 +668,13 @@ where for (num, justification) in justifs_to_process.into_iter() { debug!(target: LOG_TARGET, "🥩 Handle buffered justification for: {:?}.", num); - metric_inc!(self.base.metrics, beefy_imported_justifications); + metric_inc!(self.metrics, beefy_imported_justifications); if let Err(err) = self.finalize(justification) { error!(target: LOG_TARGET, "🥩 Error finalizing block: {}", err); } } metric_set!( - self.base.metrics, + self.metrics, beefy_buffered_justifications, self.pending_justifications.len() ); @@ -889,7 +686,7 @@ where fn try_to_vote(&mut self) -> Result<(), Error> { // Vote if there's now a new vote target. if let Some(target) = self.voting_oracle().voting_target() { - metric_set!(self.base.metrics, beefy_should_vote_on, target); + metric_set!(self.metrics, beefy_should_vote_on, target); if target > self.persisted_state.best_voted { self.do_vote(target)?; } @@ -909,7 +706,6 @@ where self.persisted_state.voting_oracle.best_grandpa_block_header.clone() } else { let hash = self - .base .backend .blockchain() .expect_block_hash_from_id(&BlockId::Number(target_number)) @@ -921,7 +717,7 @@ where Error::Backend(err_msg) })?; - self.base.backend.blockchain().expect_header(hash).map_err(|err| { + self.backend.blockchain().expect_header(hash).map_err(|err| { let err_msg = format!( "Couldn't get header for block #{:?} ({:?}) (error: {:?}), skipping vote..", target_number, hash, err @@ -941,7 +737,7 @@ where let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); - let authority_id = if let Some(id) = self.base.key_store.authority_id(validators) { + let authority_id = if let Some(id) = self.key_store.authority_id(validators) { debug!(target: LOG_TARGET, "🥩 Local authority id: {:?}", id); id } else { @@ -955,7 +751,7 @@ where let commitment = Commitment { payload, block_number: target_number, validator_set_id }; let encoded_commitment = commitment.encode(); - let signature = match self.base.key_store.sign(&authority_id, &encoded_commitment) { + let signature = match self.key_store.sign(&authority_id, &encoded_commitment) { Ok(sig) => sig, Err(err) => { warn!(target: LOG_TARGET, "🥩 Error signing commitment: {:?}", err); @@ -980,7 +776,7 @@ where .gossip_engine .gossip_message(proofs_topic::(), encoded_proof, true); } else { - metric_inc!(self.base.metrics, beefy_votes_sent); + metric_inc!(self.metrics, beefy_votes_sent); debug!(target: LOG_TARGET, "🥩 Sent vote message: {:?}", vote); let encoded_vote = GossipMessage::::Vote(vote).encode(); self.comms.gossip_engine.gossip_message(votes_topic::(), encoded_vote, false); @@ -988,8 +784,8 @@ where // Persist state after vote to avoid double voting in case of voter restarts. self.persisted_state.best_voted = target_number; - metric_set!(self.base.metrics, beefy_best_voted, target_number); - crate::aux_schema::write_voter_state(&*self.base.backend, &self.persisted_state) + metric_set!(self.metrics, beefy_best_voted, target_number); + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) .map_err(|e| Error::Backend(e.to_string())) } @@ -1163,16 +959,15 @@ where if !check_equivocation_proof::<_, _, BeefySignatureHasher>(&proof) { debug!(target: LOG_TARGET, "🥩 Skip report for bad equivocation {:?}", proof); return Ok(()) - } else if let Some(local_id) = self.base.key_store.authority_id(validators) { + } else if let Some(local_id) = self.key_store.authority_id(validators) { if offender_id == local_id { - debug!(target: LOG_TARGET, "🥩 Skip equivocation report for own equivocation"); + warn!(target: LOG_TARGET, "🥩 Skip equivocation report for own equivocation"); return Ok(()) } } let number = *proof.round_number(); let hash = self - .base .backend .blockchain() .expect_block_hash_from_id(&BlockId::Number(number)) @@ -1183,7 +978,7 @@ where ); Error::Backend(err_msg) })?; - let runtime_api = self.base.runtime.runtime_api(); + let runtime_api = self.runtime.runtime_api(); // generate key ownership proof at that block let key_owner_proof = match runtime_api .generate_key_ownership_proof(hash, validator_set_id, offender_id) @@ -1200,7 +995,7 @@ where }; // submit equivocation report at **best** block - let best_block_hash = self.base.backend.blockchain().info().best_hash; + let best_block_hash = self.backend.blockchain().info().best_hash; runtime_api .submit_report_equivocation_unsigned_extrinsic(best_block_hash, proof, key_owner_proof) .map_err(Error::RuntimeApi)?; @@ -1209,21 +1004,6 @@ where } } -/// Scan the `header` digest log for a BEEFY validator set change. Return either the new -/// validator set or `None` in case no validator set change has been signaled. -pub(crate) fn find_authorities_change(header: &B::Header) -> Option> -where - B: Block, -{ - let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); - - let filter = |log: ConsensusLog| match log { - ConsensusLog::AuthoritiesChange(validator_set) => Some(validator_set), - _ => None, - }; - header.digest().convert_first(|l| l.try_to(id).and_then(filter)) -} - /// Calculate next block number to vote on. /// /// Return `None` if there is no votable target yet. @@ -1234,7 +1014,7 @@ where // if the mandatory block (session_start) does not have a beefy justification yet, // we vote on it let target = if best_beefy < session_start { - debug!(target: LOG_TARGET, "🥩 vote target - mandatory block: #{:?}", session_start,); + debug!(target: LOG_TARGET, "🥩 vote target - mandatory block: #{:?}", session_start); session_start } else { let diff = best_grandpa.saturating_sub(best_beefy) + 1u32.into(); @@ -1260,11 +1040,42 @@ where } } +/// Verify `active` validator set for `block` against the key store +/// +/// We want to make sure that we have _at least one_ key in our keystore that +/// is part of the validator set, that's because if there are no local keys +/// then we can't perform our job as a validator. +/// +/// Note that for a non-authority node there will be no keystore, and we will +/// return an error and don't check. The error can usually be ignored. +fn verify_validator_set( + block: &NumberFor, + active: &ValidatorSet, + key_store: &BeefyKeystore, +) -> Result<(), Error> { + let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); + + let public_keys = key_store.public_keys()?; + let store: BTreeSet<&AuthorityId> = public_keys.iter().collect(); + + if store.intersection(&active).count() == 0 { + let msg = "no authority public key found in store".to_string(); + debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); + Err(Error::Keystore(msg)) + } else { + Ok(()) + } +} + #[cfg(test)] pub(crate) mod tests { use super::*; use crate::{ - communication::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, + communication::{ + gossip::GossipValidator, + notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, + request_response::outgoing_requests_engine::OnDemandJustificationsEngine, + }, tests::{ create_beefy_keystore, get_beefy_streams, make_beefy_ids, BeefyPeer, BeefyTestNet, TestApi, @@ -1274,12 +1085,16 @@ pub(crate) mod tests { use futures::{future::poll_fn, task::Poll}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, HeaderBackend}; + use sc_network_gossip::GossipEngine; use sc_network_sync::SyncingService; use sc_network_test::TestNetFactory; use sp_blockchain::Backend as BlockchainBackendT; use sp_consensus_beefy::{ - generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, - mmr::MmrRootProvider, Keyring, Payload, SignedCommitment, + known_payloads, + known_payloads::MMR_ROOT_ID, + mmr::MmrRootProvider, + test_utils::{generate_equivocation_proof, Keyring}, + ConsensusLog, Payload, SignedCommitment, }; use sp_runtime::traits::{Header as HeaderT, One}; use substrate_test_runtime_client::{ @@ -1288,10 +1103,6 @@ pub(crate) mod tests { }; impl PersistedState { - pub fn voting_oracle(&self) -> &VoterOracle { - &self.voting_oracle - } - pub fn active_round(&self) -> Result<&Rounds, Error> { self.voting_oracle.active_rounds() } @@ -1309,7 +1120,7 @@ pub(crate) mod tests { fn create_beefy_worker( peer: &mut BeefyPeer, - key: &Keyring, + key: &Keyring, min_block_delta: u32, genesis_validator_set: ValidatorSet, ) -> BeefyWorker< @@ -1319,7 +1130,7 @@ pub(crate) mod tests { TestApi, Arc>, > { - let keystore = create_beefy_keystore(*key); + let keystore = create_beefy_keystore(key); let (to_rpc_justif_sender, from_voter_justif_stream) = BeefyVersionedFinalityProofStream::::channel(); @@ -1387,13 +1198,10 @@ pub(crate) mod tests { on_demand_justifications, }; BeefyWorker { - base: BeefyWorkerBase { - backend, - runtime: api, - key_store: Some(keystore).into(), - metrics, - _phantom: Default::default(), - }, + backend, + runtime: api, + key_store: Some(keystore).into(), + metrics, payload_provider, sync: Arc::new(sync), links, @@ -1671,19 +1479,22 @@ pub(crate) mod tests { let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); // keystore doesn't contain other keys than validators' - assert_eq!(worker.base.verify_validator_set(&1, &validator_set), Ok(())); + assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), Ok(())); // unknown `Bob` key let keys = &[Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let err_msg = "no authority public key found in store".to_string(); let expected = Err(Error::Keystore(err_msg)); - assert_eq!(worker.base.verify_validator_set(&1, &validator_set), expected); + assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), expected); // worker has no keystore - worker.base.key_store = None.into(); + worker.key_store = None.into(); let expected_err = Err(Error::Keystore("no Keystore".into())); - assert_eq!(worker.base.verify_validator_set(&1, &validator_set), expected_err); + assert_eq!( + verify_validator_set::(&1, &validator_set, &worker.key_store), + expected_err + ); } #[tokio::test] @@ -1835,7 +1646,7 @@ pub(crate) mod tests { let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); - worker.base.runtime = api_alice.clone(); + worker.runtime = api_alice.clone(); // let there be a block with num = 1: let _ = net.peer(0).push_blocks(1, false); diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index 16d3a4a1441ffcf0986ea9ee0418a770ded4a60d..7f36dfc09ef8451927eb32ebd651258647abee3b 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -20,11 +20,11 @@ async-trait = "0.1.74" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } -log = "0.4.17" +log = { workspace = true, default-features = true } mockall = "0.11.3" parking_lot = "0.12.1" -serde = { version = "1.0", features = ["derive"] } -thiserror = "1.0.48" +serde = { features = ["derive"], workspace = true, default-features = true } +thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-client-api = { path = "../../api" } sc-utils = { path = "../../utils" } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 3f7b48d9f2d0d2202170818d41d4730dcfb0bfa8..1ab953525220b82a500e5a23be0b94a673be51a2 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -24,12 +24,12 @@ dyn-clone = "1.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.17" +log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", features = ["derive"] } parking_lot = "0.12.1" rand = "0.8.5" -serde_json = "1.0.111" -thiserror = "1.0" +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } fork-tree = { path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-block-builder = { path = "../../block-builder" } @@ -57,7 +57,7 @@ sp-runtime = { path = "../../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec", "test-helpers"] } -serde = "1.0.195" +serde = { workspace = true, default-features = true } tokio = "1.22.0" sc-network = { path = "../../network" } sc-network-test = { path = "../../network/test" } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index ae9ab5d9d0794872c28f60f9694ee719c103d74e..f7e87415448e8c44952b957cf365fb36b089e4b0 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -15,11 +15,11 @@ workspace = true [dependencies] finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.16" -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } -log = "0.4.8" +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", features = ["derive"] } -serde = { version = "1.0.195", features = ["derive"] } -thiserror = "1.0" +serde = { features = ["derive"], workspace = true, default-features = true } +thiserror = { workspace = true } sc-client-api = { path = "../../../api" } sc-consensus-grandpa = { path = ".." } sc-rpc = { path = "../../../rpc" } diff --git a/substrate/client/consensus/grandpa/rpc/src/lib.rs b/substrate/client/consensus/grandpa/rpc/src/lib.rs index 878cefacc479a1a221f3631db574c9191e520824..0557eab93e2956b56956f50edea118c9c30cbd76 100644 --- a/substrate/client/consensus/grandpa/rpc/src/lib.rs +++ b/substrate/client/consensus/grandpa/rpc/src/lib.rs @@ -273,7 +273,7 @@ mod tests { let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); - assert_eq!(expected_response, response.result); + assert_eq!(expected_response, response); } #[tokio::test] @@ -295,7 +295,7 @@ mod tests { let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); - assert_eq!(expected_response, response.result); + assert_eq!(expected_response, response); } #[tokio::test] @@ -317,7 +317,7 @@ mod tests { .unwrap(); let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - assert_eq!(response.result, expected); + assert_eq!(response, expected); } fn create_justification() -> GrandpaJustification { diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index 0094fb8780095b355e9fe621f90f9d090d1c5eec..ac32fed72289fd6a296de2720a75fb36c65ad1f8 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -16,15 +16,15 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } assert_matches = "1.3.0" async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.17" -serde = { version = "1.0", features = ["derive"] } -thiserror = "1.0" +log = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-client-api = { path = "../../api" } sc-consensus = { path = "../common" } diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index e3608f6716c2631e5079c08e59ef991903b12d73..c3d360f071974ab38c6f1d112c23d6705f937bd3 100644 --- a/substrate/client/consensus/manual-seal/src/lib.rs +++ b/substrate/client/consensus/manual-seal/src/lib.rs @@ -429,7 +429,9 @@ mod tests { sender, } }); - let future = run_manual_seal(ManualSealParams { + + // spawn the background authorship task + tokio::spawn(run_manual_seal(ManualSealParams { block_import: client.clone(), env, client: client.clone(), @@ -438,12 +440,8 @@ mod tests { select_chain, create_inherent_data_providers: |_, _| async { Ok(()) }, consensus_data_provider: None, - }); - std::thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().unwrap(); - // spawn the background authorship task - rt.block_on(future); - }); + })); + // submit a transaction to pool. let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await; // assert that it was successfully imported @@ -469,7 +467,10 @@ mod tests { assert_eq!(client.header(created_block.hash).unwrap().unwrap().number, 1) } - #[tokio::test] + // TODO: enable once the flakiness is fixed + // See https://github.com/paritytech/polkadot-sdk/issues/3603 + //#[tokio::test] + #[allow(unused)] async fn instant_seal_delayed_finalize() { let builder = TestClientBuilder::new(); let (client, select_chain) = builder.build_with_longest_chain(); @@ -507,7 +508,8 @@ mod tests { } }); - let future_instant_seal = run_manual_seal(ManualSealParams { + // spawn the background authorship task + tokio::spawn(run_manual_seal(ManualSealParams { block_import: client.clone(), commands_stream, env, @@ -516,24 +518,16 @@ mod tests { select_chain, create_inherent_data_providers: |_, _| async { Ok(()) }, consensus_data_provider: None, - }); - std::thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().unwrap(); - // spawn the background authorship task - rt.block_on(future_instant_seal); - }); + })); let delay_sec = 5; - let future_delayed_finalize = run_delayed_finalize(DelayedFinalizeParams { + + // spawn the background finality task + tokio::spawn(run_delayed_finalize(DelayedFinalizeParams { client: client.clone(), delay_sec, spawn_handle: spawner, - }); - std::thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().unwrap(); - // spawn the background authorship task - rt.block_on(future_delayed_finalize); - }); + })); let mut finality_stream = client.finality_notification_stream(); // submit a transaction to pool. @@ -589,7 +583,9 @@ mod tests { // this test checks that blocks are created as soon as an engine command is sent over the // stream. let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); - let future = run_manual_seal(ManualSealParams { + + // spawn the background authorship task + tokio::spawn(run_manual_seal(ManualSealParams { block_import: client.clone(), env, client: client.clone(), @@ -598,12 +594,8 @@ mod tests { select_chain, consensus_data_provider: None, create_inherent_data_providers: |_, _| async { Ok(()) }, - }); - std::thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().unwrap(); - // spawn the background authorship task - rt.block_on(future); - }); + })); + // submit a transaction to pool. let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await; // assert that it was successfully imported @@ -675,7 +667,9 @@ mod tests { // this test checks that blocks are created as soon as an engine command is sent over the // stream. let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); - let future = run_manual_seal(ManualSealParams { + + // spawn the background authorship task + tokio::spawn(run_manual_seal(ManualSealParams { block_import: client.clone(), env, client: client.clone(), @@ -684,12 +678,8 @@ mod tests { select_chain, consensus_data_provider: None, create_inherent_data_providers: |_, _| async { Ok(()) }, - }); - std::thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().unwrap(); - // spawn the background authorship task - rt.block_on(future); - }); + })); + // submit a transaction to pool. let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await; // assert that it was successfully imported @@ -781,7 +771,9 @@ mod tests { let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); - let future = run_manual_seal(ManualSealParams { + + // spawn the background authorship task + tokio::spawn(run_manual_seal(ManualSealParams { block_import: client.clone(), env, client: client.clone(), @@ -791,11 +783,8 @@ mod tests { // use a provider that pushes some post digest data consensus_data_provider: Some(Box::new(TestDigestProvider { _client: client.clone() })), create_inherent_data_providers: |_, _| async { Ok(()) }, - }); - std::thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(future); - }); + })); + let (tx, rx) = futures::channel::oneshot::channel(); sink.send(EngineCommand::SealNewBlock { parent_hash: None, diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index c59a6a271143264fa1e03dadc95302a4bc0ad67f..0791514035b43c83492175bcac67e2a6eb6aa9c6 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -20,9 +20,9 @@ async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" -thiserror = "1.0" +thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-client-api = { path = "../../api" } sc-consensus = { path = "../common" } diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 8eed24532c9fd3649f6f8dd6dc9f9a4914579e2d..75f8b29a2fd755c18d68b817499e2dfb75ea232c 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -21,7 +21,7 @@ async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.17" +log = { workspace = true, default-features = true } sc-client-api = { path = "../../api" } sc-consensus = { path = "../common" } sc-telemetry = { path = "../../telemetry" } diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index ed7b4178f287a67c72946b9829b91d91c84bb442..57ee1a8ad3315036f44e5b560fb55fa3f31c97e5 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -24,7 +24,7 @@ kvdb = "0.13.0" kvdb-memorydb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } linked-hash-map = "0.5.4" -log = "0.4.17" +log = { workspace = true, default-features = true } parity-db = "0.4.12" parking_lot = "0.12.1" sc-client-api = { path = "../api" } diff --git a/substrate/client/db/benches/state_access.rs b/substrate/client/db/benches/state_access.rs index e47559e710df1e21dab3d2a57b0c6434dd790289..9f3b8ca77c25e50986de42c5803f8615bbf3d00f 100644 --- a/substrate/client/db/benches/state_access.rs +++ b/substrate/client/db/benches/state_access.rs @@ -22,12 +22,13 @@ 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}, + generic::UncheckedExtrinsic, + testing::{Block as RawBlock, Header, MockCallU64}, 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/bench.rs b/substrate/client/db/src/bench.rs index 03ad4817b53bcea2cb349d4d05c190bb239530fa..32503cf63c0ad7eeae1ab502d38b09aa210d9bc9 100644 --- a/substrate/client/db/src/bench.rs +++ b/substrate/client/db/src/bench.rs @@ -19,7 +19,7 @@ //! State backend that's useful for benchmarking use crate::{DbState, DbStateBuilder}; -use hash_db::{Hasher, Prefix}; +use hash_db::{Hasher as DbHasher, Prefix}; use kvdb::{DBTransaction, KeyValueDB}; use linked_hash_map::LinkedHashMap; use parking_lot::Mutex; @@ -27,10 +27,7 @@ use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, TrackedStorageKey}, }; -use sp_runtime::{ - traits::{Block as BlockT, HashingFor}, - StateVersion, Storage, -}; +use sp_runtime::{traits::Hash, StateVersion, Storage}; use sp_state_machine::{ backend::Backend as StateBackend, BackendTransaction, ChildStorageCollection, DBValue, IterArgs, StorageCollection, StorageIterator, StorageKey, StorageValue, @@ -45,16 +42,16 @@ use std::{ sync::Arc, }; -type State = DbState; +type State = DbState; -struct StorageDb { +struct StorageDb { db: Arc, - _block: std::marker::PhantomData, + _phantom: std::marker::PhantomData, } -impl sp_state_machine::Storage> for StorageDb { - fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result, String> { - let prefixed_key = prefixed_key::>(key, prefix); +impl sp_state_machine::Storage for StorageDb { + fn get(&self, key: &Hasher::Output, prefix: Prefix) -> Result, String> { + let prefixed_key = prefixed_key::(key, prefix); self.db .get(0, &prefixed_key) .map_err(|e| format!("Database backend error: {:?}", e)) @@ -75,29 +72,29 @@ struct KeyTracker { } /// State that manages the backend database reference. Allows runtime to control the database. -pub struct BenchmarkingState { - root: Cell, - genesis_root: B::Hash, - state: RefCell>>, +pub struct BenchmarkingState { + root: Cell, + genesis_root: Hasher::Output, + state: RefCell>>, db: Cell>>, genesis: HashMap, (Vec, i32)>, record: Cell>>, key_tracker: Arc>, whitelist: RefCell>, - proof_recorder: Option>>, - proof_recorder_root: Cell, - shared_trie_cache: SharedTrieCache>, + proof_recorder: Option>, + proof_recorder_root: Cell, + shared_trie_cache: SharedTrieCache, } /// A raw iterator over the `BenchmarkingState`. -pub struct RawIter { - inner: as StateBackend>>::RawIter, +pub struct RawIter { + inner: as StateBackend>::RawIter, child_trie: Option>, key_tracker: Arc>, } -impl StorageIterator> for RawIter { - type Backend = BenchmarkingState; +impl StorageIterator for RawIter { + type Backend = BenchmarkingState; type Error = String; fn next_key(&mut self, backend: &Self::Backend) -> Option> { @@ -128,7 +125,7 @@ impl StorageIterator> for RawIter { } } -impl BenchmarkingState { +impl BenchmarkingState { /// Create a new instance that creates a database in a temporary dir. pub fn new( genesis: Storage, @@ -137,9 +134,9 @@ impl BenchmarkingState { enable_tracking: bool, ) -> Result { let state_version = sp_runtime::StateVersion::default(); - let mut root = B::Hash::default(); - let mut mdb = MemoryDB::>::default(); - sp_trie::trie_types::TrieDBMutBuilderV1::>::new(&mut mdb, &mut root).build(); + let mut root = Default::default(); + let mut mdb = MemoryDB::::default(); + sp_trie::trie_types::TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); let mut state = BenchmarkingState { state: RefCell::new(None), @@ -169,7 +166,7 @@ impl BenchmarkingState { child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), ) }); - let (root, transaction): (B::Hash, _) = + let (root, transaction): (Hasher::Output, _) = state.state.borrow().as_ref().unwrap().full_storage_root( genesis.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), child_delta, @@ -193,9 +190,9 @@ impl BenchmarkingState { recorder.reset(); self.proof_recorder_root.set(self.root.get()); } - let storage_db = Arc::new(StorageDb:: { db, _block: Default::default() }); + let storage_db = Arc::new(StorageDb:: { db, _phantom: Default::default() }); *self.state.borrow_mut() = Some( - DbStateBuilder::::new(storage_db, self.root.get()) + DbStateBuilder::::new(storage_db, self.root.get()) .with_optional_recorder(self.proof_recorder.clone()) .with_cache(self.shared_trie_cache.local_cache()) .build(), @@ -341,17 +338,17 @@ fn state_err() -> String { "State is not open".into() } -impl StateBackend> for BenchmarkingState { - type Error = as StateBackend>>::Error; - type TrieBackendStorage = as StateBackend>>::TrieBackendStorage; - type RawIter = RawIter; +impl StateBackend for BenchmarkingState { + type Error = as StateBackend>::Error; + type TrieBackendStorage = as StateBackend>::TrieBackendStorage; + type RawIter = RawIter; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { self.add_read_key(None, key); self.state.borrow().as_ref().ok_or_else(state_err)?.storage(key) } - fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { + fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { self.add_read_key(None, key); self.state.borrow().as_ref().ok_or_else(state_err)?.storage_hash(key) } @@ -373,7 +370,7 @@ impl StateBackend> for BenchmarkingState { &self, child_info: &ChildInfo, key: &[u8], - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { self.add_read_key(Some(child_info.storage_key()), key); self.state .borrow() @@ -385,7 +382,7 @@ impl StateBackend> for BenchmarkingState { fn closest_merkle_value( &self, key: &[u8], - ) -> Result>, Self::Error> { + ) -> Result>, Self::Error> { self.add_read_key(None, key); self.state.borrow().as_ref().ok_or_else(state_err)?.closest_merkle_value(key) } @@ -394,7 +391,7 @@ impl StateBackend> for BenchmarkingState { &self, child_info: &ChildInfo, key: &[u8], - ) -> Result>, Self::Error> { + ) -> Result>, Self::Error> { self.add_read_key(None, key); self.state .borrow() @@ -443,7 +440,7 @@ impl StateBackend> for BenchmarkingState { &self, delta: impl Iterator)>, state_version: StateVersion, - ) -> (B::Hash, BackendTransaction>) { + ) -> (Hasher::Output, BackendTransaction) { self.state .borrow() .as_ref() @@ -455,7 +452,7 @@ impl StateBackend> for BenchmarkingState { child_info: &ChildInfo, delta: impl Iterator)>, state_version: StateVersion, - ) -> (B::Hash, bool, BackendTransaction>) { + ) -> (Hasher::Output, bool, BackendTransaction) { self.state .borrow() .as_ref() @@ -479,8 +476,8 @@ impl StateBackend> for BenchmarkingState { fn commit( &self, - storage_root: as Hasher>::Out, - mut transaction: BackendTransaction>, + storage_root: ::Out, + mut transaction: BackendTransaction, main_storage_changes: StorageCollection, child_storage_changes: ChildStorageCollection, ) -> Result<(), Self::Error> { @@ -634,8 +631,7 @@ impl StateBackend> for BenchmarkingState { log::debug!(target: "benchmark", "Some proof size: {}", &proof_size); proof_size } else { - if let Some(size) = proof.encoded_compact_size::>(proof_recorder_root) - { + if let Some(size) = proof.encoded_compact_size::(proof_recorder_root) { size as u32 } else if proof_recorder_root == self.root.get() { log::debug!(target: "benchmark", "No changes - no proof"); @@ -654,7 +650,7 @@ impl StateBackend> for BenchmarkingState { } } -impl std::fmt::Debug for BenchmarkingState { +impl std::fmt::Debug for BenchmarkingState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Bench DB") } @@ -663,6 +659,7 @@ impl std::fmt::Debug for BenchmarkingState { #[cfg(test)] mod test { use crate::bench::BenchmarkingState; + use sp_runtime::traits::HashingFor; use sp_state_machine::backend::Backend as _; fn hex(hex: &str) -> Vec { @@ -681,7 +678,8 @@ mod test { ..sp_runtime::Storage::default() }; let bench_state = - BenchmarkingState::::new(storage, None, false, true).unwrap(); + BenchmarkingState::>::new(storage, None, false, true) + .unwrap(); assert_eq!(bench_state.read_write_count(), (0, 0, 0, 0)); assert_eq!(bench_state.keys(Default::default()).unwrap().count(), 1); @@ -690,9 +688,13 @@ mod test { #[test] fn read_to_main_and_child_tries() { - let bench_state = - BenchmarkingState::::new(Default::default(), None, false, true) - .unwrap(); + let bench_state = BenchmarkingState::>::new( + Default::default(), + None, + false, + true, + ) + .unwrap(); for _ in 0..2 { let child1 = sp_core::storage::ChildInfo::new_default(b"child1"); diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index 2d8622d5f12dcc798cbc4c46685df6b4a2a38658..f22022ef29a37695e2df1d432dd3b4d4d916c62e 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -101,14 +101,11 @@ pub use bench::BenchmarkingState; const CACHE_HEADERS: usize = 8; /// DB-backed patricia trie state, transaction type is an overlay of changes to commit. -pub type DbState = - sp_state_machine::TrieBackend>>, HashingFor>; +pub type DbState = sp_state_machine::TrieBackend>, H>; /// Builder for [`DbState`]. -pub type DbStateBuilder = sp_state_machine::TrieBackendBuilder< - Arc>>, - HashingFor, ->; +pub type DbStateBuilder = + sp_state_machine::TrieBackendBuilder>, Hasher>; /// Length of a [`DbHash`]. const DB_HASH_LEN: usize = 32; @@ -135,13 +132,17 @@ enum DbExtrinsic { /// It makes sure that the hash we are using stays pinned in storage /// until this structure is dropped. pub struct RefTrackingState { - state: DbState, + state: DbState>, storage: Arc>, parent_hash: Option, } impl RefTrackingState { - fn new(state: DbState, storage: Arc>, parent_hash: Option) -> Self { + fn new( + state: DbState>, + storage: Arc>, + parent_hash: Option, + ) -> Self { RefTrackingState { state, parent_hash, storage } } } @@ -162,12 +163,12 @@ impl std::fmt::Debug for RefTrackingState { /// A raw iterator over the `RefTrackingState`. pub struct RawIter { - inner: as StateBackend>>::RawIter, + inner: > as StateBackend>>::RawIter, } impl StorageIterator> for RawIter { type Backend = RefTrackingState; - type Error = as StateBackend>>::Error; + type Error = > as StateBackend>>::Error; fn next_key(&mut self, backend: &Self::Backend) -> Option> { self.inner.next_key(&backend.state) @@ -186,8 +187,9 @@ impl StorageIterator> for RawIter { } impl StateBackend> for RefTrackingState { - type Error = as StateBackend>>::Error; - type TrieBackendStorage = as StateBackend>>::TrieBackendStorage; + type Error = > as StateBackend>>::Error; + type TrieBackendStorage = + > as StateBackend>>::TrieBackendStorage; type RawIter = RawIter; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { @@ -284,7 +286,8 @@ impl StateBackend> for RefTrackingState { } impl AsTrieBackend> for RefTrackingState { - type TrieBackendStorage = as StateBackend>>::TrieBackendStorage; + type TrieBackendStorage = + > as StateBackend>>::TrieBackendStorage; fn as_trie_backend( &self, @@ -1936,7 +1939,7 @@ impl Backend { fn empty_state(&self) -> RecordStatsState, Block> { let root = EmptyStorage::::new().0; // Empty trie - let db_state = DbStateBuilder::::new(self.storage.clone(), root) + let db_state = DbStateBuilder::>::new(self.storage.clone(), root) .with_optional_cache(self.shared_trie_cache.as_ref().map(|c| c.local_cache())) .build(); let state = RefTrackingState::new(db_state, self.storage.clone(), None); @@ -2428,9 +2431,12 @@ impl sc_client_api::backend::Backend for Backend { if hash == self.blockchain.meta.read().genesis_hash { if let Some(genesis_state) = &*self.genesis_state.read() { let root = genesis_state.root; - let db_state = DbStateBuilder::::new(genesis_state.clone(), root) - .with_optional_cache(self.shared_trie_cache.as_ref().map(|c| c.local_cache())) - .build(); + let db_state = + DbStateBuilder::>::new(genesis_state.clone(), root) + .with_optional_cache( + self.shared_trie_cache.as_ref().map(|c| c.local_cache()), + ) + .build(); let state = RefTrackingState::new(db_state, self.storage.clone(), None); return Ok(RecordStatsState::new(state, None, self.state_usage.clone())) @@ -2449,11 +2455,12 @@ impl sc_client_api::backend::Backend for Backend { self.storage.state_db.pin(&hash, hdr.number.saturated_into::(), hint) { let root = hdr.state_root; - let db_state = DbStateBuilder::::new(self.storage.clone(), root) - .with_optional_cache( - self.shared_trie_cache.as_ref().map(|c| c.local_cache()), - ) - .build(); + let db_state = + DbStateBuilder::>::new(self.storage.clone(), root) + .with_optional_cache( + self.shared_trie_cache.as_ref().map(|c| c.local_cache()), + ) + .build(); let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash)); Ok(RecordStatsState::new(state, Some(hash), self.state_usage.clone())) } else { @@ -2524,7 +2531,7 @@ impl sc_client_api::backend::Backend for Backend { self.storage.state_db.pin(&hash, number.saturated_into::(), hint).map_err( |_| { sp_blockchain::Error::UnknownBlock(format!( - "State already discarded for `{:?}`", + "Unable to pin: state already discarded for `{:?}`", hash )) }, @@ -2566,7 +2573,8 @@ 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}, + generic::UncheckedExtrinsic, + testing::{Block as RawBlock, Header, MockCallU64}, traits::{BlakeTwo256, Hash}, ConsensusEngineId, StateVersion, }; @@ -2574,7 +2582,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 = UncheckedExtrinsic; + pub(crate) type Block = RawBlock; pub fn insert_header( backend: &Backend, @@ -2593,7 +2602,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; @@ -3407,7 +3416,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3429,11 +3438,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() + ); } } } @@ -3457,7 +3475,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3466,16 +3484,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(); @@ -3485,7 +3513,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(); @@ -3499,16 +3530,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()); } @@ -3529,8 +3572,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); @@ -3558,18 +3609,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![ @@ -3590,7 +3653,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(); @@ -3612,8 +3678,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![ @@ -3634,7 +3701,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(); @@ -3648,7 +3718,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(); @@ -3668,7 +3738,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], Some(index), ) .unwrap(); @@ -3702,7 +3772,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3717,7 +3787,7 @@ pub(crate) mod tests { blocks[1], None, sp_core::H256::random(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3731,7 +3801,7 @@ pub(crate) mod tests { blocks[0], None, sp_core::H256::random(), - vec![42.into()], + vec![UncheckedXt::new_transaction(42.into(), ())], None, ) .unwrap(); @@ -4204,7 +4274,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4219,7 +4289,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(); @@ -4236,27 +4309,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() @@ -4287,7 +4375,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() @@ -4295,9 +4386,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(); @@ -4312,12 +4410,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]); @@ -4327,9 +4431,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 @@ -4342,7 +4453,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])); @@ -4364,7 +4478,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4380,16 +4494,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(); @@ -4410,14 +4534,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/pinned_blocks_cache.rs b/substrate/client/db/src/pinned_blocks_cache.rs index 46c9287fb19ac1361153dbb65f4f0b353170042f..ac4aad07765cfbaa4d9c66efa4b44730b0b0a04c 100644 --- a/substrate/client/db/src/pinned_blocks_cache.rs +++ b/substrate/client/db/src/pinned_blocks_cache.rs @@ -20,7 +20,7 @@ use schnellru::{Limiter, LruMap}; use sp_runtime::{traits::Block as BlockT, Justifications}; const LOG_TARGET: &str = "db::pin"; -const PINNING_CACHE_SIZE: usize = 1024; +const PINNING_CACHE_SIZE: usize = 2048; /// Entry for pinned blocks cache. struct PinnedBlockCacheEntry { diff --git a/substrate/client/db/src/utils.rs b/substrate/client/db/src/utils.rs index abf9c4629cee47e31d18a18c827212b48fe31511..d2a5f7e718a6f0af4188fc18ed0c551a51f5c974 100644 --- a/substrate/client/db/src/utils.rs +++ b/substrate/client/db/src/utils.rs @@ -582,14 +582,19 @@ 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::{ + generic::UncheckedExtrinsic, + testing::{Block as RawBlock, MockCallU64}, + }; + + pub type UncheckedXt = UncheckedExtrinsic; + 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/Cargo.toml b/substrate/client/executor/Cargo.toml index 4e36de3c4f47c9f4f98f28d694ec3f23cbd81add..7fad7e3a2a0ebaf3a8ecde19ff9517e47ff28e75 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -23,6 +23,7 @@ tracing = "0.1.29" codec = { package = "parity-scale-codec", version = "3.6.1" } sc-executor-common = { path = "common" } +sc-executor-polkavm = { path = "polkavm" } sc-executor-wasmtime = { path = "wasmtime" } sp-api = { path = "../../primitives/api" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index 648fb9f0f5040d60d96defb07bc276e6e10cdc23..8ff34c3709a5e486fb9036a638788a532c6f296c 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -17,11 +17,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -thiserror = "1.0.48" +thiserror = { workspace = true } wasm-instrument = "0.4" sc-allocator = { path = "../../allocator" } sp-maybe-compressed-blob = { path = "../../../primitives/maybe-compressed-blob" } sp-wasm-interface = { path = "../../../primitives/wasm-interface" } +polkavm = { workspace = true } [features] default = [] diff --git a/substrate/client/executor/common/src/error.rs b/substrate/client/executor/common/src/error.rs index 2a0dc364b4103ebc53ee767300bf25cc7211fe8b..b7c7e2b701984e37d43741ecb3cc2a1efdab9bdc 100644 --- a/substrate/client/executor/common/src/error.rs +++ b/substrate/client/executor/common/src/error.rs @@ -150,6 +150,24 @@ pub enum WasmError { Other(String), } +impl From for WasmError { + fn from(error: polkavm::ProgramParseError) -> Self { + WasmError::Other(error.to_string()) + } +} + +impl From for WasmError { + fn from(error: polkavm::Error) -> Self { + WasmError::Other(error.to_string()) + } +} + +impl From for Error { + fn from(error: polkavm::Error) -> Self { + Error::Other(error.to_string()) + } +} + /// An error message with an attached backtrace. #[derive(Debug)] pub struct MessageWithBacktrace { diff --git a/substrate/client/executor/common/src/lib.rs b/substrate/client/executor/common/src/lib.rs index 751801fb30da18e48e05daedbde644ad8699ce10..ff9fab2c8889fbbc9040740cd5f5a49f158d618c 100644 --- a/substrate/client/executor/common/src/lib.rs +++ b/substrate/client/executor/common/src/lib.rs @@ -25,3 +25,7 @@ pub mod error; pub mod runtime_blob; pub mod util; pub mod wasm_runtime; + +pub(crate) fn is_polkavm_enabled() -> bool { + std::env::var_os("SUBSTRATE_ENABLE_POLKAVM").map_or(false, |value| value == "1") +} diff --git a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs index becf9e219b0b7a60f97bb08b4044897b143bd006..d689083b2f85cd7f3fc16f220c1b45a474dd87f5 100644 --- a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs @@ -17,23 +17,23 @@ // along with this program. If not, see . use crate::{error::WasmError, wasm_runtime::HeapAllocStrategy}; -use wasm_instrument::{ - export_mutable_globals, - parity_wasm::elements::{ - deserialize_buffer, serialize, ExportEntry, External, Internal, MemorySection, MemoryType, - Module, Section, - }, +use wasm_instrument::parity_wasm::elements::{ + deserialize_buffer, serialize, ExportEntry, External, Internal, MemorySection, MemoryType, + Module, Section, }; -/// A bunch of information collected from a WebAssembly module. +/// A program blob containing a Substrate runtime. #[derive(Clone)] -pub struct RuntimeBlob { - raw_module: Module, +pub struct RuntimeBlob(BlobKind); + +#[derive(Clone)] +enum BlobKind { + WebAssembly(Module), + PolkaVM(polkavm::ProgramBlob<'static>), } impl RuntimeBlob { - /// Create `RuntimeBlob` from the given wasm code. Will attempt to decompress the code before - /// deserializing it. + /// Create `RuntimeBlob` from the given WASM or PolkaVM compressed program blob. /// /// See [`sp_maybe_compressed_blob`] for details about decompression. pub fn uncompress_if_needed(wasm_code: &[u8]) -> Result { @@ -43,31 +43,26 @@ impl RuntimeBlob { Self::new(&wasm_code) } - /// Create `RuntimeBlob` from the given wasm code. + /// Create `RuntimeBlob` from the given WASM or PolkaVM program blob. /// - /// Returns `Err` if the wasm code cannot be deserialized. - pub fn new(wasm_code: &[u8]) -> Result { - let raw_module: Module = deserialize_buffer(wasm_code) - .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:?}", e)))?; - Ok(Self { raw_module }) - } - - /// The number of globals defined in locally in this module. - pub fn declared_globals_count(&self) -> u32 { - self.raw_module - .global_section() - .map(|gs| gs.entries().len() as u32) - .unwrap_or(0) - } - - /// The number of imports of globals. - pub fn imported_globals_count(&self) -> u32 { - self.raw_module.import_section().map(|is| is.globals() as u32).unwrap_or(0) - } + /// Returns `Err` if the blob cannot be deserialized. + /// + /// Will only accept a PolkaVM program if the `SUBSTRATE_ENABLE_POLKAVM` environment + /// variable is set to `1`. + pub fn new(raw_blob: &[u8]) -> Result { + if raw_blob.starts_with(b"PVM\0") { + if crate::is_polkavm_enabled() { + return Ok(Self(BlobKind::PolkaVM( + polkavm::ProgramBlob::parse(raw_blob)?.into_owned(), + ))); + } else { + return Err(WasmError::Other("expected a WASM runtime blob, found a PolkaVM runtime blob; set the 'SUBSTRATE_ENABLE_POLKAVM' environment variable to enable the experimental PolkaVM-based executor".to_string())); + } + } - /// Perform an instrumentation that makes sure that the mutable globals are exported. - pub fn expose_mutable_globals(&mut self) { - export_mutable_globals(&mut self.raw_module, "exported_internal_global"); + let raw_module: Module = deserialize_buffer(raw_blob) + .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:?}", e)))?; + Ok(Self(BlobKind::WebAssembly(raw_module))) } /// Run a pass that instrument this module so as to introduce a deterministic stack height @@ -80,26 +75,16 @@ impl RuntimeBlob { /// /// The stack cost of a function is computed based on how much locals there are and the maximum /// depth of the wasm operand stack. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn inject_stack_depth_metering(self, stack_depth_limit: u32) -> Result { let injected_module = - wasm_instrument::inject_stack_limiter(self.raw_module, stack_depth_limit).map_err( - |e| WasmError::Other(format!("cannot inject the stack limiter: {:?}", e)), - )?; - - Ok(Self { raw_module: injected_module }) - } + wasm_instrument::inject_stack_limiter(self.into_webassembly_blob()?, stack_depth_limit) + .map_err(|e| { + WasmError::Other(format!("cannot inject the stack limiter: {:?}", e)) + })?; - /// Perform an instrumentation that makes sure that a specific function `entry_point` is - /// exported - pub fn entry_point_exists(&self, entry_point: &str) -> bool { - self.raw_module - .export_section() - .map(|e| { - e.entries().iter().any(|e| { - matches!(e.internal(), Internal::Function(_)) && e.field() == entry_point - }) - }) - .unwrap_or_default() + Ok(Self(BlobKind::WebAssembly(injected_module))) } /// Converts a WASM memory import into a memory section and exports it. @@ -107,8 +92,11 @@ impl RuntimeBlob { /// Does nothing if there's no memory import. /// /// May return an error in case the WASM module is invalid. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn convert_memory_import_into_export(&mut self) -> Result<(), WasmError> { - let import_section = match self.raw_module.import_section_mut() { + let raw_module = self.as_webassembly_blob_mut()?; + let import_section = match raw_module.import_section_mut() { Some(import_section) => import_section, None => return Ok(()), }; @@ -124,7 +112,7 @@ impl RuntimeBlob { let memory_name = entry.field().to_owned(); import_entries.remove(index); - self.raw_module + raw_module .insert_section(Section::Memory(MemorySection::with_entries(vec![memory_ty]))) .map_err(|error| { WasmError::Other(format!( @@ -133,14 +121,14 @@ impl RuntimeBlob { )) })?; - if self.raw_module.export_section_mut().is_none() { + if raw_module.export_section_mut().is_none() { // A module without an export section is somewhat unrealistic, but let's do this // just in case to cover all of our bases. - self.raw_module + raw_module .insert_section(Section::Export(Default::default())) .expect("an export section can be always inserted if it doesn't exist; qed"); } - self.raw_module + raw_module .export_section_mut() .expect("export section already existed or we just added it above, so it always exists; qed") .entries_mut() @@ -156,12 +144,14 @@ impl RuntimeBlob { /// /// Will return an error in case there is no memory section present, /// or if the memory section is empty. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn setup_memory_according_to_heap_alloc_strategy( &mut self, heap_alloc_strategy: HeapAllocStrategy, ) -> Result<(), WasmError> { - let memory_section = self - .raw_module + let raw_module = self.as_webassembly_blob_mut()?; + let memory_section = raw_module .memory_section_mut() .ok_or_else(|| WasmError::Other("no memory section found".into()))?; @@ -187,8 +177,11 @@ impl RuntimeBlob { /// Scans the wasm blob for the first section with the name that matches the given. Returns the /// contents of the custom section if found or `None` otherwise. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn custom_section_contents(&self, section_name: &str) -> Option<&[u8]> { - self.raw_module + self.as_webassembly_blob() + .ok()? .custom_sections() .find(|cs| cs.name() == section_name) .map(|cs| cs.payload()) @@ -196,11 +189,45 @@ impl RuntimeBlob { /// Consumes this runtime blob and serializes it. pub fn serialize(self) -> Vec { - serialize(self.raw_module).expect("serializing into a vec should succeed; qed") + match self.0 { + BlobKind::WebAssembly(raw_module) => + serialize(raw_module).expect("serializing into a vec should succeed; qed"), + BlobKind::PolkaVM(ref blob) => blob.as_bytes().to_vec(), + } + } + + fn as_webassembly_blob(&self) -> Result<&Module, WasmError> { + match self.0 { + BlobKind::WebAssembly(ref raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } } - /// Destructure this structure into the underlying parity-wasm Module. - pub fn into_inner(self) -> Module { - self.raw_module + fn as_webassembly_blob_mut(&mut self) -> Result<&mut Module, WasmError> { + match self.0 { + BlobKind::WebAssembly(ref mut raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } + } + + fn into_webassembly_blob(self) -> Result { + match self.0 { + BlobKind::WebAssembly(raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } + } + + /// Gets a reference to the inner PolkaVM program blob, if this is a PolkaVM program. + pub fn as_polkavm_blob(&self) -> Option<&polkavm::ProgramBlob> { + match self.0 { + BlobKind::WebAssembly(..) => None, + BlobKind::PolkaVM(ref blob) => Some(blob), + } } } diff --git a/substrate/client/executor/common/src/wasm_runtime.rs b/substrate/client/executor/common/src/wasm_runtime.rs index d8e142b9d55905e3e31d2247f5a48e8e2b0f987a..e8f429a3dbb2a0451769d427a81bdf5eaef492ff 100644 --- a/substrate/client/executor/common/src/wasm_runtime.rs +++ b/substrate/client/executor/common/src/wasm_runtime.rs @@ -19,7 +19,6 @@ //! Definitions for a wasm runtime. use crate::error::Error; -use sp_wasm_interface::Value; pub use sc_allocator::AllocationStats; @@ -30,46 +29,6 @@ pub const DEFAULT_HEAP_ALLOC_STRATEGY: HeapAllocStrategy = /// Default heap allocation pages. pub const DEFAULT_HEAP_ALLOC_PAGES: u32 = 2048; -/// A method to be used to find the entrypoint when calling into the runtime -/// -/// Contains variants on how to resolve wasm function that will be invoked. -pub enum InvokeMethod<'a> { - /// Call function exported with this name. - /// - /// Located function should have (u32, u32) -> u64 signature. - Export(&'a str), - /// Call a function found in the exported table found under the given index. - /// - /// Located function should have (u32, u32) -> u64 signature. - Table(u32), - /// Call function by reference from table through a wrapper. - /// - /// Invoked function (`dispatcher_ref`) function - /// should have (u32, u32, u32) -> u64 signature. - /// - /// `func` will be passed to the invoked function as a first argument. - TableWithWrapper { - /// Wrapper for the call. - /// - /// Function pointer, index into runtime exported table. - dispatcher_ref: u32, - /// Extra argument for dispatch. - /// - /// Common usage would be to use it as an actual wasm function pointer - /// that should be invoked, but can be used as any extra argument on the - /// callee side. - /// - /// This is typically generated and invoked by the runtime itself. - func: u32, - }, -} - -impl<'a> From<&'a str> for InvokeMethod<'a> { - fn from(val: &'a str) -> InvokeMethod<'a> { - InvokeMethod::Export(val) - } -} - /// A trait that defines an abstract WASM runtime module. /// /// This can be implemented by an execution engine. @@ -87,7 +46,7 @@ pub trait WasmInstance: Send { /// Before execution, instance is reset. /// /// Returns the encoded result on success. - fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result, Error> { + fn call(&mut self, method: &str, data: &[u8]) -> Result, Error> { self.call_with_allocation_stats(method, data).0 } @@ -98,7 +57,7 @@ pub trait WasmInstance: Send { /// Returns the encoded result on success. fn call_with_allocation_stats( &mut self, - method: InvokeMethod, + method: &str, data: &[u8], ) -> (Result, Error>, Option); @@ -110,11 +69,6 @@ pub trait WasmInstance: Send { fn call_export(&mut self, method: &str, data: &[u8]) -> Result, Error> { self.call(method.into(), data) } - - /// Get the value from a global with the given `name`. - /// - /// This method is only suitable for getting immutable globals. - fn get_global_const(&mut self, name: &str) -> Result, Error>; } /// Defines the heap pages allocation strategy the wasm runtime should use. diff --git a/substrate/client/executor/polkavm/Cargo.toml b/substrate/client/executor/polkavm/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9d0eb8ccf0ee072c86195068a589309edd132ba4 --- /dev/null +++ b/substrate/client/executor/polkavm/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "sc-executor-polkavm" +version = "0.29.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "PolkaVM executor for Substrate" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +log = { workspace = true } +polkavm = { workspace = true } + +sc-executor-common = { path = "../common" } +sp-wasm-interface = { path = "../../../primitives/wasm-interface" } diff --git a/substrate/client/executor/polkavm/README.md b/substrate/client/executor/polkavm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..64fc2fa0c28485566fc60329ad8cfc0057112bc7 --- /dev/null +++ b/substrate/client/executor/polkavm/README.md @@ -0,0 +1 @@ +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/executor/polkavm/src/lib.rs b/substrate/client/executor/polkavm/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..1bd72eb33d309997832de5fca9250ca651090ce7 --- /dev/null +++ b/substrate/client/executor/polkavm/src/lib.rs @@ -0,0 +1,261 @@ +// 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 polkavm::{Caller, Reg}; +use sc_executor_common::{ + error::{Error, WasmError}, + wasm_runtime::{AllocationStats, WasmInstance, WasmModule}, +}; +use sp_wasm_interface::{ + Function, FunctionContext, HostFunctions, Pointer, Value, ValueType, WordSize, +}; + +#[repr(transparent)] +pub struct InstancePre(polkavm::InstancePre<()>); + +#[repr(transparent)] +pub struct Instance(polkavm::Instance<()>); + +impl WasmModule for InstancePre { + fn new_instance(&self) -> Result, Error> { + Ok(Box::new(Instance(self.0.instantiate()?))) + } +} + +impl WasmInstance for Instance { + fn call_with_allocation_stats( + &mut self, + name: &str, + raw_data: &[u8], + ) -> (Result, Error>, Option) { + let Some(method_index) = self.0.module().lookup_export(name) else { + return ( + Err(format!("cannot call into the runtime: export not found: '{name}'").into()), + None, + ); + }; + + let Ok(raw_data_length) = u32::try_from(raw_data.len()) else { + return ( + Err(format!("cannot call runtime method '{name}': input payload is too big").into()), + None, + ); + }; + + // TODO: This will leak guest memory; find a better solution. + let mut state_args = polkavm::StateArgs::new(); + + // Make sure the memory is cleared... + state_args.reset_memory(true); + // ...and allocate space for the input payload. + state_args.sbrk(raw_data_length); + + match self.0.update_state(state_args) { + Ok(()) => {}, + Err(polkavm::ExecutionError::Trap(trap)) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {trap}").into()), None); + }, + Err(polkavm::ExecutionError::Error(error)) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {error}").into()), None); + }, + Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), + } + + // Grab the address of where the guest's heap starts; that's where we've just allocated + // the memory for the input payload. + let data_pointer = self.0.module().memory_map().heap_base(); + + if let Err(error) = self.0.write_memory(data_pointer, raw_data) { + return (Err(format!("call into the runtime method '{name}': failed to write the input payload into guest memory: {error}").into()), None); + } + + let mut state = (); + let mut call_args = polkavm::CallArgs::new(&mut state, method_index); + call_args.args_untyped(&[data_pointer, raw_data_length]); + + match self.0.call(Default::default(), call_args) { + Ok(()) => {}, + Err(polkavm::ExecutionError::Trap(trap)) => { + return ( + Err(format!("call into the runtime method '{name}' failed: {trap}").into()), + None, + ); + }, + Err(polkavm::ExecutionError::Error(error)) => { + return ( + Err(format!("call into the runtime method '{name}' failed: {error}").into()), + None, + ); + }, + Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), + } + + let result_pointer = self.0.get_reg(Reg::A0); + let result_length = self.0.get_reg(Reg::A1); + let output = match self.0.read_memory_into_vec(result_pointer, result_length) { + Ok(output) => output, + Err(error) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to read the return payload: {error}").into()), None) + }, + }; + + (Ok(output), None) + } +} + +struct Context<'r, 'a>(&'r mut polkavm::Caller<'a, ()>); + +impl<'r, 'a> FunctionContext for Context<'r, 'a> { + fn read_memory_into( + &self, + address: Pointer, + dest: &mut [u8], + ) -> sp_wasm_interface::Result<()> { + self.0 + .read_memory_into_slice(u32::from(address), dest) + .map_err(|error| error.to_string()) + .map(|_| ()) + } + + fn write_memory(&mut self, address: Pointer, data: &[u8]) -> sp_wasm_interface::Result<()> { + self.0.write_memory(u32::from(address), data).map_err(|error| error.to_string()) + } + + fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { + let pointer = self.0.sbrk(0).expect("fetching the current heap pointer never fails"); + + // TODO: This will leak guest memory; find a better solution. + self.0.sbrk(size).ok_or_else(|| String::from("allocation failed"))?; + + Ok(Pointer::new(pointer)) + } + + fn deallocate_memory(&mut self, _ptr: Pointer) -> sp_wasm_interface::Result<()> { + // This is only used by the allocator host function, which is unused under PolkaVM. + unimplemented!("'deallocate_memory' is never used when running under PolkaVM"); + } + + fn register_panic_error_message(&mut self, _message: &str) { + unimplemented!("'register_panic_error_message' is never used when running under PolkaVM"); + } +} + +fn call_host_function( + caller: &mut Caller<()>, + function: &dyn Function, +) -> Result<(), polkavm::Trap> { + let mut args = [Value::I64(0); Reg::ARG_REGS.len()]; + let mut nth_reg = 0; + for (nth_arg, kind) in function.signature().args.iter().enumerate() { + match kind { + ValueType::I32 => { + args[nth_arg] = Value::I32(caller.get_reg(Reg::ARG_REGS[nth_reg]) as i32); + nth_reg += 1; + }, + ValueType::F32 => { + args[nth_arg] = Value::F32(caller.get_reg(Reg::ARG_REGS[nth_reg])); + nth_reg += 1; + }, + ValueType::I64 => { + let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = + Value::I64((u64::from(value_lo) | (u64::from(value_hi) << 32)) as i64); + }, + ValueType::F64 => { + let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = Value::F64(u64::from(value_lo) | (u64::from(value_hi) << 32)); + }, + } + } + + log::trace!( + "Calling host function: '{}', args = {:?}", + function.name(), + &args[..function.signature().args.len()] + ); + + let value = match function + .execute(&mut Context(caller), &mut args.into_iter().take(function.signature().args.len())) + { + Ok(value) => value, + Err(error) => { + log::warn!("Call into the host function '{}' failed: {error}", function.name()); + return Err(polkavm::Trap::default()); + }, + }; + + if let Some(value) = value { + match value { + Value::I32(value) => { + caller.set_reg(Reg::A0, value as u32); + }, + Value::F32(value) => { + caller.set_reg(Reg::A0, value); + }, + Value::I64(value) => { + caller.set_reg(Reg::A0, value as u32); + caller.set_reg(Reg::A1, (value >> 32) as u32); + }, + Value::F64(value) => { + caller.set_reg(Reg::A0, value as u32); + caller.set_reg(Reg::A1, (value >> 32) as u32); + }, + } + } + + Ok(()) +} + +pub fn create_runtime(blob: &polkavm::ProgramBlob) -> Result, WasmError> +where + H: HostFunctions, +{ + static ENGINE: std::sync::OnceLock> = + std::sync::OnceLock::new(); + + let engine = ENGINE.get_or_init(|| { + let config = polkavm::Config::from_env()?; + polkavm::Engine::new(&config) + }); + + let engine = match engine { + Ok(ref engine) => engine, + Err(ref error) => { + return Err(WasmError::Other(error.to_string())); + }, + }; + + let module = polkavm::Module::from_blob(&engine, &polkavm::ModuleConfig::default(), blob)?; + let mut linker = polkavm::Linker::new(&engine); + for function in H::host_functions() { + linker.func_new(function.name(), |mut caller| call_host_function(&mut caller, function))?; + } + + let instance_pre = linker.instantiate_pre(&module)?; + Ok(Box::new(InstancePre(instance_pre))) +} diff --git a/substrate/client/executor/src/executor.rs b/substrate/client/executor/src/executor.rs index 499bb704b16990de49d2b3311c48fa8ee2c1813e..d56a3b389ef42868d0543303c5fbd63ea8d2d884 100644 --- a/substrate/client/executor/src/executor.rs +++ b/substrate/client/executor/src/executor.rs @@ -518,7 +518,7 @@ where runtime_code, ext, heap_alloc_strategy, - |_, mut instance, _onchain_version, mut ext| { + |_, mut instance, _on_chain_version, mut ext| { with_externalities_safe(&mut **ext, move || instance.call_export(method, data)) }, ); @@ -682,18 +682,18 @@ impl CodeExecutor for NativeElseWasmExecut runtime_code, ext, heap_alloc_strategy, - |_, mut instance, onchain_version, mut ext| { - let onchain_version = - onchain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?; + |_, mut instance, on_chain_version, mut ext| { + let on_chain_version = + on_chain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?; let can_call_with = - onchain_version.can_call_with(&self.native_version.runtime_version); + on_chain_version.can_call_with(&self.native_version.runtime_version); if use_native && can_call_with { tracing::trace!( target: "executor", native = %self.native_version.runtime_version, - chain = %onchain_version, + chain = %on_chain_version, "Request for native execution succeeded", ); @@ -705,7 +705,7 @@ impl CodeExecutor for NativeElseWasmExecut tracing::trace!( target: "executor", native = %self.native_version.runtime_version, - chain = %onchain_version, + chain = %on_chain_version, "Request for native execution failed", ); } diff --git a/substrate/client/executor/src/lib.rs b/substrate/client/executor/src/lib.rs index 25bad81938f383e66eb1e63fb1c8ddcbea3a387f..6b99f0a6ee03b303d2d97ce05040828e3248312b 100644 --- a/substrate/client/executor/src/lib.rs +++ b/substrate/client/executor/src/lib.rs @@ -29,7 +29,6 @@ //! wasm engine used, instance cache. #![warn(missing_docs)] -#![recursion_limit = "128"] #[macro_use] mod executor; diff --git a/substrate/client/executor/src/wasm_runtime.rs b/substrate/client/executor/src/wasm_runtime.rs index 501279a312cc09bdaada09b64895a1e6c5a2c87a..be8344ba79b7d78f8d49880ea73754788f33ff3e 100644 --- a/substrate/client/executor/src/wasm_runtime.rs +++ b/substrate/client/executor/src/wasm_runtime.rs @@ -297,6 +297,10 @@ pub fn create_wasm_runtime_with_code( where H: HostFunctions, { + if let Some(blob) = blob.as_polkavm_blob() { + return sc_executor_polkavm::create_runtime::(blob); + } + match wasm_method { WasmExecutionMethod::Compiled { instantiation_strategy } => sc_executor_wasmtime::create_runtime::( diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index 12e6647c69522f24d9e51b3b36c87a759311c955..75cc76a235430fa33b735e8b234493a24a3e2961 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.17" +log = { workspace = true, default-features = true } cfg-if = "1.0" libc = "0.2.152" parking_lot = "0.12.1" diff --git a/substrate/client/executor/wasmtime/src/instance_wrapper.rs b/substrate/client/executor/wasmtime/src/instance_wrapper.rs index 8852532adbcaa40293f2d7dfd0a326572d3c1ca4..4f67d1df9c5f3193d508b408c48c5c1230de2b54 100644 --- a/substrate/client/executor/wasmtime/src/instance_wrapper.rs +++ b/substrate/client/executor/wasmtime/src/instance_wrapper.rs @@ -22,36 +22,12 @@ use std::sync::Arc; use crate::runtime::{InstanceCounter, ReleaseInstanceHandle, Store, StoreData}; -use sc_executor_common::{ - error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError}, - wasm_runtime::InvokeMethod, -}; -use sp_wasm_interface::{Pointer, Value, WordSize}; -use wasmtime::{ - AsContext, AsContextMut, Engine, Extern, Instance, InstancePre, Memory, Table, Val, -}; - -/// Invoked entrypoint format. -pub enum EntryPointType { - /// Direct call. - /// - /// Call is made by providing only payload reference and length. - Direct { entrypoint: wasmtime::TypedFunc<(u32, u32), u64> }, - /// Indirect call. - /// - /// Call is made by providing payload reference and length, and extra argument - /// for advanced routing. - Wrapped { - /// The extra argument passed to the runtime. It is typically a wasm function pointer. - func: u32, - dispatcher: wasmtime::TypedFunc<(u32, u32, u32), u64>, - }, -} +use sc_executor_common::error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError}; +use sp_wasm_interface::{Pointer, WordSize}; +use wasmtime::{AsContext, AsContextMut, Engine, Instance, InstancePre, Memory}; /// Wasm blob entry point. -pub struct EntryPoint { - call_type: EntryPointType, -} +pub struct EntryPoint(wasmtime::TypedFunc<(u32, u32), u64>); impl EntryPoint { /// Call this entry point. @@ -64,13 +40,7 @@ impl EntryPoint { let data_ptr = u32::from(data_ptr); let data_len = u32::from(data_len); - match self.call_type { - EntryPointType::Direct { ref entrypoint } => - entrypoint.call(&mut *store, (data_ptr, data_len)), - EntryPointType::Wrapped { func, ref dispatcher } => - dispatcher.call(&mut *store, (func, data_ptr, data_len)), - } - .map_err(|trap| { + self.0.call(&mut *store, (data_ptr, data_len)).map_err(|trap| { let host_state = store .data_mut() .host_state @@ -99,18 +69,7 @@ impl EntryPoint { let entrypoint = func .typed::<(u32, u32), u64>(ctx) .map_err(|_| "Invalid signature for direct entry point")?; - Ok(Self { call_type: EntryPointType::Direct { entrypoint } }) - } - - pub fn wrapped( - dispatcher: wasmtime::Func, - func: u32, - ctx: impl AsContext, - ) -> std::result::Result { - let dispatcher = dispatcher - .typed::<(u32, u32, u32), u64>(ctx) - .map_err(|_| "Invalid signature for wrapped entry point")?; - Ok(Self { call_type: EntryPointType::Wrapped { func, dispatcher } }) + Ok(Self(entrypoint)) } } @@ -178,10 +137,8 @@ impl InstanceWrapper { })?; let memory = get_linear_memory(&instance, &mut store)?; - let table = get_table(&instance, &mut store); store.data_mut().memory = Some(memory); - store.data_mut().table = table; Ok(InstanceWrapper { instance, store, _release_instance_handle }) } @@ -190,61 +147,17 @@ impl InstanceWrapper { /// /// An entrypoint must have a signature `(i32, i32) -> i64`, otherwise this function will return /// an error. - pub fn resolve_entrypoint(&mut self, method: InvokeMethod) -> Result { - Ok(match method { - InvokeMethod::Export(method) => { - // Resolve the requested method and verify that it has a proper signature. - let export = - self.instance.get_export(&mut self.store, method).ok_or_else(|| { - Error::from(format!("Exported method {} is not found", method)) - })?; - let func = export - .into_func() - .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?; - EntryPoint::direct(func, &self.store).map_err(|_| { - Error::from(format!("Exported function '{}' has invalid signature.", method)) - })? - }, - InvokeMethod::Table(func_ref) => { - let table = self - .instance - .get_table(&mut self.store, "__indirect_function_table") - .ok_or(Error::NoTable)?; - let val = table - .get(&mut self.store, func_ref) - .ok_or(Error::NoTableEntryWithIndex(func_ref))?; - let func = val - .funcref() - .ok_or(Error::TableElementIsNotAFunction(func_ref))? - .ok_or(Error::FunctionRefIsNull(func_ref))?; - - EntryPoint::direct(*func, &self.store).map_err(|_| { - Error::from(format!( - "Function @{} in exported table has invalid signature for direct call.", - func_ref, - )) - })? - }, - InvokeMethod::TableWithWrapper { dispatcher_ref, func } => { - let table = self - .instance - .get_table(&mut self.store, "__indirect_function_table") - .ok_or(Error::NoTable)?; - let val = table - .get(&mut self.store, dispatcher_ref) - .ok_or(Error::NoTableEntryWithIndex(dispatcher_ref))?; - let dispatcher = val - .funcref() - .ok_or(Error::TableElementIsNotAFunction(dispatcher_ref))? - .ok_or(Error::FunctionRefIsNull(dispatcher_ref))?; - - EntryPoint::wrapped(*dispatcher, func, &self.store).map_err(|_| { - Error::from(format!( - "Function @{} in exported table has invalid signature for wrapped call.", - dispatcher_ref, - )) - })? - }, + pub fn resolve_entrypoint(&mut self, method: &str) -> Result { + // Resolve the requested method and verify that it has a proper signature. + let export = self + .instance + .get_export(&mut self.store, method) + .ok_or_else(|| Error::from(format!("Exported method {} is not found", method)))?; + let func = export + .into_func() + .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?; + EntryPoint::direct(func, &self.store).map_err(|_| { + Error::from(format!("Exported function '{}' has invalid signature.", method)) }) } @@ -268,24 +181,6 @@ impl InstanceWrapper { Ok(heap_base as u32) } - - /// Get the value from a global with the given `name`. - pub fn get_global_val(&mut self, name: &str) -> Result> { - let global = match self.instance.get_export(&mut self.store, name) { - Some(global) => global, - None => return Ok(None), - }; - - let global = global.into_global().ok_or_else(|| format!("`{}` is not a global", name))?; - - match global.get(&mut self.store) { - Val::I32(val) => Ok(Some(Value::I32(val))), - Val::I64(val) => Ok(Some(Value::I64(val))), - Val::F32(val) => Ok(Some(Value::F32(val))), - Val::F64(val) => Ok(Some(Value::F64(val))), - _ => Err("Unknown value type".into()), - } - } } /// Extract linear memory instance from the given instance. @@ -301,15 +196,6 @@ fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result Option
CommittedCandidateReceipt<H = Hash>
{ - instance - .get_export(ctx, "__indirect_function_table") - .as_ref() - .cloned() - .and_then(Extern::into_table) -} - /// Functions related to memory. impl InstanceWrapper { pub(crate) fn store(&self) -> &Store { diff --git a/substrate/client/executor/wasmtime/src/runtime.rs b/substrate/client/executor/wasmtime/src/runtime.rs index ac88663f4e7915e49262ee8186bfaf7d92f6064d..595cc503272ebea7d249262c66b206cab5697d36 100644 --- a/substrate/client/executor/wasmtime/src/runtime.rs +++ b/substrate/client/executor/wasmtime/src/runtime.rs @@ -30,10 +30,10 @@ use sc_executor_common::{ error::{Error, Result, WasmError}, runtime_blob::RuntimeBlob, util::checked_range, - wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmInstance, WasmModule}, + wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; -use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; +use sp_wasm_interface::{HostFunctions, Pointer, WordSize}; use std::{ path::{Path, PathBuf}, sync::{ @@ -41,7 +41,7 @@ use std::{ Arc, }, }; -use wasmtime::{AsContext, Engine, Memory, Table}; +use wasmtime::{AsContext, Engine, Memory}; const MAX_INSTANCE_COUNT: u32 = 64; @@ -51,8 +51,6 @@ pub(crate) struct StoreData { pub(crate) host_state: Option, /// This will be always set once the store is initialized. pub(crate) memory: Option, - /// This will be set only if the runtime actually contains a table. - pub(crate) table: Option
, } impl StoreData { @@ -164,7 +162,7 @@ pub struct WasmtimeInstance { impl WasmtimeInstance { fn call_impl( &mut self, - method: InvokeMethod, + method: &str, data: &[u8], allocation_stats: &mut Option, ) -> Result> { @@ -184,20 +182,13 @@ impl WasmtimeInstance { impl WasmInstance for WasmtimeInstance { fn call_with_allocation_stats( &mut self, - method: InvokeMethod, + method: &str, data: &[u8], ) -> (Result>, Option) { let mut allocation_stats = None; let result = self.call_impl(method, data, &mut allocation_stats); (result, allocation_stats) } - - fn get_global_const(&mut self, name: &str) -> Result> { - match &mut self.strategy { - Strategy::RecreateInstance(ref mut instance_creator) => - instance_creator.instantiate()?.get_global_val(name), - } - } } /// Prepare a directory structure and a config file to enable wasmtime caching. diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index 0252e9a11572cc5f99cb30b513820e4c4f922473..bd15e94ebafab26c89f76927d9d2f9c576ca1541 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] ansi_term = "0.12.1" futures = "0.3.21" futures-timer = "3.0.1" -log = "0.4.17" +log = { workspace = true, default-features = true } sc-client-api = { path = "../api" } sc-network-common = { path = "../network/common" } sc-network-sync = { path = "../network/sync" } diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index dc6a0fe29a84876c5c117a199017d1e8bda81590..908e0aa8f38ced48facaf99d05c0d7771f03fa26 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -19,8 +19,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" parking_lot = "0.12.1" -serde_json = "1.0.111" -thiserror = "1.0" +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } sp-application-crypto = { path = "../../primitives/application-crypto" } sp-core = { path = "../../primitives/core" } sp-keystore = { path = "../../primitives/keystore" } diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 3b29f435e2a942ffe96dd02a8009af4d33693995..8b922c11cbca990a0f4f87e4e3f25bbec2a55290 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -37,7 +37,7 @@ use sp_core::bandersnatch; } sp_keystore::bls_experimental_enabled! { -use sp_core::{bls377, bls381, ecdsa_bls377}; +use sp_core::{bls377, bls381, ecdsa_bls377, KeccakHasher}; } use crate::{Error, Result}; @@ -47,6 +47,13 @@ pub struct LocalKeystore(RwLock); impl LocalKeystore { /// Create a local keystore from filesystem. + /// + /// The keystore will be created at `path`. The keystore optionally supports to encrypt/decrypt + /// the keys in the keystore using `password`. + /// + /// NOTE: Even when passing a `password`, the keys on disk appear to look like normal secret + /// uris. However, without having the correct password the secret uri will not generate the + /// correct private key. See [`SecretUri`](sp_core::crypto::SecretUri) for more information. pub fn open>(path: T, password: Option) -> Result { let inner = KeystoreInner::open(path, password)?; Ok(Self(RwLock::new(inner))) @@ -136,6 +143,13 @@ impl LocalKeystore { } impl Keystore for LocalKeystore { + /// Insert a new secret key. + /// + /// WARNING: if the secret keypair has been manually generated using a password + /// (e.g. using methods such as [`sp_core::crypto::Pair::from_phrase`]) then such + /// a password must match the one used to open the keystore via [`LocalKeystore::open`]. + /// If the passwords doesn't match then the inserted key ends up being unusable under + /// the current keystore instance. fn insert( &self, key_type: KeyTypeId, @@ -391,6 +405,20 @@ impl Keystore for LocalKeystore { self.sign::(key_type, public, msg) } + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + let sig = self.0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.sign_with_hasher::(msg)); + Ok(sig) + } + + } } diff --git a/substrate/client/merkle-mountain-range/Cargo.toml b/substrate/client/merkle-mountain-range/Cargo.toml index 201c179f302c729d4c4a5864dd44ed9bc0e2896e..60232bccb0e08d1fb65aeb6d94723c03fcf77fa1 100644 --- a/substrate/client/merkle-mountain-range/Cargo.toml +++ b/substrate/client/merkle-mountain-range/Cargo.toml @@ -16,7 +16,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3" -log = "0.4" +log = { workspace = true, default-features = true } sp-api = { path = "../../primitives/api" } sp-blockchain = { path = "../../primitives/blockchain" } sc-client-api = { path = "../api" } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index 99467e5468f07c826bc18d05f91e193e27041298..9b391b76ea00b5e48700b7213afb691c149167ab 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -16,8 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } -serde = { version = "1.0.195", features = ["derive"] } +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +serde = { features = ["derive"], workspace = true, default-features = true } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core" } @@ -25,4 +25,4 @@ sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml index 280af81b86ef631b5c99588eef28f20471c65bc8..736184f4668c8c96c660502774da90aedd85b731 100644 --- a/substrate/client/mixnet/Cargo.toml +++ b/substrate/client/mixnet/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = futures = "0.3.25" futures-timer = "3.0.2" libp2p-identity = { version = "0.1.3", features = ["peerid"] } -log = "0.4.17" +log = { workspace = true, default-features = true } mixnet = "0.7.0" multiaddr = "0.17.1" parking_lot = "0.12.1" @@ -37,4 +37,4 @@ sp-core = { path = "../../primitives/core" } sp-keystore = { path = "../../primitives/keystore" } sp-mixnet = { path = "../../primitives/mixnet" } sp-runtime = { path = "../../primitives/runtime" } -thiserror = "1.0" +thiserror = { workspace = true } diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index baf4def0b8e7d2fbfca34c17d6680d37b65fdf71..a14761c0d6e81e4eeda2e1e3d8dacd5fd7b99d4a 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -21,7 +21,7 @@ ahash = "0.8.2" futures = "0.3.21" futures-timer = "3.0.1" libp2p = "0.51.4" -log = "0.4.17" +log = { workspace = true, default-features = true } schnellru = "0.2.1" tracing = "0.1.29" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/network-gossip/src/state_machine.rs b/substrate/client/network-gossip/src/state_machine.rs index 069d7cdba16599b4b4da0965a5d8e4588478d633..f1c830341ea7337df312e9181ef0ba7caafdc2ce 100644 --- a/substrate/client/network-gossip/src/state_machine.rs +++ b/substrate/client/network-gossip/src/state_machine.rs @@ -550,7 +550,8 @@ mod tests { NotificationSenderError, NotificationSenderT as NotificationSender, ReputationChange, }; use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, H256}, + generic::UncheckedExtrinsic, + testing::{Block as RawBlock, MockCallU64, H256}, traits::NumberFor, }; use std::{ @@ -559,7 +560,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 167f112705be32a34bbdf062e0499d4c286c40fd..cbf74440dc1a83933d1e994294a7d37609c72331 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -30,16 +30,16 @@ futures-timer = "3.0.2" ip_network = "0.4.1" libp2p = { version = "0.51.4", features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "request-response", "tcp", "tokio", "websocket", "yamux"] } linked_hash_set = "0.1.3" -log = "0.4.17" +log = { workspace = true, default-features = true } mockall = "0.11.3" parking_lot = "0.12.1" partial_sort = "0.2.0" pin-project = "1.0.12" rand = "0.8.5" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } smallvec = "1.11.0" -thiserror = "1.0" +thiserror = { workspace = true } tokio = { version = "1.22.0", features = ["macros", "sync"] } tokio-stream = "0.1.7" unsigned-varint = { version = "0.7.1", features = ["asynchronous_codec", "futures"] } diff --git a/substrate/client/network/bitswap/Cargo.toml b/substrate/client/network/bitswap/Cargo.toml index 9982ef80cf6de65885e8089159bfb95fd5eafd73..7ef3ea212427848510e2e4b910efbe3d54e01a48 100644 --- a/substrate/client/network/bitswap/Cargo.toml +++ b/substrate/client/network/bitswap/Cargo.toml @@ -23,9 +23,9 @@ async-channel = "1.8.0" cid = "0.9.0" futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid"] } -log = "0.4.17" +log = { workspace = true, default-features = true } prost = "0.12" -thiserror = "1.0" +thiserror = { workspace = true } unsigned-varint = { version = "0.7.1", features = ["asynchronous_codec", "futures"] } sc-client-api = { path = "../../api" } sc-network = { path = ".." } diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index efefc6f18b6b70c847af334d4e99cbc0dda2a6b5..c757f727fb71a7c2261090d741e286d7851d8239 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -26,11 +26,11 @@ codec = { package = "parity-scale-codec", version = "3.6.1", features = [ ] } futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid"] } -log = "0.4.16" +log = { workspace = true, default-features = true } prost = "0.12" sp-blockchain = { path = "../../../primitives/blockchain" } sc-client-api = { path = "../../api" } sc-network = { path = ".." } sp-core = { path = "../../../primitives/core" } sp-runtime = { path = "../../../primitives/runtime" } -thiserror = "1.0" +thiserror = { workspace = true } diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index 0a0ce61527d1b349378fbd6f92d0cecde364d363..b6efee5d9d36ae9deffe9ecd4951176c829de0bc 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -21,7 +21,7 @@ async-channel = "1.8.0" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" libp2p = "0.51.4" -log = "0.4.17" +log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-network-common = { path = "../common" } sc-network-sync = { path = "../sync" } diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index f81b4ee77bdf4b4babbede1936d65c19bc784cb9..32ba3b6356c0ceb0dcf38bda7d333ffddf67d238 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -26,12 +26,12 @@ codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive futures = "0.3.21" futures-timer = "3.0.2" libp2p = "0.51.4" -log = "0.4.17" +log = { workspace = true, default-features = true } mockall = "0.11.3" prost = "0.12" schnellru = "0.2.1" smallvec = "1.11.0" -thiserror = "1.0" +thiserror = { workspace = true } tokio-stream = "0.1.14" tokio = { version = "1.32.0", features = ["macros", "time"] } fork-tree = { path = "../../../utils/fork-tree" } diff --git a/substrate/client/network/sync/src/blocks.rs b/substrate/client/network/sync/src/blocks.rs index 4988045a4786720771ad84d9bd3b3cb0aa96592a..a115ee94767454c14755517be82609dd22409cf4 100644 --- a/substrate/client/network/sync/src/blocks.rs +++ b/substrate/client/network/sync/src/blocks.rs @@ -265,9 +265,12 @@ mod test { use libp2p::PeerId; use sc_network_common::sync::message; use sp_core::H256; - use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; + use sp_runtime::{ + generic::UncheckedExtrinsic, + testing::{Block as RawBlock, MockCallU64}, + }; - 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 7486c091ebf13d1fef6422ab193cebd2b4dd24f9..24640fdc45576191f30d190a39ee8186d27520c8 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -33,7 +33,7 @@ use crate::{ }, strategy::{ warp::{EncodedProof, WarpProofRequest, WarpSyncParams}, - SyncingAction, SyncingConfig, SyncingStrategy, + StrategyKey, SyncingAction, SyncingConfig, SyncingStrategy, }, types::{ BadPeer, ExtendedPeerInfo, OpaqueStateRequest, OpaqueStateResponse, PeerRequest, SyncEvent, @@ -48,7 +48,7 @@ use futures::{ FutureExt, StreamExt, }; use libp2p::{request_response::OutboundFailure, PeerId}; -use log::{debug, error, trace}; +use log::{debug, error, trace, warn}; use prometheus_endpoint::{ register, Counter, Gauge, MetricSource, Opts, PrometheusError, Registry, SourcedGauge, U64, }; @@ -214,9 +214,6 @@ pub struct SyncingEngine { /// Syncing strategy. strategy: SyncingStrategy, - /// Syncing configuration for startegies. - syncing_config: SyncingConfig, - /// Blockchain client. client: Arc, @@ -441,8 +438,7 @@ where .map_or(futures::future::pending().boxed().fuse(), |rx| rx.boxed().fuse()); // Initialize syncing strategy. - let strategy = - SyncingStrategy::new(syncing_config.clone(), client.clone(), warp_sync_config)?; + let strategy = SyncingStrategy::new(syncing_config, client.clone(), warp_sync_config)?; let block_announce_protocol_name = block_announce_config.protocol_name().clone(); let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); @@ -471,7 +467,6 @@ where roles, client, strategy, - syncing_config, network_service, peers: HashMap::new(), block_announce_data_cache: LruMap::new(ByLength::new(cache_capacity)), @@ -661,8 +656,17 @@ where Some(event) => self.process_notification_event(event), None => return, }, - warp_target_block_header = &mut self.warp_sync_target_block_header_rx_fused => - self.pass_warp_sync_target_block_header(warp_target_block_header), + // TODO: setting of warp sync target block should be moved to the initialization of + // `SyncingEngine`, see https://github.com/paritytech/polkadot-sdk/issues/3537. + warp_target_block_header = &mut self.warp_sync_target_block_header_rx_fused => { + if let Err(_) = self.pass_warp_sync_target_block_header(warp_target_block_header) { + error!( + target: LOG_TARGET, + "Failed to set warp sync target block header, terminating `SyncingEngine`.", + ); + return + } + }, response_event = self.pending_responses.select_next_some() => self.process_response_event(response_event), validation_result = self.block_announce_validator.select_next_some() => @@ -675,48 +679,61 @@ where // Process actions requested by a syncing strategy. if let Err(e) = self.process_strategy_actions() { - error!("Terminating `SyncingEngine` due to fatal error: {e:?}"); + error!( + target: LOG_TARGET, + "Terminating `SyncingEngine` due to fatal error: {e:?}.", + ); return } } } fn process_strategy_actions(&mut self) -> Result<(), ClientError> { - for action in self.strategy.actions() { + for action in self.strategy.actions()? { match action { - SyncingAction::SendBlockRequest { peer_id, request } => { + 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`]). - // Furthermore, only one request at a time is allowed to any peer. - let removed = self.pending_responses.remove(&peer_id); - self.send_block_request(peer_id, request.clone()); - - trace!( - target: LOG_TARGET, - "Processed `ChainSyncAction::SendBlockRequest` to {} with {:?}, stale response removed: {}.", - peer_id, - request, - removed, - ) + 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 { + trace!( + target: LOG_TARGET, + "Processed `ChainSyncAction::SendBlockRequest` to {} from {:?} with {:?}.", + peer_id, + key, + request, + ) + } }, - SyncingAction::CancelBlockRequest { peer_id } => { - let removed = self.pending_responses.remove(&peer_id); + 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, request } => { - self.send_state_request(peer_id, request); + SyncingAction::SendStateRequest { peer_id, key, request } => { + self.send_state_request(peer_id, key, request); trace!( target: LOG_TARGET, - "Processed `ChainSyncAction::SendBlockRequest` to {peer_id}.", + "Processed `ChainSyncAction::SendStateRequest` to {peer_id}.", ); }, - SyncingAction::SendWarpProofRequest { peer_id, request } => { - self.send_warp_proof_request(peer_id, request.clone()); + SyncingAction::SendWarpProofRequest { peer_id, key, request } => { + self.send_warp_proof_request(peer_id, key, request.clone()); trace!( target: LOG_TARGET, @@ -726,7 +743,7 @@ where ); }, SyncingAction::DropPeer(BadPeer(peer_id, rep)) => { - self.pending_responses.remove(&peer_id); + self.pending_responses.remove_all(&peer_id); self.network_service .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); self.network_service.report_peer(peer_id, rep); @@ -753,20 +770,8 @@ where number, ) }, - SyncingAction::Finished => { - let connected_peers = self.peers.iter().filter_map(|(peer_id, peer)| { - peer.info.roles.is_full().then_some(( - *peer_id, - peer.info.best_hash, - peer.info.best_number, - )) - }); - self.strategy.switch_to_next( - self.syncing_config.clone(), - self.client.clone(), - connected_peers, - )?; - }, + // Nothing to do, this is handled internally by `SyncingStrategy`. + SyncingAction::Finished => {}, } } @@ -948,23 +953,18 @@ where } } - fn pass_warp_sync_target_block_header(&mut self, header: Result) { + fn pass_warp_sync_target_block_header( + &mut self, + header: Result, + ) -> Result<(), ()> { match header { - Ok(header) => - if let SyncingStrategy::WarpSyncStrategy(warp_sync) = &mut self.strategy { - warp_sync.set_target_block(header); - } else { - error!( - target: LOG_TARGET, - "Cannot set warp sync target block: no warp sync strategy is active." - ); - debug_assert!(false); - }, + Ok(header) => self.strategy.set_warp_sync_target_block_header(header), Err(err) => { error!( target: LOG_TARGET, "Failed to get target block for warp sync. Error: {err:?}", ); + Err(()) }, } } @@ -1002,7 +1002,7 @@ where } self.strategy.remove_peer(&peer_id); - self.pending_responses.remove(&peer_id); + self.pending_responses.remove_all(&peer_id); self.event_streams .retain(|stream| stream.unbounded_send(SyncEvent::PeerDisconnected(peer_id)).is_ok()); } @@ -1167,7 +1167,7 @@ where Ok(()) } - fn send_block_request(&mut self, peer_id: PeerId, request: BlockRequest) { + 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); @@ -1178,12 +1178,18 @@ where 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, request: OpaqueStateRequest) { + fn send_state_request( + &mut self, + peer_id: PeerId, + key: StrategyKey, + 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); @@ -1192,7 +1198,7 @@ where let (tx, rx) = oneshot::channel(); - self.pending_responses.insert(peer_id, PeerRequest::State, rx.boxed()); + self.pending_responses.insert(peer_id, key, PeerRequest::State, rx.boxed()); match Self::encode_state_request(&request) { Ok(data) => { @@ -1213,7 +1219,12 @@ where } } - fn send_warp_proof_request(&mut self, peer_id: PeerId, request: WarpProofRequest) { + fn send_warp_proof_request( + &mut self, + peer_id: PeerId, + key: StrategyKey, + 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); @@ -1222,7 +1233,7 @@ where let (tx, rx) = oneshot::channel(); - self.pending_responses.insert(peer_id, PeerRequest::WarpProof, rx.boxed()); + self.pending_responses.insert(peer_id, key, PeerRequest::WarpProof, rx.boxed()); match &self.warp_sync_protocol_name { Some(name) => self.network_service.start_request( @@ -1259,14 +1270,14 @@ where } fn process_response_event(&mut self, response_event: ResponseEvent) { - let ResponseEvent { peer_id, request, response } = response_event; + let ResponseEvent { peer_id, key, request, response } = response_event; match response { Ok(Ok((resp, _))) => match request { PeerRequest::Block(req) => { match self.block_downloader.block_response_into_blocks(&req, resp) { Ok(blocks) => { - self.strategy.on_block_response(peer_id, req, blocks); + self.strategy.on_block_response(peer_id, key, req, blocks); }, Err(BlockResponseError::DecodeFailed(e)) => { debug!( @@ -1311,10 +1322,10 @@ where }, }; - self.strategy.on_state_response(peer_id, response); + self.strategy.on_state_response(peer_id, key, response); }, PeerRequest::WarpProof => { - self.strategy.on_warp_proof_response(&peer_id, EncodedProof(resp)); + self.strategy.on_warp_proof_response(&peer_id, key, EncodedProof(resp)); }, }, Ok(Err(e)) => { diff --git a/substrate/client/network/sync/src/extra_requests.rs b/substrate/client/network/sync/src/justification_requests.rs similarity index 98% rename from substrate/client/network/sync/src/extra_requests.rs rename to substrate/client/network/sync/src/justification_requests.rs index cd3008d270b1f8b87b186afa4566536216714769..799b6df5831a5783038de15fab2b2eff091d64d9 100644 --- a/substrate/client/network/sync/src/extra_requests.rs +++ b/substrate/client/network/sync/src/justification_requests.rs @@ -16,6 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! Justification requests scheduling. [`ExtraRequests`] manages requesting justifications +//! from peers taking into account forks and their finalization (dropping pending requests +//! that don't make sense after one of the forks is finalized). + use crate::{ request_metrics::Metrics, strategy::chain_sync::{PeerSync, PeerSyncState}, diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 494e3b87aa95514d6377c413cdc8c850c0d06258..9f6c0f45d089ce415f9e8c0ae792de1d7a327407 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -23,12 +23,12 @@ pub use strategy::warp::{WarpSyncParams, WarpSyncPhase, WarpSyncProgress}; pub use types::{SyncEvent, SyncEventStream, SyncState, SyncStatus, SyncStatusProvider}; mod block_announce_validator; -mod extra_requests; mod futures_stream; +mod justification_requests; mod pending_responses; mod request_metrics; mod schema; -mod types; +pub mod types; pub mod block_relay_protocol; pub mod block_request_handler; diff --git a/substrate/client/network/sync/src/pending_responses.rs b/substrate/client/network/sync/src/pending_responses.rs index 21e409eb847fe600d07343cc22533af8cf5d8c36..602c69df7ff96b80c9f176dd7646d843f2c63937 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::{types::PeerRequest, LOG_TARGET}; +use crate::{strategy::StrategyKey, types::PeerRequest, LOG_TARGET}; use futures::{ channel::oneshot, future::BoxFuture, @@ -42,6 +42,7 @@ type ResponseFuture = BoxFuture<'static, ResponseResult>; /// An event we receive once a pending response future resolves. pub(crate) struct ResponseEvent { pub peer_id: PeerId, + pub key: StrategyKey, pub request: PeerRequest, pub response: ResponseResult, } @@ -49,7 +50,8 @@ pub(crate) struct ResponseEvent { /// Stream taking care of polling pending responses. pub(crate) struct PendingResponses { /// Pending responses - pending_responses: StreamMap, ResponseResult)>>, + pending_responses: + StreamMap<(PeerId, StrategyKey), BoxStream<'static, (PeerRequest, ResponseResult)>>, /// Waker to implement never terminating stream waker: Option, } @@ -62,6 +64,7 @@ impl PendingResponses { pub fn insert( &mut self, peer_id: PeerId, + key: StrategyKey, request: PeerRequest, response_future: ResponseFuture, ) { @@ -70,7 +73,7 @@ impl PendingResponses { if self .pending_responses .insert( - peer_id, + (peer_id, key), Box::pin(async move { (request, response_future.await) }.into_stream()), ) .is_some() @@ -87,8 +90,20 @@ impl PendingResponses { } } - pub fn remove(&mut self, peer_id: &PeerId) -> bool { - self.pending_responses.remove(peer_id).is_some() + pub fn remove(&mut self, peer_id: PeerId, key: StrategyKey) -> bool { + self.pending_responses.remove(&(peer_id, key)).is_some() + } + + pub fn remove_all(&mut self, peer_id: &PeerId) { + let to_remove = self + .pending_responses + .keys() + .filter(|(peer, _key)| peer == peer_id) + .cloned() + .collect::>(); + to_remove.iter().for_each(|k| { + self.pending_responses.remove(k); + }); } pub fn len(&self) -> usize { @@ -104,13 +119,13 @@ impl Stream for PendingResponses { cx: &mut Context<'_>, ) -> Poll> { match self.pending_responses.poll_next_unpin(cx) { - Poll::Ready(Some((peer_id, (request, response)))) => { + Poll::Ready(Some(((peer_id, key), (request, 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); + self.pending_responses.remove(&(peer_id, key)); - Poll::Ready(Some(ResponseEvent { peer_id, request, response })) + Poll::Ready(Some(ResponseEvent { peer_id, key, request, response })) }, Poll::Ready(None) | Poll::Pending => { self.waker = Some(cx.waker().clone()); diff --git a/substrate/client/network/sync/src/strategy.rs b/substrate/client/network/sync/src/strategy.rs index dbfb4188ec3f346d784c39ca113f28e687230ccc..dabcf37ae6321a4501095a4ba3140c1ccf424b74 100644 --- a/substrate/client/network/sync/src/strategy.rs +++ b/substrate/client/network/sync/src/strategy.rs @@ -30,7 +30,7 @@ use crate::{ }; use chain_sync::{ChainSync, ChainSyncAction, ChainSyncMode}; use libp2p::PeerId; -use log::{error, info}; +use log::{debug, error, info, warn}; use prometheus_endpoint::Registry; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; @@ -41,11 +41,11 @@ use sc_network_common::sync::{ use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::BlockOrigin; use sp_runtime::{ - traits::{Block as BlockT, NumberFor}, + traits::{Block as BlockT, Header, NumberFor}, Justifications, }; use state::{StateStrategy, StateStrategyAction}; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use warp::{EncodedProof, WarpProofRequest, WarpSync, WarpSyncAction, WarpSyncConfig}; /// Corresponding `ChainSync` mode. @@ -71,16 +71,27 @@ pub struct SyncingConfig { pub metrics_registry: Option, } +/// 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, +} + #[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, request: BlockRequest }, - /// Drop stale block request. - CancelBlockRequest { peer_id: PeerId }, + SendBlockRequest { peer_id: PeerId, key: StrategyKey, request: BlockRequest }, /// Send state request to peer. - SendStateRequest { peer_id: PeerId, request: OpaqueStateRequest }, + SendStateRequest { peer_id: PeerId, key: StrategyKey, request: OpaqueStateRequest }, /// Send warp proof request to peer. - SendWarpProofRequest { peer_id: PeerId, request: WarpProofRequest }, + SendWarpProofRequest { peer_id: PeerId, key: StrategyKey, request: WarpProofRequest }, + /// Drop stale request. + CancelRequest { peer_id: PeerId, key: StrategyKey }, /// Peer misbehaved. Disconnect, report it and cancel any requests to it. DropPeer(BadPeer), /// Import blocks. @@ -92,15 +103,75 @@ pub enum SyncingAction { number: NumberFor, justifications: Justifications, }, - /// Syncing strategy has finished. + /// Strategy finished. Nothing to do, this is handled by `SyncingStrategy`. Finished, } +impl SyncingAction { + fn is_finished(&self) -> bool { + matches!(self, SyncingAction::Finished) + } +} + +impl From> for SyncingAction { + fn from(action: WarpSyncAction) -> Self { + match action { + WarpSyncAction::SendWarpProofRequest { peer_id, request } => + SyncingAction::SendWarpProofRequest { peer_id, key: StrategyKey::Warp, 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, request } => + SyncingAction::SendStateRequest { peer_id, key: StrategyKey::State, request }, + StateStrategyAction::DropPeer(bad_peer) => SyncingAction::DropPeer(bad_peer), + StateStrategyAction::ImportBlocks { origin, blocks } => + SyncingAction::ImportBlocks { origin, blocks }, + StateStrategyAction::Finished => SyncingAction::Finished, + } + } +} + +impl From> for SyncingAction { + fn from(action: ChainSyncAction) -> Self { + match action { + ChainSyncAction::SendBlockRequest { peer_id, request } => + SyncingAction::SendBlockRequest { peer_id, key: StrategyKey::ChainSync, request }, + ChainSyncAction::SendStateRequest { peer_id, request } => + SyncingAction::SendStateRequest { peer_id, key: StrategyKey::ChainSync, request }, + ChainSyncAction::CancelRequest { peer_id } => + SyncingAction::CancelRequest { peer_id, key: StrategyKey::ChainSync }, + ChainSyncAction::DropPeer(bad_peer) => SyncingAction::DropPeer(bad_peer), + ChainSyncAction::ImportBlocks { origin, blocks } => + SyncingAction::ImportBlocks { origin, blocks }, + ChainSyncAction::ImportJustifications { peer_id, hash, number, justifications } => + SyncingAction::ImportJustifications { peer_id, hash, number, justifications }, + } + } +} + /// Proxy to specific syncing strategies. -pub enum SyncingStrategy { - WarpSyncStrategy(WarpSync), - StateSyncStrategy(StateStrategy), - ChainSyncStrategy(ChainSync), +pub struct SyncingStrategy { + /// 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 + /// [`SyncingStrategy::proceed_to_next`]. + peer_best_blocks: HashMap)>, } impl SyncingStrategy @@ -123,37 +194,51 @@ where if let SyncMode::Warp = config.mode { let warp_sync_config = warp_sync_config .expect("Warp sync configuration must be supplied in warp sync mode."); - Ok(Self::WarpSyncStrategy(WarpSync::new(client.clone(), warp_sync_config))) + let warp_sync = WarpSync::new(client.clone(), warp_sync_config); + Ok(Self { + config, + client, + warp: Some(warp_sync), + state: None, + chain_sync: None, + peer_best_blocks: Default::default(), + }) } else { - Ok(Self::ChainSyncStrategy(ChainSync::new( + let chain_sync = ChainSync::new( chain_sync_mode(config.mode), client.clone(), config.max_parallel_downloads, config.max_blocks_per_request, - config.metrics_registry, - )?)) + config.metrics_registry.clone(), + std::iter::empty(), + )?; + Ok(Self { + config, + client, + warp: None, + state: None, + chain_sync: Some(chain_sync), + peer_best_blocks: Default::default(), + }) } } /// Notify that a new peer has connected. pub fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor) { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => - strategy.add_peer(peer_id, best_hash, best_number), - SyncingStrategy::StateSyncStrategy(strategy) => - strategy.add_peer(peer_id, best_hash, best_number), - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.add_peer(peer_id, best_hash, best_number), - } + 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)); } /// Notify that a peer has disconnected. pub fn remove_peer(&mut self, peer_id: &PeerId) { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => strategy.remove_peer(peer_id), - SyncingStrategy::StateSyncStrategy(strategy) => strategy.remove_peer(peer_id), - SyncingStrategy::ChainSyncStrategy(strategy) => strategy.remove_peer(peer_id), - } + 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); } /// Submit a validated block announcement. @@ -165,14 +250,31 @@ where peer_id: PeerId, announce: &BlockAnnounce, ) -> Option<(B::Hash, NumberFor)> { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => - strategy.on_validated_block_announce(is_best, peer_id, announce), - SyncingStrategy::StateSyncStrategy(strategy) => - strategy.on_validated_block_announce(is_best, peer_id, announce), - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.on_validated_block_announce(is_best, peer_id, announce), + 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 } /// Configure an explicit fork sync request in case external code has detected that there is a @@ -183,40 +285,33 @@ where hash: &B::Hash, number: NumberFor, ) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.set_sync_fork_request(peers, hash, number), + // 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); } } /// Request extra justification. pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.request_justification(hash, number), + // Justifications can only be requested via `ChainSync`. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.request_justification(hash, number); } } /// Clear extra justification requests. pub fn clear_justification_requests(&mut self) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => strategy.clear_justification_requests(), + // Justification requests can only be cleared by `ChainSync`. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.clear_justification_requests(); } } /// Report a justification import (successful or not). pub fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.on_justification_import(hash, number, success), + // 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); } } @@ -224,36 +319,65 @@ where pub fn on_block_response( &mut self, peer_id: PeerId, + key: StrategyKey, request: BlockRequest, blocks: Vec>, ) { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => - strategy.on_block_response(peer_id, request, blocks), - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.on_block_response(peer_id, request, blocks), + 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, request, blocks); + } else { + error!( + target: LOG_TARGET, + "`on_block_response()` called with unexpected key {key:?} \ + or corresponding strategy is not active.", + ); + debug_assert!(false); } } /// Process state response. - pub fn on_state_response(&mut self, peer_id: PeerId, response: OpaqueStateResponse) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(strategy) => - strategy.on_state_response(peer_id, response), - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.on_state_response(peer_id, response), + pub 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, response); + } else { + error!( + target: LOG_TARGET, + "`on_state_response()` called with unexpected key {key:?} \ + or corresponding strategy is not active.", + ); + debug_assert!(false); } } /// Process warp proof response. - pub fn on_warp_proof_response(&mut self, peer_id: &PeerId, response: EncodedProof) { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => - strategy.on_warp_proof_response(peer_id, response), - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(_) => {}, + pub 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); } } @@ -264,226 +388,274 @@ where count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, ) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(strategy) => - strategy.on_blocks_processed(imported, count, results), - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.on_blocks_processed(imported, count, results), + // 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); } } /// Notify a syncing strategy that a block has been finalized. pub fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.on_block_finalized(hash, number), + // 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); } } /// Inform sync about a new best imported block. pub fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.update_chain_info(best_hash, best_number), + // 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); } } // Are we in major sync mode? pub fn is_major_syncing(&self) -> bool { - match self { - SyncingStrategy::WarpSyncStrategy(_) => true, - SyncingStrategy::StateSyncStrategy(_) => true, - SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.status().state.is_major_syncing(), - } + 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 startegy is active; qed"), + } } /// Get the number of peers known to the syncing strategy. pub fn num_peers(&self) -> usize { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => strategy.num_peers(), - SyncingStrategy::StateSyncStrategy(strategy) => strategy.num_peers(), - SyncingStrategy::ChainSyncStrategy(strategy) => strategy.num_peers(), - } + self.peer_best_blocks.len() } /// Returns the current sync status. pub fn status(&self) -> SyncStatus { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => strategy.status(), - SyncingStrategy::StateSyncStrategy(strategy) => strategy.status(), - SyncingStrategy::ChainSyncStrategy(strategy) => strategy.status(), + // This function presumes that startegies 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 startegy is always active; qed") } } /// Get the total number of downloaded blocks. pub fn num_downloaded_blocks(&self) -> usize { - match self { - SyncingStrategy::WarpSyncStrategy(_) => 0, - SyncingStrategy::StateSyncStrategy(_) => 0, - SyncingStrategy::ChainSyncStrategy(strategy) => strategy.num_downloaded_blocks(), - } + self.chain_sync + .as_ref() + .map_or(0, |chain_sync| chain_sync.num_downloaded_blocks()) } /// Get an estimate of the number of parallel sync requests. pub fn num_sync_requests(&self) -> usize { - match self { - SyncingStrategy::WarpSyncStrategy(_) => 0, - SyncingStrategy::StateSyncStrategy(_) => 0, - SyncingStrategy::ChainSyncStrategy(strategy) => strategy.num_sync_requests(), - } + self.chain_sync.as_ref().map_or(0, |chain_sync| chain_sync.num_sync_requests()) } /// Report Prometheus metrics pub fn report_metrics(&self) { - match self { - SyncingStrategy::WarpSyncStrategy(_) => {}, - SyncingStrategy::StateSyncStrategy(_) => {}, - SyncingStrategy::ChainSyncStrategy(strategy) => strategy.report_metrics(), + if let Some(ref chain_sync) = self.chain_sync { + chain_sync.report_metrics(); + } + } + + /// Let `WarpSync` know about target block header + pub fn set_warp_sync_target_block_header( + &mut self, + target_header: B::Header, + ) -> Result<(), ()> { + match self.config.mode { + SyncMode::Warp => match self.warp { + Some(ref mut warp) => { + warp.set_target_block(target_header); + Ok(()) + }, + None => { + // As mode is set to warp sync, but no warp sync strategy is active, this means + // that warp sync has already finished / was skipped. + warn!( + target: LOG_TARGET, + "Discarding warp sync target, as warp sync was seemingly skipped due \ + to node being (partially) synced.", + ); + Ok(()) + }, + }, + _ => { + error!( + target: LOG_TARGET, + "Cannot set warp sync target block: not in warp sync mode." + ); + debug_assert!(false); + Err(()) + }, } } /// Get actions that should be performed by the owner on the strategy's behalf #[must_use] - pub fn actions(&mut self) -> Box>> { - match self { - SyncingStrategy::WarpSyncStrategy(strategy) => - Box::new(strategy.actions().map(|action| match action { - WarpSyncAction::SendWarpProofRequest { peer_id, request } => - SyncingAction::SendWarpProofRequest { peer_id, request }, - WarpSyncAction::SendBlockRequest { peer_id, request } => - SyncingAction::SendBlockRequest { peer_id, request }, - WarpSyncAction::DropPeer(bad_peer) => SyncingAction::DropPeer(bad_peer), - WarpSyncAction::Finished => SyncingAction::Finished, - })), - SyncingStrategy::StateSyncStrategy(strategy) => - Box::new(strategy.actions().map(|action| match action { - StateStrategyAction::SendStateRequest { peer_id, request } => - SyncingAction::SendStateRequest { peer_id, request }, - StateStrategyAction::DropPeer(bad_peer) => SyncingAction::DropPeer(bad_peer), - StateStrategyAction::ImportBlocks { origin, blocks } => - SyncingAction::ImportBlocks { origin, blocks }, - StateStrategyAction::Finished => SyncingAction::Finished, - })), - SyncingStrategy::ChainSyncStrategy(strategy) => - Box::new(strategy.actions().map(|action| match action { - ChainSyncAction::SendBlockRequest { peer_id, request } => - SyncingAction::SendBlockRequest { peer_id, request }, - ChainSyncAction::CancelBlockRequest { peer_id } => - SyncingAction::CancelBlockRequest { peer_id }, - ChainSyncAction::SendStateRequest { peer_id, request } => - SyncingAction::SendStateRequest { peer_id, request }, - ChainSyncAction::DropPeer(bad_peer) => SyncingAction::DropPeer(bad_peer), - ChainSyncAction::ImportBlocks { origin, blocks } => - SyncingAction::ImportBlocks { origin, blocks }, - ChainSyncAction::ImportJustifications { - peer_id, - hash, - number, - justifications, - } => SyncingAction::ImportJustifications { - peer_id, - hash, - number, - justifications, - }, - })), + pub 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().map(Into::into).collect() + } else { + unreachable!("At least one syncing strategy is always active; qed") + }; + + if actions.iter().any(SyncingAction::is_finished) { + self.proceed_to_next()?; } + + Ok(actions) } - /// Switch to next strategy if the active one finished. - pub fn switch_to_next( - &mut self, - config: SyncingConfig, - client: Arc, - connected_peers: impl Iterator)>, - ) -> Result<(), ClientError> { - match self { - Self::WarpSyncStrategy(warp_sync) => { - match warp_sync.take_result() { - Some(res) => { - info!( - target: LOG_TARGET, - "Warp sync is complete, continuing with state sync." - ); - let state_sync = StateStrategy::new( - client, - res.target_header, - res.target_body, - res.target_justifications, - // skip proofs, only set to `true` in `FastUnsafe` sync mode - false, - connected_peers - .map(|(peer_id, _best_hash, best_number)| (peer_id, best_number)), - ); - - *self = Self::StateSyncStrategy(state_sync); - }, - None => { - error!( - target: LOG_TARGET, - "Warp sync failed. Falling back to full sync." - ); - let mut chain_sync = match ChainSync::new( - chain_sync_mode(config.mode), - client, - config.max_parallel_downloads, - config.max_blocks_per_request, - config.metrics_registry, - ) { - Ok(chain_sync) => chain_sync, - Err(e) => { - error!(target: LOG_TARGET, "Failed to start `ChainSync`."); - return Err(e) - }, - }; - // Let `ChainSync` know about connected peers. - connected_peers.into_iter().for_each( - |(peer_id, best_hash, best_number)| { - chain_sync.add_peer(peer_id, best_hash, best_number) - }, - ); - - *self = Self::ChainSyncStrategy(chain_sync); - }, - } - }, - Self::StateSyncStrategy(state_sync) => { - if state_sync.is_succeded() { - 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 mut chain_sync = match ChainSync::new( - chain_sync_mode(config.mode), - client, - config.max_parallel_downloads, - config.max_blocks_per_request, - config.metrics_registry, - ) { - Ok(chain_sync) => chain_sync, - Err(e) => { - error!(target: LOG_TARGET, "Failed to start `ChainSync`."); - return Err(e) - }, - }; - // Let `ChainSync` know about connected peers. - connected_peers.into_iter().for_each(|(peer_id, best_hash, best_number)| { - chain_sync.add_peer(peer_id, best_hash, best_number) - }); - - *self = Self::ChainSyncStrategy(chain_sync); - }, - Self::ChainSyncStrategy(_) => { - error!(target: LOG_TARGET, "`ChainSyncStrategy` is final startegy, cannot switch to next."); - debug_assert!(false); - }, + /// 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` -> `StateStartegy` -> `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.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.metrics_registry.clone(), + 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_succeded() { + 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.metrics_registry.clone(), + 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") } - Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use futures::executor::block_on; + use sc_block_builder::BlockBuilderBuilder; + use substrate_test_runtime_client::{ + ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClientBuilder, + TestClientBuilderExt, + }; + + /// Regression test for crash when starting already synced parachain node with `--sync=warp`. + /// We must remove this after setting of warp sync target block is moved to initialization of + /// `SyncingEngine` (issue https://github.com/paritytech/polkadot-sdk/issues/3537). + #[test] + fn set_target_block_finished_warp_sync() { + // Populate database with finalized state. + let mut client = Arc::new(TestClientBuilder::new().build()); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let just = (*b"TEST", Vec::new()); + client.finalize_block(block.hash(), Some(just)).unwrap(); + let target_block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().best_hash) + .with_parent_block_number(client.chain_info().best_number) + .build() + .unwrap() + .build() + .unwrap() + .block; + + // Initialize syncing strategy. + let config = SyncingConfig { + mode: SyncMode::Warp, + max_parallel_downloads: 3, + max_blocks_per_request: 64, + metrics_registry: None, + }; + let mut strategy = + SyncingStrategy::new(config, client, Some(WarpSyncConfig::WaitForTarget)).unwrap(); + + // Warp sync instantly finishes as we have finalized state in DB. + let actions = strategy.actions().unwrap(); + assert_eq!(actions.len(), 1); + assert!(matches!(actions[0], SyncingAction::Finished)); + assert!(strategy.warp.is_none()); + + // Try setting the target block. We mustn't crash. + strategy + .set_warp_sync_target_block_header(target_block.header().clone()) + .unwrap(); } } diff --git a/substrate/client/network/sync/src/strategy/chain_sync.rs b/substrate/client/network/sync/src/strategy/chain_sync.rs index 62c260d582b5a75bf38c81b9c5b3f5e65df1e8a4..ad0c75363e78ac948b4e10352328c64cefb792a1 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync.rs @@ -30,7 +30,7 @@ use crate::{ blocks::BlockCollection, - extra_requests::ExtraRequests, + justification_requests::ExtraRequests, schema::v1::StateResponse, strategy::{ state_sync::{ImportResult, StateSync, StateSyncProvider}, @@ -212,10 +212,10 @@ struct GapSync { pub enum ChainSyncAction { /// Send block request to peer. Always implies dropping a stale block request to the same peer. SendBlockRequest { peer_id: PeerId, request: BlockRequest }, - /// Drop stale block request. - CancelBlockRequest { peer_id: PeerId }, /// Send state request to peer. SendStateRequest { peer_id: PeerId, request: OpaqueStateRequest }, + /// Drop stale request. + CancelRequest { peer_id: PeerId }, /// Peer misbehaved. Disconnect, report it and cancel the block request to it. DropPeer(BadPeer), /// Import blocks. @@ -373,6 +373,7 @@ where max_parallel_downloads: u32, max_blocks_per_request: u32, metrics_registry: Option, + initial_peers: impl Iterator)>, ) -> Result { let mut sync = Self { client, @@ -405,6 +406,10 @@ where }; sync.reset_sync_start_point()?; + initial_peers.for_each(|(peer_id, best_hash, best_number)| { + sync.add_peer(peer_id, best_hash, best_number); + }); + Ok(sync) } @@ -1312,34 +1317,35 @@ where ); let old_peers = std::mem::take(&mut self.peers); - old_peers.into_iter().for_each(|(peer_id, mut p)| { - // peers that were downloading justifications - // should be kept in that state. - if let PeerSyncState::DownloadingJustification(_) = p.state { - // We make sure our commmon number is at least something we have. - trace!( - target: LOG_TARGET, - "Keeping peer {} after restart, updating common number from={} => to={} (our best).", - peer_id, - p.common_number, - self.best_queued_number, - ); - p.common_number = self.best_queued_number; - self.peers.insert(peer_id, p); - return + old_peers.into_iter().for_each(|(peer_id, mut peer_sync)| { + match peer_sync.state { + PeerSyncState::Available => { + self.add_peer(peer_id, peer_sync.best_hash, peer_sync.best_number); + }, + PeerSyncState::AncestorSearch { .. } | + PeerSyncState::DownloadingNew(_) | + PeerSyncState::DownloadingStale(_) | + PeerSyncState::DownloadingGap(_) | + PeerSyncState::DownloadingState => { + // Cancel a request first, as `add_peer` may generate a new request. + self.actions.push(ChainSyncAction::CancelRequest { peer_id }); + self.add_peer(peer_id, peer_sync.best_hash, peer_sync.best_number); + }, + PeerSyncState::DownloadingJustification(_) => { + // Peers that were downloading justifications + // should be kept in that state. + // We make sure our commmon number is at least something we have. + trace!( + target: LOG_TARGET, + "Keeping peer {} after restart, updating common number from={} => to={} (our best).", + peer_id, + peer_sync.common_number, + self.best_queued_number, + ); + peer_sync.common_number = self.best_queued_number; + self.peers.insert(peer_id, peer_sync); + }, } - - // handle peers that were in other states. - let action = match self.add_peer_inner(peer_id, p.best_hash, p.best_number) { - // since the request is not a justification, remove it from pending responses - Ok(None) => ChainSyncAction::CancelBlockRequest { peer_id }, - // update the request if the new one is available - Ok(Some(request)) => ChainSyncAction::SendBlockRequest { peer_id, request }, - // this implies that we need to drop pending response from the peer - Err(bad_peer) => ChainSyncAction::DropPeer(bad_peer), - }; - - self.actions.push(action); }); } 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 c89096bc6c9045ddb42eb7e5bb65485d7a90f851..127b6862f0e0dca6c01a88bc6ee83b1f57e7c4dc 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync/test.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync/test.rs @@ -38,7 +38,9 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { let client = Arc::new(TestClientBuilder::new().build()); let peer_id = PeerId::random(); - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 64, None, std::iter::empty()) + .unwrap(); let (a1_hash, a1_number) = { let a1 = BlockBuilderBuilder::new(&*client) @@ -91,7 +93,11 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { fn restart_doesnt_affect_peers_downloading_finality_data() { let mut client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 64, None).unwrap(); + // we request max 8 blocks to always initiate block requests to both peers for the test to be + // deterministic + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 8, None, std::iter::empty()) + .unwrap(); let peer_id1 = PeerId::random(); let peer_id2 = PeerId::random(); @@ -122,10 +128,13 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { // we wil send block requests to these peers // for these blocks we don't know about - assert!(sync - .block_requests() - .into_iter() - .all(|(p, _)| { p == peer_id1 || p == peer_id2 })); + let actions = sync.actions().collect::>(); + assert_eq!(actions.len(), 2); + assert!(actions.iter().all(|action| match action { + ChainSyncAction::SendBlockRequest { peer_id, .. } => + peer_id == &peer_id1 || peer_id == &peer_id2, + _ => false, + })); // add a new peer at a known block sync.add_peer(peer_id3, b1_hash, b1_number); @@ -146,22 +155,29 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { PeerSyncState::DownloadingJustification(b1_hash), ); - // clear old actions + // drop old actions let _ = sync.take_actions(); // we restart the sync state sync.restart(); - let actions = sync.take_actions().collect::>(); - // which should make us send out block requests to the first two peers - assert_eq!(actions.len(), 2); + // which should make us cancel and send out again block requests to the first two peers + let actions = sync.actions().collect::>(); + assert_eq!(actions.len(), 4); + let mut cancelled_first = HashSet::new(); assert!(actions.iter().all(|action| match action { - ChainSyncAction::SendBlockRequest { peer_id, .. } => - peer_id == &peer_id1 || peer_id == &peer_id2, + ChainSyncAction::CancelRequest { peer_id, .. } => { + cancelled_first.insert(peer_id); + peer_id == &peer_id1 || peer_id == &peer_id2 + }, + ChainSyncAction::SendBlockRequest { peer_id, .. } => { + assert!(cancelled_first.remove(peer_id)); + peer_id == &peer_id1 || peer_id == &peer_id2 + }, _ => false, })); - // peer 3 should be unaffected it was downloading finality data + // peer 3 should be unaffected as it was downloading finality data assert_eq!( sync.peers.get(&peer_id3).unwrap().state, PeerSyncState::DownloadingJustification(b1_hash), @@ -275,7 +291,9 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { let mut client = Arc::new(TestClientBuilder::new().build()); let info = client.info(); - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None, std::iter::empty()) + .unwrap(); let peer_id1 = PeerId::random(); let peer_id2 = PeerId::random(); @@ -421,7 +439,9 @@ fn can_sync_huge_fork() { let info = client.info(); - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None, std::iter::empty()) + .unwrap(); let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); @@ -554,7 +574,9 @@ fn syncs_fork_without_duplicate_requests() { let info = client.info(); - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None, std::iter::empty()) + .unwrap(); let finalized_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize * 2 - 1].clone(); let just = (*b"TEST", Vec::new()); @@ -689,7 +711,9 @@ fn removes_target_fork_on_disconnect() { let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..3).map(|_| build_block(&mut client, None, false)).collect::>(); - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 64, None, std::iter::empty()) + .unwrap(); let peer_id1 = PeerId::random(); let common_block = blocks[1].clone(); @@ -714,7 +738,9 @@ fn can_import_response_with_missing_blocks() { let empty_client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new(ChainSyncMode::Full, empty_client.clone(), 1, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, empty_client.clone(), 1, 64, None, std::iter::empty()) + .unwrap(); let peer_id1 = PeerId::random(); let best_block = blocks[3].clone(); @@ -745,7 +771,9 @@ fn ancestor_search_repeat() { #[test] fn sync_restart_removes_block_but_not_justification_requests() { let mut client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 1, 64, None, std::iter::empty()) + .unwrap(); let peers = vec![PeerId::random(), PeerId::random()]; @@ -813,7 +841,7 @@ fn sync_restart_removes_block_but_not_justification_requests() { let actions = sync.take_actions().collect::>(); for action in actions.iter() { match action { - ChainSyncAction::CancelBlockRequest { peer_id } => { + ChainSyncAction::CancelRequest { peer_id } => { pending_responses.remove(&peer_id); }, ChainSyncAction::SendBlockRequest { peer_id, .. } => { @@ -887,7 +915,9 @@ fn request_across_forks() { fork_blocks }; - let mut sync = ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None).unwrap(); + let mut sync = + ChainSync::new(ChainSyncMode::Full, client.clone(), 5, 64, None, std::iter::empty()) + .unwrap(); // Add the peers, all at the common ancestor 100. let common_block = blocks.last().unwrap(); diff --git a/substrate/client/network/sync/src/strategy/state.rs b/substrate/client/network/sync/src/strategy/state.rs index ae3f7b6005594d020dfc3f32602833586d16ed92..12d36ff9e01a9c16bfee482c5e9e641b13bb3b87 100644 --- a/substrate/client/network/sync/src/strategy/state.rs +++ b/substrate/client/network/sync/src/strategy/state.rs @@ -330,11 +330,6 @@ impl StateStrategy { } } - /// Get the number of peers known to syncing. - pub fn num_peers(&self) -> usize { - self.peers.len() - } - /// Get actions that should be performed by the owner on [`WarpSync`]'s behalf #[must_use] pub fn actions(&mut self) -> impl Iterator> { diff --git a/substrate/client/network/test/Cargo.toml b/substrate/client/network/test/Cargo.toml index dced6ed673057deb6959eb4b6fb001cff5be301a..4f57287a39cc8da10d3a30f769d7d584e16f0904 100644 --- a/substrate/client/network/test/Cargo.toml +++ b/substrate/client/network/test/Cargo.toml @@ -21,7 +21,7 @@ async-trait = "0.1.74" futures = "0.3.21" futures-timer = "3.0.1" libp2p = "0.51.4" -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" rand = "0.8.5" sc-block-builder = { path = "../../block-builder" } diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index 9e021059eb3da48eab08803a0b2b69819575d718..01c8ac8814d6aff1448caa18bbe8f3287139553f 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -20,7 +20,7 @@ array-bytes = "6.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" libp2p = "0.51.4" -log = "0.4.17" +log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-network = { path = ".." } sc-network-common = { path = "../common" } diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index 520523712862d7e21775f5b10a22f20d205ecdba..caa4bb03f40cba37b10444af6820833f8b4a8b84 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -26,7 +26,7 @@ hyper = { version = "0.14.16", features = ["http2", "stream"] } hyper-rustls = { version = "0.24.0", features = ["http2"] } libp2p = "0.51.4" num_cpus = "1.13" -once_cell = "1.8" +once_cell = "1.19" parking_lot = "0.12.1" rand = "0.8.5" threadpool = "1.7" @@ -42,7 +42,7 @@ sp-offchain = { path = "../../primitives/offchain" } sp-runtime = { path = "../../primitives/runtime" } sp-keystore = { path = "../../primitives/keystore" } sp-externalities = { path = "../../primitives/externalities" } -log = "0.4.17" +log = { workspace = true, default-features = true } [dev-dependencies] lazy_static = "1.4.0" diff --git a/substrate/client/proposer-metrics/Cargo.toml b/substrate/client/proposer-metrics/Cargo.toml index 40fcc722010c96b1f8a380d61f0fab6f58b4a485..f560ce2d65e6e6336c7fa372618c858616ca134e 100644 --- a/substrate/client/proposer-metrics/Cargo.toml +++ b/substrate/client/proposer-metrics/Cargo.toml @@ -16,5 +16,5 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.17" +log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/proposer-metrics/src/lib.rs b/substrate/client/proposer-metrics/src/lib.rs index 012e8ca769a96cb51141c5a13ca7ba04d76a8123..2856300cf8027b45bb0ef32b8781c533ae2e340c 100644 --- a/substrate/client/proposer-metrics/src/lib.rs +++ b/substrate/client/proposer-metrics/src/lib.rs @@ -44,11 +44,14 @@ impl MetricsLink { } /// The reason why proposing a block ended. +#[derive(Clone, Copy, PartialEq, Eq)] pub enum EndProposingReason { NoMoreTransactions, HitDeadline, HitBlockSizeLimit, HitBlockWeightLimit, + /// No transactions are allowed in the block. + TransactionForbidden, } /// Authorship metrics. @@ -112,6 +115,7 @@ impl Metrics { EndProposingReason::NoMoreTransactions => "no_more_transactions", EndProposingReason::HitBlockSizeLimit => "hit_block_size_limit", EndProposingReason::HitBlockWeightLimit => "hit_block_weight_limit", + EndProposingReason::TransactionForbidden => "transactions_forbidden", }; self.end_proposing_reason.with_label_values(&[reason]).inc(); diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 8e781151ba8d83c14adbea03e06dfb94d4b46590..1b7af6a4a52fe650dd325cc38d92daddd9c7a9fa 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -18,9 +18,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" -thiserror = "1.0" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } sc-chain-spec = { path = "../chain-spec" } sc-mixnet = { path = "../mixnet" } sc-transaction-pool-api = { path = "../transaction-pool/api" } @@ -28,4 +28,4 @@ sp-core = { path = "../../primitives/core" } sp-rpc = { path = "../../primitives/rpc" } sp-runtime = { path = "../../primitives/runtime" } sp-version = { path = "../../primitives/version" } -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index b624a14e263ad935ecdcce03de0cf3d38c3c07ea..3adc81c57d594a355212a88f83682a0441bc7acc 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -16,11 +16,14 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["server"] } -log = "0.4.17" -serde_json = "1.0.111" +jsonrpsee = { version = "0.22", features = ["server"] } +log = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } tokio = { version = "1.22.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } tower-http = { version = "0.4.0", features = ["cors"] } tower = { version = "0.4.13", features = ["util"] } http = "0.2.8" +hyper = "0.14.27" +futures = "0.3.29" +governor = "0.6.0" diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index 5d8da190f6277341d820bad65570f3eabe0e797e..ad4b444c7ff425ea84ba25e756d61854c3a4569e 100644 --- a/substrate/client/rpc-servers/src/lib.rs +++ b/substrate/client/rpc-servers/src/lib.rs @@ -22,21 +22,34 @@ pub mod middleware; -use std::{error::Error as StdError, net::SocketAddr, time::Duration}; +use std::{ + convert::Infallible, error::Error as StdError, net::SocketAddr, num::NonZeroU32, time::Duration, +}; use http::header::HeaderValue; +use hyper::{ + server::conn::AddrStream, + service::{make_service_fn, service_fn}, +}; use jsonrpsee::{ - server::middleware::{HostFilterLayer, ProxyGetRequestLayer}, - RpcModule, + server::{ + middleware::http::{HostFilterLayer, ProxyGetRequestLayer}, + stop_channel, ws, PingConfig, StopHandle, TowerServiceBuilder, + }, + Methods, RpcModule, }; use tokio::net::TcpListener; +use tower::Service; use tower_http::cors::{AllowOrigin, CorsLayer}; -pub use crate::middleware::RpcMetrics; -pub use jsonrpsee::core::{ - id_providers::{RandomIntegerIdProvider, RandomStringIdProvider}, - traits::IdProvider, +pub use jsonrpsee::{ + core::{ + id_providers::{RandomIntegerIdProvider, RandomStringIdProvider}, + traits::IdProvider, + }, + server::{middleware::rpc::RpcServiceBuilder, BatchRequestConfig}, }; +pub use middleware::{Metrics, MiddlewareLayer, RpcMetrics}; const MEGABYTE: u32 = 1024 * 1024; @@ -68,14 +81,31 @@ pub struct Config<'a, M: Send + Sync + 'static> { pub id_provider: Option>, /// Tokio runtime handle. pub tokio_handle: tokio::runtime::Handle, + /// Batch request config. + pub batch_config: BatchRequestConfig, + /// Rate limit calls per minute. + pub rate_limit: Option, +} + +#[derive(Debug, Clone)] +struct PerConnection { + methods: Methods, + stop_handle: StopHandle, + metrics: Option, + tokio_handle: tokio::runtime::Handle, + service_builder: TowerServiceBuilder, } /// Start RPC server listening on given address. -pub async fn start_server( +pub async fn start_server( config: Config<'_, M>, -) -> Result> { +) -> Result> +where + M: Send + Sync, +{ let Config { addrs, + batch_config, cors, max_payload_in_mb, max_payload_out_mb, @@ -86,13 +116,14 @@ pub async fn start_server( id_provider, tokio_handle, rpc_api, + rate_limit, } = config; let std_listener = TcpListener::bind(addrs.as_slice()).await?.into_std()?; let local_addr = std_listener.local_addr().ok(); let host_filter = hosts_filtering(cors.is_some(), local_addr); - let middleware = tower::ServiceBuilder::new() + let http_middleware = tower::ServiceBuilder::new() .option_layer(host_filter) // Proxy `GET /health` requests to internal `system_health` method. .layer(ProxyGetRequestLayer::new("/health", "system_health")?) @@ -103,10 +134,16 @@ pub async fn start_server( .max_response_body_size(max_payload_out_mb.saturating_mul(MEGABYTE)) .max_connections(max_connections) .max_subscriptions_per_connection(max_subs_per_conn) - .ping_interval(Duration::from_secs(30)) - .set_middleware(middleware) + .enable_ws_ping( + PingConfig::new() + .ping_interval(Duration::from_secs(30)) + .inactive_limit(Duration::from_secs(60)) + .max_failures(3), + ) + .set_http_middleware(http_middleware) .set_message_buffer_capacity(message_buffer_capacity) - .custom_tokio_runtime(tokio_handle); + .set_batch_request_config(batch_config) + .custom_tokio_runtime(tokio_handle.clone()); if let Some(provider) = id_provider { builder = builder.set_id_provider(provider); @@ -114,22 +151,81 @@ pub async fn start_server( builder = builder.set_id_provider(RandomStringIdProvider::new(16)); }; - let rpc_api = build_rpc_api(rpc_api); - let handle = if let Some(metrics) = metrics { - let server = builder.set_logger(metrics).build_from_tcp(std_listener)?; - server.start(rpc_api) - } else { - let server = builder.build_from_tcp(std_listener)?; - server.start(rpc_api) + let (stop_handle, server_handle) = stop_channel(); + let cfg = PerConnection { + methods: build_rpc_api(rpc_api).into(), + service_builder: builder.to_service_builder(), + metrics, + tokio_handle, + stop_handle: stop_handle.clone(), }; + let make_service = make_service_fn(move |_conn: &AddrStream| { + let cfg = cfg.clone(); + + async move { + let cfg = cfg.clone(); + + Ok::<_, Infallible>(service_fn(move |req| { + let PerConnection { service_builder, metrics, tokio_handle, stop_handle, methods } = + cfg.clone(); + + let is_websocket = ws::is_upgrade_request(&req); + let transport_label = if is_websocket { "ws" } else { "http" }; + + let middleware_layer = match (metrics, rate_limit) { + (None, None) => None, + (Some(metrics), None) => Some( + MiddlewareLayer::new().with_metrics(Metrics::new(metrics, transport_label)), + ), + (None, Some(rate_limit)) => + Some(MiddlewareLayer::new().with_rate_limit_per_minute(rate_limit)), + (Some(metrics), Some(rate_limit)) => Some( + MiddlewareLayer::new() + .with_metrics(Metrics::new(metrics, transport_label)) + .with_rate_limit_per_minute(rate_limit), + ), + }; + + let rpc_middleware = + RpcServiceBuilder::new().option_layer(middleware_layer.clone()); + + let mut svc = + service_builder.set_rpc_middleware(rpc_middleware).build(methods, stop_handle); + + async move { + if is_websocket { + let on_disconnect = svc.on_session_closed(); + + // Spawn a task to handle when the connection is closed. + tokio_handle.spawn(async move { + let now = std::time::Instant::now(); + middleware_layer.as_ref().map(|m| m.ws_connect()); + on_disconnect.await; + middleware_layer.as_ref().map(|m| m.ws_disconnect(now)); + }); + } + + svc.call(req).await + } + })) + } + }); + + let server = hyper::Server::from_tcp(std_listener)?.serve(make_service); + + tokio::spawn(async move { + let graceful = server.with_graceful_shutdown(async move { stop_handle.shutdown().await }); + let _ = graceful.await; + }); + log::info!( "Running JSON-RPC server: addr={}, allowed origins={}", local_addr.map_or_else(|| "unknown".to_string(), |a| a.to_string()), format_cors(cors) ); - Ok(handle) + Ok(server_handle) } fn hosts_filtering(enabled: bool, addr: Option) -> Option { diff --git a/substrate/client/rpc-servers/src/middleware.rs b/substrate/client/rpc-servers/src/middleware/metrics.rs similarity index 54% rename from substrate/client/rpc-servers/src/middleware.rs rename to substrate/client/rpc-servers/src/middleware/metrics.rs index fabb64eafa797189789611e01757aa7e5289b6b2..17849dc0c44846c10ed06b0f86d39783c5d29dc1 100644 --- a/substrate/client/rpc-servers/src/middleware.rs +++ b/substrate/client/rpc-servers/src/middleware/metrics.rs @@ -18,14 +18,13 @@ //! RPC middleware to collect prometheus metrics on RPC calls. -use jsonrpsee::server::logger::{ - HttpRequest, Logger, MethodKind, Params, SuccessOrError, TransportProtocol, -}; +use std::time::Instant; + +use jsonrpsee::{types::Request, MethodResponse}; use prometheus_endpoint::{ register, Counter, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, U64, }; -use std::net::SocketAddr; /// Histogram time buckets in microseconds. const HISTOGRAM_BUCKETS: [f64; 11] = [ @@ -46,10 +45,6 @@ const HISTOGRAM_BUCKETS: [f64; 11] = [ /// calls started/completed and their timings. #[derive(Debug, Clone)] pub struct RpcMetrics { - /// Number of RPC requests received since the server started. - requests_started: CounterVec, - /// Number of RPC requests completed since the server started. - requests_finished: CounterVec, /// Histogram over RPC execution times. calls_time: HistogramVec, /// Number of calls started. @@ -60,6 +55,8 @@ pub struct RpcMetrics { ws_sessions_opened: Option>, /// Number of Websocket sessions closed. ws_sessions_closed: Option>, + /// Histogram over RPC websocket sessions. + ws_sessions_time: HistogramVec, } impl RpcMetrics { @@ -67,26 +64,6 @@ impl RpcMetrics { pub fn new(metrics_registry: Option<&Registry>) -> Result, PrometheusError> { if let Some(metrics_registry) = metrics_registry { Ok(Some(Self { - requests_started: register( - CounterVec::new( - Opts::new( - "substrate_rpc_requests_started", - "Number of RPC requests (not calls) received by the server.", - ), - &["protocol"], - )?, - metrics_registry, - )?, - requests_finished: register( - CounterVec::new( - Opts::new( - "substrate_rpc_requests_finished", - "Number of RPC requests (not calls) processed by the server.", - ), - &["protocol"], - )?, - metrics_registry, - )?, calls_time: register( HistogramVec::new( HistogramOpts::new( @@ -94,7 +71,7 @@ impl RpcMetrics { "Total time [μs] of processed RPC calls", ) .buckets(HISTOGRAM_BUCKETS.to_vec()), - &["protocol", "method"], + &["protocol", "method", "is_rate_limited"], )?, metrics_registry, )?, @@ -114,7 +91,7 @@ impl RpcMetrics { "substrate_rpc_calls_finished", "Number of processed RPC calls (unique un-batched requests)", ), - &["protocol", "method", "is_error"], + &["protocol", "method", "is_error", "is_rate_limited"], )?, metrics_registry, )?, @@ -134,93 +111,117 @@ impl RpcMetrics { metrics_registry, )? .into(), + ws_sessions_time: register( + HistogramVec::new( + HistogramOpts::new( + "substrate_rpc_sessions_time", + "Total time [s] for each websocket session", + ) + .buckets(HISTOGRAM_BUCKETS.to_vec()), + &["protocol"], + )?, + metrics_registry, + )?, })) } else { Ok(None) } } -} - -impl Logger for RpcMetrics { - type Instant = std::time::Instant; - fn on_connect( - &self, - _remote_addr: SocketAddr, - _request: &HttpRequest, - transport: TransportProtocol, - ) { - if let TransportProtocol::WebSocket = transport { - self.ws_sessions_opened.as_ref().map(|counter| counter.inc()); - } + pub(crate) fn ws_connect(&self) { + self.ws_sessions_opened.as_ref().map(|counter| counter.inc()); } - fn on_request(&self, transport: TransportProtocol) -> Self::Instant { - let transport_label = transport_label_str(transport); - let now = std::time::Instant::now(); - self.requests_started.with_label_values(&[transport_label]).inc(); - now + pub(crate) fn ws_disconnect(&self, now: Instant) { + let micros = now.elapsed().as_secs(); + + self.ws_sessions_closed.as_ref().map(|counter| counter.inc()); + self.ws_sessions_time.with_label_values(&["ws"]).observe(micros as _); } - fn on_call(&self, name: &str, params: Params, kind: MethodKind, transport: TransportProtocol) { - let transport_label = transport_label_str(transport); + pub(crate) fn on_call(&self, req: &Request, transport_label: &'static str) { log::trace!( target: "rpc_metrics", - "[{}] on_call name={} params={:?} kind={}", - transport_label, - name, - params, - kind, + "[{transport_label}] on_call name={} params={:?}", + req.method_name(), + req.params(), ); - self.calls_started.with_label_values(&[transport_label, name]).inc(); + + self.calls_started + .with_label_values(&[transport_label, req.method_name()]) + .inc(); } - fn on_result( + pub(crate) fn on_response( &self, - name: &str, - success_or_error: SuccessOrError, - started_at: Self::Instant, - transport: TransportProtocol, + req: &Request, + rp: &MethodResponse, + is_rate_limited: bool, + transport_label: &'static str, + now: Instant, ) { - let transport_label = transport_label_str(transport); - let micros = started_at.elapsed().as_micros(); + log::trace!(target: "rpc_metrics", "[{transport_label}] on_response started_at={:?}", now); + log::trace!(target: "rpc_metrics::extra", "[{transport_label}] result={}", rp.as_result()); + + let micros = now.elapsed().as_micros(); log::debug!( target: "rpc_metrics", - "[{}] {} call took {} μs", - transport_label, - name, + "[{transport_label}] {} call took {} μs", + req.method_name(), micros, ); - self.calls_time.with_label_values(&[transport_label, name]).observe(micros as _); - + self.calls_time + .with_label_values(&[ + transport_label, + req.method_name(), + if is_rate_limited { "true" } else { "false" }, + ]) + .observe(micros as _); self.calls_finished .with_label_values(&[ transport_label, - name, + req.method_name(), // the label "is_error", so `success` should be regarded as false // and vice-versa to be registrered correctly. - if success_or_error.is_success() { "false" } else { "true" }, + if rp.is_success() { "false" } else { "true" }, + if is_rate_limited { "true" } else { "false" }, ]) .inc(); } +} + +/// Metrics with transport label. +#[derive(Clone, Debug)] +pub struct Metrics { + pub(crate) inner: RpcMetrics, + pub(crate) transport_label: &'static str, +} - fn on_response(&self, result: &str, started_at: Self::Instant, transport: TransportProtocol) { - let transport_label = transport_label_str(transport); - log::trace!(target: "rpc_metrics", "[{}] on_response started_at={:?}", transport_label, started_at); - log::trace!(target: "rpc_metrics::extra", "[{}] result={:?}", transport_label, result); - self.requests_finished.with_label_values(&[transport_label]).inc(); +impl Metrics { + /// Create a new [`Metrics`]. + pub fn new(metrics: RpcMetrics, transport_label: &'static str) -> Self { + Self { inner: metrics, transport_label } } - fn on_disconnect(&self, _remote_addr: SocketAddr, transport: TransportProtocol) { - if let TransportProtocol::WebSocket = transport { - self.ws_sessions_closed.as_ref().map(|counter| counter.inc()); - } + pub(crate) fn ws_connect(&self) { + self.inner.ws_connect(); } -} -fn transport_label_str(t: TransportProtocol) -> &'static str { - match t { - TransportProtocol::Http => "http", - TransportProtocol::WebSocket => "ws", + pub(crate) fn ws_disconnect(&self, now: Instant) { + self.inner.ws_disconnect(now) + } + + pub(crate) fn on_call(&self, req: &Request) { + self.inner.on_call(req, self.transport_label) + } + + pub(crate) fn on_response( + &self, + req: &Request, + rp: &MethodResponse, + is_rate_limited: bool, + now: Instant, + ) { + self.inner.on_response(req, rp, is_rate_limited, self.transport_label, now) } } diff --git a/substrate/client/rpc-servers/src/middleware/mod.rs b/substrate/client/rpc-servers/src/middleware/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..88ed8b2f433580fa2d87f1a70eacc32019027f2a --- /dev/null +++ b/substrate/client/rpc-servers/src/middleware/mod.rs @@ -0,0 +1,148 @@ +// 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 . + +//! JSON-RPC specific middleware. + +use std::{ + num::NonZeroU32, + time::{Duration, Instant}, +}; + +use futures::future::{BoxFuture, FutureExt}; +use governor::{clock::Clock, Jitter}; +use jsonrpsee::{ + server::middleware::rpc::RpcServiceT, + types::{ErrorObject, Id, Request}, + MethodResponse, +}; + +mod metrics; +mod rate_limit; + +pub use metrics::*; +pub use rate_limit::*; + +const MAX_JITTER: Duration = Duration::from_millis(50); +const MAX_RETRIES: usize = 10; + +/// JSON-RPC middleware layer. +#[derive(Debug, Clone, Default)] +pub struct MiddlewareLayer { + rate_limit: Option, + metrics: Option, +} + +impl MiddlewareLayer { + /// Create an empty MiddlewareLayer. + pub fn new() -> Self { + Self::default() + } + + /// Enable new rate limit middleware enforced per minute. + pub fn with_rate_limit_per_minute(self, n: NonZeroU32) -> Self { + Self { rate_limit: Some(RateLimit::per_minute(n)), metrics: self.metrics } + } + + /// Enable metrics middleware. + pub fn with_metrics(self, metrics: Metrics) -> Self { + Self { rate_limit: self.rate_limit, metrics: Some(metrics) } + } + + /// Register a new websocket connection. + pub fn ws_connect(&self) { + self.metrics.as_ref().map(|m| m.ws_connect()); + } + + /// Register that a websocket connection was closed. + pub fn ws_disconnect(&self, now: Instant) { + self.metrics.as_ref().map(|m| m.ws_disconnect(now)); + } +} + +impl tower::Layer for MiddlewareLayer { + type Service = Middleware; + + fn layer(&self, service: S) -> Self::Service { + Middleware { service, rate_limit: self.rate_limit.clone(), metrics: self.metrics.clone() } + } +} + +/// JSON-RPC middleware that handles metrics +/// and rate-limiting. +/// +/// These are part of the same middleware +/// because the metrics needs to know whether +/// a call was rate-limited or not because +/// it will impact the roundtrip for a call. +pub struct Middleware { + service: S, + rate_limit: Option, + metrics: Option, +} + +impl<'a, S> RpcServiceT<'a> for Middleware +where + S: Send + Sync + RpcServiceT<'a> + Clone + 'static, +{ + type Future = BoxFuture<'a, MethodResponse>; + + fn call(&self, req: Request<'a>) -> Self::Future { + let now = Instant::now(); + + self.metrics.as_ref().map(|m| m.on_call(&req)); + + let service = self.service.clone(); + let rate_limit = self.rate_limit.clone(); + let metrics = self.metrics.clone(); + + async move { + let mut is_rate_limited = false; + + if let Some(limit) = rate_limit.as_ref() { + let mut attempts = 0; + let jitter = Jitter::up_to(MAX_JITTER); + + loop { + if attempts >= MAX_RETRIES { + return reject_too_many_calls(req.id); + } + + if let Err(rejected) = limit.inner.check() { + tokio::time::sleep(jitter + rejected.wait_time_from(limit.clock.now())) + .await; + } else { + break; + } + + is_rate_limited = true; + attempts += 1; + } + } + + let rp = service.call(req.clone()).await; + metrics.as_ref().map(|m| m.on_response(&req, &rp, is_rate_limited, now)); + + rp + } + .boxed() + } +} + +fn reject_too_many_calls(id: Id) -> MethodResponse { + MethodResponse::error(id, ErrorObject::owned(-32999, "RPC rate limit exceeded", None::<()>)) +} diff --git a/substrate/client/rpc-servers/src/middleware/rate_limit.rs b/substrate/client/rpc-servers/src/middleware/rate_limit.rs new file mode 100644 index 0000000000000000000000000000000000000000..23335eb37686c30d6bf148a2fd38f75013aef606 --- /dev/null +++ b/substrate/client/rpc-servers/src/middleware/rate_limit.rs @@ -0,0 +1,47 @@ +// 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 . + +//! RPC rate limit. + +use governor::{ + clock::{DefaultClock, QuantaClock}, + middleware::NoOpMiddleware, + state::{InMemoryState, NotKeyed}, + Quota, +}; +use std::{num::NonZeroU32, sync::Arc}; + +type RateLimitInner = governor::RateLimiter; + +/// Rate limit. +#[derive(Debug, Clone)] +pub struct RateLimit { + pub(crate) inner: Arc, + pub(crate) clock: QuantaClock, +} + +impl RateLimit { + /// Create a new `RateLimit` per minute. + pub fn per_minute(n: NonZeroU32) -> Self { + let clock = QuantaClock::default(); + Self { + inner: Arc::new(RateLimitInner::direct_with_clock(Quota::per_minute(n), &clock)), + clock, + } + } +} diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 6d0e7e07848535d01cdc56214963105794a9c93f..c62b3e789d389047f66004f5f76a6bb947ce8b9e 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } # Internal chain structures for "chain_spec". sc-chain-spec = { path = "../chain-spec" } # Pool for submitting extrinsics required by "transaction" @@ -31,22 +31,24 @@ sc-client-api = { path = "../api" } sc-utils = { path = "../utils" } sc-rpc = { path = "../rpc" } codec = { package = "parity-scale-codec", version = "3.6.1" } -thiserror = "1.0" -serde = "1.0" +thiserror = { workspace = true } +serde = { workspace = true, default-features = true } hex = "0.4" futures = "0.3.21" parking_lot = "0.12.1" tokio-stream = { version = "0.1.14", features = ["sync"] } tokio = { version = "1.22.0", features = ["sync"] } array-bytes = "6.1" -log = "0.4.17" +log = { workspace = true, default-features = true } futures-util = { version = "0.3.30", default-features = false } +rand = "0.8.5" [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } tokio = { version = "1.22.0", features = ["macros"] } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } substrate-test-runtime = { path = "../../test-utils/runtime" } +substrate-test-runtime-transaction-pool = { path = "../../test-utils/runtime/transaction-pool" } sp-consensus = { path = "../../primitives/consensus/common" } sp-externalities = { path = "../../primitives/externalities" } sp-maybe-compressed-blob = { path = "../../primitives/maybe-compressed-blob" } @@ -54,3 +56,4 @@ sc-block-builder = { path = "../block-builder" } sc-service = { path = "../service", features = ["test-helpers"] } assert_matches = "1.3.0" pretty_assertions = "1.2.1" +sc-transaction-pool = { path = "../transaction-pool" } diff --git a/substrate/client/rpc-spec-v2/src/archive/tests.rs b/substrate/client/rpc-spec-v2/src/archive/tests.rs index 09b2410eac6e875b9fd19433bc67b49b6e5da947..1803ffa3a3183628a8eff81a10c05efdddc5e962 100644 --- a/substrate/client/rpc-spec-v2/src/archive/tests.rs +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -32,8 +32,7 @@ use super::{ use assert_matches::assert_matches; use codec::{Decode, Encode}; use jsonrpsee::{ - core::{EmptyServerParams as EmptyParams, Error}, - rpc_params, RpcModule, + core::EmptyServerParams as EmptyParams, rpc_params, MethodsError as Error, RpcModule, }; use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; @@ -294,7 +293,7 @@ async fn archive_call() { ) .await .unwrap_err(); - assert_matches!(err, Error::Call(err) if err.code() == 3001 && err.message().contains("Invalid parameter")); + assert_matches!(err, Error::JsonRpc(err) if err.code() == 3001 && err.message().contains("Invalid parameter")); // Pass an invalid parameters that cannot be decode. let err = api @@ -305,7 +304,7 @@ async fn archive_call() { ) .await .unwrap_err(); - assert_matches!(err, Error::Call(err) if err.code() == 3001 && err.message().contains("Invalid parameter")); + assert_matches!(err, Error::JsonRpc(err) if err.code() == 3001 && err.message().contains("Invalid parameter")); // Invalid hash. let result: MethodResult = api diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index 7c3b8d81c82aefbf14344524140005ad8cd0b479..00000e1fb277bbc49aeb343d233b00d408fc45c4 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -26,7 +26,7 @@ use crate::{ }, common::events::StorageQuery, }; -use jsonrpsee::proc_macros::rpc; +use jsonrpsee::{proc_macros::rpc, server::ResponsePayload}; use sp_rpc::list::ListOrValue; #[rpc(client, server)] @@ -59,7 +59,7 @@ pub trait ChainHeadApi { &self, follow_subscription: String, hash: Hash, - ) -> Result; + ) -> ResponsePayload<'static, MethodResponse>; /// Retrieves the header of a pinned block. /// @@ -92,7 +92,7 @@ pub trait ChainHeadApi { hash: Hash, items: Vec>, child_trie: Option, - ) -> Result; + ) -> ResponsePayload<'static, MethodResponse>; /// Call into the Runtime API at a specified block's state. /// @@ -106,7 +106,7 @@ pub trait ChainHeadApi { hash: Hash, function: String, call_parameters: String, - ) -> Result; + ) -> ResponsePayload<'static, MethodResponse>; /// Unpin a block or multiple blocks reported by the `follow` method. /// diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 0e207addcaeb71d4bedd9de2c2ba29d4f192640f..2bda22b452391e5b3ef3f7367b43331079591aa3 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -36,7 +36,8 @@ use crate::{ use codec::Encode; use futures::future::FutureExt; use jsonrpsee::{ - core::async_trait, types::SubscriptionId, PendingSubscriptionSink, SubscriptionSink, + core::async_trait, server::ResponsePayload, types::SubscriptionId, MethodResponseFuture, + PendingSubscriptionSink, SubscriptionSink, }; use log::debug; use sc_client_api::{ @@ -218,16 +219,17 @@ where &self, follow_subscription: String, hash: Block::Hash, - ) -> Result { + ) -> ResponsePayload<'static, MethodResponse> { let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | - Err(SubscriptionManagementError::ExceededLimits) => return Ok(MethodResponse::LimitReached), + Err(SubscriptionManagementError::ExceededLimits) => + return ResponsePayload::success(MethodResponse::LimitReached), Err(SubscriptionManagementError::BlockHashAbsent) => { // Block is not part of the subscription. - return Err(ChainHeadRpcError::InvalidBlock.into()) + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock); }, - Err(_) => return Err(ChainHeadRpcError::InvalidBlock.into()), + Err(_) => return ResponsePayload::error(ChainHeadRpcError::InvalidBlock), }; let operation_id = block_guard.operation().operation_id(); @@ -254,7 +256,7 @@ where hash ); self.subscriptions.remove_subscription(&follow_subscription); - return Err(ChainHeadRpcError::InvalidBlock.into()) + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock) }, Err(error) => FollowEvent::::OperationError(OperationError { operation_id: operation_id.clone(), @@ -262,8 +264,20 @@ where }), }; - let _ = block_guard.response_sender().unbounded_send(event); - Ok(MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items: None })) + let (rp, rp_fut) = method_started_response(operation_id, None); + + let fut = async move { + // Events should only by generated + // if the response was successfully propagated. + if rp_fut.await.is_err() { + return; + } + let _ = block_guard.response_sender().unbounded_send(event); + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + + rp } fn chain_head_unstable_header( @@ -294,31 +308,40 @@ where hash: Block::Hash, items: Vec>, child_trie: Option, - ) -> Result { + ) -> ResponsePayload<'static, MethodResponse> { // Gain control over parameter parsing and returned error. - let items = items + let items = match items .into_iter() .map(|query| { let key = StorageKey(parse_hex_param(query.key)?); Ok(StorageQuery { key, query_type: query.query_type }) }) - .collect::, ChainHeadRpcError>>()?; + .collect::, ChainHeadRpcError>>() + { + Ok(items) => items, + Err(err) => { + return ResponsePayload::error(err); + }, + }; - let child_trie = child_trie - .map(|child_trie| parse_hex_param(child_trie)) - .transpose()? - .map(ChildInfo::new_default_from_vec); + let child_trie = match child_trie.map(|child_trie| parse_hex_param(child_trie)).transpose() + { + Ok(c) => c.map(ChildInfo::new_default_from_vec), + Err(e) => return ResponsePayload::error(e), + }; let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, items.len()) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | - Err(SubscriptionManagementError::ExceededLimits) => return Ok(MethodResponse::LimitReached), + Err(SubscriptionManagementError::ExceededLimits) => { + return ResponsePayload::success(MethodResponse::LimitReached); + }, Err(SubscriptionManagementError::BlockHashAbsent) => { // Block is not part of the subscription. - return Err(ChainHeadRpcError::InvalidBlock.into()) + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock) }, - Err(_) => return Err(ChainHeadRpcError::InvalidBlock.into()), + Err(_) => return ResponsePayload::error(ChainHeadRpcError::InvalidBlock), }; let mut storage_client = ChainHeadStorage::::new( @@ -334,16 +357,21 @@ where let mut items = items; items.truncate(num_operations); + let (rp, rp_is_success) = method_started_response(operation_id, Some(discarded)); + let fut = async move { + // Events should only by generated + // if the response was successfully propagated. + if rp_is_success.await.is_err() { + return; + } storage_client.generate_events(block_guard, hash, items, child_trie).await; }; self.executor .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - Ok(MethodResponse::Started(MethodResponseStarted { - operation_id, - discarded_items: Some(discarded), - })) + + rp } fn chain_head_unstable_call( @@ -352,29 +380,31 @@ where hash: Block::Hash, function: String, call_parameters: String, - ) -> Result { - let call_parameters = Bytes::from(parse_hex_param(call_parameters)?); + ) -> ResponsePayload<'static, MethodResponse> { + let call_parameters = match parse_hex_param(call_parameters) { + Ok(hex) => Bytes::from(hex), + Err(err) => return ResponsePayload::error(err), + }; let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | Err(SubscriptionManagementError::ExceededLimits) => { // Invalid invalid subscription ID. - return Ok(MethodResponse::LimitReached) + return ResponsePayload::success(MethodResponse::LimitReached) }, Err(SubscriptionManagementError::BlockHashAbsent) => { // Block is not part of the subscription. - return Err(ChainHeadRpcError::InvalidBlock.into()) + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock) }, - Err(_) => return Err(ChainHeadRpcError::InvalidBlock.into()), + Err(_) => return ResponsePayload::error(ChainHeadRpcError::InvalidBlock), }; // Reject subscription if with_runtime is false. if !block_guard.has_runtime() { - return Err(ChainHeadRpcError::InvalidRuntimeCall( + return ResponsePayload::error(ChainHeadRpcError::InvalidRuntimeCall( "The runtime updates flag must be set".to_string(), - ) - .into()) + )); } let operation_id = block_guard.operation().operation_id(); @@ -395,11 +425,20 @@ where }) }); - let _ = block_guard.response_sender().unbounded_send(event); - Ok(MethodResponse::Started(MethodResponseStarted { - operation_id: operation_id.clone(), - discarded_items: None, - })) + let (rp, rp_fut) = method_started_response(operation_id, None); + + let fut = async move { + // Events should only by generated + // if the response was successfully propagated. + if rp_fut.await.is_err() { + return; + } + let _ = block_guard.response_sender().unbounded_send(event); + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + + rp } fn chain_head_unstable_unpin( @@ -424,6 +463,8 @@ where // Block is not part of the subscription. Err(ChainHeadRpcError::InvalidBlock) }, + Err(SubscriptionManagementError::DuplicateHashes) => + Err(ChainHeadRpcError::InvalidDuplicateHashes), Err(_) => Err(ChainHeadRpcError::InvalidBlock), } } @@ -461,3 +502,11 @@ where Ok(()) } } + +fn method_started_response( + operation_id: String, + discarded_items: Option, +) -> (ResponsePayload<'static, MethodResponse>, MethodResponseFuture) { + let rp = MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items }); + ResponsePayload::success(rp).notify_on_completion() +} diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index e94374aebd912b40074c194f656a1951fb097510..afa99f3aa1648823aee646304c7c2b2cd71da6e2 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 @@ -42,7 +42,14 @@ use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, Info, }; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use std::{collections::HashSet, sync::Arc}; +use std::{ + collections::{HashSet, VecDeque}, + sync::Arc, +}; + +/// The maximum number of finalized blocks provided by the +/// `Initialized` event. +const MAX_FINALIZED_BLOCKS: usize = 16; use super::subscription::InsertedSubscriptionData; @@ -95,6 +102,8 @@ struct InitialBlocks { /// /// It is a tuple of (block hash, parent hash). finalized_block_descendants: Vec<(Block::Hash, Block::Hash)>, + /// Hashes of the last finalized blocks + finalized_block_hashes: VecDeque, /// Blocks that should not be reported as pruned by the `Finalized` event. /// /// Substrate database will perform the pruning of height N at @@ -178,13 +187,14 @@ where } /// Get the in-memory blocks of the client, starting from the provided finalized hash. + /// + /// The reported blocks are pinned by this function. fn get_init_blocks_with_forks( &self, - startup_point: &StartupPoint, + finalized: Block::Hash, ) -> Result, SubscriptionManagementError> { let blockchain = self.backend.blockchain(); let leaves = blockchain.leaves()?; - let finalized = startup_point.finalized_hash; let mut pruned_forks = HashSet::new(); let mut finalized_block_descendants = Vec::new(); let mut unique_descendants = HashSet::new(); @@ -198,17 +208,47 @@ where // Ensure a `NewBlock` event is generated for all children of the // finalized block. Describe the tree route as (child_node, parent_node) // Note: the order of elements matters here. - let parents = std::iter::once(finalized).chain(blocks.clone()); + let mut parent = finalized; + for child in blocks { + let pair = (child, parent); - for pair in blocks.zip(parents) { if unique_descendants.insert(pair) { + // The finalized block is pinned below. + self.sub_handle.pin_block(&self.sub_id, child)?; finalized_block_descendants.push(pair); } + + parent = child; } } } - Ok(InitialBlocks { finalized_block_descendants, pruned_forks }) + let mut current_block = finalized; + // The header of the finalized block must not be pruned. + let Some(header) = blockchain.header(current_block)? else { + return Err(SubscriptionManagementError::BlockHeaderAbsent); + }; + + // Report at most `MAX_FINALIZED_BLOCKS`. Note: The node might not have that many blocks. + let mut finalized_block_hashes = VecDeque::with_capacity(MAX_FINALIZED_BLOCKS); + + // Pin the finalized block. + self.sub_handle.pin_block(&self.sub_id, current_block)?; + finalized_block_hashes.push_front(current_block); + current_block = *header.parent_hash(); + + for _ in 0..MAX_FINALIZED_BLOCKS - 1 { + let Ok(Some(header)) = blockchain.header(current_block) else { break }; + // Block cannot be reported if pinning fails. + if self.sub_handle.pin_block(&self.sub_id, current_block).is_err() { + break + }; + + finalized_block_hashes.push_front(current_block); + current_block = *header.parent_hash(); + } + + Ok(InitialBlocks { finalized_block_descendants, finalized_block_hashes, pruned_forks }) } /// Generate the initial events reported by the RPC `follow` method. @@ -220,18 +260,17 @@ where startup_point: &StartupPoint, ) -> Result<(Vec>, HashSet), SubscriptionManagementError> { - let init = self.get_init_blocks_with_forks(startup_point)?; + let init = self.get_init_blocks_with_forks(startup_point.finalized_hash)?; + // The initialized event is the first one sent. let initial_blocks = init.finalized_block_descendants; + let finalized_block_hashes = init.finalized_block_hashes; - // The initialized event is the first one sent. let finalized_block_hash = startup_point.finalized_hash; - self.sub_handle.pin_block(&self.sub_id, finalized_block_hash)?; - let finalized_block_runtime = self.generate_runtime_event(finalized_block_hash, None); let initialized_event = FollowEvent::Initialized(Initialized { - finalized_block_hash, + finalized_block_hashes: finalized_block_hashes.into(), finalized_block_runtime, with_runtime: self.with_runtime, }); @@ -240,8 +279,6 @@ where finalized_block_descendants.push(initialized_event); for (child, parent) in initial_blocks.into_iter() { - self.sub_handle.pin_block(&self.sub_id, child)?; - let new_runtime = self.generate_runtime_event(child, Some(parent)); let event = FollowEvent::NewBlock(NewBlock { diff --git a/substrate/client/rpc-spec-v2/src/chain_head/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/error.rs index bf290edb29eefd4a3dbe2316973ada8447cdd933..8c50e445aa0cf6480d3a672f7120cd7a492f4c99 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/error.rs @@ -32,6 +32,9 @@ pub enum Error { /// Wait-for-continue event not generated. #[error("Wait for continue event was not generated for the subscription")] InvalidContinue, + /// Received duplicate hashes for the `chainHead_unpin` method. + #[error("Received duplicate hashes for the `chainHead_unpin` method")] + InvalidDuplicateHashes, /// Invalid parameter provided to the RPC method. #[error("Invalid parameter: {0}")] InvalidParam(String), @@ -49,6 +52,8 @@ pub mod rpc_spec_v2 { pub const INVALID_RUNTIME_CALL: i32 = -32802; /// Wait-for-continue event not generated. pub const INVALID_CONTINUE: i32 = -32803; + /// Received duplicate hashes for the `chainHead_unpin` method. + pub const INVALID_DUPLICATE_HASHES: i32 = -32804; } /// General purpose errors, as defined in @@ -71,6 +76,8 @@ impl From for ErrorObject<'static> { ErrorObject::owned(rpc_spec_v2::INVALID_RUNTIME_CALL, msg, None::<()>), Error::InvalidContinue => ErrorObject::owned(rpc_spec_v2::INVALID_CONTINUE, msg, None::<()>), + Error::InvalidDuplicateHashes => + ErrorObject::owned(rpc_spec_v2::INVALID_DUPLICATE_HASHES, msg, None::<()>), Error::InvalidParam(_) => ErrorObject::owned(json_rpc_spec::INVALID_PARAM_ERROR, msg, None::<()>), Error::InternalError(_) => diff --git a/substrate/client/rpc-spec-v2/src/chain_head/event.rs b/substrate/client/rpc-spec-v2/src/chain_head/event.rs index 560ab87eab405968e9b7348bfd37792307b87a8f..e0c804d16eb17853876a8b4bfd38d42d4b506f49 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/event.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/event.rs @@ -111,8 +111,8 @@ impl From for RuntimeEvent { #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Initialized { - /// The hash of the latest finalized block. - pub finalized_block_hash: Hash, + /// The hash of the lastest finalized blocks. + pub finalized_block_hashes: Vec, /// The runtime version of the finalized block. /// /// # Note @@ -135,12 +135,12 @@ impl Serialize for Initialized { { if self.with_runtime { let mut state = serializer.serialize_struct("Initialized", 2)?; - state.serialize_field("finalizedBlockHash", &self.finalized_block_hash)?; + state.serialize_field("finalizedBlockHashes", &self.finalized_block_hashes)?; state.serialize_field("finalizedBlockRuntime", &self.finalized_block_runtime)?; state.end() } else { let mut state = serializer.serialize_struct("Initialized", 1)?; - state.serialize_field("finalizedBlockHash", &self.finalized_block_hash)?; + state.serialize_field("finalizedBlockHashes", &self.finalized_block_hashes)?; state.end() } } @@ -348,13 +348,13 @@ mod tests { fn follow_initialized_event_no_updates() { // Runtime flag is false. let event: FollowEvent = FollowEvent::Initialized(Initialized { - finalized_block_hash: "0x1".into(), + finalized_block_hashes: vec!["0x1".into()], finalized_block_runtime: None, with_runtime: false, }); let ser = serde_json::to_string(&event).unwrap(); - let exp = r#"{"event":"initialized","finalizedBlockHash":"0x1"}"#; + let exp = r#"{"event":"initialized","finalizedBlockHashes":["0x1"]}"#; assert_eq!(ser, exp); let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); @@ -373,7 +373,7 @@ mod tests { let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.into() }); let mut initialized = Initialized { - finalized_block_hash: "0x1".into(), + finalized_block_hashes: vec!["0x1".into()], finalized_block_runtime: Some(runtime_event), with_runtime: true, }; @@ -381,7 +381,7 @@ mod tests { let ser = serde_json::to_string(&event).unwrap(); let exp = concat!( - r#"{"event":"initialized","finalizedBlockHash":"0x1","#, + r#"{"event":"initialized","finalizedBlockHashes":["0x1"],"#, r#""finalizedBlockRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","#, r#""specVersion":1,"implVersion":0,"apis":{},"transactionVersion":0}}}"#, ); diff --git a/substrate/client/rpc-spec-v2/src/chain_head/mod.rs b/substrate/client/rpc-spec-v2/src/chain_head/mod.rs index 4cbbd00f64f31f04f44ff83f9e5980e7d22e7308..c9fe19aca2b1898da25e45019e1924256d732d9a 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/mod.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/mod.rs @@ -23,7 +23,7 @@ //! Methods are prefixed by `chainHead`. #[cfg(test)] -mod test_utils; +pub mod test_utils; #[cfg(test)] mod tests; diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs index 38e8fd7384fcbd222bbfc385de602a834613c07d..2c22e51ca4dc70102fca98f4eea7f66d8e044a02 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs @@ -38,6 +38,9 @@ pub enum SubscriptionManagementError { /// The specified subscription ID is not present. #[error("Subscription is absent")] SubscriptionAbsent, + /// The unpin method was called with duplicate hashes. + #[error("Duplicate hashes")] + DuplicateHashes, /// Custom error. #[error("Subscription error {0}")] Custom(String), @@ -52,7 +55,8 @@ impl PartialEq for SubscriptionManagementError { (Self::Blockchain(_), Self::Blockchain(_)) | (Self::BlockHashAbsent, Self::BlockHashAbsent) | (Self::BlockHeaderAbsent, Self::BlockHeaderAbsent) | - (Self::SubscriptionAbsent, Self::SubscriptionAbsent) => true, + (Self::SubscriptionAbsent, Self::SubscriptionAbsent) | + (Self::DuplicateHashes, Self::DuplicateHashes) => true, (Self::Custom(lhs), Self::Custom(rhs)) => lhs == rhs, _ => false, } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index 2b250f3dc2cf2d0b52a222256b314eefc035a310..d2879679501fd17eada1b826ff01478cce24b7a3 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -22,7 +22,7 @@ use sc_client_api::Backend; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::Block as BlockT; use std::{ - collections::{hash_map::Entry, HashMap}, + collections::{hash_map::Entry, HashMap, HashSet}, sync::{atomic::AtomicBool, Arc}, time::{Duration, Instant}, }; @@ -750,11 +750,27 @@ impl> SubscriptionsInner { } } + /// Ensure the provided hashes are unique. + fn ensure_hash_uniqueness( + hashes: impl IntoIterator + Clone, + ) -> Result<(), SubscriptionManagementError> { + let mut set = HashSet::new(); + hashes.into_iter().try_for_each(|hash| { + if !set.insert(hash) { + Err(SubscriptionManagementError::DuplicateHashes) + } else { + Ok(()) + } + }) + } + pub fn unpin_blocks( &mut self, sub_id: &str, hashes: impl IntoIterator + Clone, ) -> Result<(), SubscriptionManagementError> { + Self::ensure_hash_uniqueness(hashes.clone())?; + let Some(sub) = self.subs.get_mut(sub_id) else { return Err(SubscriptionManagementError::SubscriptionAbsent) }; @@ -985,6 +1001,76 @@ mod tests { assert!(block_state.is_none()); } + #[test] + fn unpin_duplicate_hashes() { + let (backend, mut client) = init_backend(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let hash_1 = block.header.hash(); + futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_1) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; + let hash_2 = block.header.hash(); + futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(hash_2) + .with_parent_block_number(2) + .build() + .unwrap() + .build() + .unwrap() + .block; + let hash_3 = block.header.hash(); + futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + + let mut subs = + SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); + let id_1 = "abc".to_string(); + let id_2 = "abcd".to_string(); + + // Pin all blocks for the first subscription. + let _stop = subs.insert_subscription(id_1.clone(), true).unwrap(); + assert_eq!(subs.pin_block(&id_1, hash_1).unwrap(), true); + assert_eq!(subs.pin_block(&id_1, hash_2).unwrap(), true); + assert_eq!(subs.pin_block(&id_1, hash_3).unwrap(), true); + + // Pin only block 2 for the second subscription. + let _stop = subs.insert_subscription(id_2.clone(), true).unwrap(); + assert_eq!(subs.pin_block(&id_2, hash_2).unwrap(), true); + + // Check reference count. + assert_eq!(*subs.global_blocks.get(&hash_1).unwrap(), 1); + assert_eq!(*subs.global_blocks.get(&hash_2).unwrap(), 2); + assert_eq!(*subs.global_blocks.get(&hash_3).unwrap(), 1); + + // Unpin the same block twice. + let err = subs.unpin_blocks(&id_1, vec![hash_1, hash_1, hash_2, hash_2]).unwrap_err(); + assert_eq!(err, SubscriptionManagementError::DuplicateHashes); + + // Check reference count must be unaltered. + assert_eq!(*subs.global_blocks.get(&hash_1).unwrap(), 1); + assert_eq!(*subs.global_blocks.get(&hash_2).unwrap(), 2); + assert_eq!(*subs.global_blocks.get(&hash_3).unwrap(), 1); + + // Unpin the blocks correctly. + subs.unpin_blocks(&id_1, vec![hash_1, hash_2]).unwrap(); + assert_eq!(subs.global_blocks.get(&hash_1), None); + assert_eq!(*subs.global_blocks.get(&hash_2).unwrap(), 1); + assert_eq!(*subs.global_blocks.get(&hash_3).unwrap(), 1); + } + #[test] fn subscription_lock_block() { let builder = TestClientBuilder::new(); diff --git a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs index d63a98a5cb0d93b3633864bd3405ad38c2b6e799..e81bd4bfa0b04aa3ad9e25e47e83e9ace1c7f985 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs @@ -63,7 +63,7 @@ impl ChainHeadMockClient { BlockImportNotification::new(header.hash(), BlockOrigin::Own, header, true, None, sink); for sink in self.import_sinks.lock().iter_mut() { - sink.unbounded_send(notification.clone()).unwrap(); + let _ = sink.unbounded_send(notification.clone()); } } @@ -83,7 +83,7 @@ impl ChainHeadMockClient { let notification = FinalityNotification::from_summary(summary, sink); for sink in self.finality_sinks.lock().iter_mut() { - sink.unbounded_send(notification.clone()).unwrap(); + let _ = sink.unbounded_send(notification.clone()); } } } 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 955a361e3eadb455891a68e8ec7e74e4a95c84e0..4d9dfb24e0a93bc45669ff1af4899eeb27694c18 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -27,8 +27,7 @@ use assert_matches::assert_matches; use codec::{Decode, Encode}; use futures::Future; use jsonrpsee::{ - core::{error::Error, server::Subscription as RpcSubscription}, - rpc_params, RpcModule, + core::server::Subscription as RpcSubscription, rpc_params, MethodsError as Error, RpcModule, }; use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; @@ -174,7 +173,7 @@ async fn follow_subscription_produces_blocks() { // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Initialized(Initialized { - finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], finalized_block_runtime: None, with_runtime: false, }); @@ -243,12 +242,12 @@ async fn follow_with_runtime() { let event: FollowEvent = get_next_event(&mut sub).await; // it is basically json-encoded substrate_test_runtime_client::runtime::VERSION - let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":0,\ - \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ + let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ + \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",5],\ [\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\ [\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\ - [\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":0}"; + [\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":1}"; let runtime: RuntimeVersion = serde_json::from_str(runtime_str).unwrap(); @@ -256,7 +255,7 @@ async fn follow_with_runtime() { Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone().into() })); // Runtime must always be reported with the first event. let expected = FollowEvent::Initialized(Initialized { - finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], finalized_block_runtime, with_runtime: false, }); @@ -359,7 +358,7 @@ async fn get_header() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Obtain the valid header. @@ -388,7 +387,7 @@ async fn get_body() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call. @@ -473,7 +472,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Pass an invalid parameters that cannot be decode. @@ -486,7 +485,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::json_rpc_spec::INVALID_PARAM_ERROR && err.message().contains("Invalid parameter") + Error::JsonRpc(err) if err.code() == super::error::json_rpc_spec::INVALID_PARAM_ERROR && err.message().contains("Invalid parameter") ); // Valid call. @@ -589,7 +588,7 @@ async fn call_runtime_without_flag() { .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_RUNTIME_CALL && err.message().contains("subscription was started with `withRuntime` set to `false`") + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_RUNTIME_CALL && err.message().contains("subscription was started with `withRuntime` set to `false`") ); } @@ -627,7 +626,7 @@ async fn get_storage_hash() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -895,7 +894,7 @@ async fn get_storage_value() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -1345,7 +1344,7 @@ async fn follow_generates_initial_blocks() { // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Initialized(Initialized { - finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], finalized_block_runtime: None, with_runtime: false, }); @@ -1571,7 +1570,7 @@ async fn follow_with_unpin() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // To not exceed the number of pinned blocks, we need to unpin before the next import. @@ -1617,6 +1616,108 @@ async fn follow_with_unpin() { assert!(sub.next::>().await.is_none()); } +#[tokio::test] +async fn unpin_duplicate_hashes() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: 3, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + }, + ) + .into_rpc(); + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let sub_id = sub.subscription_id(); + let sub_id = serde_json::to_string(&sub_id).unwrap(); + + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + // Try to unpin duplicate hashes. + let err = api + .call::<_, serde_json::Value>( + "chainHead_unstable_unpin", + rpc_params![&sub_id, vec![&block_hash, &block_hash]], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::JsonRpc(err) if err.code() == super::error::rpc_spec_v2::INVALID_DUPLICATE_HASHES && err.message() == "Received duplicate hashes for the `chainHead_unpin` method" + ); + + // Block tree: + // finalized_block -> block -> block2 + let block2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block.hash()) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_hash_2 = format!("{:?}", block2.header.hash()); + client.import(BlockOrigin::Own, block2.clone()).await.unwrap(); + + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + // Try to unpin duplicate hashes. + let err = api + .call::<_, serde_json::Value>( + "chainHead_unstable_unpin", + rpc_params![&sub_id, vec![&block_hash, &block_hash_2, &block_hash]], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::JsonRpc(err) if err.code() == super::error::rpc_spec_v2::INVALID_DUPLICATE_HASHES && err.message() == "Received duplicate hashes for the `chainHead_unpin` method" + ); + + // Can unpin blocks. + let _res: () = api + .call("chainHead_unstable_unpin", rpc_params![&sub_id, vec![&block_hash, &block_hash_2]]) + .await + .unwrap(); +} + #[tokio::test] async fn follow_with_multiple_unpin_hashes() { let builder = TestClientBuilder::new(); @@ -1720,7 +1821,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); let _res: () = api @@ -1737,7 +1838,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Unpin multiple blocks. @@ -1755,7 +1856,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); let err = api @@ -1766,7 +1867,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::JsonRpc(ref err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); } @@ -1795,7 +1896,7 @@ async fn follow_prune_best_block() { // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Initialized(Initialized { - finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], finalized_block_runtime: None, with_runtime: false, }); @@ -1980,6 +2081,7 @@ async fn follow_forks_pruned_block() { // ^^^ finalized // -> block 1 -> block 2_f -> block 3_f // + let finalized_hash = client.info().finalized_hash; let block_1 = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().genesis_hash) @@ -1989,6 +2091,7 @@ async fn follow_forks_pruned_block() { .build() .unwrap() .block; + let block_1_hash = block_1.header.hash(); client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); let block_2 = BlockBuilderBuilder::new(&*client) @@ -1999,6 +2102,7 @@ async fn follow_forks_pruned_block() { .build() .unwrap() .block; + let block_2_hash = block_2.header.hash(); client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); let block_3 = BlockBuilderBuilder::new(&*client) @@ -2055,7 +2159,12 @@ async fn follow_forks_pruned_block() { // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Initialized(Initialized { - finalized_block_hash: format!("{:?}", block_3_hash), + finalized_block_hashes: vec![ + format!("{:?}", finalized_hash), + format!("{:?}", block_1_hash), + format!("{:?}", block_2_hash), + format!("{:?}", block_3_hash), + ], finalized_block_runtime: None, with_runtime: false, }); @@ -2209,7 +2318,7 @@ async fn follow_report_multiple_pruned_block() { // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Initialized(Initialized { - finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], finalized_block_runtime: None, with_runtime: false, }); @@ -2531,7 +2640,7 @@ async fn follow_finalized_before_new_block() { let finalized_hash = client.info().finalized_hash; let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Initialized(Initialized { - finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], finalized_block_runtime: None, with_runtime: false, }); diff --git a/substrate/client/rpc-spec-v2/src/transaction/api.rs b/substrate/client/rpc-spec-v2/src/transaction/api.rs index 53c83b662a35fdcb67a5e212307c6b5ec7c2a61f..33af9c9533388a1e4d5832a390c8eb96da756905 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/api.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/api.rs @@ -18,8 +18,8 @@ //! API trait for transactions. -use crate::transaction::event::TransactionEvent; -use jsonrpsee::proc_macros::rpc; +use crate::transaction::{error::ErrorBroadcast, event::TransactionEvent}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use sp_core::Bytes; #[rpc(client, server)] @@ -28,6 +28,10 @@ pub trait TransactionApi { /// /// See [`TransactionEvent`](crate::transaction::event::TransactionEvent) for details on /// transaction life cycle. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. #[subscription( name = "transactionWatch_unstable_submitAndWatch" => "transactionWatch_unstable_watchEvent", unsubscribe = "transactionWatch_unstable_unwatch", @@ -35,3 +39,22 @@ pub trait TransactionApi { )] fn submit_and_watch(&self, bytes: Bytes); } + +#[rpc(client, server)] +pub trait TransactionBroadcastApi { + /// Broadcast an extrinsic to the chain. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "transaction_unstable_broadcast")] + fn broadcast(&self, bytes: Bytes) -> RpcResult>; + + /// Broadcast an extrinsic to the chain. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "transaction_unstable_stop")] + fn stop_broadcast(&self, operation_id: String) -> Result<(), ErrorBroadcast>; +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/error.rs b/substrate/client/rpc-spec-v2/src/transaction/error.rs index d2de07afd5955cd2d41148bab0119384b117bf42..116977af66001096ff7cb14775b768451833a866 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/error.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/error.rs @@ -21,6 +21,7 @@ //! Errors are interpreted as transaction events for subscriptions. use crate::transaction::event::{TransactionError, TransactionEvent}; +use jsonrpsee::types::error::ErrorObject; use sc_transaction_pool_api::error::Error as PoolError; use sp_runtime::transaction_validity::InvalidTransaction; @@ -98,3 +99,29 @@ impl From for TransactionEvent { } } } + +/// TransactionBroadcast error. +#[derive(Debug, thiserror::Error)] +pub enum ErrorBroadcast { + /// The provided operation ID is invalid. + #[error("Invalid operation id")] + InvalidOperationID, +} + +/// General purpose errors, as defined in +/// . +pub mod json_rpc_spec { + /// Invalid parameter error. + pub const INVALID_PARAM_ERROR: i32 = -32602; +} + +impl From for ErrorObject<'static> { + fn from(e: ErrorBroadcast) -> Self { + let msg = e.to_string(); + + match e { + ErrorBroadcast::InvalidOperationID => + ErrorObject::owned(json_rpc_spec::INVALID_PARAM_ERROR, msg, None::<()>), + } + } +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/event.rs b/substrate/client/rpc-spec-v2/src/transaction/event.rs index 8b80fcda17beb22cece35c928f10d72175fa9458..882ac8490b07c00432c4296964b7f995329df3dc 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/event.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/event.rs @@ -20,23 +20,6 @@ use serde::{Deserialize, Serialize}; -/// The transaction was broadcasted to a number of peers. -/// -/// # Note -/// -/// The RPC does not guarantee that the peers have received the -/// transaction. -/// -/// When the number of peers is zero, the event guarantees that -/// shutting down the local node will lead to the transaction -/// not being included in the chain. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TransactionBroadcasted { - /// The number of peers the transaction was broadcasted to. - pub num_peers: usize, -} - /// The transaction was included in a block of the chain. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -59,9 +42,6 @@ pub struct TransactionError { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionDropped { - /// True if the transaction was broadcasted to other peers and - /// may still be included in the block. - pub broadcasted: bool, /// Reason of the event. pub error: String, } @@ -70,20 +50,17 @@ pub struct TransactionDropped { /// /// The status events can be grouped based on their kinds as: /// -/// 1. Runtime validated the transaction: +/// 1. Runtime validated the transaction and it entered the pool: /// - `Validated` /// -/// 2. Inside the `Ready` queue: -/// - `Broadcast` -/// -/// 3. Leaving the pool: +/// 2. Leaving the pool: /// - `BestChainBlockIncluded` /// - `Invalid` /// -/// 4. Block finalized: +/// 3. Block finalized: /// - `Finalized` /// -/// 5. At any time: +/// 4. At any time: /// - `Dropped` /// - `Error` /// @@ -101,8 +78,6 @@ pub struct TransactionDropped { pub enum TransactionEvent { /// The transaction was validated by the runtime. Validated, - /// The transaction was broadcasted to a number of peers. - Broadcasted(TransactionBroadcasted), /// The transaction was included in a best block of the chain. /// /// # Note @@ -159,7 +134,6 @@ enum TransactionEventBlockIR { #[serde(tag = "event")] enum TransactionEventNonBlockIR { Validated, - Broadcasted(TransactionBroadcasted), Error(TransactionError), Invalid(TransactionError), Dropped(TransactionDropped), @@ -186,8 +160,6 @@ impl From> for TransactionEventIR { match value { TransactionEvent::Validated => TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Validated), - TransactionEvent::Broadcasted(event) => - TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Broadcasted(event)), TransactionEvent::BestChainBlockIncluded(event) => TransactionEventIR::Block(TransactionEventBlockIR::BestChainBlockIncluded(event)), TransactionEvent::Finalized(event) => @@ -207,8 +179,6 @@ impl From> for TransactionEvent { match value { TransactionEventIR::NonBlock(status) => match status { TransactionEventNonBlockIR::Validated => TransactionEvent::Validated, - TransactionEventNonBlockIR::Broadcasted(event) => - TransactionEvent::Broadcasted(event), TransactionEventNonBlockIR::Error(event) => TransactionEvent::Error(event), TransactionEventNonBlockIR::Invalid(event) => TransactionEvent::Invalid(event), TransactionEventNonBlockIR::Dropped(event) => TransactionEvent::Dropped(event), @@ -239,19 +209,6 @@ mod tests { assert_eq!(event_dec, event); } - #[test] - fn broadcasted_event() { - let event: TransactionEvent<()> = - TransactionEvent::Broadcasted(TransactionBroadcasted { num_peers: 2 }); - let ser = serde_json::to_string(&event).unwrap(); - - let exp = r#"{"event":"broadcasted","numPeers":2}"#; - assert_eq!(ser, exp); - - let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); - assert_eq!(event_dec, event); - } - #[test] fn best_chain_event() { let event: TransactionEvent<()> = TransactionEvent::BestChainBlockIncluded(None); @@ -320,13 +277,11 @@ mod tests { #[test] fn dropped_event() { - let event: TransactionEvent<()> = TransactionEvent::Dropped(TransactionDropped { - broadcasted: true, - error: "abc".to_string(), - }); + let event: TransactionEvent<()> = + TransactionEvent::Dropped(TransactionDropped { error: "abc".to_string() }); let ser = serde_json::to_string(&event).unwrap(); - let exp = r#"{"event":"dropped","broadcasted":true,"error":"abc"}"#; + let exp = r#"{"event":"dropped","error":"abc"}"#; assert_eq!(ser, exp); let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); diff --git a/substrate/client/rpc-spec-v2/src/transaction/mod.rs b/substrate/client/rpc-spec-v2/src/transaction/mod.rs index 212912ba1c728feb5e01614a74fcab09ce5bc079..514ccf047dc28570c78543755577661a6a7791af 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/mod.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/mod.rs @@ -25,14 +25,16 @@ //! //! Methods are prefixed by `transaction`. +#[cfg(test)] +mod tests; + pub mod api; pub mod error; pub mod event; pub mod transaction; +pub mod transaction_broadcast; -pub use api::TransactionApiServer; -pub use event::{ - TransactionBlock, TransactionBroadcasted, TransactionDropped, TransactionError, - TransactionEvent, -}; +pub use api::{TransactionApiServer, TransactionBroadcastApiServer}; +pub use event::{TransactionBlock, TransactionDropped, TransactionError, TransactionEvent}; pub use transaction::Transaction; +pub use transaction_broadcast::TransactionBroadcast; diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/executor.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/executor.rs new file mode 100644 index 0000000000000000000000000000000000000000..ff9aca79887c3f29025697f9f5832c914735e0d6 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/executor.rs @@ -0,0 +1,100 @@ +// 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 sp_core::{testing::TaskExecutor, traits::SpawnNamed}; +use std::sync::{atomic::AtomicUsize, Arc}; +use tokio::sync::mpsc; + +/// Wrap the `TaskExecutor` to know when the broadcast future is dropped. +#[derive(Clone)] +pub struct TaskExecutorBroadcast { + executor: TaskExecutor, + sender: mpsc::UnboundedSender<()>, + num_tasks: Arc, +} + +/// The channel that receives events when the broadcast futures are dropped. +pub type TaskExecutorRecv = mpsc::UnboundedReceiver<()>; + +/// The state of the `TaskExecutorBroadcast`. +pub struct TaskExecutorState { + pub recv: TaskExecutorRecv, + pub num_tasks: Arc, +} + +impl TaskExecutorState { + pub fn num_tasks(&self) -> usize { + self.num_tasks.load(std::sync::atomic::Ordering::Acquire) + } +} + +impl TaskExecutorBroadcast { + /// Construct a new `TaskExecutorBroadcast` and a receiver to know when the broadcast futures + /// are dropped. + pub fn new() -> (Self, TaskExecutorState) { + let (sender, recv) = mpsc::unbounded_channel(); + let num_tasks = Arc::new(AtomicUsize::new(0)); + + ( + Self { executor: TaskExecutor::new(), sender, num_tasks: num_tasks.clone() }, + TaskExecutorState { recv, num_tasks }, + ) + } +} + +impl SpawnNamed for TaskExecutorBroadcast { + fn spawn( + &self, + name: &'static str, + group: Option<&'static str>, + future: futures::future::BoxFuture<'static, ()>, + ) { + let sender = self.sender.clone(); + let num_tasks = self.num_tasks.clone(); + + let future = Box::pin(async move { + num_tasks.fetch_add(1, std::sync::atomic::Ordering::AcqRel); + future.await; + num_tasks.fetch_sub(1, std::sync::atomic::Ordering::AcqRel); + + let _ = sender.send(()); + }); + + self.executor.spawn(name, group, future) + } + + fn spawn_blocking( + &self, + name: &'static str, + group: Option<&'static str>, + future: futures::future::BoxFuture<'static, ()>, + ) { + let sender = self.sender.clone(); + let num_tasks = self.num_tasks.clone(); + + let future = Box::pin(async move { + num_tasks.fetch_add(1, std::sync::atomic::Ordering::AcqRel); + future.await; + num_tasks.fetch_sub(1, std::sync::atomic::Ordering::AcqRel); + + let _ = sender.send(()); + }); + + self.executor.spawn_blocking(name, group, future) + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..aa8ac572dec9d8d6de9212fcb94c97ce2b804da4 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/middleware_pool.rs @@ -0,0 +1,187 @@ +// 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 codec::Encode; +use futures::Future; +use sc_transaction_pool::BasicPool; +use sc_transaction_pool_api::{ + ImportNotificationStream, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, + TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, +}; + +use crate::hex_string; +use futures::{FutureExt, StreamExt}; + +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use std::{collections::HashMap, pin::Pin, sync::Arc}; +use substrate_test_runtime_transaction_pool::TestApi; +use tokio::sync::mpsc; + +pub type Block = substrate_test_runtime_client::runtime::Block; + +pub type TxTestPool = MiddlewarePool; +pub type TxStatusType = sc_transaction_pool_api::TransactionStatus< + sc_transaction_pool_api::TxHash, + sc_transaction_pool_api::BlockHash, +>; +pub type TxStatusTypeTest = TxStatusType; + +/// The type of the event that the middleware captures. +#[derive(Debug, PartialEq)] +pub enum MiddlewarePoolEvent { + TransactionStatus { + transaction: String, + status: sc_transaction_pool_api::TransactionStatus< + ::Hash, + ::Hash, + >, + }, + PoolError { + transaction: String, + err: String, + }, +} + +/// The channel that receives events when the broadcast futures are dropped. +pub type MiddlewarePoolRecv = mpsc::UnboundedReceiver; + +/// Add a middleware to the transaction pool. +/// +/// This wraps the `submit_and_watch` to gain access to the events. +pub struct MiddlewarePool { + pub inner_pool: Arc>, + /// Send the middleware events to the test. + sender: mpsc::UnboundedSender, +} + +impl MiddlewarePool { + /// Construct a new [`MiddlewarePool`]. + pub fn new(pool: Arc>) -> (Self, MiddlewarePoolRecv) { + let (sender, recv) = mpsc::unbounded_channel(); + (MiddlewarePool { inner_pool: pool, sender }, recv) + } +} + +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( + &self, + at: ::Hash, + source: TransactionSource, + xts: Vec>, + ) -> PoolFuture, Self::Error>>, Self::Error> { + self.inner_pool.submit_at(at, source, xts) + } + + fn submit_one( + &self, + at: ::Hash, + source: TransactionSource, + xt: TransactionFor, + ) -> PoolFuture, Self::Error> { + self.inner_pool.submit_one(at, source, xt) + } + + 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(); + let transaction = hex_string(&xt.encode()); + + 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(), + }); + + status + }); + + Ok(watcher.boxed()) + } + .boxed() + } + + fn remove_invalid(&self, hashes: &[TxHash]) -> Vec> { + self.inner_pool.remove_invalid(hashes) + } + + fn status(&self) -> PoolStatus { + self.inner_pool.status() + } + + fn import_notification_stream(&self) -> ImportNotificationStream> { + self.inner_pool.import_notification_stream() + } + + fn hash_of(&self, xt: &TransactionFor) -> TxHash { + self.inner_pool.hash_of(xt) + } + + fn on_broadcasted(&self, propagations: HashMap, Vec>) { + self.inner_pool.on_broadcasted(propagations) + } + + fn ready_transaction(&self, hash: &TxHash) -> Option> { + self.inner_pool.ready_transaction(hash) + } + + fn ready_at( + &self, + at: NumberFor, + ) -> Pin< + Box< + dyn Future< + Output = Box> + Send>, + > + Send, + >, + > { + self.inner_pool.ready_at(at) + } + + fn ready(&self) -> Box> + Send> { + self.inner_pool.ready() + } + + fn futures(&self) -> Vec { + self.inner_pool.futures() + } +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/mod.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..ab0caaf906fd08049ccf6c9f421d3134d3689322 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/mod.rs @@ -0,0 +1,24 @@ +// 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 . + +mod executor; +mod middleware_pool; +#[macro_use] +mod setup; + +mod transaction_broadcast_tests; diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/setup.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/setup.rs new file mode 100644 index 0000000000000000000000000000000000000000..04ee7b9b4c94c4f3eac763ad06ba9b8964c2287e --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/setup.rs @@ -0,0 +1,120 @@ +// 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::{ + chain_head::test_utils::ChainHeadMockClient, + transaction::{ + api::TransactionBroadcastApiServer, + tests::executor::{TaskExecutorBroadcast, TaskExecutorState}, + TransactionBroadcast as RpcTransactionBroadcast, + }, +}; +use futures::Future; +use jsonrpsee::RpcModule; +use sc_transaction_pool::*; +use std::{pin::Pin, sync::Arc}; +use substrate_test_runtime_client::{prelude::*, Client}; +use substrate_test_runtime_transaction_pool::TestApi; + +use crate::transaction::tests::middleware_pool::{MiddlewarePool, MiddlewarePoolRecv}; + +pub type Block = substrate_test_runtime_client::runtime::Block; + +/// Initial Alice account nonce. +pub const ALICE_NONCE: u64 = 209; + +fn create_basic_pool_with_genesis( + test_api: Arc, + options: Options, +) -> (BasicPool, Pin + Send>>) { + let genesis_hash = { + test_api + .chain() + .read() + .block_by_number + .get(&0) + .map(|blocks| blocks[0].0.header.hash()) + .expect("there is block 0. qed") + }; + BasicPool::new_test(test_api, genesis_hash, genesis_hash, options) +} + +fn maintained_pool( + options: Options, +) -> (BasicPool, Arc, futures::executor::ThreadPool) { + let api = Arc::new(TestApi::with_alice_nonce(ALICE_NONCE)); + let (pool, background_task) = create_basic_pool_with_genesis(api.clone(), options); + + let thread_pool = futures::executor::ThreadPool::new().unwrap(); + thread_pool.spawn_ok(background_task); + (pool, api, thread_pool) +} + +pub fn setup_api( + options: Options, +) -> ( + Arc, + Arc, + Arc>>, + RpcModule>>>, + TaskExecutorState, + MiddlewarePoolRecv, +) { + let (pool, api, _) = maintained_pool(options); + let (pool, pool_state) = MiddlewarePool::new(Arc::new(pool).clone()); + let pool = Arc::new(pool); + + let builder = TestClientBuilder::new(); + let client = Arc::new(builder.build()); + let client_mock = Arc::new(ChainHeadMockClient::new(client.clone())); + + let (task_executor, executor_recv) = TaskExecutorBroadcast::new(); + + let tx_api = + RpcTransactionBroadcast::new(client_mock.clone(), pool.clone(), Arc::new(task_executor)) + .into_rpc(); + + (api, pool, client_mock, tx_api, executor_recv, pool_state) +} + +/// Get the next event from the provided middleware in at most 5 seconds. +macro_rules! get_next_event { + ($middleware:expr) => { + tokio::time::timeout(std::time::Duration::from_secs(5), $middleware.recv()) + .await + .unwrap() + .unwrap() + }; +} + +/// Collect the next number of transaction events from the provided middleware. +macro_rules! get_next_tx_events { + ($middleware:expr, $num:expr) => {{ + let mut events = std::collections::HashMap::new(); + for _ in 0..$num { + let event = get_next_event!($middleware); + match event { + crate::transaction::tests::middleware_pool::MiddlewarePoolEvent::TransactionStatus { transaction, status } => { + events.entry(transaction).or_insert_with(|| vec![]).push(status); + }, + other => panic!("Expected TransactionStatus, received {:?}", other), + }; + } + events + }}; +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..690a1a64d7460c656f5180c59120c951dfb04472 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs @@ -0,0 +1,523 @@ +// 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::{hex_string, transaction::error::json_rpc_spec}; +use assert_matches::assert_matches; +use codec::Encode; +use jsonrpsee::{rpc_params, MethodsError as Error}; +use sc_transaction_pool::{Options, PoolLimit}; +use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionPool}; +use std::sync::Arc; +use substrate_test_runtime_client::AccountKeyring::*; +use substrate_test_runtime_transaction_pool::uxt; + +// Test helpers. +use crate::transaction::tests::{ + middleware_pool::{MiddlewarePoolEvent, TxStatusTypeTest}, + setup::{setup_api, ALICE_NONCE}, +}; + +#[tokio::test] +async fn tx_broadcast_enters_pool() { + let (api, pool, client_mock, tx_api, mut exec_middleware, mut pool_middleware) = + setup_api(Default::default()); + + // Start at block 1. + let block_1_header = api.push_block(1, vec![], true); + + let uxt = uxt(Alice, ALICE_NONCE); + let xt = hex_string(&uxt.encode()); + + let operation_id: String = + tx_api.call("transaction_unstable_broadcast", rpc_params![&xt]).await.unwrap(); + + // Announce block 1 to `transaction_unstable_broadcast`. + client_mock.trigger_import_stream(block_1_header).await; + + // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction pool. + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::Ready + } + ); + + assert_eq!(1, pool.inner_pool.status().ready); + assert_eq!(uxt.encode().len(), pool.inner_pool.status().ready_bytes); + + // Import block 2 with the transaction included. + let block_2_header = api.push_block(2, vec![uxt.clone()], true); + let block_2 = block_2_header.hash(); + + // Announce block 2 to the pool. + let event = ChainEvent::NewBestBlock { hash: block_2, tree_route: None }; + pool.inner_pool.maintain(event).await; + assert_eq!(0, pool.inner_pool.status().ready); + + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::InBlock((block_2, 0)) + } + ); + + // The future broadcast awaits for the finalized status to be reached. + // Force the future to exit by calling stop. + let _: () = tx_api + .call("transaction_unstable_stop", rpc_params![&operation_id]) + .await + .unwrap(); + + // Ensure the broadcast future finishes. + let _ = get_next_event!(&mut exec_middleware.recv); + assert_eq!(0, exec_middleware.num_tasks()); +} + +#[tokio::test] +async fn tx_broadcast_invalid_tx() { + let (_, pool, _, tx_api, mut exec_middleware, _) = setup_api(Default::default()); + + // Invalid parameters. + let err = tx_api + .call::<_, serde_json::Value>("transaction_unstable_broadcast", [1u8]) + .await + .unwrap_err(); + assert_matches!(err, + Error::JsonRpc(err) if err.code() == json_rpc_spec::INVALID_PARAM_ERROR && err.message() == "Invalid params" + ); + + assert_eq!(0, pool.status().ready); + + // Invalid transaction that cannot be decoded. The broadcast silently exits. + let xt = "0xdeadbeef"; + let operation_id: String = + tx_api.call("transaction_unstable_broadcast", rpc_params![&xt]).await.unwrap(); + + assert_eq!(0, pool.status().ready); + + // Await the broadcast future to exit. + // Without this we'd be subject to races, where we try to call the stop before the tx is + // dropped. + let _ = get_next_event!(&mut exec_middleware.recv); + assert_eq!(0, exec_middleware.num_tasks()); + + // The broadcast future was dropped, and the operation is no longer active. + // When the operation is not active, either from the tx being finalized or a + // terminal error; the stop method should return an error. + let err = tx_api + .call::<_, serde_json::Value>("transaction_unstable_stop", rpc_params![&operation_id]) + .await + .unwrap_err(); + assert_matches!(err, + Error::JsonRpc(err) if err.code() == json_rpc_spec::INVALID_PARAM_ERROR && err.message() == "Invalid operation id" + ); +} + +#[tokio::test] +async fn tx_stop_with_invalid_operation_id() { + let (_, _, _, tx_api, _, _) = setup_api(Default::default()); + + // Make an invalid stop call. + let err = tx_api + .call::<_, serde_json::Value>("transaction_unstable_stop", ["invalid_operation_id"]) + .await + .unwrap_err(); + assert_matches!(err, + Error::JsonRpc(err) if err.code() == json_rpc_spec::INVALID_PARAM_ERROR && err.message() == "Invalid operation id" + ); +} + +#[tokio::test] +async fn tx_broadcast_resubmits_future_nonce_tx() { + let (api, pool, client_mock, tx_api, mut exec_middleware, mut pool_middleware) = + setup_api(Default::default()); + + // Start at block 1. + let block_1_header = api.push_block(1, vec![], true); + let block_1 = block_1_header.hash(); + + let current_uxt = uxt(Alice, ALICE_NONCE); + let current_xt = hex_string(¤t_uxt.encode()); + // This lives in the future. + let future_uxt = uxt(Alice, ALICE_NONCE + 1); + let future_xt = hex_string(&future_uxt.encode()); + + let future_operation_id: String = tx_api + .call("transaction_unstable_broadcast", rpc_params![&future_xt]) + .await + .unwrap(); + + // Announce block 1 to `transaction_unstable_broadcast`. + client_mock.trigger_import_stream(block_1_header).await; + + // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction pool. + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: future_xt.clone(), + status: TxStatusTypeTest::Future + } + ); + + let event = ChainEvent::NewBestBlock { hash: block_1, tree_route: None }; + pool.inner_pool.maintain(event).await; + assert_eq!(0, pool.inner_pool.status().ready); + // Ensure the tx is in the future. + assert_eq!(1, pool.inner_pool.status().future); + + let block_2_header = api.push_block(2, vec![], true); + let block_2 = block_2_header.hash(); + + let operation_id: String = tx_api + .call("transaction_unstable_broadcast", rpc_params![¤t_xt]) + .await + .unwrap(); + assert_ne!(future_operation_id, operation_id); + + // Announce block 2 to `transaction_unstable_broadcast`. + client_mock.trigger_import_stream(block_2_header).await; + + // Collect the events of both transactions. + let events = get_next_tx_events!(&mut pool_middleware, 2); + // Transactions entered the ready queue. + assert_eq!(events.get(¤t_xt).unwrap(), &vec![TxStatusTypeTest::Ready]); + assert_eq!(events.get(&future_xt).unwrap(), &vec![TxStatusTypeTest::Ready]); + + let event = ChainEvent::NewBestBlock { hash: block_2, tree_route: None }; + pool.inner_pool.maintain(event).await; + assert_eq!(2, pool.inner_pool.status().ready); + assert_eq!(0, pool.inner_pool.status().future); + + // Finalize transactions. + let block_3_header = api.push_block(3, vec![current_uxt, future_uxt], true); + let block_3 = block_3_header.hash(); + client_mock.trigger_import_stream(block_3_header).await; + + let event = ChainEvent::Finalized { hash: block_3, tree_route: Arc::from(vec![]) }; + pool.inner_pool.maintain(event).await; + assert_eq!(0, pool.inner_pool.status().ready); + assert_eq!(0, pool.inner_pool.status().future); + + let events = get_next_tx_events!(&mut pool_middleware, 4); + assert_eq!( + events.get(¤t_xt).unwrap(), + &vec![TxStatusTypeTest::InBlock((block_3, 0)), TxStatusTypeTest::Finalized((block_3, 0))] + ); + assert_eq!( + events.get(&future_xt).unwrap(), + &vec![TxStatusTypeTest::InBlock((block_3, 1)), TxStatusTypeTest::Finalized((block_3, 1))] + ); + + // Both broadcast futures must exit. + let _ = get_next_event!(&mut exec_middleware.recv); + let _ = get_next_event!(&mut exec_middleware.recv); + assert_eq!(0, exec_middleware.num_tasks()); +} + +/// This test is similar to `tx_broadcast_enters_pool` +/// However the last block is announced as finalized to force the +/// broadcast future to exit before the `stop` is called. +#[tokio::test] +async fn tx_broadcast_stop_after_broadcast_finishes() { + let (api, pool, client_mock, tx_api, mut exec_middleware, mut pool_middleware) = + setup_api(Default::default()); + + // Start at block 1. + let block_1_header = api.push_block(1, vec![], true); + + let uxt = uxt(Alice, ALICE_NONCE); + let xt = hex_string(&uxt.encode()); + + let operation_id: String = + tx_api.call("transaction_unstable_broadcast", rpc_params![&xt]).await.unwrap(); + + // Announce block 1 to `transaction_unstable_broadcast`. + client_mock.trigger_import_stream(block_1_header).await; + + // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction + // pool.inner_pool. + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::Ready + } + ); + + assert_eq!(1, pool.inner_pool.status().ready); + assert_eq!(uxt.encode().len(), pool.inner_pool.status().ready_bytes); + + // Import block 2 with the transaction included. + let block_2_header = api.push_block(2, vec![uxt.clone()], true); + let block_2 = block_2_header.hash(); + + // Announce block 2 to the pool.inner_pool. + let event = ChainEvent::Finalized { hash: block_2, tree_route: Arc::from(vec![]) }; + pool.inner_pool.maintain(event).await; + + assert_eq!(0, pool.inner_pool.status().ready); + + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::InBlock((block_2, 0)) + } + ); + + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::Finalized((block_2, 0)) + } + ); + + // Ensure the broadcast future terminated properly. + let _ = get_next_event!(&mut exec_middleware.recv); + assert_eq!(0, exec_middleware.num_tasks()); + + // The operation ID is no longer valid, check that the broadcast future + // cleared out the inner state of the operation. + let err = tx_api + .call::<_, serde_json::Value>("transaction_unstable_stop", rpc_params![&operation_id]) + .await + .unwrap_err(); + assert_matches!(err, + Error::JsonRpc(err) if err.code() == json_rpc_spec::INVALID_PARAM_ERROR && err.message() == "Invalid operation id" + ); +} + +#[tokio::test] +async fn tx_broadcast_resubmits_invalid_tx() { + let limits = PoolLimit { count: 8192, total_bytes: 20 * 1024 * 1024 }; + let options = Options { + ready: limits.clone(), + future: limits, + reject_future_transactions: false, + // This ensures that a transaction is not banned. + ban_time: std::time::Duration::ZERO, + }; + + let (api, pool, client_mock, tx_api, mut exec_middleware, mut pool_middleware) = + setup_api(options); + + let uxt = uxt(Alice, ALICE_NONCE); + let xt = hex_string(&uxt.encode()); + let _operation_id: String = + tx_api.call("transaction_unstable_broadcast", rpc_params![&xt]).await.unwrap(); + + let block_1_header = api.push_block(1, vec![], true); + let block_1 = block_1_header.hash(); + // Announce block 1 to `transaction_unstable_broadcast`. + client_mock.trigger_import_stream(block_1_header).await; + + // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction pool. + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::Ready, + } + ); + assert_eq!(1, pool.inner_pool.status().ready); + assert_eq!(uxt.encode().len(), pool.inner_pool.status().ready_bytes); + + // Mark the transaction as invalid from the API, causing a temporary ban. + api.add_invalid(&uxt); + + // Push an event to the pool to ensure the transaction is excluded. + let event = ChainEvent::NewBestBlock { hash: block_1, tree_route: None }; + pool.inner_pool.maintain(event).await; + assert_eq!(1, pool.inner_pool.status().ready); + + // Ensure the `transaction_unstable_broadcast` is aware of the invalid transaction. + let event = get_next_event!(&mut pool_middleware); + // Because we have received an `Invalid` status, we try to broadcast the transaction with the + // next announced block. + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::Invalid + } + ); + + // Import block 2. + let block_2_header = api.push_block(2, vec![], true); + client_mock.trigger_import_stream(block_2_header).await; + + // Ensure we propagate the temporary ban error to `submit_and_watch`. + // This ensures we'll loop again with the next annmounced block and try to resubmit the + // transaction. The transaction remains temporarily banned until the pool is maintained. + let event = get_next_event!(&mut pool_middleware); + assert_matches!(event, MiddlewarePoolEvent::PoolError { transaction, err } if transaction == xt && err.contains("Transaction temporarily Banned")); + + // Import block 3. + let block_3_header = api.push_block(3, vec![], true); + let block_3 = block_3_header.hash(); + // Remove the invalid transaction from the pool to allow it to pass through. + api.remove_invalid(&uxt); + let event = ChainEvent::NewBestBlock { hash: block_3, tree_route: None }; + // We have to maintain the pool to ensure the transaction is no longer invalid. + // This clears out the banned transactions. + pool.inner_pool.maintain(event).await; + assert_eq!(0, pool.inner_pool.status().ready); + + // Announce block to `transaction_unstable_broadcast`. + client_mock.trigger_import_stream(block_3_header).await; + + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::Ready, + } + ); + assert_eq!(1, pool.inner_pool.status().ready); + + let block_4_header = api.push_block(4, vec![uxt], true); + let block_4 = block_4_header.hash(); + let event = ChainEvent::Finalized { hash: block_4, tree_route: Arc::from(vec![]) }; + pool.inner_pool.maintain(event).await; + + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::InBlock((block_4, 0)), + } + ); + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: xt.clone(), + status: TxStatusTypeTest::Finalized((block_4, 0)), + } + ); + + // Ensure the broadcast future terminated properly. + let _ = get_next_event!(&mut exec_middleware.recv); + assert_eq!(0, exec_middleware.num_tasks()); +} + +/// This is similar to `tx_broadcast_resubmits_invalid_tx`. +/// However, it forces the tx to be resubmited because of the pool +/// limits. Which is a different code path than the invalid tx. +#[tokio::test] +async fn tx_broadcast_resubmits_dropped_tx() { + let limits = PoolLimit { count: 1, total_bytes: 1000 }; + let options = Options { + ready: limits.clone(), + future: limits, + reject_future_transactions: false, + // This ensures that a transaction is not banned. + ban_time: std::time::Duration::ZERO, + }; + + let (api, pool, client_mock, tx_api, _, mut pool_middleware) = setup_api(options); + + let current_uxt = uxt(Alice, ALICE_NONCE); + let current_xt = hex_string(¤t_uxt.encode()); + // This lives in the future. + let future_uxt = uxt(Alice, ALICE_NONCE + 1); + let future_xt = hex_string(&future_uxt.encode()); + + // By default the `validate_transaction` mock uses priority 1 for + // transactions. Bump the priority to ensure other transactions + // are immediately dropped. + api.set_priority(¤t_uxt, 10); + + let current_operation_id: String = tx_api + .call("transaction_unstable_broadcast", rpc_params![¤t_xt]) + .await + .unwrap(); + + // Announce block 1 to `transaction_unstable_broadcast`. + let block_1_header = api.push_block(1, vec![], true); + let event = + ChainEvent::Finalized { hash: block_1_header.hash(), tree_route: Arc::from(vec![]) }; + pool.inner_pool.maintain(event).await; + client_mock.trigger_import_stream(block_1_header).await; + + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::TransactionStatus { + transaction: current_xt.clone(), + status: TxStatusTypeTest::Ready, + } + ); + assert_eq!(1, pool.inner_pool.status().ready); + + // The future tx has priority 2, smaller than the current 10. + api.set_priority(&future_uxt, 2); + let future_operation_id: String = tx_api + .call("transaction_unstable_broadcast", rpc_params![&future_xt]) + .await + .unwrap(); + assert_ne!(current_operation_id, future_operation_id); + + let block_2_header = api.push_block(2, vec![], true); + let event = + ChainEvent::Finalized { hash: block_2_header.hash(), tree_route: Arc::from(vec![]) }; + pool.inner_pool.maintain(event).await; + client_mock.trigger_import_stream(block_2_header).await; + + // We must have at most 1 transaction in the pool, as per limits above. + assert_eq!(1, pool.inner_pool.status().ready); + + let event = get_next_event!(&mut pool_middleware); + assert_eq!( + event, + MiddlewarePoolEvent::PoolError { + transaction: future_xt.clone(), + err: "Transaction couldn't enter the pool because of the limit".into() + } + ); + + let block_3_header = api.push_block(3, vec![current_uxt], true); + let event = + ChainEvent::Finalized { hash: block_3_header.hash(), tree_route: Arc::from(vec![]) }; + pool.inner_pool.maintain(event).await; + client_mock.trigger_import_stream(block_3_header.clone()).await; + + // The first tx is in a finalzied block; the future tx must enter the pool. + let events = get_next_tx_events!(&mut pool_middleware, 3); + assert_eq!( + events.get(¤t_xt).unwrap(), + &vec![ + TxStatusTypeTest::InBlock((block_3_header.hash(), 0)), + TxStatusTypeTest::Finalized((block_3_header.hash(), 0)) + ] + ); + // The dropped transaction was resubmitted. + assert_eq!(events.get(&future_xt).unwrap(), &vec![TxStatusTypeTest::Ready]); +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs index b2cfa36c9c99f7bd3db5072e8adaabd1c6fed962..d44006392dca4a05a6c9f5bbf872c75bc7d5ee52 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs @@ -22,28 +22,22 @@ use crate::{ transaction::{ api::TransactionApiServer, error::Error, - event::{ - TransactionBlock, TransactionBroadcasted, TransactionDropped, TransactionError, - TransactionEvent, - }, + event::{TransactionBlock, TransactionDropped, TransactionError, TransactionEvent}, }, SubscriptionTaskExecutor, }; +use codec::Decode; +use futures::{StreamExt, TryFutureExt}; use jsonrpsee::{core::async_trait, types::error::ErrorObject, PendingSubscriptionSink}; +use sc_rpc::utils::pipe_from_stream; use sc_transaction_pool_api::{ error::IntoPoolError, BlockHash, TransactionFor, TransactionPool, TransactionSource, TransactionStatus, }; -use std::sync::Arc; - -use sc_rpc::utils::pipe_from_stream; -use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_runtime::traits::Block as BlockT; - -use codec::Decode; -use futures::{StreamExt, TryFutureExt}; +use std::sync::Arc; /// An API for transaction RPC calls. pub struct Transaction { @@ -82,7 +76,7 @@ where Pool: TransactionPool + Sync + Send + 'static, Pool::Hash: Unpin, ::Hash: Unpin, - Client: HeaderBackend + ProvideRuntimeApi + Send + Sync + 'static, + Client: HeaderBackend + Send + Sync + 'static, { fn submit_and_watch(&self, pending: PendingSubscriptionSink, xt: Bytes) { let client = self.client.clone(); @@ -116,9 +110,7 @@ where match submit.await { Ok(stream) => { - let mut state = TransactionState::new(); - let stream = - stream.filter_map(move |event| async move { state.handle_event(event) }); + let stream = stream.filter_map(move |event| async move { handle_event(event) }); pipe_from_stream(pending, stream.boxed()).await; }, Err(err) => { @@ -134,66 +126,34 @@ where } } -/// The transaction's state that needs to be preserved between -/// multiple events generated by the transaction-pool. -/// -/// # Note -/// -/// In the future, the RPC server can submit only the last event when multiple -/// identical events happen in a row. -#[derive(Clone, Copy)] -struct TransactionState { - /// True if the transaction was previously broadcasted. - broadcasted: bool, -} - -impl TransactionState { - /// Construct a new [`TransactionState`]. - pub fn new() -> Self { - TransactionState { broadcasted: false } - } - - /// Handle events generated by the transaction-pool and convert them - /// to the new API expected state. - #[inline] - pub fn handle_event( - &mut self, - event: TransactionStatus, - ) -> Option> { - match event { - TransactionStatus::Ready | TransactionStatus::Future => - Some(TransactionEvent::::Validated), - TransactionStatus::Broadcast(peers) => { - // Set the broadcasted flag once if we submitted the transaction to - // at least one peer. - self.broadcasted = self.broadcasted || !peers.is_empty(); - - Some(TransactionEvent::Broadcasted(TransactionBroadcasted { - num_peers: peers.len(), - })) - }, - TransactionStatus::InBlock((hash, index)) => - Some(TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock { - hash, - index, - }))), - TransactionStatus::Retracted(_) => Some(TransactionEvent::BestChainBlockIncluded(None)), - TransactionStatus::FinalityTimeout(_) => - Some(TransactionEvent::Dropped(TransactionDropped { - broadcasted: self.broadcasted, - error: "Maximum number of finality watchers has been reached".into(), - })), - TransactionStatus::Finalized((hash, index)) => - Some(TransactionEvent::Finalized(TransactionBlock { hash, index })), - TransactionStatus::Usurped(_) => Some(TransactionEvent::Invalid(TransactionError { - error: "Extrinsic was rendered invalid by another extrinsic".into(), - })), - TransactionStatus::Dropped => Some(TransactionEvent::Invalid(TransactionError { - error: "Extrinsic dropped from the pool due to exceeding limits".into(), - })), - TransactionStatus::Invalid => Some(TransactionEvent::Invalid(TransactionError { - error: "Extrinsic marked as invalid".into(), +/// Handle events generated by the transaction-pool and convert them +/// to the new API expected state. +#[inline] +pub fn handle_event( + event: TransactionStatus, +) -> Option> { + match event { + TransactionStatus::Ready | TransactionStatus::Future => + Some(TransactionEvent::::Validated), + TransactionStatus::InBlock((hash, index)) => + Some(TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock { hash, index }))), + TransactionStatus::Retracted(_) => Some(TransactionEvent::BestChainBlockIncluded(None)), + TransactionStatus::FinalityTimeout(_) => + Some(TransactionEvent::Dropped(TransactionDropped { + error: "Maximum number of finality watchers has been reached".into(), })), - } + TransactionStatus::Finalized((hash, index)) => + Some(TransactionEvent::Finalized(TransactionBlock { hash, index })), + TransactionStatus::Usurped(_) => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic was rendered invalid by another extrinsic".into(), + })), + TransactionStatus::Dropped => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic dropped from the pool due to exceeding limits".into(), + })), + TransactionStatus::Invalid => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic marked as invalid".into(), + })), + // These are the events that are not supported by the new API. + TransactionStatus::Broadcast(_) => None, } } diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs new file mode 100644 index 0000000000000000000000000000000000000000..92c838261874a816335b6d7e82c7df7667e2c235 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs @@ -0,0 +1,251 @@ +// 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 . + +//! API implementation for broadcasting transactions. + +use crate::{transaction::api::TransactionBroadcastApiServer, SubscriptionTaskExecutor}; +use codec::Decode; +use futures::{FutureExt, Stream, StreamExt}; +use futures_util::stream::AbortHandle; +use jsonrpsee::core::{async_trait, RpcResult}; +use parking_lot::RwLock; +use rand::{distributions::Alphanumeric, Rng}; +use sc_client_api::BlockchainEvents; +use sc_transaction_pool_api::{ + error::IntoPoolError, TransactionFor, TransactionPool, TransactionSource, +}; +use sp_blockchain::HeaderBackend; +use sp_core::Bytes; +use sp_runtime::traits::Block as BlockT; +use std::{collections::HashMap, sync::Arc}; + +use super::error::ErrorBroadcast; + +/// An API for transaction RPC calls. +pub struct TransactionBroadcast { + /// Substrate client. + client: Arc, + /// Transactions pool. + pool: Arc, + /// Executor to spawn subscriptions. + executor: SubscriptionTaskExecutor, + /// The brodcast operation IDs. + broadcast_ids: Arc>>, +} + +/// The state of a broadcast operation. +struct BroadcastState { + /// Handle to abort the running future that broadcasts the transaction. + handle: AbortHandle, +} + +impl TransactionBroadcast { + /// Creates a new [`TransactionBroadcast`]. + pub fn new(client: Arc, pool: Arc, executor: SubscriptionTaskExecutor) -> Self { + TransactionBroadcast { client, pool, executor, broadcast_ids: Default::default() } + } + + /// Generate an unique operation ID for the `transaction_broadcast` RPC method. + pub fn generate_unique_id(&self) -> String { + let generate_operation_id = || { + // The length of the operation ID. + const OPERATION_ID_LEN: usize = 16; + + rand::thread_rng() + .sample_iter(Alphanumeric) + .take(OPERATION_ID_LEN) + .map(char::from) + .collect::() + }; + + let mut id = generate_operation_id(); + + let broadcast_ids = self.broadcast_ids.read(); + + while broadcast_ids.contains_key(&id) { + id = generate_operation_id(); + } + + id + } +} + +/// Currently we treat all RPC transactions as externals. +/// +/// Possibly in the future we could allow opt-in for special treatment +/// of such transactions, so that the block authors can inject +/// some unique transactions via RPC and have them included in the pool. +const TX_SOURCE: TransactionSource = TransactionSource::External; + +#[async_trait] +impl TransactionBroadcastApiServer for TransactionBroadcast +where + Pool: TransactionPool + Sync + Send + 'static, + Pool::Error: IntoPoolError, + ::Hash: Unpin, + Client: HeaderBackend + BlockchainEvents + Send + Sync + 'static, +{ + fn broadcast(&self, bytes: Bytes) -> RpcResult> { + let pool = self.pool.clone(); + + // The unique ID of this operation. + let id = self.generate_unique_id(); + + let mut best_block_import_stream = + Box::pin(self.client.import_notification_stream().filter_map( + |notification| async move { notification.is_new_best.then_some(notification.hash) }, + )); + + let broadcast_transaction_fut = async move { + // There is nothing we could do with an extrinsic of invalid format. + let Ok(decoded_extrinsic) = TransactionFor::::decode(&mut &bytes[..]) else { + return; + }; + + // Flag to determine if the we should broadcast the transaction again. + let mut is_done = false; + + while !is_done { + // Wait for the last block to become available. + let Some(best_block_hash) = + last_stream_element(&mut best_block_import_stream).await + else { + return; + }; + + let mut stream = match pool + .submit_and_watch(best_block_hash, TX_SOURCE, decoded_extrinsic.clone()) + .await + { + Ok(stream) => stream, + // The transaction was not included to the pool. + Err(e) => { + let Ok(pool_err) = e.into_pool_error() else { return }; + + if pool_err.is_retriable() { + // Try to resubmit the transaction at a later block for + // recoverable errors. + continue + } else { + return; + } + }, + }; + + while let Some(event) = stream.next().await { + // Check if the transaction could be submitted again + // at a later time. + if event.is_retriable() { + break; + } + + // Stop if this is the final event of the transaction stream + // and the event is not retriable. + if event.is_final() { + is_done = true; + break; + } + } + } + }; + + // Convert the future into an abortable future, for easily terminating it from the + // `transaction_stop` method. + let (fut, handle) = futures::future::abortable(broadcast_transaction_fut); + let broadcast_ids = self.broadcast_ids.clone(); + let drop_id = id.clone(); + // The future expected by the executor must be `Future` instead of + // `Future>`. + let fut = fut.map(move |_| { + // Remove the entry from the broadcast IDs map. + broadcast_ids.write().remove(&drop_id); + }); + + // Keep track of this entry and the abortable handle. + { + let mut broadcast_ids = self.broadcast_ids.write(); + broadcast_ids.insert(id.clone(), BroadcastState { handle }); + } + + sc_rpc::utils::spawn_subscription_task(&self.executor, fut); + + Ok(Some(id)) + } + + fn stop_broadcast(&self, operation_id: String) -> Result<(), ErrorBroadcast> { + let mut broadcast_ids = self.broadcast_ids.write(); + + let Some(broadcast_state) = broadcast_ids.remove(&operation_id) else { + return Err(ErrorBroadcast::InvalidOperationID) + }; + + broadcast_state.handle.abort(); + + Ok(()) + } +} + +/// Returns the last element of the providided stream, or `None` if the stream is closed. +async fn last_stream_element(stream: &mut S) -> Option +where + S: Stream + Unpin, +{ + let Some(mut element) = stream.next().await else { return None }; + + // We are effectively polling the stream for the last available item at this time. + // The `now_or_never` returns `None` if the stream is `Pending`. + // + // If the stream contains `Hash0x1 Hash0x2 Hash0x3 Hash0x4`, we want only `Hash0x4`. + while let Some(next) = stream.next().now_or_never() { + let Some(next) = next else { + // Nothing to do if the stream terminated. + return None + }; + element = next; + } + + Some(element) +} + +#[cfg(test)] +mod tests { + use super::*; + use tokio_stream::wrappers::ReceiverStream; + + #[tokio::test] + async fn check_last_stream_element() { + let (tx, rx) = tokio::sync::mpsc::channel(16); + + let mut stream = ReceiverStream::new(rx); + // Check the stream with one element queued. + tx.send(1).await.unwrap(); + assert_eq!(last_stream_element(&mut stream).await, Some(1)); + + // Check the stream with multiple elements. + tx.send(1).await.unwrap(); + tx.send(2).await.unwrap(); + tx.send(3).await.unwrap(); + assert_eq!(last_stream_element(&mut stream).await, Some(3)); + + // Drop the stream with some elements + tx.send(1).await.unwrap(); + tx.send(2).await.unwrap(); + drop(tx); + assert_eq!(last_stream_element(&mut stream).await, None); + } +} diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index 6917eb0b551a98253c7908b353d8c40a581ff3b7..f65e6c9a59ec1c6c593d00c7639ca4bef26e4319 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" -jsonrpsee = { version = "0.20.3", features = ["server"] } -log = "0.4.17" +jsonrpsee = { version = "0.22", features = ["server"] } +log = { workspace = true, default-features = true } parking_lot = "0.12.1" -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } sc-block-builder = { path = "../block-builder" } sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } diff --git a/substrate/client/rpc/src/author/tests.rs b/substrate/client/rpc/src/author/tests.rs index 471016a015da124e839c65e54e73d58ad3ff22a4..937870eb53fd9b2ec4800c8eca343bb111560eef 100644 --- a/substrate/client/rpc/src/author/tests.rs +++ b/substrate/client/rpc/src/author/tests.rs @@ -21,10 +21,7 @@ use super::*; use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; use codec::Encode; -use jsonrpsee::{ - core::{EmptyServerParams as EmptyParams, Error as RpcError}, - RpcModule, -}; +use jsonrpsee::{core::EmptyServerParams as EmptyParams, MethodsError as RpcError, RpcModule}; use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::TransactionStatus; use sp_core::{ @@ -103,7 +100,7 @@ async fn author_submit_transaction_should_not_cause_error() { assert_matches!( api.call::<_, H256>("author_submitExtrinsic", [xt]).await, - Err(RpcError::Call(err)) if err.message().contains("Already Imported") && err.code() == 1013 + Err(RpcError::JsonRpc(err)) if err.message().contains("Already Imported") && err.code() == 1013 ); } @@ -160,7 +157,7 @@ async fn author_should_return_watch_validation_error() { assert_matches!( failed_sub, - Err(RpcError::Call(err)) if err.message().contains("Invalid Transaction") && err.code() == 1010 + Err(RpcError::JsonRpc(err)) if err.message().contains("Invalid Transaction") && err.code() == 1010 ); } @@ -276,7 +273,7 @@ async fn author_has_session_keys() { assert_matches!( api.call::<_, bool>("author_hasSessionKeys", vec![Bytes::from(vec![1, 2, 3])]).await, - Err(RpcError::Call(err)) if err.message().contains("Session keys are not encoded correctly") + Err(RpcError::JsonRpc(err)) if err.message().contains("Session keys are not encoded correctly") ); } diff --git a/substrate/client/rpc/src/dev/tests.rs b/substrate/client/rpc/src/dev/tests.rs index 5eb4897056cc438cc06bc3332056681136f82a9e..e8f9ba4990d255789cda8c92c17f71cca924399f 100644 --- a/substrate/client/rpc/src/dev/tests.rs +++ b/substrate/client/rpc/src/dev/tests.rs @@ -100,7 +100,7 @@ async fn deny_unsafe_works() { let (resp, _) = api.raw_json_request(&request, 1).await.expect("Raw calls should succeed"); assert_eq!( - resp.result, + resp, r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"# ); } diff --git a/substrate/client/rpc/src/state/tests.rs b/substrate/client/rpc/src/state/tests.rs index 25a34faed9a66c2cedadedfc1b71a397f37c4131..dd866e671c5095dca9b5851111340a4e32f71e67 100644 --- a/substrate/client/rpc/src/state/tests.rs +++ b/substrate/client/rpc/src/state/tests.rs @@ -21,7 +21,7 @@ use super::*; use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; use futures::executor; -use jsonrpsee::core::{EmptyServerParams as EmptyParams, Error as RpcError}; +use jsonrpsee::{core::EmptyServerParams as EmptyParams, MethodsError as RpcError}; use sc_block_builder::BlockBuilderBuilder; use sc_rpc_api::DenyUnsafe; use sp_consensus::BlockOrigin; @@ -475,7 +475,7 @@ async fn should_return_runtime_version() { // it is basically json-encoded substrate_test_runtime_client::runtime::VERSION let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ - \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ + \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",5],\ [\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\ [\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\ @@ -525,7 +525,7 @@ async fn wildcard_storage_subscriptions_are_rpc_unsafe() { let api_rpc = api.into_rpc(); let err = api_rpc.subscribe_unbounded("state_subscribeStorage", EmptyParams::new()).await; - assert_matches!(err, Err(RpcError::Call(e)) if e.message() == "RPC call is unsafe to be called externally"); + assert_matches!(err, Err(RpcError::JsonRpc(e)) if e.message() == "RPC call is unsafe to be called externally"); } #[tokio::test] diff --git a/substrate/client/rpc/src/system/tests.rs b/substrate/client/rpc/src/system/tests.rs index 21d13ccfafaa7fc46d6726966f66aa14f96fc595..03967c63523c79610009b0edb4ac4e6618b99040 100644 --- a/substrate/client/rpc/src/system/tests.rs +++ b/substrate/client/rpc/src/system/tests.rs @@ -19,10 +19,7 @@ use super::{helpers::SyncState, *}; use assert_matches::assert_matches; use futures::prelude::*; -use jsonrpsee::{ - core::{EmptyServerParams as EmptyParams, Error as RpcError}, - RpcModule, -}; +use jsonrpsee::{core::EmptyServerParams as EmptyParams, MethodsError as RpcError, RpcModule}; use sc_network::{self, config::Role, PeerId}; use sc_rpc_api::system::helpers::PeerInfo; use sc_utils::mpsc::tracing_unbounded; @@ -311,7 +308,7 @@ async fn system_network_add_reserved() { let bad_peer_id = ["/ip4/198.51.100.19/tcp/30333"]; assert_matches!( api(None).call::<_, ()>("system_addReservedPeer", bad_peer_id).await, - Err(RpcError::Call(err)) if err.message().contains("Peer id is missing from the address") + Err(RpcError::JsonRpc(err)) if err.message().contains("Peer id is missing from the address") ); } @@ -327,7 +324,7 @@ async fn system_network_remove_reserved() { assert_matches!( api(None).call::<_, String>("system_removeReservedPeer", bad_peer_id).await, - Err(RpcError::Call(err)) if err.message().contains("base-58 decode error: provided string contained invalid character '/' at byte 0") + Err(RpcError::JsonRpc(err)) if err.message().contains("base-58 decode error: provided string contained invalid character '/' at byte 0") ); } #[tokio::test] diff --git a/substrate/client/rpc/src/utils.rs b/substrate/client/rpc/src/utils.rs index b5ae4a2b6bc7fed26be4faf7c6ae9383dfdabd5f..6ec48efef846c719db4e009b3a14926db0577d5f 100644 --- a/substrate/client/rpc/src/utils.rs +++ b/substrate/client/rpc/src/utils.rs @@ -80,7 +80,7 @@ where Either::Left((Ok(sink), _)) => break sink, Either::Right((Some(msg), f)) => { if buf.push_back(msg).is_err() { - log::warn!(target: "rpc", "Subscription::accept failed buffer limit={} exceed; dropping subscription", buf.max_cap); + log::warn!(target: "rpc", "Subscription::accept failed buffer limit={} exceeded; dropping subscription", buf.max_cap); return } accept_fut = f; @@ -125,7 +125,13 @@ async fn inner_pipe_from_stream( // New item from the stream Either::Right((Either::Right((Some(v), n)), c)) => { if buf.push_back(v).is_err() { - log::warn!(target: "rpc", "Subscription buffer limit={} exceed; dropping subscription", buf.max_cap); + log::warn!( + target: "rpc", + "Subscription buffer limit={} exceeded for subscription={} conn_id={}; dropping subscription", + buf.max_cap, + sink.method_name(), + sink.connection_id() + ); return } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 1c95112aa6b0e714eeb0ea4cc24c76a026bf60b4..bbf67d1fbd0af6dceada3b73178004558044d0b2 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -28,17 +28,17 @@ runtime-benchmarks = [ ] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["server"] } -thiserror = "1.0.48" +jsonrpsee = { version = "0.22", features = ["server"] } +thiserror = { workspace = true } futures = "0.3.21" rand = "0.8.5" parking_lot = "0.12.1" -log = "0.4.17" +log = { workspace = true, default-features = true } futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.12" -serde = "1.0.195" -serde_json = "1.0.111" +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sc-keystore = { path = "../keystore" } sp-runtime = { path = "../../primitives/runtime" } sp-trie = { path = "../../primitives/trie" } @@ -84,6 +84,7 @@ tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "tim tempfile = "3.1.0" directories = "5.0.1" static_init = "1.0.3" +schnellru = "0.2.1" [dev-dependencies] substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index aa9c1b80a29a95bd77efbda35620c132b624bd9b..35e8b53a09cf2d802a0c4a873f7ecb8099764e83 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -19,8 +19,8 @@ //! Substrate Client use super::block_rules::{BlockRules, LookupResult as BlockLookupResult}; -use futures::{FutureExt, StreamExt}; -use log::{error, info, trace, warn}; +use crate::client::notification_pinning::NotificationPinningWorker; +use log::{debug, info, trace, warn}; use parking_lot::{Mutex, RwLock}; use prometheus_endpoint::Registry; use rand::Rng; @@ -38,7 +38,7 @@ use sc_client_api::{ execution_extensions::ExecutionExtensions, notifications::{StorageEventStream, StorageNotifications}, CallExecutor, ExecutorProvider, KeysIter, OnFinalityAction, OnImportAction, PairsIter, - ProofProvider, UsageProvider, + ProofProvider, UnpinWorkerMessage, UsageProvider, }; use sc_consensus::{ BlockCheckParams, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction, @@ -114,7 +114,7 @@ where block_rules: BlockRules, config: ClientConfig, telemetry: Option, - unpin_worker_sender: TracingUnboundedSender, + unpin_worker_sender: TracingUnboundedSender>, _phantom: PhantomData, } @@ -326,19 +326,35 @@ where // dropped, the block will be unpinned automatically. if let Some(ref notification) = finality_notification { if let Err(err) = self.backend.pin_block(notification.hash) { - error!( + debug!( "Unable to pin block for finality notification. hash: {}, Error: {}", notification.hash, err ); - }; + } else { + let _ = self + .unpin_worker_sender + .unbounded_send(UnpinWorkerMessage::AnnouncePin(notification.hash)) + .map_err(|e| { + log::error!( + "Unable to send AnnouncePin worker message for finality: {e}" + ) + }); + } } if let Some(ref notification) = import_notification { if let Err(err) = self.backend.pin_block(notification.hash) { - error!( + debug!( "Unable to pin block for import notification. hash: {}, Error: {}", notification.hash, err ); + } else { + let _ = self + .unpin_worker_sender + .unbounded_send(UnpinWorkerMessage::AnnouncePin(notification.hash)) + .map_err(|e| { + log::error!("Unable to send AnnouncePin worker message for import: {e}") + }); }; } @@ -416,25 +432,12 @@ where backend.commit_operation(op)?; } - let (unpin_worker_sender, mut rx) = - tracing_unbounded::("unpin-worker-channel", 10_000); - let task_backend = Arc::downgrade(&backend); - spawn_handle.spawn( - "unpin-worker", - None, - async move { - while let Some(message) = rx.next().await { - if let Some(backend) = task_backend.upgrade() { - backend.unpin_block(message); - } else { - log::debug!("Terminating unpin-worker, backend reference was dropped."); - return - } - } - log::debug!("Terminating unpin-worker, stream terminated.") - } - .boxed(), + let (unpin_worker_sender, rx) = tracing_unbounded::>( + "notification-pinning-worker-channel", + 10_000, ); + let unpin_worker = NotificationPinningWorker::new(rx, backend.clone()); + spawn_handle.spawn("notification-pinning-worker", None, Box::pin(unpin_worker.run())); Ok(Client { backend, @@ -675,8 +678,10 @@ where // This is use by fast sync for runtime version to be resolvable from // changes. - let state_version = - resolve_state_version_from_wasm(&storage, &self.executor)?; + let state_version = resolve_state_version_from_wasm::<_, HashingFor>( + &storage, + &self.executor, + )?; let state_root = operation.op.reset_storage(storage, state_version)?; if state_root != *import_headers.post().state_root() { // State root mismatch when importing state. This should not happen in diff --git a/substrate/client/service/src/client/mod.rs b/substrate/client/service/src/client/mod.rs index a13fd4317e1553d379ea068c516e74072d3c8c95..0703cc2b47d144d4e67418cfb9966cd1cd209392 100644 --- a/substrate/client/service/src/client/mod.rs +++ b/substrate/client/service/src/client/mod.rs @@ -47,6 +47,7 @@ mod block_rules; mod call_executor; mod client; +mod notification_pinning; mod wasm_override; mod wasm_substitutes; diff --git a/substrate/client/service/src/client/notification_pinning.rs b/substrate/client/service/src/client/notification_pinning.rs new file mode 100644 index 0000000000000000000000000000000000000000..80de91c02f1ae0273d42edc79d442aa312d09356 --- /dev/null +++ b/substrate/client/service/src/client/notification_pinning.rs @@ -0,0 +1,353 @@ +// 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 . + +//! Notification pinning related logic. +//! +//! This file contains a worker that should be started when a new client instance is created. +//! The goal is to avoid pruning of blocks that have active notifications in the node. Every +//! recipient of notifications should receive the chance to act upon them. In addition, notification +//! listeners can hold onto a [`sc_client_api::UnpinHandle`] to keep a block pinned. Once the handle +//! is dropped, a message is sent and the worker unpins the respective block. +use std::{ + marker::PhantomData, + sync::{Arc, Weak}, +}; + +use futures::StreamExt; +use sc_client_api::{Backend, UnpinWorkerMessage}; + +use sc_utils::mpsc::TracingUnboundedReceiver; +use schnellru::Limiter; +use sp_runtime::traits::Block as BlockT; + +const LOG_TARGET: &str = "db::notification_pinning"; +const NOTIFICATION_PINNING_LIMIT: usize = 1024; + +/// A limiter which automatically unpins blocks that leave the data structure. +#[derive(Clone, Debug)] +struct UnpinningByLengthLimiter> { + max_length: usize, + backend: Weak, + _phantom: PhantomData, +} + +impl> UnpinningByLengthLimiter { + /// Creates a new length limiter with a given `max_length`. + pub fn new(max_length: usize, backend: Weak) -> UnpinningByLengthLimiter { + UnpinningByLengthLimiter { max_length, backend, _phantom: PhantomData::::default() } + } +} + +impl> Limiter + for UnpinningByLengthLimiter +{ + type KeyToInsert<'a> = Block::Hash; + type LinkType = usize; + + fn is_over_the_limit(&self, length: usize) -> bool { + length > self.max_length + } + + fn on_insert( + &mut self, + _length: usize, + key: Self::KeyToInsert<'_>, + value: u32, + ) -> Option<(Block::Hash, u32)> { + log::debug!(target: LOG_TARGET, "Pinning block based on notification. hash = {key}"); + if self.max_length > 0 { + Some((key, value)) + } else { + None + } + } + + fn on_replace( + &mut self, + _length: usize, + _old_key: &mut Block::Hash, + _new_key: Block::Hash, + _old_value: &mut u32, + _new_value: &mut u32, + ) -> bool { + true + } + + fn on_removed(&mut self, key: &mut Block::Hash, references: &mut u32) { + // If reference count was larger than 0 on removal, + // the item was removed due to capacity limitations. + // Since the cache should be large enough for pinned items, + // we want to know about these evictions. + if *references > 0 { + log::warn!( + target: LOG_TARGET, + "Notification block pinning limit reached. Unpinning block with hash = {key:?}" + ); + if let Some(backend) = self.backend.upgrade() { + (0..*references).for_each(|_| backend.unpin_block(*key)); + } + } else { + log::trace!( + target: LOG_TARGET, + "Unpinned block. hash = {key:?}", + ) + } + } + + fn on_cleared(&mut self) {} + + fn on_grow(&mut self, _new_memory_usage: usize) -> bool { + true + } +} + +/// Worker for the handling of notification pinning. +/// +/// It receives messages from a receiver and pins/unpins based on the incoming messages. +/// All notification related unpinning should go through this worker. If the maximum number of +/// notification pins is reached, the block from the oldest notification is unpinned. +pub struct NotificationPinningWorker> { + unpin_message_rx: TracingUnboundedReceiver>, + task_backend: Weak, + pinned_blocks: schnellru::LruMap>, +} + +impl> NotificationPinningWorker { + /// Creates a new `NotificationPinningWorker`. + pub fn new( + unpin_message_rx: TracingUnboundedReceiver>, + task_backend: Arc, + ) -> Self { + let pinned_blocks = + schnellru::LruMap::>::new( + UnpinningByLengthLimiter::new( + NOTIFICATION_PINNING_LIMIT, + Arc::downgrade(&task_backend), + ), + ); + Self { unpin_message_rx, task_backend: Arc::downgrade(&task_backend), pinned_blocks } + } + + fn handle_announce_message(&mut self, hash: Block::Hash) { + if let Some(entry) = self.pinned_blocks.get_or_insert(hash, Default::default) { + *entry = *entry + 1; + } + } + + fn handle_unpin_message(&mut self, hash: Block::Hash) -> Result<(), ()> { + if let Some(refcount) = self.pinned_blocks.peek_mut(&hash) { + *refcount = *refcount - 1; + if *refcount == 0 { + self.pinned_blocks.remove(&hash); + } + if let Some(backend) = self.task_backend.upgrade() { + log::debug!(target: LOG_TARGET, "Reducing pinning refcount for block hash = {hash:?}"); + backend.unpin_block(hash); + } else { + log::debug!(target: LOG_TARGET, "Terminating unpin-worker, backend reference was dropped."); + return Err(()) + } + } else { + log::debug!(target: LOG_TARGET, "Received unpin message for already unpinned block. hash = {hash:?}"); + } + Ok(()) + } + + /// Start working on the received messages. + /// + /// The worker maintains a map which keeps track of the pinned blocks and their reference count. + /// Depending upon the received message, it acts to pin/unpin the block. + pub async fn run(mut self) { + while let Some(message) = self.unpin_message_rx.next().await { + match message { + UnpinWorkerMessage::AnnouncePin(hash) => self.handle_announce_message(hash), + UnpinWorkerMessage::Unpin(hash) => + if self.handle_unpin_message(hash).is_err() { + return + }, + } + } + log::debug!(target: LOG_TARGET, "Terminating unpin-worker, stream terminated.") + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use sc_client_api::{Backend, UnpinWorkerMessage}; + use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; + use sp_core::H256; + use sp_runtime::traits::Block as BlockT; + + type Block = substrate_test_runtime_client::runtime::Block; + + use super::{NotificationPinningWorker, UnpinningByLengthLimiter}; + + impl> NotificationPinningWorker { + fn new_with_limit( + unpin_message_rx: TracingUnboundedReceiver>, + task_backend: Arc, + limit: usize, + ) -> Self { + let pinned_blocks = + schnellru::LruMap::>::new( + UnpinningByLengthLimiter::new(limit, Arc::downgrade(&task_backend)), + ); + Self { unpin_message_rx, task_backend: Arc::downgrade(&task_backend), pinned_blocks } + } + + fn lru( + &self, + ) -> &schnellru::LruMap> { + &self.pinned_blocks + } + } + + #[test] + fn pinning_worker_handles_base_case() { + let (_tx, rx) = tracing_unbounded("testing", 1000); + + let backend = Arc::new(sc_client_api::in_mem::Backend::::new()); + + let hash = H256::random(); + + let mut worker = NotificationPinningWorker::new(rx, backend.clone()); + + // Block got pinned and unpin message should unpin in the backend. + let _ = backend.pin_block(hash); + assert_eq!(backend.pin_refs(&hash), Some(1)); + + worker.handle_announce_message(hash); + assert_eq!(worker.lru().len(), 1); + + let _ = worker.handle_unpin_message(hash); + + assert_eq!(backend.pin_refs(&hash), Some(0)); + assert!(worker.lru().is_empty()); + } + + #[test] + fn pinning_worker_handles_multiple_pins() { + let (_tx, rx) = tracing_unbounded("testing", 1000); + + let backend = Arc::new(sc_client_api::in_mem::Backend::::new()); + + let hash = H256::random(); + + let mut worker = NotificationPinningWorker::new(rx, backend.clone()); + // Block got pinned multiple times. + let _ = backend.pin_block(hash); + let _ = backend.pin_block(hash); + let _ = backend.pin_block(hash); + assert_eq!(backend.pin_refs(&hash), Some(3)); + + worker.handle_announce_message(hash); + worker.handle_announce_message(hash); + worker.handle_announce_message(hash); + assert_eq!(worker.lru().len(), 1); + + let _ = worker.handle_unpin_message(hash); + assert_eq!(backend.pin_refs(&hash), Some(2)); + let _ = worker.handle_unpin_message(hash); + assert_eq!(backend.pin_refs(&hash), Some(1)); + let _ = worker.handle_unpin_message(hash); + assert_eq!(backend.pin_refs(&hash), Some(0)); + assert!(worker.lru().is_empty()); + + let _ = worker.handle_unpin_message(hash); + assert_eq!(backend.pin_refs(&hash), Some(0)); + } + + #[test] + fn pinning_worker_handles_too_many_unpins() { + let (_tx, rx) = tracing_unbounded("testing", 1000); + + let backend = Arc::new(sc_client_api::in_mem::Backend::::new()); + + let hash = H256::random(); + let hash2 = H256::random(); + + let mut worker = NotificationPinningWorker::new(rx, backend.clone()); + // Block was announced once but unpinned multiple times. The worker should ignore the + // additional unpins. + let _ = backend.pin_block(hash); + let _ = backend.pin_block(hash); + let _ = backend.pin_block(hash); + assert_eq!(backend.pin_refs(&hash), Some(3)); + + worker.handle_announce_message(hash); + assert_eq!(worker.lru().len(), 1); + + let _ = worker.handle_unpin_message(hash); + assert_eq!(backend.pin_refs(&hash), Some(2)); + let _ = worker.handle_unpin_message(hash); + assert_eq!(backend.pin_refs(&hash), Some(2)); + assert!(worker.lru().is_empty()); + + let _ = worker.handle_unpin_message(hash2); + assert!(worker.lru().is_empty()); + assert_eq!(backend.pin_refs(&hash2), None); + } + + #[test] + fn pinning_worker_should_evict_when_limit_reached() { + let (_tx, rx) = tracing_unbounded("testing", 1000); + + let backend = Arc::new(sc_client_api::in_mem::Backend::::new()); + + let hash1 = H256::random(); + let hash2 = H256::random(); + let hash3 = H256::random(); + let hash4 = H256::random(); + + // Only two items fit into the cache. + let mut worker = NotificationPinningWorker::new_with_limit(rx, backend.clone(), 2); + + // Multiple blocks are announced but the cache size is too small. We expect that blocks + // are evicted by the cache and unpinned in the backend. + let _ = backend.pin_block(hash1); + let _ = backend.pin_block(hash2); + let _ = backend.pin_block(hash3); + assert_eq!(backend.pin_refs(&hash1), Some(1)); + assert_eq!(backend.pin_refs(&hash2), Some(1)); + assert_eq!(backend.pin_refs(&hash3), Some(1)); + + worker.handle_announce_message(hash1); + assert!(worker.lru().peek(&hash1).is_some()); + worker.handle_announce_message(hash2); + assert!(worker.lru().peek(&hash2).is_some()); + worker.handle_announce_message(hash3); + assert!(worker.lru().peek(&hash3).is_some()); + assert!(worker.lru().peek(&hash2).is_some()); + assert_eq!(worker.lru().len(), 2); + + // Hash 1 should have gotten unpinned, since its oldest. + assert_eq!(backend.pin_refs(&hash1), Some(0)); + assert_eq!(backend.pin_refs(&hash2), Some(1)); + assert_eq!(backend.pin_refs(&hash3), Some(1)); + + // Hash 2 is getting bumped. + worker.handle_announce_message(hash2); + assert_eq!(worker.lru().peek(&hash2), Some(&2)); + + // Since hash 2 was accessed, evict hash 3. + worker.handle_announce_message(hash4); + assert_eq!(worker.lru().peek(&hash3), None); + } +} diff --git a/substrate/client/service/src/config.rs b/substrate/client/service/src/config.rs index 3e68f5b58defc40b802b359e68b116a1fd734e15..35262ff493b44f07a94f1d35f1a3e765251a1897 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -18,6 +18,7 @@ //! Service configuration. +pub use jsonrpsee::server::BatchRequestConfig as RpcBatchRequestConfig; use prometheus_endpoint::Registry; use sc_chain_spec::ChainSpec; pub use sc_client_db::{BlocksPruning, Database, DatabaseSource, PruningMode}; @@ -39,6 +40,7 @@ use sp_core::crypto::SecretString; use std::{ io, iter, net::SocketAddr, + num::NonZeroU32, path::{Path, PathBuf}, }; use tempfile::TempDir; @@ -102,6 +104,10 @@ pub struct Configuration { pub rpc_port: u16, /// The number of messages the JSON-RPC server is allowed to keep in memory. pub rpc_message_buffer_capacity: u32, + /// JSON-RPC server batch config. + pub rpc_batch_config: RpcBatchRequestConfig, + /// RPC rate limit per minute. + pub rpc_rate_limit: Option, /// Prometheus endpoint configuration. `None` if disabled. pub prometheus_config: Option, /// Telemetry service URL. `None` if disabled. diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index a76e1544bfbb9882f34e5a465f20b4671160fe87..9480d4a0b07276a5131be17579964c04abda1f1d 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -38,7 +38,7 @@ use std::{collections::HashMap, net::SocketAddr}; use codec::{Decode, Encode}; use futures::{pin_mut, FutureExt, StreamExt}; -use jsonrpsee::{core::Error as JsonRpseeError, RpcModule}; +use jsonrpsee::RpcModule; use log::{debug, error, warn}; use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider}; use sc_network::{ @@ -109,17 +109,14 @@ impl RpcHandlers { pub async fn rpc_query( &self, json_query: &str, - ) -> Result<(String, tokio::sync::mpsc::Receiver), JsonRpseeError> { + ) -> Result<(String, tokio::sync::mpsc::Receiver), serde_json::Error> { // Because `tokio::sync::mpsc::channel` is used under the hood // it will panic if it's set to usize::MAX. // // This limit is used to prevent panics and is large enough. const TOKIO_MPSC_MAX_SIZE: usize = tokio::sync::Semaphore::MAX_PERMITS; - self.0 - .raw_json_request(json_query, TOKIO_MPSC_MAX_SIZE) - .await - .map(|(method_res, recv)| (method_res.result, recv)) + self.0.raw_json_request(json_query, TOKIO_MPSC_MAX_SIZE).await } /// Provides access to the underlying `RpcModule` @@ -396,6 +393,7 @@ where let server_config = sc_rpc_server::Config { addrs: [addr, backup_addr], + batch_config: config.rpc_batch_config, max_connections: config.rpc_max_connections, max_payload_in_mb: config.rpc_max_request_size, max_payload_out_mb: config.rpc_max_response_size, @@ -406,6 +404,7 @@ where id_provider: rpc_id_provider, cors: config.rpc_cors.as_ref(), tokio_handle: config.tokio_handle.clone(), + rate_limit: config.rpc_rate_limit, }; // TODO: https://github.com/paritytech/substrate/issues/13773 diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index 625d8286396e7778dd7271db772d143550dc6b5e..ee7e60f6011701f9d12fdb521db8226c883dbfe4 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -19,7 +19,7 @@ async-channel = "1.8.0" array-bytes = "6.1" fdlimit = "0.3.0" futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } parity-scale-codec = "3.6.1" parking_lot = "0.12.1" tempfile = "3.1.0" diff --git a/substrate/client/service/test/src/lib.rs b/substrate/client/service/test/src/lib.rs index 9b88300bf53048502f2579891886f2832ba6d530..349538965ee1fa04bd0acfff42b517ae40452c1c 100644 --- a/substrate/client/service/test/src/lib.rs +++ b/substrate/client/service/test/src/lib.rs @@ -29,7 +29,7 @@ use sc_network::{ use sc_network_sync::SyncingService; use sc_service::{ client::Client, - config::{BasePath, DatabaseSource, KeystoreConfig}, + config::{BasePath, DatabaseSource, KeystoreConfig, RpcBatchRequestConfig}, BlocksPruning, ChainSpecExtension, Configuration, Error, GenericChainSpec, Role, RuntimeGenesis, SpawnTaskHandle, TaskManager, }; @@ -254,6 +254,8 @@ fn node_config< rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, rpc_message_buffer_capacity: Default::default(), + rpc_batch_config: RpcBatchRequestConfig::Unlimited, + rpc_rate_limit: None, prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/client/state-db/Cargo.toml b/substrate/client/state-db/Cargo.toml index 3f86a0da88e4244573d43e19997ed6dadd05767f..400dda20c223443687292315b4974e5125570553 100644 --- a/substrate/client/state-db/Cargo.toml +++ b/substrate/client/state-db/Cargo.toml @@ -17,6 +17,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/statement-store/Cargo.toml b/substrate/client/statement-store/Cargo.toml index ed2292593790afbb61a20d588cda84c502189c7a..676f6cb36f67992c86db1174cbbf96e02e53d1b1 100644 --- a/substrate/client/statement-store/Cargo.toml +++ b/substrate/client/statement-store/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" parity-db = "0.4.12" tokio = { version = "1.22.0", features = ["time"] } diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index f4db58d6bb0ce364fd6c9402f1e7aa00f897cca9..b2120b3efc4396801bdbcaf0a7867ab6692908d3 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -12,9 +12,9 @@ homepage = "https://substrate.io" workspace = true [dependencies] -clap = { version = "4.4.18", features = ["derive", "string"] } -log = "0.4.17" +clap = { version = "4.5.1", features = ["derive", "string"] } +log = { workspace = true, default-features = true } fs4 = "0.7.0" sp-core = { path = "../../primitives/core" } tokio = { version = "1.22.0", features = ["time"] } -thiserror = "1.0.48" +thiserror = { workspace = true } diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 328ecd17f75b371311437c708a070f9f8137bc08..09dc611caa044debeabce4f15686465535f076ed 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" -thiserror = "1.0.48" +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } sc-consensus-babe = { path = "../consensus/babe" } diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index c09fa41d4df478b135315aea28516ed259d65d55..ba58452ffb58bfd737235beb285e6e46c992967d 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -19,13 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.19" libc = "0.2" -log = "0.4.17" +log = { workspace = true, default-features = true } rand = "0.8.5" rand_pcg = "0.3.1" derive_more = "0.99" regex = "1" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sc-telemetry = { path = "../telemetry" } sp-core = { path = "../../primitives/core" } sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 3270a2e148dbfe5ac2a83ddf6f7fdc1ebb2c279b..8ab00202f0ba6828dbf210e44d6337393ba1d391 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -20,12 +20,12 @@ targets = ["x86_64-unknown-linux-gnu"] chrono = "0.4.31" futures = "0.3.21" libp2p = { version = "0.51.4", features = ["dns", "tcp", "tokio", "wasm-ext", "websocket"] } -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" pin-project = "1.0.12" sc-utils = { path = "../utils" } rand = "0.8.5" -serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.111" -thiserror = "1.0.48" +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } wasm-timer = "0.2.5" diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index 9f0f5fb6936fe98df880b1c62188ef77f881802d..61e6f7d0bab5b2422b3354edb10e1753d3ef1e7a 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -22,12 +22,12 @@ chrono = "0.4.31" codec = { package = "parity-scale-codec", version = "3.6.1" } lazy_static = "1.4.0" libc = "0.2.152" -log = { version = "0.4.17" } +log = { workspace = true, default-features = true } parking_lot = "0.12.1" regex = "1.6.0" rustc-hash = "1.1.0" -serde = "1.0.195" -thiserror = "1.0.48" +serde = { workspace = true, default-features = true } +thiserror = { workspace = true } tracing = "0.1.29" tracing-log = "0.1.3" tracing-subscriber = { version = "0.2.25", features = ["parking_lot"] } diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 4a826d9f4fce07089a7c26e48621c2af6fb21e62..fec34aa0bca935e22f0f7d7faea17cac5d8f10bb 100644 --- a/substrate/client/tracing/proc-macro/Cargo.toml +++ b/substrate/client/tracing/proc-macro/Cargo.toml @@ -20,5 +20,5 @@ proc-macro = true [dependencies] proc-macro-crate = "3.0.0" proc-macro2 = "1.0.56" -quote = { version = "1.0.28", features = ["proc-macro"] } -syn = { version = "2.0.48", features = ["extra-traits", "full", "parsing", "proc-macro"] } +quote = { features = ["proc-macro"], workspace = true } +syn = { features = ["extra-traits", "full", "parsing", "proc-macro"], workspace = true } diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index b491f7bcafdabc53b172ed18cebf6f49d078391c..2ca37afd61b84a7228852290d5075841c993a503 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -21,10 +21,10 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" futures-timer = "3.0.2" linked-hash-map = "0.5.4" -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" -serde = { version = "1.0.195", features = ["derive"] } -thiserror = "1.0.48" +serde = { features = ["derive"], workspace = true, default-features = true } +thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } sc-client-api = { path = "../api" } sc-transaction-pool-api = { path = "api" } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index f5fba65a06839e61347372b80af1226e7be142af..d52e4783fabce48992dec01e83c61bc7a3074a20 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -15,12 +15,12 @@ workspace = true async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" -log = "0.4.17" -serde = { version = "1.0.195", features = ["derive"] } -thiserror = "1.0.48" +log = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +thiserror = { workspace = true } sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core", default-features = false } sp-runtime = { path = "../../../primitives/runtime", default-features = false } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { 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 e521502f66fb1cbd3e85ef4b85ec9839d83e8d9f..d0744bfa3e192bcd5e6795ee96540c503c8ebec5 100644 --- a/substrate/client/transaction-pool/api/src/error.rs +++ b/substrate/client/transaction-pool/api/src/error.rs @@ -71,6 +71,30 @@ pub enum Error { RejectedFutureTransaction, } +impl Error { + /// Returns true if the transaction could be re-submitted to the pool in the future. + /// + /// For example, `Error::ImmediatelyDropped` is retriable, because the transaction + /// may enter the pool if there is space for it in the future. + pub fn is_retriable(&self) -> bool { + match self { + // An invalid transaction is temporarily banned, however it can + // become valid at a later time. + Error::TemporarilyBanned | + // The pool is full at the moment. + Error::ImmediatelyDropped | + // The block id is not known to the pool. + // The node might be lagging behind, or during a warp sync. + Error::InvalidBlockId(_) | + // The pool is configured to not accept future transactions. + Error::RejectedFutureTransaction => { + true + } + _ => false + } + } +} + /// Transaction pool error conversion. pub trait IntoPoolError: std::error::Error + Send + Sized + Sync { /// Try to extract original `Error` diff --git a/substrate/client/transaction-pool/api/src/lib.rs b/substrate/client/transaction-pool/api/src/lib.rs index a795917528f9cca0831068fc77dd346fd2390838..0a313c5b782d90f9dab5e3de326160c37cc8a45d 100644 --- a/substrate/client/transaction-pool/api/src/lib.rs +++ b/substrate/client/transaction-pool/api/src/lib.rs @@ -62,20 +62,27 @@ impl PoolStatus { /// /// The status events can be grouped based on their kinds as: /// 1. Entering/Moving within the pool: -/// - `Future` -/// - `Ready` +/// - [Future](TransactionStatus::Future) +/// - [Ready](TransactionStatus::Ready) /// 2. Inside `Ready` queue: -/// - `Broadcast` +/// - [Broadcast](TransactionStatus::Broadcast) /// 3. Leaving the pool: -/// - `InBlock` -/// - `Invalid` -/// - `Usurped` -/// - `Dropped` +/// - [InBlock](TransactionStatus::InBlock) +/// - [Invalid](TransactionStatus::Invalid) +/// - [Usurped](TransactionStatus::Usurped) +/// - [Dropped](TransactionStatus::Dropped) /// 4. Re-entering the pool: -/// - `Retracted` +/// - [Retracted](TransactionStatus::Retracted) /// 5. Block finalized: -/// - `Finalized` -/// - `FinalityTimeout` +/// - [Finalized](TransactionStatus::Finalized) +/// - [FinalityTimeout](TransactionStatus::FinalityTimeout) +/// +/// Transactions are first placed in either the `Ready` or `Future` queues of the transaction pool. +/// Substrate validates the transaction before it enters the pool. +/// +/// A transaction is placed in the `Future` queue if it will become valid at a future time. +/// For example, submitting a transaction with a higher account nonce than the current +/// expected nonce will place the transaction in the `Future` queue. /// /// The events will always be received in the order described above, however /// there might be cases where transactions alternate between `Future` and `Ready` @@ -88,19 +95,37 @@ impl PoolStatus { /// 1. Due to possible forks, the transaction that ends up being in included /// in one block, may later re-enter the pool or be marked as invalid. /// 2. Transaction `Dropped` at one point, may later re-enter the pool if some other -/// transactions are removed. +/// transactions are removed. A `Dropped` transaction may re-enter the pool only if it is +/// resubmitted. /// 3. `Invalid` transaction may become valid at some point in the future. /// (Note that runtimes are encouraged to use `UnknownValidity` to inform the pool about -/// such case). +/// such case). An `Invalid` transaction may re-enter the pool only if it is resubmitted. /// 4. `Retracted` transactions might be included in some next block. /// -/// The stream is considered finished only when either `Finalized` or `FinalityTimeout` -/// event is triggered. You are however free to unsubscribe from notifications at any point. -/// The first one will be emitted when the block, in which transaction was included gets -/// finalized. The `FinalityTimeout` event will be emitted when the block did not reach finality +/// The `FinalityTimeout` event will be emitted when the block did not reach finality /// within 512 blocks. This either indicates that finality is not available for your chain, /// or that finality gadget is lagging behind. If you choose to wait for finality longer, you can /// re-subscribe for a particular transaction hash manually again. +/// +/// ### Last Event +/// +/// The stream is considered finished when one of the following events happen: +/// - [Finalized](TransactionStatus::Finalized) +/// - [FinalityTimeout](TransactionStatus::FinalityTimeout) +/// - [Usurped](TransactionStatus::Usurped) +/// - [Invalid](TransactionStatus::Invalid) +/// - [Dropped](TransactionStatus::Dropped) +/// +/// See [`TransactionStatus::is_final`] for more details. +/// +/// ### Resubmit Transactions +/// +/// Users might resubmit the transaction at a later time for the following events: +/// - [FinalityTimeout](TransactionStatus::FinalityTimeout) +/// - [Invalid](TransactionStatus::Invalid) +/// - [Dropped](TransactionStatus::Dropped) +/// +/// See [`TransactionStatus::is_retriable`] for more details. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum TransactionStatus { @@ -131,6 +156,38 @@ pub enum TransactionStatus { Invalid, } +impl TransactionStatus { + /// Returns true if this is the last event emitted by [`TransactionStatusStream`]. + pub fn is_final(&self) -> bool { + // The state must be kept in sync with `crate::graph::Sender`. + match self { + Self::Usurped(_) | + Self::Finalized(_) | + Self::FinalityTimeout(_) | + Self::Invalid | + Self::Dropped => true, + _ => false, + } + } + + /// Returns true if the transaction could be re-submitted to the pool in the future. + /// + /// For example, `TransactionStatus::Dropped` is retriable, because the transaction + /// may enter the pool if there is space for it in the future. + pub fn is_retriable(&self) -> bool { + match self { + // The number of finality watchers has been reached. + Self::FinalityTimeout(_) | + // An invalid transaction might be valid at a later time. + Self::Invalid | + // The transaction was dropped because of the limits of the pool. + // It can reenter the pool when other transactions are removed / finalized. + Self::Dropped => true, + _ => false, + } + } +} + /// The stream of transaction events. pub type TransactionStatusStream = dyn Stream> + Send; diff --git a/substrate/client/transaction-pool/src/lib.rs b/substrate/client/transaction-pool/src/lib.rs index faa3f455a580c8713ced21b14818da874fd972a7..730cfe367122b4a92c5d776743deba5136d6fa9e 100644 --- a/substrate/client/transaction-pool/src/lib.rs +++ b/substrate/client/transaction-pool/src/lib.rs @@ -164,8 +164,9 @@ where 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(Default::default(), true.into(), pool_api.clone())); + 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(), @@ -658,8 +659,13 @@ where }) .unwrap_or_default() .into_iter() - .filter(|tx| tx.is_signed().unwrap_or(true)); - + // TODO [#2415]: This isn't really what we mean - we really want a + // `tx.is_transaction`, since bare transactions may be gossipped as in the case + // of Frontier txs or claims. This will be sorted once we dispense with the + // concept of bare transactions and make inherents the only possible type of + // extrinsics which are bare. At this point we can change this to + // `tx.is_transaction()`. + .filter(|tx| !tx.is_bare()); let mut resubmitted_to_report = 0; resubmit_transactions.extend(block_transactions.into_iter().filter(|tx| { diff --git a/substrate/client/transaction-pool/tests/pool.rs b/substrate/client/transaction-pool/tests/pool.rs index 6b1a197440c11e69805465ed4c7195f07eaafc0f..461b9860d414a3495dc34bf4f149963fa4d0a903 100644 --- a/substrate/client/transaction-pool/tests/pool.rs +++ b/substrate/client/transaction-pool/tests/pool.rs @@ -73,7 +73,7 @@ fn create_basic_pool_with_genesis( .map(|blocks| blocks[0].0.header.hash()) .expect("there is block 0. qed") }; - BasicPool::new_test(test_api, genesis_hash, genesis_hash) + BasicPool::new_test(test_api, genesis_hash, genesis_hash, Default::default()) } fn create_basic_pool(test_api: TestApi) -> BasicPool { @@ -994,6 +994,7 @@ fn import_notification_to_pool_maintain_works() { )), best_hash, finalized_hash, + Default::default(), ) .0, ); diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml index ec7b3d0eb0dcbbb23e5512b4d3cf582a4eb25e54..7f604219bc09a96ebb8114df01e10f7d474a87f4 100644 --- a/substrate/client/utils/Cargo.toml +++ b/substrate/client/utils/Cargo.toml @@ -17,7 +17,7 @@ async-channel = "1.8.0" futures = "0.3.21" futures-timer = "3.0.2" lazy_static = "1.4.0" -log = "0.4" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" prometheus = { version = "0.13.0", default-features = false } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 9419eb15974b368cc706e9b7092f50e86149bb80..6746723e72f79498cf764199866936b93373858e 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -19,8 +19,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # external deps -parity-scale-codec = { version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.6.0", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.2.2", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.6.0", default-features = false, features = [ + "derive", +] } # primitive deps, used for developing FRAME pallets. sp-runtime = { default-features = false, path = "../primitives/runtime" } @@ -48,8 +52,7 @@ frame-executive = { default-features = false, path = "../frame/executive", optio frame-system-rpc-runtime-api = { default-features = false, path = "../frame/system/rpc/runtime-api", optional = true } docify = "0.2.7" -simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b", optional = true } -log = { version = "0.4.20", default-features = false } +log = { workspace = true } [dev-dependencies] pallet-examples = { path = "./examples" } @@ -58,8 +61,6 @@ pallet-examples = { path = "./examples" } default = ["runtime", "std"] experimental = ["frame-support/experimental"] runtime = [ - "frame-executive", - "frame-system-rpc-runtime-api", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -69,6 +70,9 @@ runtime = [ "sp-session", "sp-transaction-pool", "sp-version", + + "frame-executive", + "frame-system-rpc-runtime-api", ] std = [ "frame-executive?/std", @@ -78,7 +82,6 @@ std = [ "log/std", "parity-scale-codec/std", "scale-info/std", - "simple-mermaid", "sp-api?/std", "sp-arithmetic/std", "sp-block-builder?/std", diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index 955f9e268c6f1e80c778a596d171f74260a08c8e..bc873ad69c803a9f686d5329cffde11c76e8dc35 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { version = "6.1", optional = true } -log = { version = "0.4.14", default-features = false } +log = { workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index 9fe0e29b42cd9526a1e221531dd5946846b17b90..4ccd0fc08f6ac1c8ac7e6009b555a470eb4a2779 100644 --- a/substrate/frame/alliance/src/benchmarking.rs +++ b/substrate/frame/alliance/src/benchmarking.rs @@ -26,7 +26,7 @@ use core::{ }; use sp_runtime::traits::{Bounded, Hash, StaticLookup}; -use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, BenchmarkError}; +use frame_benchmarking::{account, v2::*, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System, RawOrigin as SystemOrigin}; diff --git a/substrate/frame/alliance/src/migration.rs b/substrate/frame/alliance/src/migration.rs index e3a44a7887e976cfa6c5d0cfd48c251348edb26b..432f09a16f47772ead741a0f312eefeb795e2d69 100644 --- a/substrate/frame/alliance/src/migration.rs +++ b/substrate/frame/alliance/src/migration.rs @@ -19,19 +19,19 @@ use crate::{Config, Pallet, Weight, LOG_TARGET}; use frame_support::{pallet_prelude::*, storage::migration, traits::OnRuntimeUpgrade}; use log; -/// The current storage version. +/// The in-code storage version. pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); /// Wrapper for all migrations of this pallet. pub fn migrate, I: 'static>() -> Weight { - let onchain_version = Pallet::::on_chain_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); let mut weight: Weight = Weight::zero(); - if onchain_version < 1 { + if on_chain_version < 1 { weight = weight.saturating_add(v0_to_v1::migrate::()); } - if onchain_version < 2 { + if on_chain_version < 2 { weight = weight.saturating_add(v1_to_v2::migrate::()); } diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index 4a65485ed8f6643e2ab38e49150eb3901ded7559..fd44d33ef93ce3a212d67847f021f2f91077d461 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -208,7 +208,7 @@ impl ProposalProvider for AllianceProposalProvider } fn proposal_of(proposal_hash: H256) -> Option { - AllianceMotion::proposal_of(proposal_hash) + pallet_collective::ProposalOf::::get(proposal_hash) } } diff --git a/substrate/frame/alliance/src/tests.rs b/substrate/frame/alliance/src/tests.rs index 8011627b237af15e8d30379bf14afc2564421050..710de5a54bc95a607b51f4078db94d7c24c92272 100644 --- a/substrate/frame/alliance/src/tests.rs +++ b/substrate/frame/alliance/src/tests.rs @@ -187,8 +187,8 @@ fn propose_works() { Box::new(proposal.clone()), proposal_len )); - assert_eq!(*AllianceMotion::proposals(), vec![hash]); - assert_eq!(AllianceMotion::proposal_of(&hash), Some(proposal)); + assert_eq!(*pallet_collective::Proposals::::get(), vec![hash]); + assert_eq!(pallet_collective::ProposalOf::::get(&hash), Some(proposal)); assert_eq!( System::events(), vec![EventRecord { diff --git a/substrate/frame/alliance/src/weights.rs b/substrate/frame/alliance/src/weights.rs index b5bb50957207f6c75cbca0479d97127ffcca572a..0b2d1fca43ca68d3691ee533cf451cc560108390 100644 --- a/substrate/frame/alliance/src/weights.rs +++ b/substrate/frame/alliance/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_alliance +//! Autogenerated weights for `pallet_alliance` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/alliance/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/alliance/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_alliance. +/// Weight functions needed for `pallet_alliance`. pub trait WeightInfo { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight; fn vote(m: u32, ) -> Weight; @@ -74,205 +73,209 @@ pub trait WeightInfo { fn abdicate_fellow_status() -> Weight; } -/// Weights for pallet_alliance using the Substrate node and recommended hardware. +/// Weights for `pallet_alliance` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion ProposalOf (r:1 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalCount (r:1 w:1) - /// Proof Skipped: AllianceMotion ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Voting (r:0 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:0 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `653 + m * (32 ±0) + p * (35 ±0)` + // Measured: `654 + m * (32 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` - // Minimum execution time: 36_908_000 picoseconds. - Weight::from_parts(39_040_304, 6676) - // Standard Error: 131 - .saturating_add(Weight::from_parts(781, 0).saturating_mul(b.into())) - // Standard Error: 1_375 - .saturating_add(Weight::from_parts(48_745, 0).saturating_mul(m.into())) - // Standard Error: 1_358 - .saturating_add(Weight::from_parts(148_047, 0).saturating_mul(p.into())) + // Minimum execution time: 30_801_000 picoseconds. + Weight::from_parts(32_942_969, 6676) + // Standard Error: 112 + .saturating_add(Weight::from_parts(614, 0).saturating_mul(b.into())) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(45_758, 0).saturating_mul(m.into())) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(136_600, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1042 + m * (64 ±0)` + // Measured: `1113 + m * (64 ±0)` // Estimated: `6676 + m * (64 ±0)` - // Minimum execution time: 30_166_000 picoseconds. - Weight::from_parts(32_798_454, 6676) - // Standard Error: 1_432 - .saturating_add(Weight::from_parts(83_001, 0).saturating_mul(m.into())) + // Minimum execution time: 29_705_000 picoseconds. + Weight::from_parts(30_274_070, 6676) + // Standard Error: 884 + .saturating_add(Weight::from_parts(71_178, 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())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:0 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `576 + m * (96 ±0) + p * (36 ±0)` + // Measured: `640 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 45_173_000 picoseconds. - Weight::from_parts(42_192_020, 6676) - // Standard Error: 1_456 - .saturating_add(Weight::from_parts(66_751, 0).saturating_mul(m.into())) - // Standard Error: 1_420 - .saturating_add(Weight::from_parts(158_161, 0).saturating_mul(p.into())) + // Minimum execution time: 38_596_000 picoseconds. + Weight::from_parts(36_445_536, 6676) + // Standard Error: 1_217 + .saturating_add(Weight::from_parts(69_976, 0).saturating_mul(m.into())) + // Standard Error: 1_187 + .saturating_add(Weight::from_parts(149_706, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:1 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[4, 100]`. /// 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: `1087 + m * (96 ±0) + p * (39 ±0)` + // Measured: `1220 + m * (96 ±0) + p * (39 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` - // Minimum execution time: 58_290_000 picoseconds. - Weight::from_parts(54_924_919, 6676) - // Standard Error: 157 - .saturating_add(Weight::from_parts(464, 0).saturating_mul(b.into())) - // Standard Error: 1_665 - .saturating_add(Weight::from_parts(73_183, 0).saturating_mul(m.into())) - // Standard Error: 1_623 - .saturating_add(Weight::from_parts(168_318, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 57_602_000 picoseconds. + Weight::from_parts(55_147_214, 6676) + // Standard Error: 127 + .saturating_add(Weight::from_parts(1_650, 0).saturating_mul(b.into())) + // Standard Error: 1_346 + .saturating_add(Weight::from_parts(56_056, 0).saturating_mul(m.into())) + // Standard Error: 1_312 + .saturating_add(Weight::from_parts(168_247, 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())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:1 w:0) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:0 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `577 + m * (96 ±0) + p * (36 ±0)` + // Measured: `641 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 46_794_000 picoseconds. - Weight::from_parts(43_092_958, 6676) - // Standard Error: 1_273 - .saturating_add(Weight::from_parts(71_054, 0).saturating_mul(m.into())) - // Standard Error: 1_257 - .saturating_add(Weight::from_parts(152_820, 0).saturating_mul(p.into())) + // Minimum execution time: 40_755_000 picoseconds. + Weight::from_parts(36_953_935, 6676) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(73_240, 0).saturating_mul(m.into())) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(149_412, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:1 w:0) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:0 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `684 + m * (96 ±0) + p * (35 ±0)` + // Measured: `694 + m * (96 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 47_338_000 picoseconds. - Weight::from_parts(41_257_479, 6676) - // Standard Error: 119 - .saturating_add(Weight::from_parts(1_019, 0).saturating_mul(b.into())) - // Standard Error: 1_277 - .saturating_add(Weight::from_parts(78_453, 0).saturating_mul(m.into())) - // Standard Error: 1_231 - .saturating_add(Weight::from_parts(150_991, 0).saturating_mul(p.into())) + // Minimum execution time: 41_113_000 picoseconds. + Weight::from_parts(36_610_116, 6676) + // Standard Error: 92 + .saturating_add(Weight::from_parts(1_157, 0).saturating_mul(b.into())) + // Standard Error: 984 + .saturating_add(Weight::from_parts(63_050, 0).saturating_mul(m.into())) + // Standard Error: 949 + .saturating_add(Weight::from_parts(150_420, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:2 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Members (r:1 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:1 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `217` + // Measured: `250` // Estimated: `12362` - // Minimum execution time: 35_012_000 picoseconds. - Weight::from_parts(24_288_079, 12362) - // Standard Error: 878 - .saturating_add(Weight::from_parts(153_615, 0).saturating_mul(m.into())) - // Standard Error: 867 - .saturating_add(Weight::from_parts(129_307, 0).saturating_mul(z.into())) + // Minimum execution time: 30_249_000 picoseconds. + Weight::from_parts(21_364_868, 12362) + // Standard Error: 887 + .saturating_add(Weight::from_parts(131_624, 0).saturating_mul(m.into())) + // Standard Error: 877 + .saturating_add(Weight::from_parts(105_379, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Alliance Members (r:2 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Alliance DepositOf (r:200 w:50) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) - /// Storage: System Account (r:50 w:50) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::DepositOf` (r:200 w:50) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:50 w:50) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `x` is `[1, 100]`. /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. @@ -280,14 +283,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` - // Minimum execution time: 309_235_000 picoseconds. - Weight::from_parts(311_279_000, 12362) - // Standard Error: 26_510 - .saturating_add(Weight::from_parts(543_475, 0).saturating_mul(x.into())) - // Standard Error: 26_382 - .saturating_add(Weight::from_parts(603_169, 0).saturating_mul(y.into())) - // Standard Error: 52_716 - .saturating_add(Weight::from_parts(16_264_836, 0).saturating_mul(z.into())) + // Minimum execution time: 307_414_000 picoseconds. + Weight::from_parts(309_960_000, 12362) + // Standard Error: 29_278 + .saturating_add(Weight::from_parts(588_774, 0).saturating_mul(x.into())) + // Standard Error: 29_137 + .saturating_add(Weight::from_parts(563_245, 0).saturating_mul(y.into())) + // Standard Error: 58_221 + .saturating_add(Weight::from_parts(13_947_604, 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()))) @@ -298,397 +301,401 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) } - /// Storage: Alliance Rule (r:0 w:1) - /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) + /// Storage: `Alliance::Rule` (r:0 w:1) + /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) fn set_rule() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_833_000 picoseconds. - Weight::from_parts(9_313_000, 0) + // Minimum execution time: 6_156_000 picoseconds. + Weight::from_parts(6_560_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) + /// 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: `246` + // Measured: `279` // Estimated: `10187` - // Minimum execution time: 12_231_000 picoseconds. - Weight::from_parts(12_761_000, 10187) + // Minimum execution time: 8_988_000 picoseconds. + Weight::from_parts(9_476_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .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) + /// Storage: `Alliance::Announcements` (r:1 w:1) + /// 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: `319` + // Measured: `352` // Estimated: `10187` - // Minimum execution time: 13_079_000 picoseconds. - Weight::from_parts(13_612_000, 10187) + // Minimum execution time: 10_126_000 picoseconds. + Weight::from_parts(10_755_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Alliance Members (r:3 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Alliance DepositOf (r:0 w:1) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Alliance::DepositOf` (r:0 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `468` + // Measured: `501` // Estimated: `18048` - // Minimum execution time: 44_574_000 picoseconds. - Weight::from_parts(46_157_000, 18048) + // Minimum execution time: 38_878_000 picoseconds. + Weight::from_parts(40_493_000, 18048) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Alliance Members (r:3 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) + /// 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: `367` + // Measured: `400` // Estimated: `18048` - // Minimum execution time: 26_114_000 picoseconds. - Weight::from_parts(27_069_000, 18048) + // Minimum execution time: 23_265_000 picoseconds. + Weight::from_parts(24_703_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Alliance Members (r:2 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `443` + // Measured: `476` // Estimated: `12362` - // Minimum execution time: 25_882_000 picoseconds. - Weight::from_parts(26_923_000, 12362) + // Minimum execution time: 23_049_000 picoseconds. + Weight::from_parts(23_875_000, 12362) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Alliance Members (r:4 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Alliance RetiringMembers (r:0 w:1) - /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Alliance::Members` (r:4 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::RetiringMembers` (r:0 w:1) + /// 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: `443` + // Measured: `476` // Estimated: `23734` - // Minimum execution time: 34_112_000 picoseconds. - Weight::from_parts(35_499_000, 23734) + // Minimum execution time: 29_124_000 picoseconds. + Weight::from_parts(30_369_000, 23734) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Alliance RetiringMembers (r:1 w:1) - /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: Alliance Members (r:1 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: Alliance DepositOf (r:1 w:1) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Alliance::RetiringMembers` (r:1 w:1) + /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Alliance::Members` (r:1 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::DepositOf` (r:1 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `687` + // Measured: `720` // Estimated: `6676` - // Minimum execution time: 41_239_000 picoseconds. - Weight::from_parts(42_764_000, 6676) + // Minimum execution time: 36_376_000 picoseconds. + Weight::from_parts(38_221_000, 6676) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Alliance Members (r:3 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Alliance DepositOf (r:1 w:1) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::DepositOf` (r:1 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `707` + // Measured: `740` // Estimated: `18048` - // Minimum execution time: 68_071_000 picoseconds. - Weight::from_parts(71_808_000, 18048) + // Minimum execution time: 56_560_000 picoseconds. + Weight::from_parts(58_621_000, 18048) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `279` // Estimated: `27187` - // Minimum execution time: 7_006_000 picoseconds. - Weight::from_parts(7_253_000, 27187) - // Standard Error: 3_403 - .saturating_add(Weight::from_parts(1_680_082, 0).saturating_mul(n.into())) - // Standard Error: 1_333 - .saturating_add(Weight::from_parts(72_943, 0).saturating_mul(l.into())) + // Minimum execution time: 5_191_000 picoseconds. + Weight::from_parts(5_410_000, 27187) + // Standard Error: 3_215 + .saturating_add(Weight::from_parts(1_018_569, 0).saturating_mul(n.into())) + // Standard Error: 1_259 + .saturating_add(Weight::from_parts(68_712, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + l * (100 ±0) + n * (289 ±0)` // Estimated: `27187` - // Minimum execution time: 7_292_000 picoseconds. - Weight::from_parts(7_629_000, 27187) - // Standard Error: 176_225 - .saturating_add(Weight::from_parts(16_646_429, 0).saturating_mul(n.into())) - // Standard Error: 69_017 - .saturating_add(Weight::from_parts(310_978, 0).saturating_mul(l.into())) + // Minimum execution time: 5_361_000 picoseconds. + Weight::from_parts(5_494_000, 27187) + // Standard Error: 181_133 + .saturating_add(Weight::from_parts(16_322_982, 0).saturating_mul(n.into())) + // Standard Error: 70_940 + .saturating_add(Weight::from_parts(343_581, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Alliance Members (r:3 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:3 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `443` + // Measured: `476` // Estimated: `18048` - // Minimum execution time: 31_798_000 picoseconds. - Weight::from_parts(33_463_000, 18048) + // Minimum execution time: 28_856_000 picoseconds. + Weight::from_parts(29_875_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion ProposalOf (r:1 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalCount (r:1 w:1) - /// Proof Skipped: AllianceMotion ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Voting (r:0 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:0 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `653 + m * (32 ±0) + p * (35 ±0)` + // Measured: `654 + m * (32 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` - // Minimum execution time: 36_908_000 picoseconds. - Weight::from_parts(39_040_304, 6676) - // Standard Error: 131 - .saturating_add(Weight::from_parts(781, 0).saturating_mul(b.into())) - // Standard Error: 1_375 - .saturating_add(Weight::from_parts(48_745, 0).saturating_mul(m.into())) - // Standard Error: 1_358 - .saturating_add(Weight::from_parts(148_047, 0).saturating_mul(p.into())) + // Minimum execution time: 30_801_000 picoseconds. + Weight::from_parts(32_942_969, 6676) + // Standard Error: 112 + .saturating_add(Weight::from_parts(614, 0).saturating_mul(b.into())) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(45_758, 0).saturating_mul(m.into())) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(136_600, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1042 + m * (64 ±0)` + // Measured: `1113 + m * (64 ±0)` // Estimated: `6676 + m * (64 ±0)` - // Minimum execution time: 30_166_000 picoseconds. - Weight::from_parts(32_798_454, 6676) - // Standard Error: 1_432 - .saturating_add(Weight::from_parts(83_001, 0).saturating_mul(m.into())) + // Minimum execution time: 29_705_000 picoseconds. + Weight::from_parts(30_274_070, 6676) + // Standard Error: 884 + .saturating_add(Weight::from_parts(71_178, 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())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:0 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `576 + m * (96 ±0) + p * (36 ±0)` + // Measured: `640 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 45_173_000 picoseconds. - Weight::from_parts(42_192_020, 6676) - // Standard Error: 1_456 - .saturating_add(Weight::from_parts(66_751, 0).saturating_mul(m.into())) - // Standard Error: 1_420 - .saturating_add(Weight::from_parts(158_161, 0).saturating_mul(p.into())) + // Minimum execution time: 38_596_000 picoseconds. + Weight::from_parts(36_445_536, 6676) + // Standard Error: 1_217 + .saturating_add(Weight::from_parts(69_976, 0).saturating_mul(m.into())) + // Standard Error: 1_187 + .saturating_add(Weight::from_parts(149_706, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:1 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[4, 100]`. /// 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: `1087 + m * (96 ±0) + p * (39 ±0)` + // Measured: `1220 + m * (96 ±0) + p * (39 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` - // Minimum execution time: 58_290_000 picoseconds. - Weight::from_parts(54_924_919, 6676) - // Standard Error: 157 - .saturating_add(Weight::from_parts(464, 0).saturating_mul(b.into())) - // Standard Error: 1_665 - .saturating_add(Weight::from_parts(73_183, 0).saturating_mul(m.into())) - // Standard Error: 1_623 - .saturating_add(Weight::from_parts(168_318, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 57_602_000 picoseconds. + Weight::from_parts(55_147_214, 6676) + // Standard Error: 127 + .saturating_add(Weight::from_parts(1_650, 0).saturating_mul(b.into())) + // Standard Error: 1_346 + .saturating_add(Weight::from_parts(56_056, 0).saturating_mul(m.into())) + // Standard Error: 1_312 + .saturating_add(Weight::from_parts(168_247, 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())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:1 w:0) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:0 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `577 + m * (96 ±0) + p * (36 ±0)` + // Measured: `641 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 46_794_000 picoseconds. - Weight::from_parts(43_092_958, 6676) - // Standard Error: 1_273 - .saturating_add(Weight::from_parts(71_054, 0).saturating_mul(m.into())) - // Standard Error: 1_257 - .saturating_add(Weight::from_parts(152_820, 0).saturating_mul(p.into())) + // Minimum execution time: 40_755_000 picoseconds. + Weight::from_parts(36_953_935, 6676) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(73_240, 0).saturating_mul(m.into())) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(149_412, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:1 w:0) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Voting (r:1 w:1) - /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:1 w:0) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:1 w:0) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Proposals (r:1 w:1) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion ProposalOf (r:0 w:1) - /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:1 w:0) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Voting` (r:1 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:1 w:0) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:1 w:0) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `684 + m * (96 ±0) + p * (35 ±0)` + // Measured: `694 + m * (96 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 47_338_000 picoseconds. - Weight::from_parts(41_257_479, 6676) - // Standard Error: 119 - .saturating_add(Weight::from_parts(1_019, 0).saturating_mul(b.into())) - // Standard Error: 1_277 - .saturating_add(Weight::from_parts(78_453, 0).saturating_mul(m.into())) - // Standard Error: 1_231 - .saturating_add(Weight::from_parts(150_991, 0).saturating_mul(p.into())) + // Minimum execution time: 41_113_000 picoseconds. + Weight::from_parts(36_610_116, 6676) + // Standard Error: 92 + .saturating_add(Weight::from_parts(1_157, 0).saturating_mul(b.into())) + // Standard Error: 984 + .saturating_add(Weight::from_parts(63_050, 0).saturating_mul(m.into())) + // Standard Error: 949 + .saturating_add(Weight::from_parts(150_420, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Alliance Members (r:2 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Members (r:1 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:1 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `217` + // Measured: `250` // Estimated: `12362` - // Minimum execution time: 35_012_000 picoseconds. - Weight::from_parts(24_288_079, 12362) - // Standard Error: 878 - .saturating_add(Weight::from_parts(153_615, 0).saturating_mul(m.into())) - // Standard Error: 867 - .saturating_add(Weight::from_parts(129_307, 0).saturating_mul(z.into())) + // Minimum execution time: 30_249_000 picoseconds. + Weight::from_parts(21_364_868, 12362) + // Standard Error: 887 + .saturating_add(Weight::from_parts(131_624, 0).saturating_mul(m.into())) + // Standard Error: 877 + .saturating_add(Weight::from_parts(105_379, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Alliance Members (r:2 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Alliance DepositOf (r:200 w:50) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) - /// Storage: System Account (r:50 w:50) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::DepositOf` (r:200 w:50) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:50 w:50) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `x` is `[1, 100]`. /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. @@ -696,14 +703,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` - // Minimum execution time: 309_235_000 picoseconds. - Weight::from_parts(311_279_000, 12362) - // Standard Error: 26_510 - .saturating_add(Weight::from_parts(543_475, 0).saturating_mul(x.into())) - // Standard Error: 26_382 - .saturating_add(Weight::from_parts(603_169, 0).saturating_mul(y.into())) - // Standard Error: 52_716 - .saturating_add(Weight::from_parts(16_264_836, 0).saturating_mul(z.into())) + // Minimum execution time: 307_414_000 picoseconds. + Weight::from_parts(309_960_000, 12362) + // Standard Error: 29_278 + .saturating_add(Weight::from_parts(588_774, 0).saturating_mul(x.into())) + // Standard Error: 29_137 + .saturating_add(Weight::from_parts(563_245, 0).saturating_mul(y.into())) + // Standard Error: 58_221 + .saturating_add(Weight::from_parts(13_947_604, 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()))) @@ -714,194 +721,194 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) } - /// Storage: Alliance Rule (r:0 w:1) - /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) + /// Storage: `Alliance::Rule` (r:0 w:1) + /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) fn set_rule() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_833_000 picoseconds. - Weight::from_parts(9_313_000, 0) + // Minimum execution time: 6_156_000 picoseconds. + Weight::from_parts(6_560_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) + /// 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: `246` + // Measured: `279` // Estimated: `10187` - // Minimum execution time: 12_231_000 picoseconds. - Weight::from_parts(12_761_000, 10187) + // Minimum execution time: 8_988_000 picoseconds. + Weight::from_parts(9_476_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .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) + /// Storage: `Alliance::Announcements` (r:1 w:1) + /// 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: `319` + // Measured: `352` // Estimated: `10187` - // Minimum execution time: 13_079_000 picoseconds. - Weight::from_parts(13_612_000, 10187) + // Minimum execution time: 10_126_000 picoseconds. + Weight::from_parts(10_755_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Alliance Members (r:3 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Alliance DepositOf (r:0 w:1) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Alliance::DepositOf` (r:0 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `468` + // Measured: `501` // Estimated: `18048` - // Minimum execution time: 44_574_000 picoseconds. - Weight::from_parts(46_157_000, 18048) + // Minimum execution time: 38_878_000 picoseconds. + Weight::from_parts(40_493_000, 18048) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Alliance Members (r:3 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) + /// 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: `367` + // Measured: `400` // Estimated: `18048` - // Minimum execution time: 26_114_000 picoseconds. - Weight::from_parts(27_069_000, 18048) + // Minimum execution time: 23_265_000 picoseconds. + Weight::from_parts(24_703_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Alliance Members (r:2 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:2 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `443` + // Measured: `476` // Estimated: `12362` - // Minimum execution time: 25_882_000 picoseconds. - Weight::from_parts(26_923_000, 12362) + // Minimum execution time: 23_049_000 picoseconds. + Weight::from_parts(23_875_000, 12362) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Alliance Members (r:4 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Alliance RetiringMembers (r:0 w:1) - /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Alliance::Members` (r:4 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::RetiringMembers` (r:0 w:1) + /// 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: `443` + // Measured: `476` // Estimated: `23734` - // Minimum execution time: 34_112_000 picoseconds. - Weight::from_parts(35_499_000, 23734) + // Minimum execution time: 29_124_000 picoseconds. + Weight::from_parts(30_369_000, 23734) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Alliance RetiringMembers (r:1 w:1) - /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: Alliance Members (r:1 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: Alliance DepositOf (r:1 w:1) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Alliance::RetiringMembers` (r:1 w:1) + /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Alliance::Members` (r:1 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `Alliance::DepositOf` (r:1 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `687` + // Measured: `720` // Estimated: `6676` - // Minimum execution time: 41_239_000 picoseconds. - Weight::from_parts(42_764_000, 6676) + // Minimum execution time: 36_376_000 picoseconds. + Weight::from_parts(38_221_000, 6676) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Alliance Members (r:3 w:1) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Alliance DepositOf (r:1 w:1) - /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:3 w:1) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Alliance::DepositOf` (r:1 w:1) + /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `707` + // Measured: `740` // Estimated: `18048` - // Minimum execution time: 68_071_000 picoseconds. - Weight::from_parts(71_808_000, 18048) + // Minimum execution time: 56_560_000 picoseconds. + Weight::from_parts(58_621_000, 18048) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `279` // Estimated: `27187` - // Minimum execution time: 7_006_000 picoseconds. - Weight::from_parts(7_253_000, 27187) - // Standard Error: 3_403 - .saturating_add(Weight::from_parts(1_680_082, 0).saturating_mul(n.into())) - // Standard Error: 1_333 - .saturating_add(Weight::from_parts(72_943, 0).saturating_mul(l.into())) + // Minimum execution time: 5_191_000 picoseconds. + Weight::from_parts(5_410_000, 27187) + // Standard Error: 3_215 + .saturating_add(Weight::from_parts(1_018_569, 0).saturating_mul(n.into())) + // Standard Error: 1_259 + .saturating_add(Weight::from_parts(68_712, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) - /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) - /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) + /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) + /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + l * (100 ±0) + n * (289 ±0)` // Estimated: `27187` - // Minimum execution time: 7_292_000 picoseconds. - Weight::from_parts(7_629_000, 27187) - // Standard Error: 176_225 - .saturating_add(Weight::from_parts(16_646_429, 0).saturating_mul(n.into())) - // Standard Error: 69_017 - .saturating_add(Weight::from_parts(310_978, 0).saturating_mul(l.into())) + // Minimum execution time: 5_361_000 picoseconds. + Weight::from_parts(5_494_000, 27187) + // Standard Error: 181_133 + .saturating_add(Weight::from_parts(16_322_982, 0).saturating_mul(n.into())) + // Standard Error: 70_940 + .saturating_add(Weight::from_parts(343_581, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Alliance Members (r:3 w:2) - /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) - /// Storage: AllianceMotion Proposals (r:1 w:0) - /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Members (r:0 w:1) - /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AllianceMotion Prime (r:0 w:1) - /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Alliance::Members` (r:3 w:2) + /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:0) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Members` (r:0 w:1) + /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Prime` (r:0 w:1) + /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `443` + // Measured: `476` // Estimated: `18048` - // Minimum execution time: 31_798_000 picoseconds. - Weight::from_parts(33_463_000, 18048) + // Minimum execution time: 28_856_000 picoseconds. + Weight::from_parts(29_875_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index cca4b138a5a09c72f94b6365d85cffa54c4bbefe..d8912799303d9078015128e54ecb5f2b092006a9 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -40,7 +40,7 @@ //! non-native asset 1, you would pass in a path of `[DOT, 1]` or `[1, DOT]`. If you want to swap //! from non-native asset 1 to non-native asset 2, you would pass in a path of `[1, DOT, 2]`. //! -//! (For an example of configuring this pallet to use `MultiLocation` as an asset id, see the +//! (For an example of configuring this pallet to use `Location` as an asset id, see the //! cumulus repo). //! //! Here is an example `state_call` that asks for a quote of a pool of native versus asset 1: @@ -427,6 +427,11 @@ pub mod pallet { /// Params `amount1_min`/`amount2_min` represent that. /// `mint_to` will be sent the liquidity tokens that represent this share of the pool. /// + /// NOTE: when encountering an incorrect exchange rate and non-withdrawable pool liquidity, + /// batch an atomic call with [`Pallet::add_liquidity`] and + /// [`Pallet::swap_exact_tokens_for_tokens`] or [`Pallet::swap_tokens_for_exact_tokens`] + /// calls to render the liquidity withdrawable and rectify the exchange rate. + /// /// Once liquidity is added, someone may successfully call /// [`Pallet::swap_exact_tokens_for_tokens`] successfully. #[pallet::call_index(1)] diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 6c19f834cb8ff5cf83f796bb4b1570e8e7f525ca..870538a68cc7105802672972bdf394e36f7bbc87 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -29,15 +29,14 @@ use frame_support::{ fungible::{NativeFromLeft, NativeOrWithId, UnionOf}, imbalance::ResolveAssetTo, }, - AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, + AsEnsureOriginWithArg, ConstU128, ConstU32, }, PalletId, }; use frame_system::{EnsureSigned, EnsureSignedBy}; use sp_arithmetic::Permill; -use sp_core::H256; use sp_runtime::{ - traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, + traits::{AccountIdConversion, IdentityLookup}, BuildStorage, }; @@ -56,29 +55,10 @@ construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = u128; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/asset-rate/src/lib.rs b/substrate/frame/asset-rate/src/lib.rs index d4afca8b73c4b2978bbed954c05aee4e2a645ee5..befabfe54aa0e766d498eccf2201de4e9c0f2fc9 100644 --- a/substrate/frame/asset-rate/src/lib.rs +++ b/substrate/frame/asset-rate/src/lib.rs @@ -59,8 +59,14 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::{fungible::Inspect, tokens::ConversionFromAssetBalance}; -use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128}; +use frame_support::traits::{ + fungible::Inspect, + tokens::{ConversionFromAssetBalance, ConversionToAssetBalance}, +}; +use sp_runtime::{ + traits::{CheckedDiv, Zero}, + FixedPointNumber, FixedU128, +}; use sp_std::boxed::Box; pub use pallet::*; @@ -144,6 +150,8 @@ pub mod pallet { UnknownAssetKind, /// The given asset ID already has an assigned conversion rate and cannot be re-created. AlreadyExists, + /// Overflow ocurred when calculating the inverse rate. + Overflow, } #[pallet::call] @@ -246,3 +254,25 @@ where pallet::ConversionRateToNative::::set(asset_id.clone(), Some(1.into())); } } + +/// Exposes conversion of a native balance to an asset balance. +impl ConversionToAssetBalance, AssetKindOf, BalanceOf> for Pallet +where + T: Config, +{ + type Error = pallet::Error; + + fn to_asset_balance( + balance: BalanceOf, + asset_kind: AssetKindOf, + ) -> Result, pallet::Error> { + let rate = pallet::ConversionRateToNative::::get(asset_kind) + .ok_or(pallet::Error::::UnknownAssetKind.into())?; + + // We cannot use `saturating_div` here so we use `checked_div`. + Ok(FixedU128::from_u32(1) + .checked_div(&rate) + .ok_or(pallet::Error::::Overflow.into())? + .saturating_mul_int(balance)) + } +} diff --git a/substrate/frame/asset-rate/src/mock.rs b/substrate/frame/asset-rate/src/mock.rs index d6044e09ccd1c821b43bd54708f89cb5fd1e1ac9..5981b05676414e9ec5251be0bcf2e554d589107a 100644 --- a/substrate/frame/asset-rate/src/mock.rs +++ b/substrate/frame/asset-rate/src/mock.rs @@ -18,15 +18,8 @@ //! The crate's mock. use crate as pallet_asset_rate; -use frame_support::{ - derive_impl, - traits::{ConstU16, ConstU64}, -}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use frame_support::{derive_impl, traits::ConstU64}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -41,29 +34,8 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/asset-rate/src/tests.rs b/substrate/frame/asset-rate/src/tests.rs index 452265476093b034256907e9d2a232c91041f772..fc7bf2f150311b638ba3a7bc939d6b62ba927cc0 100644 --- a/substrate/frame/asset-rate/src/tests.rs +++ b/substrate/frame/asset-rate/src/tests.rs @@ -131,12 +131,19 @@ fn convert_works() { FixedU128::from_float(2.51) )); - let conversion = , ::AssetKind, BalanceOf, >>::from_asset_balance(10, ASSET_ID); - assert_eq!(conversion.expect("Conversion rate exists for asset"), 25); + assert_eq!(conversion_from_asset.expect("Conversion rate exists for asset"), 25); + + let conversion_to_asset = , + ::AssetKind, + BalanceOf, + >>::to_asset_balance(25, ASSET_ID); + assert_eq!(conversion_to_asset.expect("Conversion rate exists for asset"), 9); }); } @@ -151,3 +158,21 @@ fn convert_unknown_throws() { assert!(conversion.is_err()); }); } + +#[test] +fn convert_overflow_throws() { + new_test_ext().execute_with(|| { + assert_ok!(AssetRate::create( + RuntimeOrigin::root(), + Box::new(ASSET_ID), + FixedU128::from_u32(0) + )); + + let conversion = , + ::AssetKind, + BalanceOf, + >>::to_asset_balance(10, ASSET_ID); + assert!(conversion.is_err()); + }); +} diff --git a/substrate/frame/asset-rate/src/weights.rs b/substrate/frame/asset-rate/src/weights.rs index 582e20e56d7dc7f40a0cbb3838622b309e8223d4..b8723ee3bed5cbc124a8e7c1237e5c1af2e5a154 100644 --- a/substrate/frame/asset-rate/src/weights.rs +++ b/substrate/frame/asset-rate/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_asset_rate +//! Autogenerated weights for `pallet_asset_rate` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/asset-rate/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/asset-rate/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,83 +49,83 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_asset_rate. +/// Weight functions needed for `pallet_asset_rate`. pub trait WeightInfo { fn create() -> Weight; fn update() -> Weight; fn remove() -> Weight; } -/// Weights for pallet_asset_rate using the Substrate node and recommended hardware. +/// Weights for `pallet_asset_rate` using the Substrate node and recommended hardware. 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) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3501` - // Minimum execution time: 11_700_000 picoseconds. - Weight::from_parts(12_158_000, 3501) + // Minimum execution time: 9_447_000 picoseconds. + Weight::from_parts(10_078_000, 3501) .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) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn update() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 12_119_000 picoseconds. - Weight::from_parts(12_548_000, 3501) + // Minimum execution time: 9_844_000 picoseconds. + Weight::from_parts(10_240_000, 3501) .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) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn remove() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 12_541_000 picoseconds. - Weight::from_parts(12_956_000, 3501) + // Minimum execution time: 10_411_000 picoseconds. + Weight::from_parts(10_686_000, 3501) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// 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) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3501` - // Minimum execution time: 11_700_000 picoseconds. - Weight::from_parts(12_158_000, 3501) + // Minimum execution time: 9_447_000 picoseconds. + Weight::from_parts(10_078_000, 3501) .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) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn update() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 12_119_000 picoseconds. - Weight::from_parts(12_548_000, 3501) + // Minimum execution time: 9_844_000 picoseconds. + Weight::from_parts(10_240_000, 3501) .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) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn remove() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 12_541_000 picoseconds. - Weight::from_parts(12_956_000, 3501) + // Minimum execution time: 10_411_000 picoseconds. + Weight::from_parts(10_686_000, 3501) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index 6fe3a27236052d1139327a549f9276caa6730c3b..2efc96348cb5447b792c334256076a395f646719 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } # Needed for various traits. In our case, `OnFinalize`. diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 4a3c185758d5a72af61948b482418753efd75918..36a9423a315a7b0c4caa2c0d57615ace92c197e5 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -208,7 +208,7 @@ pub mod pallet { }; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] @@ -226,10 +226,42 @@ pub mod pallet { } } - #[pallet::config] + /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. + pub mod config_preludes { + use super::*; + use frame_support::{derive_impl, traits::ConstU64}; + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + #[inject_runtime_type] + type RuntimeEvent = (); + type Balance = u64; + 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 StringLimit = ConstU32<50>; + type Extra = (); + type CallbackHandle = (); + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + } + } + + #[pallet::config(with_default)] /// The module configuration trait. pub trait Config: frame_system::Config { /// The overarching event type. + #[pallet::no_default_bounds] type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -262,10 +294,12 @@ pub mod pallet { type AssetIdParameter: Parameter + From + Into + MaxEncodedLen; /// The currency mechanism. + #[pallet::no_default] type Currency: ReservableCurrency; /// Standard asset class creation is only allowed if the origin attempting it and the /// asset class are in this set. + #[pallet::no_default] type CreateOrigin: EnsureOriginWithArg< Self::RuntimeOrigin, Self::AssetId, @@ -274,28 +308,34 @@ pub mod pallet { /// The origin which may forcibly create or destroy an asset or otherwise alter privileged /// attributes. + #[pallet::no_default] type ForceOrigin: EnsureOrigin; /// The basic amount of funds that must be reserved for an asset. #[pallet::constant] + #[pallet::no_default_bounds] type AssetDeposit: Get>; /// The amount of funds that must be reserved for a non-provider asset account to be /// maintained. #[pallet::constant] + #[pallet::no_default_bounds] type AssetAccountDeposit: Get>; /// The basic amount of funds that must be reserved when adding metadata to your asset. #[pallet::constant] + #[pallet::no_default_bounds] type MetadataDepositBase: Get>; /// The additional funds that must be reserved for the number of bytes you store in your /// metadata. #[pallet::constant] + #[pallet::no_default_bounds] type MetadataDepositPerByte: Get>; /// The amount of funds that must be reserved when creating a new approval. #[pallet::constant] + #[pallet::no_default_bounds] type ApprovalDeposit: Get>; /// The maximum length of a name or symbol stored on-chain. @@ -304,6 +344,7 @@ pub mod pallet { /// A hook to allow a per-asset, per-account minimum balance to be enforced. This must be /// respected in all permissionless operations. + #[pallet::no_default] type Freezer: FrozenBalance; /// Additional data to be stored with an account's asset balance. diff --git a/substrate/frame/assets/src/migration.rs b/substrate/frame/assets/src/migration.rs index ff0ffbff0d362fbd630e22dcb293f28e2b75469c..dd7c12293e80f410301bb47cca013ae4f013e72f 100644 --- a/substrate/frame/assets/src/migration.rs +++ b/substrate/frame/assets/src/migration.rs @@ -67,9 +67,9 @@ pub mod v1 { pub struct MigrateToV1(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { - let current_version = Pallet::::current_storage_version(); - let onchain_version = Pallet::::on_chain_storage_version(); - if onchain_version == 0 && current_version == 1 { + let in_code_version = Pallet::::in_code_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); + if on_chain_version == 0 && in_code_version == 1 { let mut translated = 0u64; Asset::::translate::< OldAssetDetails>, @@ -78,12 +78,12 @@ pub mod v1 { translated.saturating_inc(); Some(old_value.migrate_to_v1()) }); - current_version.put::>(); + in_code_version.put::>(); log::info!( target: LOG_TARGET, "Upgraded {} pools, storage to version {:?}", translated, - current_version + in_code_version ); T::DbWeight::get().reads_writes(translated + 1, translated + 1) } else { @@ -116,13 +116,13 @@ pub mod v1 { "the asset count before and after the migration should be the same" ); - let current_version = Pallet::::current_storage_version(); - let onchain_version = Pallet::::on_chain_storage_version(); + let in_code_version = Pallet::::in_code_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); - frame_support::ensure!(current_version == 1, "must_upgrade"); + frame_support::ensure!(in_code_version == 1, "must_upgrade"); ensure!( - current_version == onchain_version, - "after migration, the current_version and onchain_version should be the same" + in_code_version == on_chain_version, + "after migration, the in_code_version and on_chain_version should be the same" ); Asset::::iter().try_for_each(|(_id, asset)| -> Result<(), TryRuntimeError> { diff --git a/substrate/frame/assets/src/mock.rs b/substrate/frame/assets/src/mock.rs index 6dda08eaff8bb781fb7f29fc514f1672784de372..906febb0214fcd9cb125ddd5d307413b9abbbca9 100644 --- a/substrate/frame/assets/src/mock.rs +++ b/substrate/frame/assets/src/mock.rs @@ -25,12 +25,8 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; -use sp_core::H256; use sp_io::storage; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -48,28 +44,8 @@ type AssetId = u32; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); type MaxConsumers = ConstU32<3>; } @@ -132,27 +108,13 @@ impl AssetsCallbackHandle { } } +#[derive_impl(crate::config_preludes::TestDefaultConfig)] impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = u64; - type AssetId = u32; - type AssetIdParameter = u32; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU64<1>; - type AssetAccountDeposit = ConstU64<10>; - type MetadataDepositBase = ConstU64<1>; - type MetadataDepositPerByte = ConstU64<1>; - type ApprovalDeposit = ConstU64<1>; - type StringLimit = ConstU32<50>; type Freezer = TestFreezer; - type WeightInfo = (); type CallbackHandle = AssetsCallbackHandle; - type Extra = (); - type RemoveItemsLimit = ConstU32<5>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } use std::collections::HashMap; diff --git a/substrate/frame/assets/src/weights.rs b/substrate/frame/assets/src/weights.rs index f20f7e317cff7c32d280b2e6fa9eaa9aa0fdbd57..f5199105fe354c221779bbacab6a99b33dce3981 100644 --- a/substrate/frame/assets/src/weights.rs +++ b/substrate/frame/assets/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_assets +//! Autogenerated weights for `pallet_assets` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/assets/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/assets/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_assets. +/// Weight functions needed for `pallet_assets`. pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; @@ -86,882 +85,890 @@ pub trait WeightInfo { fn block() -> Weight; } -/// Weights for pallet_assets using the Substrate node and recommended hardware. +/// Weights for `pallet_assets` using the Substrate node and recommended hardware. 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, 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: 31_340_000 picoseconds. - Weight::from_parts(31_977_000, 3675) + // Minimum execution time: 24_690_000 picoseconds. + Weight::from_parts(25_878_000, 3675) .saturating_add(T::DbWeight::get().reads(2_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 13_342_000 picoseconds. - Weight::from_parts(13_782_000, 3675) + // Minimum execution time: 10_997_000 picoseconds. + Weight::from_parts(11_369_000, 3675) .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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn start_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 14_437_000 picoseconds. - Weight::from_parts(14_833_000, 3675) + // Minimum execution time: 11_536_000 picoseconds. + Weight::from_parts(12_309_000, 3675) .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:1001 w:1000) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1000 w:1000) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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:1001 w:1000) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1000 w:1000) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` // Estimated: `3675 + c * (2609 ±0)` - // Minimum execution time: 18_728_000 picoseconds. - Weight::from_parts(18_982_000, 3675) - // Standard Error: 11_708 - .saturating_add(Weight::from_parts(14_363_570, 0).saturating_mul(c.into())) + // Minimum execution time: 15_798_000 picoseconds. + Weight::from_parts(16_005_000, 3675) + // Standard Error: 7_818 + .saturating_add(Weight::from_parts(12_826_278, 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)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) } - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Approvals (r:1001 w:1000) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1001 w:1000) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 18_611_000 picoseconds. - Weight::from_parts(18_970_000, 3675) - // Standard Error: 13_224 - .saturating_add(Weight::from_parts(16_397_299, 0).saturating_mul(a.into())) + // Minimum execution time: 16_334_000 picoseconds. + Weight::from_parts(16_616_000, 3675) + // Standard Error: 6_402 + .saturating_add(Weight::from_parts(13_502_238, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) } - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:0) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, 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::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_504_000 picoseconds. - Weight::from_parts(14_906_000, 3675) + // Minimum execution time: 12_278_000 picoseconds. + Weight::from_parts(12_834_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:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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`) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 26_653_000 picoseconds. - Weight::from_parts(27_260_000, 3675) + // Minimum execution time: 21_793_000 picoseconds. + Weight::from_parts(22_284_000, 3675) .saturating_add(T::DbWeight::get().reads(2_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 Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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`) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 33_625_000 picoseconds. - Weight::from_parts(34_474_000, 3675) + // Minimum execution time: 28_712_000 picoseconds. + Weight::from_parts(29_710_000, 3675) .saturating_add(T::DbWeight::get().reads(2_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 Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `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() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 47_609_000 picoseconds. - Weight::from_parts(48_476_000, 6208) + // Minimum execution time: 41_331_000 picoseconds. + Weight::from_parts(42_362_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_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) + /// 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_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 41_625_000 picoseconds. - Weight::from_parts(43_030_000, 6208) + // Minimum execution time: 37_316_000 picoseconds. + Weight::from_parts(38_200_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_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) + /// 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 force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 47_661_000 picoseconds. - Weight::from_parts(48_469_000, 6208) + // Minimum execution time: 41_347_000 picoseconds. + Weight::from_parts(42_625_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// 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: `Assets::Asset` (r:1 w:0) + /// 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`) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 17_727_000 picoseconds. - Weight::from_parts(18_384_000, 3675) + // Minimum execution time: 15_072_000 picoseconds. + Weight::from_parts(15_925_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// 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: `Assets::Asset` (r:1 w:0) + /// 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`) fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 17_657_000 picoseconds. - Weight::from_parts(18_282_000, 3675) + // Minimum execution time: 14_991_000 picoseconds. + Weight::from_parts(15_987_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn freeze_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 13_743_000 picoseconds. - Weight::from_parts(14_193_000, 3675) + // Minimum execution time: 11_296_000 picoseconds. + Weight::from_parts(12_052_000, 3675) .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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn thaw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 13_653_000 picoseconds. - Weight::from_parts(14_263_000, 3675) + // Minimum execution time: 11_446_000 picoseconds. + Weight::from_parts(11_791_000, 3675) .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 Metadata (r:1 w:0) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, 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::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_328_000 picoseconds. - Weight::from_parts(16_042_000, 3675) + // Minimum execution time: 13_134_000 picoseconds. + Weight::from_parts(13_401_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_097_000 picoseconds. - Weight::from_parts(14_641_000, 3675) + // Minimum execution time: 11_395_000 picoseconds. + Weight::from_parts(11_718_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// 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: 29_535_000 picoseconds. - Weight::from_parts(31_456_892, 3675) + // Minimum execution time: 25_147_000 picoseconds. + Weight::from_parts(26_614_272, 3675) + // Standard Error: 959 + .saturating_add(Weight::from_parts(2_300, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 30_680_000 picoseconds. - Weight::from_parts(31_930_000, 3675) + // Minimum execution time: 26_094_000 picoseconds. + Weight::from_parts(27_199_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// 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 force_set_metadata(_n: u32, s: u32, ) -> Weight { + fn force_set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 14_660_000 picoseconds. - Weight::from_parts(15_718_387, 3675) - // Standard Error: 622 - .saturating_add(Weight::from_parts(2_640, 0).saturating_mul(s.into())) + // Minimum execution time: 11_977_000 picoseconds. + Weight::from_parts(12_719_933, 3675) + // Standard Error: 429 + .saturating_add(Weight::from_parts(3_239, 0).saturating_mul(n.into())) + // Standard Error: 429 + .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 30_853_000 picoseconds. - Weight::from_parts(31_483_000, 3675) + // Minimum execution time: 25_859_000 picoseconds. + Weight::from_parts(26_654_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn force_asset_status() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 13_632_000 picoseconds. - Weight::from_parts(14_077_000, 3675) + // Minimum execution time: 10_965_000 picoseconds. + Weight::from_parts(11_595_000, 3675) .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 Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 33_780_000 picoseconds. - Weight::from_parts(34_533_000, 3675) + // Minimum execution time: 28_427_000 picoseconds. + Weight::from_parts(29_150_000, 3675) .saturating_add(T::DbWeight::get().reads(2_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 Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) - /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, 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_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `6208` - // Minimum execution time: 67_712_000 picoseconds. - Weight::from_parts(69_946_000, 6208) + // Minimum execution time: 60_227_000 picoseconds. + Weight::from_parts(61_839_000, 6208) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 36_668_000 picoseconds. - Weight::from_parts(37_637_000, 3675) + // Minimum execution time: 30_738_000 picoseconds. + Weight::from_parts(31_988_000, 3675) .saturating_add(T::DbWeight::get().reads(2_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 Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 36_685_000 picoseconds. - Weight::from_parts(37_950_000, 3675) + // Minimum execution time: 31_444_000 picoseconds. + Weight::from_parts(32_126_000, 3675) .saturating_add(T::DbWeight::get().reads(2_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn set_min_balance() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_466_000 picoseconds. - Weight::from_parts(14_924_000, 3675) + // Minimum execution time: 11_890_000 picoseconds. + Weight::from_parts(12_462_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn touch() -> Weight { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3675` - // Minimum execution time: 34_874_000 picoseconds. - Weight::from_parts(36_330_000, 3675) + // Minimum execution time: 30_675_000 picoseconds. + Weight::from_parts(31_749_000, 3675) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn touch_other() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 33_278_000 picoseconds. - Weight::from_parts(34_104_000, 3675) + // Minimum execution time: 28_290_000 picoseconds. + Weight::from_parts(29_405_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn refund() -> Weight { // Proof Size summary in bytes: // Measured: `579` // Estimated: `3675` - // Minimum execution time: 32_898_000 picoseconds. - Weight::from_parts(33_489_000, 3675) + // Minimum execution time: 30_195_000 picoseconds. + Weight::from_parts(31_105_000, 3675) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn refund_other() -> Weight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3675` - // Minimum execution time: 31_243_000 picoseconds. - Weight::from_parts(31_909_000, 3675) + // Minimum execution time: 27_785_000 picoseconds. + Weight::from_parts(28_783_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// 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: `Assets::Asset` (r:1 w:0) + /// 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`) fn block() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 17_692_000 picoseconds. - Weight::from_parts(18_253_000, 3675) + // Minimum execution time: 15_318_000 picoseconds. + Weight::from_parts(16_113_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, 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: 31_340_000 picoseconds. - Weight::from_parts(31_977_000, 3675) + // Minimum execution time: 24_690_000 picoseconds. + Weight::from_parts(25_878_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 13_342_000 picoseconds. - Weight::from_parts(13_782_000, 3675) + // Minimum execution time: 10_997_000 picoseconds. + Weight::from_parts(11_369_000, 3675) .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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn start_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 14_437_000 picoseconds. - Weight::from_parts(14_833_000, 3675) + // Minimum execution time: 11_536_000 picoseconds. + Weight::from_parts(12_309_000, 3675) .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:1001 w:1000) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1000 w:1000) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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:1001 w:1000) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1000 w:1000) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` // Estimated: `3675 + c * (2609 ±0)` - // Minimum execution time: 18_728_000 picoseconds. - Weight::from_parts(18_982_000, 3675) - // Standard Error: 11_708 - .saturating_add(Weight::from_parts(14_363_570, 0).saturating_mul(c.into())) + // Minimum execution time: 15_798_000 picoseconds. + Weight::from_parts(16_005_000, 3675) + // Standard Error: 7_818 + .saturating_add(Weight::from_parts(12_826_278, 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)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) } - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Approvals (r:1001 w:1000) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1001 w:1000) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 18_611_000 picoseconds. - Weight::from_parts(18_970_000, 3675) - // Standard Error: 13_224 - .saturating_add(Weight::from_parts(16_397_299, 0).saturating_mul(a.into())) + // Minimum execution time: 16_334_000 picoseconds. + Weight::from_parts(16_616_000, 3675) + // Standard Error: 6_402 + .saturating_add(Weight::from_parts(13_502_238, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) } - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:0) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, 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::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_504_000 picoseconds. - Weight::from_parts(14_906_000, 3675) + // Minimum execution time: 12_278_000 picoseconds. + Weight::from_parts(12_834_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:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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`) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 26_653_000 picoseconds. - Weight::from_parts(27_260_000, 3675) + // Minimum execution time: 21_793_000 picoseconds. + Weight::from_parts(22_284_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_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 Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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`) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 33_625_000 picoseconds. - Weight::from_parts(34_474_000, 3675) + // Minimum execution time: 28_712_000 picoseconds. + Weight::from_parts(29_710_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_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 Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `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() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 47_609_000 picoseconds. - Weight::from_parts(48_476_000, 6208) + // Minimum execution time: 41_331_000 picoseconds. + Weight::from_parts(42_362_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_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) + /// 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_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 41_625_000 picoseconds. - Weight::from_parts(43_030_000, 6208) + // Minimum execution time: 37_316_000 picoseconds. + Weight::from_parts(38_200_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_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) + /// 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 force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 47_661_000 picoseconds. - Weight::from_parts(48_469_000, 6208) + // Minimum execution time: 41_347_000 picoseconds. + Weight::from_parts(42_625_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// 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: `Assets::Asset` (r:1 w:0) + /// 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`) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 17_727_000 picoseconds. - Weight::from_parts(18_384_000, 3675) + // Minimum execution time: 15_072_000 picoseconds. + Weight::from_parts(15_925_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// 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: `Assets::Asset` (r:1 w:0) + /// 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`) fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 17_657_000 picoseconds. - Weight::from_parts(18_282_000, 3675) + // Minimum execution time: 14_991_000 picoseconds. + Weight::from_parts(15_987_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn freeze_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 13_743_000 picoseconds. - Weight::from_parts(14_193_000, 3675) + // Minimum execution time: 11_296_000 picoseconds. + Weight::from_parts(12_052_000, 3675) .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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn thaw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 13_653_000 picoseconds. - Weight::from_parts(14_263_000, 3675) + // Minimum execution time: 11_446_000 picoseconds. + Weight::from_parts(11_791_000, 3675) .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 Metadata (r:1 w:0) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, 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::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_328_000 picoseconds. - Weight::from_parts(16_042_000, 3675) + // Minimum execution time: 13_134_000 picoseconds. + Weight::from_parts(13_401_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_097_000 picoseconds. - Weight::from_parts(14_641_000, 3675) + // Minimum execution time: 11_395_000 picoseconds. + Weight::from_parts(11_718_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// 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: 29_535_000 picoseconds. - Weight::from_parts(31_456_892, 3675) + // Minimum execution time: 25_147_000 picoseconds. + Weight::from_parts(26_614_272, 3675) + // Standard Error: 959 + .saturating_add(Weight::from_parts(2_300, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 30_680_000 picoseconds. - Weight::from_parts(31_930_000, 3675) + // Minimum execution time: 26_094_000 picoseconds. + Weight::from_parts(27_199_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// 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 force_set_metadata(_n: u32, s: u32, ) -> Weight { + fn force_set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 14_660_000 picoseconds. - Weight::from_parts(15_718_387, 3675) - // Standard Error: 622 - .saturating_add(Weight::from_parts(2_640, 0).saturating_mul(s.into())) + // Minimum execution time: 11_977_000 picoseconds. + Weight::from_parts(12_719_933, 3675) + // Standard Error: 429 + .saturating_add(Weight::from_parts(3_239, 0).saturating_mul(n.into())) + // Standard Error: 429 + .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 30_853_000 picoseconds. - Weight::from_parts(31_483_000, 3675) + // Minimum execution time: 25_859_000 picoseconds. + Weight::from_parts(26_654_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn force_asset_status() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 13_632_000 picoseconds. - Weight::from_parts(14_077_000, 3675) + // Minimum execution time: 10_965_000 picoseconds. + Weight::from_parts(11_595_000, 3675) .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 Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 33_780_000 picoseconds. - Weight::from_parts(34_533_000, 3675) + // Minimum execution time: 28_427_000 picoseconds. + Weight::from_parts(29_150_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_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 Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) - /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, 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_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `6208` - // Minimum execution time: 67_712_000 picoseconds. - Weight::from_parts(69_946_000, 6208) + // Minimum execution time: 60_227_000 picoseconds. + Weight::from_parts(61_839_000, 6208) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 36_668_000 picoseconds. - Weight::from_parts(37_637_000, 3675) + // Minimum execution time: 30_738_000 picoseconds. + Weight::from_parts(31_988_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_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 Approvals (r:1 w:1) - /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, 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::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 36_685_000 picoseconds. - Weight::from_parts(37_950_000, 3675) + // Minimum execution time: 31_444_000 picoseconds. + Weight::from_parts(32_126_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_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::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn set_min_balance() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_466_000 picoseconds. - Weight::from_parts(14_924_000, 3675) + // Minimum execution time: 11_890_000 picoseconds. + Weight::from_parts(12_462_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn touch() -> Weight { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3675` - // Minimum execution time: 34_874_000 picoseconds. - Weight::from_parts(36_330_000, 3675) + // Minimum execution time: 30_675_000 picoseconds. + Weight::from_parts(31_749_000, 3675) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn touch_other() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 33_278_000 picoseconds. - Weight::from_parts(34_104_000, 3675) + // Minimum execution time: 28_290_000 picoseconds. + Weight::from_parts(29_405_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn refund() -> Weight { // Proof Size summary in bytes: // Measured: `579` // Estimated: `3675` - // Minimum execution time: 32_898_000 picoseconds. - Weight::from_parts(33_489_000, 3675) + // Minimum execution time: 30_195_000 picoseconds. + Weight::from_parts(31_105_000, 3675) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, 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: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) fn refund_other() -> Weight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3675` - // Minimum execution time: 31_243_000 picoseconds. - Weight::from_parts(31_909_000, 3675) + // Minimum execution time: 27_785_000 picoseconds. + Weight::from_parts(28_783_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Assets Asset (r:1 w:0) - /// 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: `Assets::Asset` (r:1 w:0) + /// 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`) fn block() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 17_692_000 picoseconds. - Weight::from_parts(18_253_000, 3675) + // Minimum execution time: 15_318_000 picoseconds. + Weight::from_parts(16_113_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/atomic-swap/src/tests.rs b/substrate/frame/atomic-swap/src/tests.rs index 4a4b96f7aae05a874bc662848135fad1380e49c3..4b444d888ed5e228a4951258092b0bdbdcf6e597 100644 --- a/substrate/frame/atomic-swap/src/tests.rs +++ b/substrate/frame/atomic-swap/src/tests.rs @@ -24,11 +24,7 @@ use frame_support::{ derive_impl, traits::{ConstU32, ConstU64}, }; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -43,29 +39,8 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index 7620d172ffc98934b066558a7399d4ff3a163985..de698487efa7fa6c1cc37cc89e872b9603a9f253 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/aura/src/mock.rs b/substrate/frame/aura/src/mock.rs index d87fea8fc81ebcc9ccb2fb03875a4c45959b7057..8bc3e407158317164730e839bf954fd5f8e5e597 100644 --- a/substrate/frame/aura/src/mock.rs +++ b/substrate/frame/aura/src/mock.rs @@ -25,8 +25,7 @@ use frame_support::{ traits::{ConstU32, ConstU64, DisabledValidators}, }; use sp_consensus_aura::{ed25519::AuthorityId, AuthorityIndex}; -use sp_core::H256; -use sp_runtime::{testing::UintAuthorityId, traits::IdentityLookup, BuildStorage}; +use sp_runtime::{testing::UintAuthorityId, BuildStorage}; type Block = frame_system::mocking::MockBlock; @@ -43,29 +42,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_timestamp::Config for Test { diff --git a/substrate/frame/authority-discovery/src/lib.rs b/substrate/frame/authority-discovery/src/lib.rs index 640c0c8759ebef6c390e9119fb1b96361bc34e25..2b4dfaf1aea8c804af7b4893be7057c53c347896 100644 --- a/substrate/frame/authority-discovery/src/lib.rs +++ b/substrate/frame/authority-discovery/src/lib.rs @@ -168,13 +168,10 @@ impl OneSessionHandler for Pallet { mod tests { use super::*; use crate as pallet_authority_discovery; - use frame_support::{ - derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, - }; + use frame_support::{derive_impl, parameter_types, traits::ConstU32}; use sp_application_crypto::Pair; use sp_authority_discovery::AuthorityPair; - use sp_core::{crypto::key_types, H256}; + use sp_core::crypto::key_types; use sp_io::TestExternalities; use sp_runtime::{ testing::UintAuthorityId, @@ -227,29 +224,9 @@ mod tests { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AuthorityId; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } pub struct TestSessionHandler; diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index 8f49faaa2d602bb9c8f8894e45f28d481adf2670..fc7385efa1f14c371af682304f3e1c8d3c614c2d 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index a6e44390dbc534e15e3a1658513c6ce9fa25088e..5fb107dde3bad06e6f4812d27ff1159a95194442 100644 --- a/substrate/frame/babe/src/lib.rs +++ b/substrate/frame/babe/src/lib.rs @@ -323,7 +323,7 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, - pub epoch_config: Option, + pub epoch_config: BabeEpochConfiguration, #[serde(skip)] pub _config: sp_std::marker::PhantomData, } @@ -333,9 +333,7 @@ pub mod pallet { fn build(&self) { SegmentIndex::::put(0); Pallet::::initialize_genesis_authorities(&self.authorities); - EpochConfig::::put( - self.epoch_config.clone().expect("epoch_config must not be None"), - ); + EpochConfig::::put(&self.epoch_config); } } diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index b693f4fce9bde662c8badee8f0e675648597ea58..1ba0cdd0cc12e91ce11a545a40f7d0288bd3bbe0 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -37,8 +37,9 @@ use sp_core::{ use sp_io; use sp_runtime::{ curve::PiecewiseLinear, + generic::UncheckedExtrinsic, impl_opaque_keys, - testing::{Digest, DigestItem, Header, TestXt}, + testing::{Digest, DigestItem, Header}, traits::{Header as _, OpaqueKeys}, BuildStorage, Perbill, }; @@ -74,7 +75,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = TestXt; + type Extrinsic = UncheckedExtrinsic; } impl_opaque_keys! { diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index b8ab099a0694220b933758fbd96a6635216d572f..f9ae462e16d729f9652da114f5ebcef4cc2f21b7 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -33,7 +33,7 @@ frame-system = { path = "../system", default-features = false } frame-election-provider-support = { path = "../election-provider-support", default-features = false } # third party -log = { version = "0.4.17", default-features = false } +log = { workspace = true } docify = "0.2.7" aquamarine = { version = "0.5.0" } diff --git a/substrate/frame/bags-list/remote-tests/Cargo.toml b/substrate/frame/bags-list/remote-tests/Cargo.toml index fb61a9867783a32084dc363f6ac18c76ed4f3e10..266355f5cabe19214643db024e641339acd60630 100644 --- a/substrate/frame/bags-list/remote-tests/Cargo.toml +++ b/substrate/frame/bags-list/remote-tests/Cargo.toml @@ -34,4 +34,4 @@ sp-std = { path = "../../../primitives/std" } remote-externalities = { package = "frame-remote-externalities", path = "../../../utils/frame/remote-externalities" } # others -log = "0.4.17" +log = { workspace = true, default-features = true } diff --git a/substrate/frame/bags-list/src/weights.rs b/substrate/frame/bags-list/src/weights.rs index d929c6bb95963c3eaee8ce0d16b127adcb64956e..804b702cc9a12c9f6a371b1ad019fd96038c7bb5 100644 --- a/substrate/frame/bags-list/src/weights.rs +++ b/substrate/frame/bags-list/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_bags_list +//! Autogenerated weights for `pallet_bags_list` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/bags-list/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/bags-list/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,123 +49,123 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_bags_list. +/// Weight functions needed for `pallet_bags_list`. pub trait WeightInfo { fn rebag_non_terminal() -> Weight; fn rebag_terminal() -> Weight; fn put_in_front_of() -> Weight; } -/// Weights for pallet_bags_list using the Substrate node and recommended hardware. +/// Weights for `pallet_bags_list` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:4 w:4) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// 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: `1724` + // Measured: `1719` // Estimated: `11506` - // Minimum execution time: 62_137_000 picoseconds. - Weight::from_parts(64_050_000, 11506) + // Minimum execution time: 55_856_000 picoseconds. + Weight::from_parts(59_022_000, 11506) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1618` + // Measured: `1613` // Estimated: `8877` - // Minimum execution time: 60_880_000 picoseconds. - Weight::from_parts(62_078_000, 8877) + // Minimum execution time: 55_418_000 picoseconds. + Weight::from_parts(57_352_000, 8877) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `VoterList::ListNodes` (r:4 w:4) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:2 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:2 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// 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: `1930` + // Measured: `1925` // Estimated: `11506` - // Minimum execution time: 68_911_000 picoseconds. - Weight::from_parts(70_592_000, 11506) + // Minimum execution time: 63_820_000 picoseconds. + Weight::from_parts(65_530_000, 11506) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:4 w:4) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// 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: `1724` + // Measured: `1719` // Estimated: `11506` - // Minimum execution time: 62_137_000 picoseconds. - Weight::from_parts(64_050_000, 11506) + // Minimum execution time: 55_856_000 picoseconds. + Weight::from_parts(59_022_000, 11506) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1618` + // Measured: `1613` // Estimated: `8877` - // Minimum execution time: 60_880_000 picoseconds. - Weight::from_parts(62_078_000, 8877) + // Minimum execution time: 55_418_000 picoseconds. + Weight::from_parts(57_352_000, 8877) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `VoterList::ListNodes` (r:4 w:4) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:2 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:2 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// 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: `1930` + // Measured: `1925` // Estimated: `11506` - // Minimum execution time: 68_911_000 picoseconds. - Weight::from_parts(70_592_000, 11506) + // Minimum execution time: 63_820_000 picoseconds. + Weight::from_parts(65_530_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 e47e916a274de8074b58692e36df47610efb186b..db114290ed8650bd59a105ff350cf7291e6b9830 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } @@ -53,6 +53,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/lib.rs b/substrate/frame/balances/src/lib.rs index 7dd087eabd6343df653905856c078d3f6f2a3908..e87aa6f9311e30311066e21e73e8e006787fed90 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -320,7 +320,7 @@ pub mod pallet { type MaxFreezes: Get; } - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: frame_support::traits::StorageVersion = frame_support::traits::StorageVersion::new(1); diff --git a/substrate/frame/balances/src/migration.rs b/substrate/frame/balances/src/migration.rs index ba6819ec6e814da69807c8717a088df2451b6cb5..38d9c07ff7e002f6a7a57189b7ebce6830b52c75 100644 --- a/substrate/frame/balances/src/migration.rs +++ b/substrate/frame/balances/src/migration.rs @@ -22,9 +22,9 @@ use frame_support::{ }; fn migrate_v0_to_v1, I: 'static>(accounts: &[T::AccountId]) -> Weight { - let onchain_version = Pallet::::on_chain_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); - if onchain_version == 0 { + if on_chain_version == 0 { let total = accounts .iter() .map(|a| Pallet::::total_balance(a)) @@ -76,9 +76,9 @@ impl, A: Get>, I: 'static> OnRuntimeUpgrade pub struct ResetInactive(PhantomData<(T, I)>); impl, I: 'static> OnRuntimeUpgrade for ResetInactive { fn on_runtime_upgrade() -> Weight { - let onchain_version = Pallet::::on_chain_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); - if onchain_version == 1 { + if on_chain_version == 1 { // Remove the old `StorageVersion` type. frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( Pallet::::name().as_bytes(), diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 46a4c4caefc3d72ad45adf58243f3430344d4813..10bb79901f8c2a63f41289b061416ebcf51b8997 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 "; @@ -240,17 +241,17 @@ 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, ) .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, @@ -271,17 +272,17 @@ 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, ) .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, diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index 91452b292b56f90083c0f82aa3a1b361fb3d7baf..ee076a10fd1085b9c9e6830606e40993db8b3364 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -26,18 +26,18 @@ use frame_support::{ dispatch::{DispatchInfo, GetDispatchInfo}, parameter_types, traits::{ - fungible, ConstU32, ConstU64, ConstU8, Imbalance as ImbalanceT, OnUnbalanced, - StorageMapShim, StoredMap, VariantCount, WhitelistedStorageKeys, + fungible, ConstU32, ConstU8, Imbalance as ImbalanceT, OnUnbalanced, StorageMapShim, + StoredMap, VariantCount, WhitelistedStorageKeys, }, weights::{IdentityFee, Weight}, }; use frame_system::{self as system, RawOrigin}; use pallet_transaction_payment::{ChargeTransactionPayment, CurrencyAdapter, Multiplier}; use scale_info::TypeInfo; -use sp_core::{hexdisplay::HexDisplay, H256}; +use sp_core::hexdisplay::HexDisplay; use sp_io; use sp_runtime::{ - traits::{BadOrigin, IdentityLookup, SignedExtension, Zero}, + traits::{BadOrigin, Zero}, ArithmeticError, BuildStorage, DispatchError, DispatchResult, FixedPointNumber, RuntimeDebug, TokenError, }; @@ -92,38 +92,17 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = super::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for Test { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); } pub(crate) type Balance = u64; diff --git a/substrate/frame/balances/src/weights.rs b/substrate/frame/balances/src/weights.rs index f875ea189ba1bce61b5fd6aec0c3aab54fb72bf2..6bcfe050af714326aded0eda4fe05c1d5c149e31 100644 --- a/substrate/frame/balances/src/weights.rs +++ b/substrate/frame/balances/src/weights.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-20, STEPS: `50`, REPEAT: `20`, 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: `runner-j8vvqcjr-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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --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 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_balances -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/balances/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,8 +71,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 46_329_000 picoseconds. - Weight::from_parts(47_297_000, 3593) + // Minimum execution time: 46_407_000 picoseconds. + Weight::from_parts(47_561_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -80,8 +82,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 36_187_000 picoseconds. - Weight::from_parts(36_900_000, 3593) + // Minimum execution time: 36_574_000 picoseconds. + Weight::from_parts(37_682_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -91,8 +93,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 13_498_000 picoseconds. - Weight::from_parts(14_143_000, 3593) + // Minimum execution time: 13_990_000 picoseconds. + Weight::from_parts(14_568_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -102,8 +104,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_756_000 picoseconds. - Weight::from_parts(19_553_000, 3593) + // Minimum execution time: 19_594_000 picoseconds. + Weight::from_parts(20_148_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -113,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 47_826_000 picoseconds. - Weight::from_parts(48_834_000, 6196) + // Minimum execution time: 47_945_000 picoseconds. + Weight::from_parts(49_363_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -124,8 +126,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 44_621_000 picoseconds. - Weight::from_parts(45_151_000, 3593) + // Minimum execution time: 45_205_000 picoseconds. + Weight::from_parts(45_952_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -135,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_194_000 picoseconds. - Weight::from_parts(16_945_000, 3593) + // Minimum execution time: 16_593_000 picoseconds. + Weight::from_parts(17_123_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -147,10 +149,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 15_782_000 picoseconds. - Weight::from_parts(16_118_000, 990) - // Standard Error: 10_499 - .saturating_add(Weight::from_parts(13_327_660, 0).saturating_mul(u.into())) + // Minimum execution time: 16_182_000 picoseconds. + Weight::from_parts(16_412_000, 990) + // Standard Error: 10_148 + .saturating_add(Weight::from_parts(13_382_459, 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())) @@ -159,8 +161,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_157_000 picoseconds. - Weight::from_parts(6_507_000, 0) + // Minimum execution time: 6_478_000 picoseconds. + Weight::from_parts(6_830_000, 0) } } @@ -172,8 +174,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 46_329_000 picoseconds. - Weight::from_parts(47_297_000, 3593) + // Minimum execution time: 46_407_000 picoseconds. + Weight::from_parts(47_561_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -183,8 +185,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 36_187_000 picoseconds. - Weight::from_parts(36_900_000, 3593) + // Minimum execution time: 36_574_000 picoseconds. + Weight::from_parts(37_682_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -194,8 +196,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 13_498_000 picoseconds. - Weight::from_parts(14_143_000, 3593) + // Minimum execution time: 13_990_000 picoseconds. + Weight::from_parts(14_568_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -205,8 +207,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_756_000 picoseconds. - Weight::from_parts(19_553_000, 3593) + // Minimum execution time: 19_594_000 picoseconds. + Weight::from_parts(20_148_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -216,8 +218,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 47_826_000 picoseconds. - Weight::from_parts(48_834_000, 6196) + // Minimum execution time: 47_945_000 picoseconds. + Weight::from_parts(49_363_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -227,8 +229,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 44_621_000 picoseconds. - Weight::from_parts(45_151_000, 3593) + // Minimum execution time: 45_205_000 picoseconds. + Weight::from_parts(45_952_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -238,8 +240,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_194_000 picoseconds. - Weight::from_parts(16_945_000, 3593) + // Minimum execution time: 16_593_000 picoseconds. + Weight::from_parts(17_123_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -250,10 +252,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 15_782_000 picoseconds. - Weight::from_parts(16_118_000, 990) - // Standard Error: 10_499 - .saturating_add(Weight::from_parts(13_327_660, 0).saturating_mul(u.into())) + // Minimum execution time: 16_182_000 picoseconds. + Weight::from_parts(16_412_000, 990) + // Standard Error: 10_148 + .saturating_add(Weight::from_parts(13_382_459, 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())) @@ -262,7 +264,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_157_000 picoseconds. - Weight::from_parts(6_507_000, 0) + // Minimum execution time: 6_478_000 picoseconds. + Weight::from_parts(6_830_000, 0) } } diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 250a6fb450ca730476ecdba5bc8d5e81a0490b62..17707731773118b7028f3cff8031982c0c5d704b 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -14,9 +14,9 @@ workspace = true [dependencies] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index ba02cf1460d3ec32e8358169437ee0a2c93a5b39..e38eaa6fb0787aca48b07fad57e0ea0adffbe7e4 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -13,9 +13,9 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-authorship = { path = "../authorship", default-features = false } diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 9cce479890a48f7753be76b809f13abc1baa045d..5d963d309a4966cae1cb77516dda51c98b7154bf 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -29,8 +29,8 @@ use pallet_session::historical as pallet_session_historical; use sp_core::{crypto::KeyTypeId, ConstU128}; use sp_io::TestExternalities; use sp_runtime::{ - app_crypto::ecdsa::Public, curve::PiecewiseLinear, impl_opaque_keys, testing::TestXt, - traits::OpaqueKeys, BuildStorage, Perbill, + app_crypto::ecdsa::Public, curve::PiecewiseLinear, generic::UncheckedExtrinsic, + impl_opaque_keys, traits::OpaqueKeys, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; use sp_state_machine::BasicExternalities; @@ -73,7 +73,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = TestXt; + type Extrinsic = UncheckedExtrinsic; } parameter_types! { diff --git a/substrate/frame/beefy/src/tests.rs b/substrate/frame/beefy/src/tests.rs index bf5ae19510ce9320c7aac3b705db605db16ecebd..453cf19a4fe156a76ed13a7da4fe59d95d4260f0 100644 --- a/substrate/frame/beefy/src/tests.rs +++ b/substrate/frame/beefy/src/tests.rs @@ -15,21 +15,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::vec; - use codec::Encode; -use sp_consensus_beefy::{ - check_equivocation_proof, generate_equivocation_proof, known_payloads::MMR_ROOT_ID, - Keyring as BeefyKeyring, Payload, ValidatorSet, KEY_TYPE as BEEFY_KEY_TYPE, -}; - -use sp_runtime::DigestItem; +use std::vec; use frame_support::{ assert_err, assert_ok, dispatch::{GetDispatchInfo, Pays}, traits::{Currency, KeyOwnerProofSystem, OnInitialize}, }; +use sp_consensus_beefy::{ + check_equivocation_proof, + known_payloads::MMR_ROOT_ID, + test_utils::{generate_equivocation_proof, Keyring as BeefyKeyring}, + Payload, ValidatorSet, KEY_TYPE as BEEFY_KEY_TYPE, +}; +use sp_runtime::DigestItem; use crate::{mock::*, Call, Config, Error, Weight, WeightInfo}; diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 38c7bc2b905d37531f97906616f490ab4d4181a1..bf42aae979cd0edd3a00ca98f8aacaba55d807dc 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } linregress = { version = "0.5.1", optional = true } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } paste = "1.0" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-support-procedural = { path = "../support/procedural", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/benchmarking/src/weights.rs b/substrate/frame/benchmarking/src/weights.rs index 13d73e420cce256080d117e3bab56842d302b3a0..76f9a3fe52b564d552b698ac94e44e8c98660deb 100644 --- a/substrate/frame/benchmarking/src/weights.rs +++ b/substrate/frame/benchmarking/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for frame_benchmarking +//! Autogenerated weights for `frame_benchmarking` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/benchmarking/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/benchmarking/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for frame_benchmarking. +/// Weight functions needed for `frame_benchmarking`. pub trait WeightInfo { fn addition(i: u32, ) -> Weight; fn subtraction(i: u32, ) -> Weight; @@ -60,7 +59,7 @@ pub trait WeightInfo { fn sr25519_verification(i: u32, ) -> Weight; } -/// Weights for frame_benchmarking using the Substrate node and recommended hardware. +/// Weights for `frame_benchmarking` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1000000]`. @@ -68,101 +67,101 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 147_000 picoseconds. - Weight::from_parts(185_656, 0) + // Minimum execution time: 150_000 picoseconds. + Weight::from_parts(190_440, 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: 146_000 picoseconds. - Weight::from_parts(189_816, 0) + // Minimum execution time: 151_000 picoseconds. + Weight::from_parts(201_397, 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: 148_000 picoseconds. - Weight::from_parts(202_367, 0) + // Minimum execution time: 152_000 picoseconds. + Weight::from_parts(187_862, 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: 143_000 picoseconds. - Weight::from_parts(189_693, 0) + // Minimum execution time: 146_000 picoseconds. + Weight::from_parts(215_191, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 24_167_071_000 picoseconds. - Weight::from_parts(24_391_749_000, 0) + // Minimum execution time: 25_432_823_000 picoseconds. + Weight::from_parts(25_568_846_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: 231_000 picoseconds. - Weight::from_parts(2_998_013, 0) - // Standard Error: 6_256 - .saturating_add(Weight::from_parts(55_456_705, 0).saturating_mul(i.into())) + // Minimum execution time: 193_000 picoseconds. + Weight::from_parts(3_846_690, 0) + // Standard Error: 6_694 + .saturating_add(Weight::from_parts(40_647_582, 0).saturating_mul(i.into())) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { /// The range of component `i` is `[0, 1000000]`. fn addition(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 147_000 picoseconds. - Weight::from_parts(185_656, 0) + // Minimum execution time: 150_000 picoseconds. + Weight::from_parts(190_440, 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: 146_000 picoseconds. - Weight::from_parts(189_816, 0) + // Minimum execution time: 151_000 picoseconds. + Weight::from_parts(201_397, 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: 148_000 picoseconds. - Weight::from_parts(202_367, 0) + // Minimum execution time: 152_000 picoseconds. + Weight::from_parts(187_862, 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: 143_000 picoseconds. - Weight::from_parts(189_693, 0) + // Minimum execution time: 146_000 picoseconds. + Weight::from_parts(215_191, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 24_167_071_000 picoseconds. - Weight::from_parts(24_391_749_000, 0) + // Minimum execution time: 25_432_823_000 picoseconds. + Weight::from_parts(25_568_846_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: 231_000 picoseconds. - Weight::from_parts(2_998_013, 0) - // Standard Error: 6_256 - .saturating_add(Weight::from_parts(55_456_705, 0).saturating_mul(i.into())) + // Minimum execution time: 193_000 picoseconds. + Weight::from_parts(3_846_690, 0) + // Standard Error: 6_694 + .saturating_add(Weight::from_parts(40_647_582, 0).saturating_mul(i.into())) } } diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index df7c3c0cbe56098a03a87e462f71da07f4432f8f..191a38d20b2faf4a923bc074afd905c523c8a2c1 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index b0e3c085e65df02413f121fc4c819c823822cfab..da6596617dac4cc893cf27dfd9806436822cf516 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -31,9 +31,8 @@ use frame_support::{ PalletId, }; -use sp_core::H256; use sp_runtime::{ - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, IdentityLookup}, BuildStorage, Perbill, Storage, }; @@ -61,29 +60,10 @@ type Balance = u64; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/bounties/src/weights.rs b/substrate/frame/bounties/src/weights.rs index a172d15b56cc9a2a4686e3d6af61d9560635d5be..1f0e38b6702e99c4b27229c740abf76acd03f309 100644 --- a/substrate/frame/bounties/src/weights.rs +++ b/substrate/frame/bounties/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_bounties +//! Autogenerated weights for `pallet_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/bounties/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/bounties/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_bounties. +/// Weight functions needed for `pallet_bounties`. pub trait WeightInfo { fn propose_bounty(d: u32, ) -> Weight; fn approve_bounty() -> Weight; @@ -65,169 +64,169 @@ pub trait WeightInfo { fn spend_funds(b: u32, ) -> Weight; } -/// Weights for pallet_bounties using the Substrate node and recommended hardware. +/// Weights for `pallet_bounties` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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(314), added: 2789, 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(314), added: 2789, 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, 300]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `309` // Estimated: `3593` - // Minimum execution time: 29_384_000 picoseconds. - Weight::from_parts(30_820_018, 3593) - // Standard Error: 298 - .saturating_add(Weight::from_parts(2_920, 0).saturating_mul(d.into())) + // Minimum execution time: 24_286_000 picoseconds. + Weight::from_parts(25_657_314, 3593) + // Standard Error: 215 + .saturating_add(Weight::from_parts(1_116, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_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) + /// 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: `368` + // Measured: `401` // Estimated: `3642` - // Minimum execution time: 10_873_000 picoseconds. - Weight::from_parts(11_421_000, 3642) + // Minimum execution time: 12_526_000 picoseconds. + Weight::from_parts(13_373_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: `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: `388` + // Measured: `421` // Estimated: `3642` - // Minimum execution time: 9_181_000 picoseconds. - Weight::from_parts(9_726_000, 3642) + // Minimum execution time: 11_807_000 picoseconds. + Weight::from_parts(12_340_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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// 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: `564` + // Measured: `597` // Estimated: `3642` - // Minimum execution time: 30_257_000 picoseconds. - Weight::from_parts(30_751_000, 3642) + // Minimum execution time: 27_183_000 picoseconds. + Weight::from_parts(28_250_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) + /// 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: `560` + // Measured: `593` // Estimated: `3642` - // Minimum execution time: 27_850_000 picoseconds. - Weight::from_parts(28_821_000, 3642) + // Minimum execution time: 26_775_000 picoseconds. + Weight::from_parts(27_667_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: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, 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`) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `572` + // Measured: `605` // Estimated: `3642` - // Minimum execution time: 19_164_000 picoseconds. - Weight::from_parts(20_136_000, 3642) + // Minimum execution time: 16_089_000 picoseconds. + Weight::from_parts(16_909_000, 3642) .saturating_add(T::DbWeight::get().reads(2_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: 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(314), added: 2789, mode: MaxEncodedLen) + /// 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(314), added: 2789, mode: `MaxEncodedLen`) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `936` + // Measured: `969` // Estimated: `8799` - // Minimum execution time: 120_235_000 picoseconds. - Weight::from_parts(121_673_000, 8799) + // Minimum execution time: 104_973_000 picoseconds. + Weight::from_parts(107_696_000, 8799) .saturating_add(T::DbWeight::get().reads(5_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) - /// 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(314), added: 2789, 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(314), added: 2789, mode: `MaxEncodedLen`) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `616` + // Measured: `649` // Estimated: `3642` - // Minimum execution time: 35_713_000 picoseconds. - Weight::from_parts(37_174_000, 3642) + // Minimum execution time: 30_702_000 picoseconds. + Weight::from_parts(32_615_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) - /// 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: `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(314), added: 2789, mode: `MaxEncodedLen`) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `852` + // Measured: `885` // Estimated: `6196` - // Minimum execution time: 81_037_000 picoseconds. - Weight::from_parts(83_294_000, 6196) + // Minimum execution time: 72_055_000 picoseconds. + Weight::from_parts(73_900_000, 6196) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// 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: `424` + // Measured: `457` // Estimated: `3642` - // Minimum execution time: 15_348_000 picoseconds. - Weight::from_parts(15_776_000, 3642) + // Minimum execution time: 12_057_000 picoseconds. + Weight::from_parts(12_744_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// 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 { // Proof Size summary in bytes: - // Measured: `4 + b * (297 ±0)` + // Measured: `37 + b * (297 ±0)` // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 5_082_000 picoseconds. - Weight::from_parts(5_126_000, 1887) - // Standard Error: 21_949 - .saturating_add(Weight::from_parts(42_635_308, 0).saturating_mul(b.into())) + // Minimum execution time: 3_489_000 picoseconds. + Weight::from_parts(8_384_129, 1887) + // Standard Error: 18_066 + .saturating_add(Weight::from_parts(31_612_331, 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)) @@ -236,168 +235,168 @@ impl WeightInfo for SubstrateWeight { } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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(314), added: 2789, 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(314), added: 2789, 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, 300]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `309` // Estimated: `3593` - // Minimum execution time: 29_384_000 picoseconds. - Weight::from_parts(30_820_018, 3593) - // Standard Error: 298 - .saturating_add(Weight::from_parts(2_920, 0).saturating_mul(d.into())) + // Minimum execution time: 24_286_000 picoseconds. + Weight::from_parts(25_657_314, 3593) + // Standard Error: 215 + .saturating_add(Weight::from_parts(1_116, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_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) + /// 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: `368` + // Measured: `401` // Estimated: `3642` - // Minimum execution time: 10_873_000 picoseconds. - Weight::from_parts(11_421_000, 3642) + // Minimum execution time: 12_526_000 picoseconds. + Weight::from_parts(13_373_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: `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: `388` + // Measured: `421` // Estimated: `3642` - // Minimum execution time: 9_181_000 picoseconds. - Weight::from_parts(9_726_000, 3642) + // Minimum execution time: 11_807_000 picoseconds. + Weight::from_parts(12_340_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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// 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: `564` + // Measured: `597` // Estimated: `3642` - // Minimum execution time: 30_257_000 picoseconds. - Weight::from_parts(30_751_000, 3642) + // Minimum execution time: 27_183_000 picoseconds. + Weight::from_parts(28_250_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) + /// 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: `560` + // Measured: `593` // Estimated: `3642` - // Minimum execution time: 27_850_000 picoseconds. - Weight::from_parts(28_821_000, 3642) + // Minimum execution time: 26_775_000 picoseconds. + Weight::from_parts(27_667_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: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, 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`) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `572` + // Measured: `605` // Estimated: `3642` - // Minimum execution time: 19_164_000 picoseconds. - Weight::from_parts(20_136_000, 3642) + // Minimum execution time: 16_089_000 picoseconds. + Weight::from_parts(16_909_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_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: 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(314), added: 2789, mode: MaxEncodedLen) + /// 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(314), added: 2789, mode: `MaxEncodedLen`) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `936` + // Measured: `969` // Estimated: `8799` - // Minimum execution time: 120_235_000 picoseconds. - Weight::from_parts(121_673_000, 8799) + // Minimum execution time: 104_973_000 picoseconds. + Weight::from_parts(107_696_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_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) - /// 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(314), added: 2789, 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(314), added: 2789, mode: `MaxEncodedLen`) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `616` + // Measured: `649` // Estimated: `3642` - // Minimum execution time: 35_713_000 picoseconds. - Weight::from_parts(37_174_000, 3642) + // Minimum execution time: 30_702_000 picoseconds. + Weight::from_parts(32_615_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) - /// 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: `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(314), added: 2789, mode: `MaxEncodedLen`) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `852` + // Measured: `885` // Estimated: `6196` - // Minimum execution time: 81_037_000 picoseconds. - Weight::from_parts(83_294_000, 6196) + // Minimum execution time: 72_055_000 picoseconds. + Weight::from_parts(73_900_000, 6196) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// 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: `424` + // Measured: `457` // Estimated: `3642` - // Minimum execution time: 15_348_000 picoseconds. - Weight::from_parts(15_776_000, 3642) + // Minimum execution time: 12_057_000 picoseconds. + Weight::from_parts(12_744_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// 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 { // Proof Size summary in bytes: - // Measured: `4 + b * (297 ±0)` + // Measured: `37 + b * (297 ±0)` // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 5_082_000 picoseconds. - Weight::from_parts(5_126_000, 1887) - // Standard Error: 21_949 - .saturating_add(Weight::from_parts(42_635_308, 0).saturating_mul(b.into())) + // Minimum execution time: 3_489_000 picoseconds. + Weight::from_parts(8_384_129, 1887) + // Standard Error: 18_066 + .saturating_add(Weight::from_parts(31_612_331, 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/adapt_price.rs b/substrate/frame/broker/src/adapt_price.rs index 8266625687a23073a335bcab58db6ef7c33c8d80..fbcd7afdf0da059fb7023de3422f15b2344d5407 100644 --- a/substrate/frame/broker/src/adapt_price.rs +++ b/substrate/frame/broker/src/adapt_price.rs @@ -19,6 +19,7 @@ use crate::CoreIndex; use sp_arithmetic::{traits::One, FixedU64}; +use sp_runtime::Saturating; /// Type for determining how to set price. pub trait AdaptPrice { @@ -49,14 +50,24 @@ impl AdaptPrice for () { pub struct Linear; impl AdaptPrice for Linear { fn leadin_factor_at(when: FixedU64) -> FixedU64 { - FixedU64::from(2) - when + FixedU64::from(2).saturating_sub(when) } fn adapt_price(sold: CoreIndex, target: CoreIndex, limit: CoreIndex) -> FixedU64 { if sold <= target { - FixedU64::from_rational(sold.into(), target.into()) + // Range of [0.5, 1.0]. + FixedU64::from_rational(1, 2).saturating_add(FixedU64::from_rational( + sold.into(), + target.saturating_mul(2).into(), + )) } else { - FixedU64::one() + - FixedU64::from_rational((sold - target).into(), (limit - target).into()) + // Range of (1.0, 2]. + + // Unchecked math: In this branch we know that sold > target. The limit must be >= sold + // by construction, and thus target must be < limit. + FixedU64::one().saturating_add(FixedU64::from_rational( + (sold - target).into(), + (limit - target).into(), + )) } } } @@ -81,4 +92,23 @@ mod tests { } } } + + #[test] + fn linear_bound_check() { + // Using constraints from pallet implementation i.e. `limit >= sold`. + // Check extremes + let limit = 10; + let target = 5; + + // Maximally sold: `sold == limit` + assert_eq!(Linear::adapt_price(limit, target, limit), FixedU64::from_float(2.0)); + // Ideally sold: `sold == target` + assert_eq!(Linear::adapt_price(target, target, limit), FixedU64::one()); + // Minimally sold: `sold == 0` + assert_eq!(Linear::adapt_price(0, target, limit), FixedU64::from_float(0.5)); + // Optimistic target: `target == limit` + assert_eq!(Linear::adapt_price(limit, limit, limit), FixedU64::one()); + // Pessimistic target: `target == 0` + assert_eq!(Linear::adapt_price(limit, 0, limit), FixedU64::from_float(2.0)); + } } diff --git a/substrate/frame/broker/src/coretime_interface.rs b/substrate/frame/broker/src/coretime_interface.rs index 9e853e8f3fe0b1e2f76e3fac57b9ce0b8d03ab07..58efa7fa92bb0fa6c29a45375593f2246f5eaa8a 100644 --- a/substrate/frame/broker/src/coretime_interface.rs +++ b/substrate/frame/broker/src/coretime_interface.rs @@ -51,7 +51,7 @@ pub enum CoreAssignment { pub type RCBlockNumberOf = as BlockNumberProvider>::BlockNumber; /// Relay chain block number provider of `T` that implements [`CoretimeInterface`]. -pub type RCBlockNumberProviderOf = ::RealyChainBlockNumberProvider; +pub type RCBlockNumberProviderOf = ::RelayChainBlockNumberProvider; /// Type able to accept Coretime scheduling instructions and provide certain usage information. /// Generally implemented by the Relay-chain or some means of communicating with it. @@ -65,7 +65,7 @@ pub trait CoretimeInterface { type Balance: AtLeast32BitUnsigned; /// A provider for the relay chain block number. - type RealyChainBlockNumberProvider: BlockNumberProvider; + type RelayChainBlockNumberProvider: BlockNumberProvider; /// Requests the Relay-chain to alter the number of schedulable cores to `count`. Under normal /// operation, the Relay-chain SHOULD send a `notify_core_count(count)` message back. @@ -128,7 +128,7 @@ pub trait CoretimeInterface { impl CoretimeInterface for () { type AccountId = (); type Balance = u64; - type RealyChainBlockNumberProvider = (); + type RelayChainBlockNumberProvider = (); fn request_core_count(_count: CoreIndex) {} fn request_revenue_info_at(_when: RCBlockNumberOf) {} diff --git a/substrate/frame/broker/src/mock.rs b/substrate/frame/broker/src/mock.rs index 19c72340353c66d9bedf5d016e02dad7102116cb..ac327c4143e7b51e5350a0065ab861b1618ca0f5 100644 --- a/substrate/frame/broker/src/mock.rs +++ b/substrate/frame/broker/src/mock.rs @@ -77,7 +77,7 @@ pub struct TestCoretimeProvider; impl CoretimeInterface for TestCoretimeProvider { type AccountId = u64; type Balance = u64; - type RealyChainBlockNumberProvider = System; + type RelayChainBlockNumberProvider = System; fn request_core_count(count: CoreIndex) { CoreCountInbox::::put(count); } diff --git a/substrate/frame/broker/src/tests.rs b/substrate/frame/broker/src/tests.rs index e5efb70ae8d5a9a3ef4370592d2c2f1f461be228..3e1e36f7d4489c2ad6c7e1e555f1c8a40250083a 100644 --- a/substrate/frame/broker/src/tests.rs +++ b/substrate/frame/broker/src/tests.rs @@ -863,6 +863,29 @@ fn cannot_set_expired_lease() { }); } +#[test] +fn short_leases_are_cleaned() { + TestExt::new().region_length(3).execute_with(|| { + assert_ok!(Broker::do_start_sales(200, 1)); + advance_to(2); + + // New leases are allowed to expire within this region given expiry > `current_timeslice`. + assert_noop!( + Broker::do_set_lease(1000, Broker::current_timeslice()), + Error::::AlreadyExpired + ); + assert_eq!(Leases::::get().len(), 0); + assert_ok!(Broker::do_set_lease(1000, Broker::current_timeslice().saturating_add(1))); + assert_eq!(Leases::::get().len(), 1); + + // But are cleaned up in the next rotate_sale. + let config = Configuration::::get().unwrap(); + let timeslice_period: u64 = ::TimeslicePeriod::get(); + advance_to(timeslice_period.saturating_mul(config.region_length.into())); + assert_eq!(Leases::::get().len(), 0); + }); +} + #[test] fn leases_are_limited() { TestExt::new().execute_with(|| { diff --git a/substrate/frame/broker/src/tick_impls.rs b/substrate/frame/broker/src/tick_impls.rs index 8b7860c8e3af6daaaa433d9b7d093c94f292a5a6..388370bce4d4b8045122c02ad758b62b4476fd15 100644 --- a/substrate/frame/broker/src/tick_impls.rs +++ b/substrate/frame/broker/src/tick_impls.rs @@ -216,7 +216,9 @@ impl Pallet { let assignment = CoreAssignment::Task(task); let schedule = BoundedVec::truncate_from(vec![ScheduleItem { mask, assignment }]); Workplan::::insert((region_begin, first_core), &schedule); - let expiring = until >= region_begin && until < region_end; + // Separate these to avoid missed expired leases hanging around forever. + let expired = until < region_end; + let expiring = until >= region_begin && expired; if expiring { // last time for this one - make it renewable. let renewal_id = AllowedRenewalId { core: first_core, when: region_end }; @@ -231,7 +233,7 @@ impl Pallet { Self::deposit_event(Event::LeaseEnding { when: region_end, task }); } first_core.saturating_inc(); - !expiring + !expired }); Leases::::put(&leases); diff --git a/substrate/frame/broker/src/weights.rs b/substrate/frame/broker/src/weights.rs index a8f50eeee6e6ceaf284c1764a68411956753cfff..133ea63e35f7539c69d07cd4d442a4ce97aab80f 100644 --- a/substrate/frame/broker/src/weights.rs +++ b/substrate/frame/broker/src/weights.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_broker` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-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-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-pzhd7p6z-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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_broker +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_broker -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/broker/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -87,8 +89,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_040_000 picoseconds. - Weight::from_parts(3_344_000, 0) + // Minimum execution time: 2_701_000 picoseconds. + Weight::from_parts(2_902_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -97,8 +99,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 21_259_000 picoseconds. - Weight::from_parts(22_110_000, 7496) + // Minimum execution time: 18_056_000 picoseconds. + Weight::from_parts(19_093_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -108,8 +110,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 20_330_000 picoseconds. - Weight::from_parts(20_826_000, 7496) + // Minimum execution time: 17_233_000 picoseconds. + Weight::from_parts(17_788_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -119,8 +121,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 13_411_000 picoseconds. - Weight::from_parts(13_960_000, 1526) + // Minimum execution time: 9_740_000 picoseconds. + Weight::from_parts(10_504_000, 1526) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -139,14 +141,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(n: u32, ) -> Weight { + fn start_sales(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 57_770_000 picoseconds. - Weight::from_parts(61_047_512, 8499) - // Standard Error: 165 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + // Minimum execution time: 49_728_000 picoseconds. + Weight::from_parts(52_765_861, 8499) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)) } @@ -162,10 +162,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `568` - // Estimated: `2053` - // Minimum execution time: 51_196_000 picoseconds. - Weight::from_parts(52_382_000, 2053) + // Measured: `635` + // Estimated: `2120` + // Minimum execution time: 41_986_000 picoseconds. + Weight::from_parts(43_465_000, 2120) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -185,10 +185,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `686` + // Measured: `753` // Estimated: `4698` - // Minimum execution time: 71_636_000 picoseconds. - Weight::from_parts(73_679_000, 4698) + // Minimum execution time: 61_779_000 picoseconds. + Weight::from_parts(62_563_000, 4698) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -198,8 +198,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_182_000 picoseconds. - Weight::from_parts(19_775_000, 3550) + // Minimum execution time: 16_962_000 picoseconds. + Weight::from_parts(17_733_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -209,21 +209,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 20_688_000 picoseconds. - Weight::from_parts(21_557_000, 3550) + // Minimum execution time: 18_380_000 picoseconds. + Weight::from_parts(19_105_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Broker::Regions` (r:1 w:2) + /// Storage: `Broker::Regions` (r:1 w:3) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 21_190_000 picoseconds. - Weight::from_parts(22_215_000, 3550) + // Minimum execution time: 20_115_000 picoseconds. + Weight::from_parts(20_741_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -237,8 +237,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 34_591_000 picoseconds. - Weight::from_parts(36_227_000, 4681) + // Minimum execution time: 31_339_000 picoseconds. + Weight::from_parts(32_639_000, 4681) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -256,8 +256,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 40_346_000 picoseconds. - Weight::from_parts(41_951_000, 5996) + // Minimum execution time: 37_542_000 picoseconds. + Weight::from_parts(38_521_000, 5996) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -272,10 +272,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 75_734_000 picoseconds. - Weight::from_parts(78_168_395, 6196) - // Standard Error: 63_180 - .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) + // Minimum execution time: 66_176_000 picoseconds. + Weight::from_parts(68_356_745, 6196) + // Standard Error: 68_008 + .saturating_add(Weight::from_parts(1_558_419, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -287,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 46_383_000 picoseconds. - Weight::from_parts(47_405_000, 3593) + // Minimum execution time: 41_130_000 picoseconds. + Weight::from_parts(41_914_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -300,8 +300,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 30_994_000 picoseconds. - Weight::from_parts(31_979_000, 3550) + // Minimum execution time: 31_042_000 picoseconds. + Weight::from_parts(34_087_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -315,8 +315,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 37_584_000 picoseconds. - Weight::from_parts(44_010_000, 3533) + // Minimum execution time: 39_116_000 picoseconds. + Weight::from_parts(39_990_000, 3533) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -330,10 +330,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `830` + // Measured: `995` // Estimated: `3593` - // Minimum execution time: 45_266_000 picoseconds. - Weight::from_parts(48_000_000, 3593) + // Minimum execution time: 47_547_000 picoseconds. + Weight::from_parts(50_274_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -343,34 +343,32 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) fn drop_renewal() -> Weight { // Proof Size summary in bytes: - // Measured: `525` + // Measured: `661` // Estimated: `4698` - // Minimum execution time: 25_365_000 picoseconds. - Weight::from_parts(26_920_000, 4698) + // Minimum execution time: 26_707_000 picoseconds. + Weight::from_parts(27_217_000, 4698) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// The range of component `n` is `[0, 1000]`. - fn request_core_count(n: u32, ) -> Weight { + fn request_core_count(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_519_000 picoseconds. - Weight::from_parts(7_098_698, 0) - // Standard Error: 20 - .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) + // Minimum execution time: 4_651_000 picoseconds. + Weight::from_parts(5_231_385, 0) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn process_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `3563` - // Minimum execution time: 7_608_000 picoseconds. - Weight::from_parts(8_157_815, 3563) - // Standard Error: 26 - .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) + // Measured: `404` + // Estimated: `1487` + // Minimum execution time: 6_806_000 picoseconds. + Weight::from_parts(7_264_002, 1487) + // Standard Error: 21 + .saturating_add(Weight::from_parts(31, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -386,10 +384,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `905` - // Estimated: `4370` - // Minimum execution time: 59_993_000 picoseconds. - Weight::from_parts(61_752_000, 4370) + // Measured: `972` + // Estimated: `4437` + // Minimum execution time: 48_297_000 picoseconds. + Weight::from_parts(49_613_000, 4437) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -408,10 +406,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 41_863_000 picoseconds. - Weight::from_parts(44_033_031, 8499) - // Standard Error: 116 - .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) + // Minimum execution time: 36_715_000 picoseconds. + Weight::from_parts(38_580_380, 8499) + // Standard Error: 91 + .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } @@ -423,8 +421,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 9_588_000 picoseconds. - Weight::from_parts(9_925_000, 3493) + // Minimum execution time: 7_564_000 picoseconds. + Weight::from_parts(7_932_000, 3493) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -436,8 +434,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 19_308_000 picoseconds. - Weight::from_parts(20_482_000, 4681) + // Minimum execution time: 17_082_000 picoseconds. + Weight::from_parts(17_662_000, 4681) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -445,28 +443,35 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 147_000 picoseconds. - Weight::from_parts(184_000, 0) + // Minimum execution time: 175_000 picoseconds. + Weight::from_parts(223_000, 0) } + /// Storage: `Broker::CoreCountInbox` (r:0 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) fn notify_core_count() -> Weight { - T::DbWeight::get().reads_writes(1, 1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_432_000 picoseconds. + Weight::from_parts(2_536_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Status` (r:1 w:1) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:0) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `699` - // Estimated: `4164` - // Minimum execution time: 19_824_000 picoseconds. - Weight::from_parts(20_983_000, 4164) + // Measured: `603` + // Estimated: `4068` + // Minimum execution time: 13_080_000 picoseconds. + Weight::from_parts(13_937_000, 4068) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -478,8 +483,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_040_000 picoseconds. - Weight::from_parts(3_344_000, 0) + // Minimum execution time: 2_701_000 picoseconds. + Weight::from_parts(2_902_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -488,8 +493,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 21_259_000 picoseconds. - Weight::from_parts(22_110_000, 7496) + // Minimum execution time: 18_056_000 picoseconds. + Weight::from_parts(19_093_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -499,8 +504,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 20_330_000 picoseconds. - Weight::from_parts(20_826_000, 7496) + // Minimum execution time: 17_233_000 picoseconds. + Weight::from_parts(17_788_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -510,8 +515,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 13_411_000 picoseconds. - Weight::from_parts(13_960_000, 1526) + // Minimum execution time: 9_740_000 picoseconds. + Weight::from_parts(10_504_000, 1526) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -530,14 +535,12 @@ impl WeightInfo for () { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(n: u32, ) -> Weight { + fn start_sales(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 57_770_000 picoseconds. - Weight::from_parts(61_047_512, 8499) - // Standard Error: 165 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + // Minimum execution time: 49_728_000 picoseconds. + Weight::from_parts(52_765_861, 8499) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(16_u64)) } @@ -553,10 +556,10 @@ impl WeightInfo for () { /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `568` - // Estimated: `2053` - // Minimum execution time: 51_196_000 picoseconds. - Weight::from_parts(52_382_000, 2053) + // Measured: `635` + // Estimated: `2120` + // Minimum execution time: 41_986_000 picoseconds. + Weight::from_parts(43_465_000, 2120) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -576,10 +579,10 @@ impl WeightInfo for () { /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `686` + // Measured: `753` // Estimated: `4698` - // Minimum execution time: 71_636_000 picoseconds. - Weight::from_parts(73_679_000, 4698) + // Minimum execution time: 61_779_000 picoseconds. + Weight::from_parts(62_563_000, 4698) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -589,8 +592,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_182_000 picoseconds. - Weight::from_parts(19_775_000, 3550) + // Minimum execution time: 16_962_000 picoseconds. + Weight::from_parts(17_733_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -600,21 +603,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 20_688_000 picoseconds. - Weight::from_parts(21_557_000, 3550) + // Minimum execution time: 18_380_000 picoseconds. + Weight::from_parts(19_105_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Broker::Regions` (r:1 w:2) + /// Storage: `Broker::Regions` (r:1 w:3) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 21_190_000 picoseconds. - Weight::from_parts(22_215_000, 3550) + // Minimum execution time: 20_115_000 picoseconds. + Weight::from_parts(20_741_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -628,8 +631,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 34_591_000 picoseconds. - Weight::from_parts(36_227_000, 4681) + // Minimum execution time: 31_339_000 picoseconds. + Weight::from_parts(32_639_000, 4681) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -647,8 +650,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 40_346_000 picoseconds. - Weight::from_parts(41_951_000, 5996) + // Minimum execution time: 37_542_000 picoseconds. + Weight::from_parts(38_521_000, 5996) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -663,10 +666,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 75_734_000 picoseconds. - Weight::from_parts(78_168_395, 6196) - // Standard Error: 63_180 - .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) + // Minimum execution time: 66_176_000 picoseconds. + Weight::from_parts(68_356_745, 6196) + // Standard Error: 68_008 + .saturating_add(Weight::from_parts(1_558_419, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -678,8 +681,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 46_383_000 picoseconds. - Weight::from_parts(47_405_000, 3593) + // Minimum execution time: 41_130_000 picoseconds. + Weight::from_parts(41_914_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -691,8 +694,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 30_994_000 picoseconds. - Weight::from_parts(31_979_000, 3550) + // Minimum execution time: 31_042_000 picoseconds. + Weight::from_parts(34_087_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -706,8 +709,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 37_584_000 picoseconds. - Weight::from_parts(44_010_000, 3533) + // Minimum execution time: 39_116_000 picoseconds. + Weight::from_parts(39_990_000, 3533) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -721,10 +724,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `830` + // Measured: `995` // Estimated: `3593` - // Minimum execution time: 45_266_000 picoseconds. - Weight::from_parts(48_000_000, 3593) + // Minimum execution time: 47_547_000 picoseconds. + Weight::from_parts(50_274_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -734,34 +737,32 @@ impl WeightInfo for () { /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) fn drop_renewal() -> Weight { // Proof Size summary in bytes: - // Measured: `525` + // Measured: `661` // Estimated: `4698` - // Minimum execution time: 25_365_000 picoseconds. - Weight::from_parts(26_920_000, 4698) + // Minimum execution time: 26_707_000 picoseconds. + Weight::from_parts(27_217_000, 4698) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// The range of component `n` is `[0, 1000]`. - fn request_core_count(n: u32, ) -> Weight { + fn request_core_count(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_519_000 picoseconds. - Weight::from_parts(7_098_698, 0) - // Standard Error: 20 - .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) + // Minimum execution time: 4_651_000 picoseconds. + Weight::from_parts(5_231_385, 0) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn process_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `3563` - // Minimum execution time: 7_608_000 picoseconds. - Weight::from_parts(8_157_815, 3563) - // Standard Error: 26 - .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) + // Measured: `404` + // Estimated: `1487` + // Minimum execution time: 6_806_000 picoseconds. + Weight::from_parts(7_264_002, 1487) + // Standard Error: 21 + .saturating_add(Weight::from_parts(31, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -777,10 +778,10 @@ impl WeightInfo for () { /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `905` - // Estimated: `4370` - // Minimum execution time: 59_993_000 picoseconds. - Weight::from_parts(61_752_000, 4370) + // Measured: `972` + // Estimated: `4437` + // Minimum execution time: 48_297_000 picoseconds. + Weight::from_parts(49_613_000, 4437) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -799,10 +800,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 41_863_000 picoseconds. - Weight::from_parts(44_033_031, 8499) - // Standard Error: 116 - .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) + // Minimum execution time: 36_715_000 picoseconds. + Weight::from_parts(38_580_380, 8499) + // Standard Error: 91 + .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } @@ -814,8 +815,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 9_588_000 picoseconds. - Weight::from_parts(9_925_000, 3493) + // Minimum execution time: 7_564_000 picoseconds. + Weight::from_parts(7_932_000, 3493) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -827,8 +828,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 19_308_000 picoseconds. - Weight::from_parts(20_482_000, 4681) + // Minimum execution time: 17_082_000 picoseconds. + Weight::from_parts(17_662_000, 4681) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -836,28 +837,34 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 147_000 picoseconds. - Weight::from_parts(184_000, 0) + // Minimum execution time: 175_000 picoseconds. + Weight::from_parts(223_000, 0) } + /// Storage: `Broker::CoreCountInbox` (r:0 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) fn notify_core_count() -> Weight { - RocksDbWeight::get().reads(1) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_432_000 picoseconds. + Weight::from_parts(2_536_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Status` (r:1 w:1) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:0) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `699` - // Estimated: `4164` - // Minimum execution time: 19_824_000 picoseconds. - Weight::from_parts(20_983_000, 4164) + // Measured: `603` + // Estimated: `4068` + // Minimum execution time: 13_080_000 picoseconds. + Weight::from_parts(13_937_000, 4068) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index bcd8426c31645114230c03ca17fce6d67469c521..589ca95a7516148531434fc641af40f0f36796bb 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index d663b8d9961de87d14a202b393a9a4259f5bcdba..276a90a3e29cf78c91e0dc141d57e90c41df7d20 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -32,9 +32,8 @@ use frame_support::{ PalletId, }; -use sp_core::H256; use sp_runtime::{ - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, IdentityLookup}, BuildStorage, Perbill, Permill, TokenError, }; @@ -64,29 +63,10 @@ type Balance = u64; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = u128; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/child-bounties/src/weights.rs b/substrate/frame/child-bounties/src/weights.rs index e4c1f238e88b7f94e177ab6005fca0beb3e91d1f..6427517b45b040a649e59c90c2a2bd920e1e7621 100644 --- a/substrate/frame/child-bounties/src/weights.rs +++ b/substrate/frame/child-bounties/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_child_bounties +//! Autogenerated weights for `pallet_child_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/child-bounties/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/child-bounties/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_child_bounties. +/// Weight functions needed for `pallet_child_bounties`. pub trait WeightInfo { fn add_child_bounty(d: u32, ) -> Weight; fn propose_curator() -> Weight; @@ -62,288 +61,288 @@ pub trait WeightInfo { fn close_child_bounty_active() -> Weight; } -/// Weights for pallet_child_bounties using the Substrate node and recommended hardware. +/// Weights for `pallet_child_bounties` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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(314), added: 2789, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:0 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// 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(314), added: 2789, 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 { // Proof Size summary in bytes: - // Measured: `712` + // Measured: `745` // Estimated: `6196` - // Minimum execution time: 69_805_000 picoseconds. - Weight::from_parts(73_216_717, 6196) + // Minimum execution time: 60_674_000 picoseconds. + Weight::from_parts(63_477_428, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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: `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: `766` + // Measured: `799` // Estimated: `3642` - // Minimum execution time: 18_190_000 picoseconds. - Weight::from_parts(18_932_000, 3642) + // Minimum execution time: 17_754_000 picoseconds. + Weight::from_parts(18_655_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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) + /// 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: `912` + // Measured: `945` // Estimated: `3642` - // Minimum execution time: 35_035_000 picoseconds. - Weight::from_parts(35_975_000, 3642) + // Minimum execution time: 31_580_000 picoseconds. + Weight::from_parts(32_499_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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) + /// 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: `912` + // Measured: `945` // Estimated: `3642` - // Minimum execution time: 37_636_000 picoseconds. - Weight::from_parts(38_610_000, 3642) + // Minimum execution time: 33_536_000 picoseconds. + Weight::from_parts(34_102_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `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: `809` + // Measured: `842` // Estimated: `3642` - // Minimum execution time: 22_457_000 picoseconds. - Weight::from_parts(23_691_000, 3642) + // Minimum execution time: 18_295_000 picoseconds. + Weight::from_parts(19_496_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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(314), added: 2789, 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::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`) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `682` // Estimated: `8799` - // Minimum execution time: 118_272_000 picoseconds. - Weight::from_parts(121_646_000, 8799) + // Minimum execution time: 102_367_000 picoseconds. + Weight::from_parts(104_352_000, 8799) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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(314), added: 2789, mode: MaxEncodedLen) + /// 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(314), added: 2789, mode: `MaxEncodedLen`) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1012` + // Measured: `1045` // Estimated: `6196` - // Minimum execution time: 75_717_000 picoseconds. - Weight::from_parts(77_837_000, 6196) + // Minimum execution time: 69_051_000 picoseconds. + Weight::from_parts(71_297_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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(314), added: 2789, mode: MaxEncodedLen) + /// 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(314), added: 2789, mode: `MaxEncodedLen`) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1199` + // Measured: `1232` // Estimated: `8799` - // Minimum execution time: 94_215_000 picoseconds. - Weight::from_parts(97_017_000, 8799) + // Minimum execution time: 84_053_000 picoseconds. + Weight::from_parts(86_072_000, 8799) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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(314), added: 2789, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:0 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// 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(314), added: 2789, 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 { // Proof Size summary in bytes: - // Measured: `712` + // Measured: `745` // Estimated: `6196` - // Minimum execution time: 69_805_000 picoseconds. - Weight::from_parts(73_216_717, 6196) + // Minimum execution time: 60_674_000 picoseconds. + Weight::from_parts(63_477_428, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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: `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: `766` + // Measured: `799` // Estimated: `3642` - // Minimum execution time: 18_190_000 picoseconds. - Weight::from_parts(18_932_000, 3642) + // Minimum execution time: 17_754_000 picoseconds. + Weight::from_parts(18_655_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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) + /// 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: `912` + // Measured: `945` // Estimated: `3642` - // Minimum execution time: 35_035_000 picoseconds. - Weight::from_parts(35_975_000, 3642) + // Minimum execution time: 31_580_000 picoseconds. + Weight::from_parts(32_499_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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) + /// 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: `912` + // Measured: `945` // Estimated: `3642` - // Minimum execution time: 37_636_000 picoseconds. - Weight::from_parts(38_610_000, 3642) + // Minimum execution time: 33_536_000 picoseconds. + Weight::from_parts(34_102_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `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: `809` + // Measured: `842` // Estimated: `3642` - // Minimum execution time: 22_457_000 picoseconds. - Weight::from_parts(23_691_000, 3642) + // Minimum execution time: 18_295_000 picoseconds. + Weight::from_parts(19_496_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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(314), added: 2789, 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::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`) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `682` // Estimated: `8799` - // Minimum execution time: 118_272_000 picoseconds. - Weight::from_parts(121_646_000, 8799) + // Minimum execution time: 102_367_000 picoseconds. + Weight::from_parts(104_352_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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(314), added: 2789, mode: MaxEncodedLen) + /// 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(314), added: 2789, mode: `MaxEncodedLen`) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1012` + // Measured: `1045` // Estimated: `6196` - // Minimum execution time: 75_717_000 picoseconds. - Weight::from_parts(77_837_000, 6196) + // Minimum execution time: 69_051_000 picoseconds. + Weight::from_parts(71_297_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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(314), added: 2789, mode: MaxEncodedLen) + /// 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(314), added: 2789, mode: `MaxEncodedLen`) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1199` + // Measured: `1232` // Estimated: `8799` - // Minimum execution time: 94_215_000 picoseconds. - Weight::from_parts(97_017_000, 8799) + // Minimum execution time: 84_053_000 picoseconds. + Weight::from_parts(86_072_000, 8799) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index 91bb36bb89ec79fa8a71b0a4a41888383aab5553..e19e1496e7b5016819b1efaede408b19ae013c48 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/collective/src/benchmarking.rs b/substrate/frame/collective/src/benchmarking.rs index af10eae5b673d53b03298b3e0cba48c885dec69b..7b5df17b60a696a17b706dd01f05f2a01d3e787e 100644 --- a/substrate/frame/collective/src/benchmarking.rs +++ b/substrate/frame/collective/src/benchmarking.rs @@ -105,7 +105,7 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Root, new_members.clone(), new_members.last().cloned(), T::MaxMembers::get()) verify { new_members.sort(); - assert_eq!(Collective::::members(), new_members); + assert_eq!(Members::::get(), new_members); } execute { @@ -199,14 +199,14 @@ benchmarks_instance_pallet! { )?; } - assert_eq!(Collective::::proposals().len(), (p - 1) as usize); + assert_eq!(Proposals::::get().len(), (p - 1) as usize); let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(p, b as usize) }.into(); }: propose(SystemOrigin::Signed(caller.clone()), threshold, Box::new(proposal.clone()), bytes_in_storage) verify { // New proposal is recorded - assert_eq!(Collective::::proposals().len(), p as usize); + assert_eq!(Proposals::::get().len(), p as usize); let proposal_hash = T::Hashing::hash_of(&proposal); assert_last_event::(Event::Proposed { account: caller, proposal_index: p - 1, proposal_hash, threshold }.into()); } @@ -269,7 +269,7 @@ benchmarks_instance_pallet! { approve, )?; - assert_eq!(Collective::::proposals().len(), p as usize); + assert_eq!(Proposals::::get().len(), p as usize); // Voter switches vote to nay, but does not kill the vote, just updates + inserts let approve = false; @@ -280,8 +280,8 @@ benchmarks_instance_pallet! { }: _(SystemOrigin::Signed(voter), last_hash, index, approve) verify { // All proposals exist and the last proposal has just been updated. - assert_eq!(Collective::::proposals().len(), p as usize); - let voting = Collective::::voting(&last_hash).ok_or("Proposal Missing")?; + assert_eq!(Proposals::::get().len(), p as usize); + let voting = Voting::::get(&last_hash).ok_or("Proposal Missing")?; assert_eq!(voting.ayes.len(), (m - 3) as usize); assert_eq!(voting.nays.len(), 1); } @@ -344,7 +344,7 @@ benchmarks_instance_pallet! { approve, )?; - assert_eq!(Collective::::proposals().len(), p as usize); + assert_eq!(Proposals::::get().len(), p as usize); // Voter switches vote to nay, which kills the vote let approve = false; @@ -361,7 +361,7 @@ benchmarks_instance_pallet! { }: close(SystemOrigin::Signed(voter), last_hash, index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. - assert_eq!(Collective::::proposals().len(), (p - 1) as usize); + assert_eq!(Proposals::::get().len(), (p - 1) as usize); assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); } @@ -428,7 +428,7 @@ benchmarks_instance_pallet! { true, )?; - assert_eq!(Collective::::proposals().len(), p as usize); + assert_eq!(Proposals::::get().len(), p as usize); // Caller switches vote to aye, which passes the vote let index = p - 1; @@ -442,7 +442,7 @@ benchmarks_instance_pallet! { }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::MAX, bytes_in_storage) verify { // The last proposal is removed. - assert_eq!(Collective::::proposals().len(), (p - 1) as usize); + assert_eq!(Proposals::::get().len(), (p - 1) as usize); assert_last_event::(Event::Executed { proposal_hash: last_hash, result: Ok(()) }.into()); } @@ -519,12 +519,12 @@ benchmarks_instance_pallet! { )?; System::::set_block_number(BlockNumberFor::::max_value()); - assert_eq!(Collective::::proposals().len(), p as usize); + assert_eq!(Proposals::::get().len(), p as usize); // Prime nay will close it as disapproved }: close(SystemOrigin::Signed(caller), last_hash, index, Weight::MAX, bytes_in_storage) verify { - assert_eq!(Collective::::proposals().len(), (p - 1) as usize); + assert_eq!(Proposals::::get().len(), (p - 1) as usize); assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); } @@ -591,12 +591,12 @@ benchmarks_instance_pallet! { // caller is prime, prime already votes aye by creating the proposal System::::set_block_number(BlockNumberFor::::max_value()); - assert_eq!(Collective::::proposals().len(), p as usize); + assert_eq!(Proposals::::get().len(), p as usize); // Prime aye will close it as approved }: close(SystemOrigin::Signed(caller), last_hash, p - 1, Weight::MAX, bytes_in_storage) verify { - assert_eq!(Collective::::proposals().len(), (p - 1) as usize); + assert_eq!(Proposals::::get().len(), (p - 1) as usize); assert_last_event::(Event::Executed { proposal_hash: last_hash, result: Ok(()) }.into()); } @@ -640,11 +640,11 @@ benchmarks_instance_pallet! { } System::::set_block_number(BlockNumberFor::::max_value()); - assert_eq!(Collective::::proposals().len(), p as usize); + assert_eq!(Proposals::::get().len(), p as usize); }: _(SystemOrigin::Root, last_hash) verify { - assert_eq!(Collective::::proposals().len(), (p - 1) as usize); + assert_eq!(Proposals::::get().len(), (p - 1) as usize); assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); } diff --git a/substrate/frame/collective/src/lib.rs b/substrate/frame/collective/src/lib.rs index 10f989e5c4cc6ef92c258c21455d8f227dcf3dbe..882e99a6d0051306a103630a893d9fb44b803072 100644 --- a/substrate/frame/collective/src/lib.rs +++ b/substrate/frame/collective/src/lib.rs @@ -40,7 +40,6 @@ //! If there are not, or if no prime is set, then the motion is dropped without being executed. #![cfg_attr(not(feature = "std"), no_std)] -#![recursion_limit = "128"] use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -177,7 +176,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] @@ -262,36 +261,30 @@ pub mod pallet { /// The hashes of the active proposals. #[pallet::storage] - #[pallet::getter(fn proposals)] pub type Proposals, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; /// Actual proposal for a given hash, if it's current. #[pallet::storage] - #[pallet::getter(fn proposal_of)] pub type ProposalOf, I: 'static = ()> = StorageMap<_, Identity, T::Hash, >::Proposal, OptionQuery>; /// Votes on a given proposal, if it is ongoing. #[pallet::storage] - #[pallet::getter(fn voting)] pub type Voting, I: 'static = ()> = StorageMap<_, Identity, T::Hash, Votes>, OptionQuery>; /// Proposals so far. #[pallet::storage] - #[pallet::getter(fn proposal_count)] pub type ProposalCount, I: 'static = ()> = StorageValue<_, u32, ValueQuery>; /// The current members of the collective. This is stored sorted (just by value). #[pallet::storage] - #[pallet::getter(fn members)] pub type Members, I: 'static = ()> = StorageValue<_, Vec, ValueQuery>; /// The prime member that helps determine the default vote behavior in case of absentations. #[pallet::storage] - #[pallet::getter(fn prime)] pub type Prime, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>; #[pallet::event] @@ -460,7 +453,7 @@ pub mod pallet { #[pallet::compact] length_bound: u32, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let members = Self::members(); + let members = Members::::get(); ensure!(members.contains(&who), Error::::NotMember); let proposal_len = proposal.encoded_size(); ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); @@ -520,7 +513,7 @@ pub mod pallet { #[pallet::compact] length_bound: u32, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let members = Self::members(); + let members = Members::::get(); ensure!(members.contains(&who), Error::::NotMember); if threshold < 2 { @@ -566,7 +559,7 @@ pub mod pallet { approve: bool, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let members = Self::members(); + let members = Members::::get(); ensure!(members.contains(&who), Error::::NotMember); // Detects first vote of the member in the motion @@ -670,7 +663,7 @@ impl, I: 'static> Pallet { pub fn is_member(who: &T::AccountId) -> bool { // Note: The dispatchables *do not* use this to check membership so make sure // to update those if this is changed. - Self::members().contains(who) + Members::::get().contains(who) } /// Execute immediately when adding a new proposal. @@ -689,7 +682,7 @@ impl, I: 'static> Pallet { let proposal_hash = T::Hashing::hash_of(&proposal); ensure!(!>::contains_key(proposal_hash), Error::::DuplicateProposal); - let seats = Self::members().len() as MemberCount; + let seats = Members::::get().len() as MemberCount; let result = proposal.dispatch(RawOrigin::Members(1, seats).into()); Self::deposit_event(Event::Executed { proposal_hash, @@ -722,7 +715,7 @@ impl, I: 'static> Pallet { Ok(proposals.len()) })?; - let index = Self::proposal_count(); + let index = ProposalCount::::get(); >::mutate(|i| *i += 1); >::insert(proposal_hash, proposal); let votes = { @@ -748,7 +741,7 @@ impl, I: 'static> Pallet { index: ProposalIndex, approve: bool, ) -> Result { - let mut voting = Self::voting(&proposal).ok_or(Error::::ProposalMissing)?; + let mut voting = Voting::::get(&proposal).ok_or(Error::::ProposalMissing)?; ensure!(voting.index == index, Error::::WrongIndex); let position_yes = voting.ayes.iter().position(|a| a == &who); @@ -799,12 +792,12 @@ impl, I: 'static> Pallet { proposal_weight_bound: Weight, length_bound: u32, ) -> DispatchResultWithPostInfo { - let voting = Self::voting(&proposal_hash).ok_or(Error::::ProposalMissing)?; + let voting = Voting::::get(&proposal_hash).ok_or(Error::::ProposalMissing)?; ensure!(voting.index == index, Error::::WrongIndex); let mut no_votes = voting.nays.len() as MemberCount; let mut yes_votes = voting.ayes.len() as MemberCount; - let seats = Self::members().len() as MemberCount; + let seats = Members::::get().len() as MemberCount; let approved = yes_votes >= voting.threshold; let disapproved = seats.saturating_sub(no_votes) < voting.threshold; // Allow (dis-)approving the proposal as soon as there are enough votes. @@ -838,7 +831,7 @@ impl, I: 'static> Pallet { // Only allow actual closing of the proposal after the voting period has ended. ensure!(frame_system::Pallet::::block_number() >= voting.end, Error::::TooEarly); - let prime_vote = Self::prime().map(|who| voting.ayes.iter().any(|a| a == &who)); + let prime_vote = Prime::::get().map(|who| voting.ayes.iter().any(|a| a == &who)); // default voting strategy. let default = T::DefaultVote::default_vote(prime_vote, yes_votes, no_votes, seats); @@ -979,29 +972,28 @@ impl, I: 'static> Pallet { /// * The prime account must be a member of the collective. #[cfg(any(feature = "try-runtime", test))] fn do_try_state() -> Result<(), TryRuntimeError> { - Self::proposals() - .into_iter() - .try_for_each(|proposal| -> Result<(), TryRuntimeError> { + Proposals::::get().into_iter().try_for_each( + |proposal| -> Result<(), TryRuntimeError> { ensure!( - Self::proposal_of(proposal).is_some(), + ProposalOf::::get(proposal).is_some(), "Proposal hash from `Proposals` is not found inside the `ProposalOf` mapping." ); Ok(()) - })?; + }, + )?; ensure!( - Self::proposals().into_iter().count() <= Self::proposal_count() as usize, + Proposals::::get().into_iter().count() <= ProposalCount::::get() as usize, "The actual number of proposals is greater than `ProposalCount`" ); ensure!( - Self::proposals().into_iter().count() == >::iter_keys().count(), + Proposals::::get().into_iter().count() == >::iter_keys().count(), "Proposal count inside `Proposals` is not equal to the proposal count in `ProposalOf`" ); - Self::proposals() - .into_iter() - .try_for_each(|proposal| -> Result<(), TryRuntimeError> { - if let Some(votes) = Self::voting(proposal) { + Proposals::::get().into_iter().try_for_each( + |proposal| -> Result<(), TryRuntimeError> { + if let Some(votes) = Voting::::get(proposal) { let ayes = votes.ayes.len(); let nays = votes.nays.len(); @@ -1011,13 +1003,13 @@ impl, I: 'static> Pallet { ); } Ok(()) - })?; + }, + )?; let mut proposal_indices = vec![]; - Self::proposals() - .into_iter() - .try_for_each(|proposal| -> Result<(), TryRuntimeError> { - if let Some(votes) = Self::voting(proposal) { + Proposals::::get().into_iter().try_for_each( + |proposal| -> Result<(), TryRuntimeError> { + if let Some(votes) = Voting::::get(proposal) { let proposal_index = votes.index; ensure!( !proposal_indices.contains(&proposal_index), @@ -1026,12 +1018,13 @@ impl, I: 'static> Pallet { proposal_indices.push(proposal_index); } Ok(()) - })?; + }, + )?; >::iter_keys().try_for_each( |proposal_hash| -> Result<(), TryRuntimeError> { ensure!( - Self::proposals().contains(&proposal_hash), + Proposals::::get().contains(&proposal_hash), "`Proposals` doesn't contain the proposal hash from the `Voting` storage map." ); Ok(()) @@ -1039,17 +1032,17 @@ impl, I: 'static> Pallet { )?; ensure!( - Self::members().len() <= T::MaxMembers::get() as usize, + Members::::get().len() <= T::MaxMembers::get() as usize, "The member count is greater than `MaxMembers`." ); ensure!( - Self::members().windows(2).all(|members| members[0] <= members[1]), + Members::::get().windows(2).all(|members| members[0] <= members[1]), "The members are not sorted by value." ); - if let Some(prime) = Self::prime() { - ensure!(Self::members().contains(&prime), "Prime account is not a member."); + if let Some(prime) = Prime::::get() { + ensure!(Members::::get().contains(&prime), "Prime account is not a member."); } Ok(()) @@ -1083,7 +1076,7 @@ impl, I: 'static> ChangeMembers for Pallet { // remove accounts from all current voting in motions. let mut outgoing = outgoing.to_vec(); outgoing.sort(); - for h in Self::proposals().into_iter() { + for h in Proposals::::get().into_iter() { >::mutate(h, |v| { if let Some(mut votes) = v.take() { votes.ayes = votes diff --git a/substrate/frame/collective/src/tests.rs b/substrate/frame/collective/src/tests.rs index dbc3fbe69b3bf27b2151963979fc1d571d9bcc7c..92418794c5fb70fb44d0b60572ef18e3a617cfd9 100644 --- a/substrate/frame/collective/src/tests.rs +++ b/substrate/frame/collective/src/tests.rs @@ -26,14 +26,10 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EventRecord, Phase}; use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::{testing::Header, traits::BlakeTwo256, BuildStorage}; 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 @@ -93,29 +89,7 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl Config for Test { type RuntimeOrigin = RuntimeOrigin; @@ -219,8 +193,8 @@ fn default_max_proposal_weight() -> Weight { #[test] fn motions_basic_environment_works() { ExtBuilder::default().build_and_execute(|| { - assert_eq!(Collective::members(), vec![1, 2, 3]); - assert_eq!(*Collective::proposals(), Vec::::new()); + assert_eq!(Members::::get(), vec![1, 2, 3]); + assert_eq!(*Proposals::::get(), Vec::::new()); }); } @@ -231,7 +205,7 @@ fn initialize_members_sorts_members() { ExtBuilder::default() .set_collective_members(unsorted_members) .build_and_execute(|| { - assert_eq!(Collective::members(), expected_members); + assert_eq!(Members::::get(), expected_members); }); } @@ -245,8 +219,8 @@ fn set_members_with_prime_works() { Some(3), MaxMembers::get() )); - assert_eq!(Collective::members(), members.clone()); - assert_eq!(Collective::prime(), Some(3)); + assert_eq!(Members::::get(), members.clone()); + assert_eq!(Prime::::get(), Some(3)); assert_noop!( Collective::set_members(RuntimeOrigin::root(), members, Some(4), MaxMembers::get()), Error::::PrimeAccountNotMember @@ -658,12 +632,12 @@ fn removal_of_old_voters_votes_works() { assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![], end }) ); Collective::change_members_sorted(&[4], &[1], &[2, 3, 4]); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![], end }) ); @@ -679,12 +653,12 @@ fn removal_of_old_voters_votes_works() { assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, false)); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3], end }) ); Collective::change_members_sorted(&[], &[3], &[2, 4]); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![], end }) ); }); @@ -706,7 +680,7 @@ fn removal_of_old_voters_votes_works_with_set_members() { assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![], end }) ); assert_ok!(Collective::set_members( @@ -716,7 +690,7 @@ fn removal_of_old_voters_votes_works_with_set_members() { MaxMembers::get() )); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![], end }) ); @@ -732,7 +706,7 @@ fn removal_of_old_voters_votes_works_with_set_members() { assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, false)); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3], end }) ); assert_ok!(Collective::set_members( @@ -742,7 +716,7 @@ fn removal_of_old_voters_votes_works_with_set_members() { MaxMembers::get() )); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![], end }) ); }); @@ -761,10 +735,10 @@ fn propose_works() { Box::new(proposal.clone()), proposal_len )); - assert_eq!(*Collective::proposals(), vec![hash]); - assert_eq!(Collective::proposal_of(&hash), Some(proposal)); + assert_eq!(*Proposals::::get(), vec![hash]); + assert_eq!(ProposalOf::::get(&hash), Some(proposal)); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![], nays: vec![], end }) ); @@ -924,13 +898,13 @@ fn motions_vote_after_works() { )); // Initially there a no votes when the motion is proposed. assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![], end }) ); // Cast first aye vote. assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![1], nays: vec![], end }) ); // Try to cast a duplicate aye vote. @@ -941,7 +915,7 @@ fn motions_vote_after_works() { // Cast a nay vote. assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, false)); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![1], end }) ); // Try to cast a duplicate nay vote. @@ -992,7 +966,7 @@ fn motions_all_first_vote_free_works() { proposal_len, )); assert_eq!( - Collective::voting(&hash), + Voting::::get(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![], end }) ); @@ -1057,14 +1031,14 @@ fn motions_reproposing_disapproved_works() { proposal_weight, proposal_len )); - assert_eq!(*Collective::proposals(), vec![]); + assert_eq!(*Proposals::::get(), vec![]); assert_ok!(Collective::propose( RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); - assert_eq!(*Collective::proposals(), vec![hash]); + assert_eq!(*Proposals::::get(), vec![hash]); }); } diff --git a/substrate/frame/collective/src/weights.rs b/substrate/frame/collective/src/weights.rs index eece6a006b8f2bda108645e3d8b165a37ad04335..85744b4de9daed455a18b42a16d05933b78d4939 100644 --- a/substrate/frame/collective/src/weights.rs +++ b/substrate/frame/collective/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_collective +//! Autogenerated weights for `pallet_collective` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/collective/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/collective/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_collective. +/// Weight functions needed for `pallet_collective`. pub trait WeightInfo { fn set_members(m: u32, n: u32, p: u32, ) -> Weight; fn execute(b: u32, m: u32, ) -> Weight; @@ -64,30 +63,30 @@ pub trait WeightInfo { fn disapprove_proposal(p: u32, ) -> Weight; } -/// Weights for pallet_collective using the Substrate node and recommended hardware. +/// Weights for `pallet_collective` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Council Members (r:1 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:100 w:100) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Voting` (r:100 w:100) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:0 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15861 + m * (1967 ±24) + p * (4332 ±24)` - // Minimum execution time: 17_506_000 picoseconds. - Weight::from_parts(17_767_000, 15861) - // Standard Error: 60_220 - .saturating_add(Weight::from_parts(4_374_805, 0).saturating_mul(m.into())) - // Standard Error: 60_220 - .saturating_add(Weight::from_parts(8_398_316, 0).saturating_mul(p.into())) + // Estimated: `15894 + m * (1967 ±23) + p * (4332 ±23)` + // Minimum execution time: 15_559_000 picoseconds. + Weight::from_parts(15_870_000, 15894) + // Standard Error: 54_310 + .saturating_add(Weight::from_parts(4_117_753, 0).saturating_mul(m.into())) + // Standard Error: 54_310 + .saturating_add(Weight::from_parts(7_677_627, 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)) @@ -95,245 +94,261 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `202 + m * (32 ±0)` - // Estimated: `1688 + m * (32 ±0)` - // Minimum execution time: 16_203_000 picoseconds. - Weight::from_parts(15_348_267, 1688) - // Standard Error: 37 - .saturating_add(Weight::from_parts(1_766, 0).saturating_mul(b.into())) - // Standard Error: 382 - .saturating_add(Weight::from_parts(15_765, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `380 + m * (32 ±0)` + // Estimated: `3997 + m * (32 ±0)` + // Minimum execution time: 19_024_000 picoseconds. + Weight::from_parts(18_153_872, 3997) + // Standard Error: 46 + .saturating_add(Weight::from_parts(1_933, 0).saturating_mul(b.into())) + // Standard Error: 478 + .saturating_add(Weight::from_parts(18_872, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:0) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:0) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `202 + m * (32 ±0)` - // Estimated: `3668 + m * (32 ±0)` - // Minimum execution time: 18_642_000 picoseconds. - Weight::from_parts(17_708_609, 3668) - // Standard Error: 58 - .saturating_add(Weight::from_parts(2_285, 0).saturating_mul(b.into())) - // Standard Error: 598 - .saturating_add(Weight::from_parts(30_454, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `380 + m * (32 ±0)` + // Estimated: `3997 + m * (32 ±0)` + // Minimum execution time: 20_895_000 picoseconds. + Weight::from_parts(20_081_761, 3997) + // Standard Error: 57 + .saturating_add(Weight::from_parts(1_982, 0).saturating_mul(b.into())) + // Standard Error: 594 + .saturating_add(Weight::from_parts(32_085, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalCount (r:1 w:1) - /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// 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) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `492 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3884 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 27_067_000 picoseconds. - Weight::from_parts(25_456_964, 3884) - // Standard Error: 112 - .saturating_add(Weight::from_parts(3_773, 0).saturating_mul(b.into())) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(32_783, 0).saturating_mul(m.into())) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(194_388, 0).saturating_mul(p.into())) + // Measured: `525 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `3917 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 22_068_000 picoseconds. + Weight::from_parts(19_639_088, 3917) + // Standard Error: 104 + .saturating_add(Weight::from_parts(3_896, 0).saturating_mul(b.into())) + // Standard Error: 1_095 + .saturating_add(Weight::from_parts(31_634, 0).saturating_mul(m.into())) + // Standard Error: 1_081 + .saturating_add(Weight::from_parts(178_702, 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, 33).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `941 + m * (64 ±0)` - // Estimated: `4405 + m * (64 ±0)` - // Minimum execution time: 26_055_000 picoseconds. - Weight::from_parts(27_251_907, 4405) - // Standard Error: 1_008 - .saturating_add(Weight::from_parts(65_947, 0).saturating_mul(m.into())) + // Measured: `974 + m * (64 ±0)` + // Estimated: `4438 + m * (64 ±0)` + // Minimum execution time: 22_395_000 picoseconds. + Weight::from_parts(23_025_217, 4438) + // Standard Error: 842 + .saturating_add(Weight::from_parts(58_102, 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())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:0 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `530 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3975 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 28_363_000 picoseconds. - Weight::from_parts(28_733_464, 3975) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(43_236, 0).saturating_mul(m.into())) - // Standard Error: 1_244 - .saturating_add(Weight::from_parts(180_187, 0).saturating_mul(p.into())) + // Measured: `563 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4008 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 24_179_000 picoseconds. + Weight::from_parts(23_846_394, 4008) + // Standard Error: 1_052 + .saturating_add(Weight::from_parts(40_418, 0).saturating_mul(m.into())) + // Standard Error: 1_026 + .saturating_add(Weight::from_parts(171_653, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// 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: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4149 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_391_000 picoseconds. - Weight::from_parts(42_695_215, 4149) - // Standard Error: 167 - .saturating_add(Weight::from_parts(3_622, 0).saturating_mul(b.into())) - // Standard Error: 1_772 - .saturating_add(Weight::from_parts(33_830, 0).saturating_mul(m.into())) - // Standard Error: 1_727 - .saturating_add(Weight::from_parts(205_374, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `1010 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4327 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 42_129_000 picoseconds. + Weight::from_parts(40_808_957, 4327) + // Standard Error: 134 + .saturating_add(Weight::from_parts(3_579, 0).saturating_mul(b.into())) + // Standard Error: 1_425 + .saturating_add(Weight::from_parts(37_166, 0).saturating_mul(m.into())) + // Standard Error: 1_389 + .saturating_add(Weight::from_parts(200_986, 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())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:0) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:0 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `550 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3995 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 31_368_000 picoseconds. - Weight::from_parts(32_141_835, 3995) - // Standard Error: 1_451 - .saturating_add(Weight::from_parts(36_372, 0).saturating_mul(m.into())) - // Standard Error: 1_415 - .saturating_add(Weight::from_parts(210_635, 0).saturating_mul(p.into())) + // Measured: `583 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4028 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 26_385_000 picoseconds. + Weight::from_parts(25_713_839, 4028) + // Standard Error: 1_254 + .saturating_add(Weight::from_parts(36_206, 0).saturating_mul(m.into())) + // Standard Error: 1_223 + .saturating_add(Weight::from_parts(195_114, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:0) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4169 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 43_271_000 picoseconds. - Weight::from_parts(45_495_648, 4169) - // Standard Error: 174 - .saturating_add(Weight::from_parts(3_034, 0).saturating_mul(b.into())) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(42_209, 0).saturating_mul(m.into())) - // Standard Error: 1_793 - .saturating_add(Weight::from_parts(207_525, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Measured: `1030 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4347 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 42_903_000 picoseconds. + Weight::from_parts(43_152_907, 4347) + // Standard Error: 146 + .saturating_add(Weight::from_parts(3_459, 0).saturating_mul(b.into())) + // Standard Error: 1_548 + .saturating_add(Weight::from_parts(35_321, 0).saturating_mul(m.into())) + // Standard Error: 1_509 + .saturating_add(Weight::from_parts(202_541, 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())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// 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) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:0 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `359 + p * (32 ±0)` - // Estimated: `1844 + p * (32 ±0)` - // Minimum execution time: 15_170_000 picoseconds. - Weight::from_parts(17_567_243, 1844) - // Standard Error: 1_430 - .saturating_add(Weight::from_parts(169_040, 0).saturating_mul(p.into())) + // Measured: `392 + p * (32 ±0)` + // Estimated: `1877 + p * (32 ±0)` + // Minimum execution time: 12_656_000 picoseconds. + Weight::from_parts(14_032_951, 1877) + // Standard Error: 1_025 + .saturating_add(Weight::from_parts(159_143, 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())) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Council Members (r:1 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:100 w:100) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Voting` (r:100 w:100) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:0 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15861 + m * (1967 ±24) + p * (4332 ±24)` - // Minimum execution time: 17_506_000 picoseconds. - Weight::from_parts(17_767_000, 15861) - // Standard Error: 60_220 - .saturating_add(Weight::from_parts(4_374_805, 0).saturating_mul(m.into())) - // Standard Error: 60_220 - .saturating_add(Weight::from_parts(8_398_316, 0).saturating_mul(p.into())) + // Estimated: `15894 + m * (1967 ±23) + p * (4332 ±23)` + // Minimum execution time: 15_559_000 picoseconds. + Weight::from_parts(15_870_000, 15894) + // Standard Error: 54_310 + .saturating_add(Weight::from_parts(4_117_753, 0).saturating_mul(m.into())) + // Standard Error: 54_310 + .saturating_add(Weight::from_parts(7_677_627, 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)) @@ -341,216 +356,232 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `202 + m * (32 ±0)` - // Estimated: `1688 + m * (32 ±0)` - // Minimum execution time: 16_203_000 picoseconds. - Weight::from_parts(15_348_267, 1688) - // Standard Error: 37 - .saturating_add(Weight::from_parts(1_766, 0).saturating_mul(b.into())) - // Standard Error: 382 - .saturating_add(Weight::from_parts(15_765, 0).saturating_mul(m.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `380 + m * (32 ±0)` + // Estimated: `3997 + m * (32 ±0)` + // Minimum execution time: 19_024_000 picoseconds. + Weight::from_parts(18_153_872, 3997) + // Standard Error: 46 + .saturating_add(Weight::from_parts(1_933, 0).saturating_mul(b.into())) + // Standard Error: 478 + .saturating_add(Weight::from_parts(18_872, 0).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:0) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:0) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `202 + m * (32 ±0)` - // Estimated: `3668 + m * (32 ±0)` - // Minimum execution time: 18_642_000 picoseconds. - Weight::from_parts(17_708_609, 3668) - // Standard Error: 58 - .saturating_add(Weight::from_parts(2_285, 0).saturating_mul(b.into())) - // Standard Error: 598 - .saturating_add(Weight::from_parts(30_454, 0).saturating_mul(m.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `380 + m * (32 ±0)` + // Estimated: `3997 + m * (32 ±0)` + // Minimum execution time: 20_895_000 picoseconds. + Weight::from_parts(20_081_761, 3997) + // Standard Error: 57 + .saturating_add(Weight::from_parts(1_982, 0).saturating_mul(b.into())) + // Standard Error: 594 + .saturating_add(Weight::from_parts(32_085, 0).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalCount (r:1 w:1) - /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// 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) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `492 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3884 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 27_067_000 picoseconds. - Weight::from_parts(25_456_964, 3884) - // Standard Error: 112 - .saturating_add(Weight::from_parts(3_773, 0).saturating_mul(b.into())) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(32_783, 0).saturating_mul(m.into())) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(194_388, 0).saturating_mul(p.into())) + // Measured: `525 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `3917 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 22_068_000 picoseconds. + Weight::from_parts(19_639_088, 3917) + // Standard Error: 104 + .saturating_add(Weight::from_parts(3_896, 0).saturating_mul(b.into())) + // Standard Error: 1_095 + .saturating_add(Weight::from_parts(31_634, 0).saturating_mul(m.into())) + // Standard Error: 1_081 + .saturating_add(Weight::from_parts(178_702, 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, 33).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `941 + m * (64 ±0)` - // Estimated: `4405 + m * (64 ±0)` - // Minimum execution time: 26_055_000 picoseconds. - Weight::from_parts(27_251_907, 4405) - // Standard Error: 1_008 - .saturating_add(Weight::from_parts(65_947, 0).saturating_mul(m.into())) + // Measured: `974 + m * (64 ±0)` + // Estimated: `4438 + m * (64 ±0)` + // Minimum execution time: 22_395_000 picoseconds. + Weight::from_parts(23_025_217, 4438) + // Standard Error: 842 + .saturating_add(Weight::from_parts(58_102, 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())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:0 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `530 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3975 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 28_363_000 picoseconds. - Weight::from_parts(28_733_464, 3975) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(43_236, 0).saturating_mul(m.into())) - // Standard Error: 1_244 - .saturating_add(Weight::from_parts(180_187, 0).saturating_mul(p.into())) + // Measured: `563 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4008 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 24_179_000 picoseconds. + Weight::from_parts(23_846_394, 4008) + // Standard Error: 1_052 + .saturating_add(Weight::from_parts(40_418, 0).saturating_mul(m.into())) + // Standard Error: 1_026 + .saturating_add(Weight::from_parts(171_653, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// 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: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4149 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_391_000 picoseconds. - Weight::from_parts(42_695_215, 4149) - // Standard Error: 167 - .saturating_add(Weight::from_parts(3_622, 0).saturating_mul(b.into())) - // Standard Error: 1_772 - .saturating_add(Weight::from_parts(33_830, 0).saturating_mul(m.into())) - // Standard Error: 1_727 - .saturating_add(Weight::from_parts(205_374, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Measured: `1010 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4327 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 42_129_000 picoseconds. + Weight::from_parts(40_808_957, 4327) + // Standard Error: 134 + .saturating_add(Weight::from_parts(3_579, 0).saturating_mul(b.into())) + // Standard Error: 1_425 + .saturating_add(Weight::from_parts(37_166, 0).saturating_mul(m.into())) + // Standard Error: 1_389 + .saturating_add(Weight::from_parts(200_986, 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())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:0) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:0 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `550 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3995 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 31_368_000 picoseconds. - Weight::from_parts(32_141_835, 3995) - // Standard Error: 1_451 - .saturating_add(Weight::from_parts(36_372, 0).saturating_mul(m.into())) - // Standard Error: 1_415 - .saturating_add(Weight::from_parts(210_635, 0).saturating_mul(p.into())) + // Measured: `583 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4028 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 26_385_000 picoseconds. + Weight::from_parts(25_713_839, 4028) + // Standard Error: 1_254 + .saturating_add(Weight::from_parts(36_206, 0).saturating_mul(m.into())) + // Standard Error: 1_223 + .saturating_add(Weight::from_parts(195_114, 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())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Council::Voting` (r:1 w:1) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:1 w:0) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:0) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:1 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `Council::Proposals` (r:1 w:1) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4169 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 43_271_000 picoseconds. - Weight::from_parts(45_495_648, 4169) - // Standard Error: 174 - .saturating_add(Weight::from_parts(3_034, 0).saturating_mul(b.into())) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(42_209, 0).saturating_mul(m.into())) - // Standard Error: 1_793 - .saturating_add(Weight::from_parts(207_525, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Measured: `1030 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4347 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 42_903_000 picoseconds. + Weight::from_parts(43_152_907, 4347) + // Standard Error: 146 + .saturating_add(Weight::from_parts(3_459, 0).saturating_mul(b.into())) + // Standard Error: 1_548 + .saturating_add(Weight::from_parts(35_321, 0).saturating_mul(m.into())) + // Standard Error: 1_509 + .saturating_add(Weight::from_parts(202_541, 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())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// 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) + /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::ProposalOf` (r:0 w:1) + /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `359 + p * (32 ±0)` - // Estimated: `1844 + p * (32 ±0)` - // Minimum execution time: 15_170_000 picoseconds. - Weight::from_parts(17_567_243, 1844) - // Standard Error: 1_430 - .saturating_add(Weight::from_parts(169_040, 0).saturating_mul(p.into())) + // Measured: `392 + p * (32 ±0)` + // Estimated: `1877 + p * (32 ±0)` + // Minimum execution time: 12_656_000 picoseconds. + Weight::from_parts(14_032_951, 1877) + // Standard Error: 1_025 + .saturating_add(Weight::from_parts(159_143, 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())) diff --git a/substrate/frame/contracts/CHANGELOG.md b/substrate/frame/contracts/CHANGELOG.md deleted file mode 100644 index aca94e5b149152d5c598102c633048baa17d1276..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/CHANGELOG.md +++ /dev/null @@ -1,116 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -The semantic versioning guarantees cover the interface to the Substrate runtime which -includes this pallet as a dependency. This module will also add storage migrations whenever -changes require it. Stability with regard to offchain tooling is explicitly excluded from -this guarantee: For example adding a new field to an in-storage data structure will require -changes to frontends to properly display it. However, those changes will still be regarded -as a minor version bump. - -The interface provided to smart contracts will adhere to semver with one exception: Even -major version bumps will be backwards compatible with regard to already deployed contracts. -In other words: Upgrading this pallet will not break pre-existing contracts. - -## [Unreleased] - -### Added - -- Forbid calling back to contracts after switching to runtime -[#13443](https://github.com/paritytech/substrate/pull/13443) - -- Allow contracts to dispatch calls into the runtime (**unstable**) -[#9276](https://github.com/paritytech/substrate/pull/9276) - -- New version of `seal_call` that offers more features. -[#8909](https://github.com/paritytech/substrate/pull/8909) - -- New `instantiate` RPC that allows clients to dry-run contract instantiation. -[#8451](https://github.com/paritytech/substrate/pull/8451) - -- New version of `seal_random` which exposes additional information. -[#8329](https://github.com/paritytech/substrate/pull/8329) - -### Changed - -- Replaced storage rent with automatic storage deposits -[#9669](https://github.com/paritytech/substrate/pull/9669) -[#10082](https://github.com/paritytech/substrate/pull/10082) - -- Replaced `seal_println` with the `seal_debug_message` API which allows outputting debug -messages to the console and RPC clients. -[#8773](https://github.com/paritytech/substrate/pull/8773) -[#9550](https://github.com/paritytech/substrate/pull/9550) - -- Make storage and fields of `Schedule` private to the crate. -[#8359](https://github.com/paritytech/substrate/pull/8359) - -### Fixed - -- Remove pre-charging which caused wrongly estimated weights -[#8976](https://github.com/paritytech/substrate/pull/8976) - -## [v3.0.0] 2021-02-25 - -This version constitutes the first release that brings any stability guarantees (see above). - -### Added - -- Emit an event when a contract terminates (self-destructs). -[#8014](https://github.com/paritytech/substrate/pull/8014) - -- Charge rent for code stored on the chain in addition to the already existing -rent that is paid for data storage. -[#7935](https://github.com/paritytech/substrate/pull/7935) - -- Allow the runtime to configure per storage item costs in addition -to the already existing per byte costs. -[#7819](https://github.com/paritytech/substrate/pull/7819) - -- Contracts are now deleted lazily so that the user who removes a contract -does not need to pay for the deletion of the contract storage. -[#7740](https://github.com/paritytech/substrate/pull/7740) - -- Allow runtime authors to define chain extensions in order to provide custom -functionality to contracts. -[#7548](https://github.com/paritytech/substrate/pull/7548) -[#8003](https://github.com/paritytech/substrate/pull/8003) - -- Proper weights which are fully automated by benchmarking. -[#6715](https://github.com/paritytech/substrate/pull/6715) -[#7017](https://github.com/paritytech/substrate/pull/7017) -[#7361](https://github.com/paritytech/substrate/pull/7361) - -### Changed - -- Collect the rent for one block during instantiation. -[#7847](https://github.com/paritytech/substrate/pull/7847) - -- Instantiation takes a `salt` argument to allow for easier instantion of the -same code by the same sender. -[#7482](https://github.com/paritytech/substrate/pull/7482) - -- Improve the information returned by the `contracts_call` RPC. -[#7468](https://github.com/paritytech/substrate/pull/7468) - -- Simplify the node configuration necessary to add this module. -[#7409](https://github.com/paritytech/substrate/pull/7409) - -### Fixed - -- Consider the code size of a contract in the weight that is charged for -loading a contract from storage. -[#8086](https://github.com/paritytech/substrate/pull/8086) - -- Fix possible overflow in storage size calculation -[#7885](https://github.com/paritytech/substrate/pull/7885) - -- Cap the surcharge reward that can be claimed. -[#7870](https://github.com/paritytech/substrate/pull/7870) - -- Fix a possible DoS vector where contracts could allocate too large buffers. -[#7818](https://github.com/paritytech/substrate/pull/7818) diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index de49983a4b3fa89309b939d03e76aa053c1fd16d..be3bafcd23fa107b12005ebe45da874e2a55e16b 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -24,8 +24,8 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "max-encoded-len", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -log = { version = "0.4", default-features = false } -serde = { version = "1", optional = true, features = ["derive"] } +log = { workspace = true } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } smallvec = { version = "1", default-features = false, features = [ "const_generics", ] } diff --git a/substrate/frame/contracts/benchmarks/README.md b/substrate/frame/contracts/benchmarks/README.md deleted file mode 100644 index e4441d6bab2c425a37639830f12ca303db30d1fa..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/benchmarks/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Benchmarks - -This directory contains real world ([ink!](https://use.ink), [solang](https://github.com/hyperledger/solang)) contracts -which are used in macro benchmarks. Those benchmarks are not used to determine weights but rather to compare different -contract languages and execution engines with larger wasm modules. - -Files in this directory are used by `#[extra]` benchmarks in `src/benchmarking`. The json files are for informational -purposes only and are not consumed by the benchmarks. diff --git a/substrate/frame/contracts/benchmarks/ink_erc20.json b/substrate/frame/contracts/benchmarks/ink_erc20.json deleted file mode 100644 index 390dd9b06cd4cd3ee57f83f64c9089508c68464d..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/benchmarks/ink_erc20.json +++ /dev/null @@ -1,819 +0,0 @@ -{ - "metadataVersion": "0.1.0", - "source": { - "hash": "0x6be8492017fe96b7a92bb39b4ede04b96effb8fcaf9237bfdccef7d9e732c760", - "language": "ink! 3.0.0-rc4", - "compiler": "rustc 1.56.0-nightly" - }, - "contract": { - "name": "erc20", - "version": "3.0.0-rc4", - "authors": [ - "Parity Technologies " - ] - }, - "spec": { - "constructors": [ - { - "args": [ - { - "name": "initial_supply", - "type": { - "displayName": [ - "Balance" - ], - "type": 1 - } - } - ], - "docs": [ - "Creates a new ERC-20 contract with the specified initial supply." - ], - "name": [ - "new" - ], - "selector": "0x9bae9d5e" - } - ], - "docs": [], - "events": [ - { - "args": [ - { - "docs": [], - "indexed": true, - "name": "from", - "type": { - "displayName": [ - "Option" - ], - "type": 15 - } - }, - { - "docs": [], - "indexed": true, - "name": "to", - "type": { - "displayName": [ - "Option" - ], - "type": 15 - } - }, - { - "docs": [], - "indexed": false, - "name": "value", - "type": { - "displayName": [ - "Balance" - ], - "type": 1 - } - } - ], - "docs": [ - " Event emitted when a token transfer occurs." - ], - "name": "Transfer" - }, - { - "args": [ - { - "docs": [], - "indexed": true, - "name": "owner", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - }, - { - "docs": [], - "indexed": true, - "name": "spender", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - }, - { - "docs": [], - "indexed": false, - "name": "value", - "type": { - "displayName": [ - "Balance" - ], - "type": 1 - } - } - ], - "docs": [ - " Event emitted when an approval occurs that `spender` is allowed to withdraw", - " up to the amount of `value` tokens from `owner`." - ], - "name": "Approval" - } - ], - "messages": [ - { - "args": [], - "docs": [ - " Returns the total token supply." - ], - "mutates": false, - "name": [ - "total_supply" - ], - "payable": false, - "returnType": { - "displayName": [ - "Balance" - ], - "type": 1 - }, - "selector": "0xdb6375a8" - }, - { - "args": [ - { - "name": "owner", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - } - ], - "docs": [ - " Returns the account balance for the specified `owner`.", - "", - " Returns `0` if the account is non-existent." - ], - "mutates": false, - "name": [ - "balance_of" - ], - "payable": false, - "returnType": { - "displayName": [ - "Balance" - ], - "type": 1 - }, - "selector": "0x0f755a56" - }, - { - "args": [ - { - "name": "owner", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "spender", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - } - ], - "docs": [ - " Returns the amount which `spender` is still allowed to withdraw from `owner`.", - "", - " Returns `0` if no allowance has been set `0`." - ], - "mutates": false, - "name": [ - "allowance" - ], - "payable": false, - "returnType": { - "displayName": [ - "Balance" - ], - "type": 1 - }, - "selector": "0x6a00165e" - }, - { - "args": [ - { - "name": "to", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "value", - "type": { - "displayName": [ - "Balance" - ], - "type": 1 - } - } - ], - "docs": [ - " Transfers `value` amount of tokens from the caller's account to account `to`.", - "", - " On success a `Transfer` event is emitted.", - "", - " # Errors", - "", - " Returns `InsufficientBalance` error if there are not enough tokens on", - " the caller's account balance." - ], - "mutates": true, - "name": [ - "transfer" - ], - "payable": false, - "returnType": { - "displayName": [ - "Result" - ], - "type": 12 - }, - "selector": "0x84a15da1" - }, - { - "args": [ - { - "name": "spender", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "value", - "type": { - "displayName": [ - "Balance" - ], - "type": 1 - } - } - ], - "docs": [ - " Allows `spender` to withdraw from the caller's account multiple times, up to", - " the `value` amount.", - "", - " If this function is called again it overwrites the current allowance with `value`.", - "", - " An `Approval` event is emitted." - ], - "mutates": true, - "name": [ - "approve" - ], - "payable": false, - "returnType": { - "displayName": [ - "Result" - ], - "type": 12 - }, - "selector": "0x681266a0" - }, - { - "args": [ - { - "name": "from", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "to", - "type": { - "displayName": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "value", - "type": { - "displayName": [ - "Balance" - ], - "type": 1 - } - } - ], - "docs": [ - " Transfers `value` tokens on the behalf of `from` to the account `to`.", - "", - " This can be used to allow a contract to transfer tokens on ones behalf and/or", - " to charge fees in sub-currencies, for example.", - "", - " On success a `Transfer` event is emitted.", - "", - " # Errors", - "", - " Returns `InsufficientAllowance` error if there are not enough tokens allowed", - " for the caller to withdraw from `from`.", - "", - " Returns `InsufficientBalance` error if there are not enough tokens on", - " the account balance of `from`." - ], - "mutates": true, - "name": [ - "transfer_from" - ], - "payable": false, - "returnType": { - "displayName": [ - "Result" - ], - "type": 12 - }, - "selector": "0x0b396f18" - } - ] - }, - "storage": { - "struct": { - "fields": [ - { - "layout": { - "cell": { - "key": "0x0000000000000000000000000000000000000000000000000000000000000000", - "ty": 1 - } - }, - "name": "total_supply" - }, - { - "layout": { - "struct": { - "fields": [ - { - "layout": { - "struct": { - "fields": [ - { - "layout": { - "cell": { - "key": "0x0100000000000000000000000000000000000000000000000000000000000000", - "ty": 2 - } - }, - "name": "header" - }, - { - "layout": { - "struct": { - "fields": [ - { - "layout": { - "cell": { - "key": "0x0200000000000000000000000000000000000000000000000000000000000000", - "ty": 3 - } - }, - "name": "len" - }, - { - "layout": { - "array": { - "cellsPerElem": 1, - "layout": { - "cell": { - "key": "0x0200000001000000000000000000000000000000000000000000000000000000", - "ty": 4 - } - }, - "len": 4294967295, - "offset": "0x0300000000000000000000000000000000000000000000000000000000000000" - } - }, - "name": "elems" - } - ] - } - }, - "name": "entries" - } - ] - } - }, - "name": "keys" - }, - { - "layout": { - "hash": { - "layout": { - "cell": { - "key": "0x0300000001000000000000000000000000000000000000000000000000000000", - "ty": 9 - } - }, - "offset": "0x0200000001000000000000000000000000000000000000000000000000000000", - "strategy": { - "hasher": "Blake2x256", - "postfix": "", - "prefix": "0x696e6b20686173686d6170" - } - } - }, - "name": "values" - } - ] - } - }, - "name": "balances" - }, - { - "layout": { - "struct": { - "fields": [ - { - "layout": { - "struct": { - "fields": [ - { - "layout": { - "cell": { - "key": "0x0300000001000000000000000000000000000000000000000000000000000000", - "ty": 2 - } - }, - "name": "header" - }, - { - "layout": { - "struct": { - "fields": [ - { - "layout": { - "cell": { - "key": "0x0400000001000000000000000000000000000000000000000000000000000000", - "ty": 3 - } - }, - "name": "len" - }, - { - "layout": { - "array": { - "cellsPerElem": 1, - "layout": { - "cell": { - "key": "0x0400000002000000000000000000000000000000000000000000000000000000", - "ty": 10 - } - }, - "len": 4294967295, - "offset": "0x0500000001000000000000000000000000000000000000000000000000000000" - } - }, - "name": "elems" - } - ] - } - }, - "name": "entries" - } - ] - } - }, - "name": "keys" - }, - { - "layout": { - "hash": { - "layout": { - "cell": { - "key": "0x0500000002000000000000000000000000000000000000000000000000000000", - "ty": 9 - } - }, - "offset": "0x0400000002000000000000000000000000000000000000000000000000000000", - "strategy": { - "hasher": "Blake2x256", - "postfix": "", - "prefix": "0x696e6b20686173686d6170" - } - } - }, - "name": "values" - } - ] - } - }, - "name": "allowances" - } - ] - } - }, - "types": [ - { - "def": { - "primitive": "u128" - } - }, - { - "def": { - "composite": { - "fields": [ - { - "name": "last_vacant", - "type": 3, - "typeName": "Index" - }, - { - "name": "len", - "type": 3, - "typeName": "u32" - }, - { - "name": "len_entries", - "type": 3, - "typeName": "u32" - } - ] - } - }, - "path": [ - "ink_storage", - "collections", - "stash", - "Header" - ] - }, - { - "def": { - "primitive": "u32" - } - }, - { - "def": { - "variant": { - "variants": [ - { - "fields": [ - { - "type": 8, - "typeName": "VacantEntry" - } - ], - "name": "Vacant" - }, - { - "fields": [ - { - "type": 5, - "typeName": "T" - } - ], - "name": "Occupied" - } - ] - } - }, - "params": [ - 5 - ], - "path": [ - "ink_storage", - "collections", - "stash", - "Entry" - ] - }, - { - "def": { - "composite": { - "fields": [ - { - "type": 6, - "typeName": "[u8; 32]" - } - ] - } - }, - "path": [ - "ink_env", - "types", - "AccountId" - ] - }, - { - "def": { - "array": { - "len": 32, - "type": 7 - } - } - }, - { - "def": { - "primitive": "u8" - } - }, - { - "def": { - "composite": { - "fields": [ - { - "name": "next", - "type": 3, - "typeName": "Index" - }, - { - "name": "prev", - "type": 3, - "typeName": "Index" - } - ] - } - }, - "path": [ - "ink_storage", - "collections", - "stash", - "VacantEntry" - ] - }, - { - "def": { - "composite": { - "fields": [ - { - "name": "value", - "type": 1, - "typeName": "V" - }, - { - "name": "key_index", - "type": 3, - "typeName": "KeyIndex" - } - ] - } - }, - "params": [ - 1 - ], - "path": [ - "ink_storage", - "collections", - "hashmap", - "ValueEntry" - ] - }, - { - "def": { - "variant": { - "variants": [ - { - "fields": [ - { - "type": 8, - "typeName": "VacantEntry" - } - ], - "name": "Vacant" - }, - { - "fields": [ - { - "type": 11, - "typeName": "T" - } - ], - "name": "Occupied" - } - ] - } - }, - "params": [ - 11 - ], - "path": [ - "ink_storage", - "collections", - "stash", - "Entry" - ] - }, - { - "def": { - "tuple": [ - 5, - 5 - ] - } - }, - { - "def": { - "variant": { - "variants": [ - { - "fields": [ - { - "type": 13, - "typeName": "T" - } - ], - "name": "Ok" - }, - { - "fields": [ - { - "type": 14, - "typeName": "E" - } - ], - "name": "Err" - } - ] - } - }, - "params": [ - 13, - 14 - ], - "path": [ - "Result" - ] - }, - { - "def": { - "tuple": [] - } - }, - { - "def": { - "variant": { - "variants": [ - { - "discriminant": 0, - "name": "InsufficientBalance" - }, - { - "discriminant": 1, - "name": "InsufficientAllowance" - } - ] - } - }, - "path": [ - "erc20", - "erc20", - "Error" - ] - }, - { - "def": { - "variant": { - "variants": [ - { - "name": "None" - }, - { - "fields": [ - { - "type": 5, - "typeName": "T" - } - ], - "name": "Some" - } - ] - } - }, - "params": [ - 5 - ], - "path": [ - "Option" - ] - } - ] -} \ No newline at end of file diff --git a/substrate/frame/contracts/benchmarks/ink_erc20.wasm b/substrate/frame/contracts/benchmarks/ink_erc20.wasm deleted file mode 100644 index ffd522760a02dd8416f8ee04db02c32e2172b8ff..0000000000000000000000000000000000000000 Binary files a/substrate/frame/contracts/benchmarks/ink_erc20.wasm and /dev/null differ diff --git a/substrate/frame/contracts/benchmarks/ink_erc20_test.wasm b/substrate/frame/contracts/benchmarks/ink_erc20_test.wasm deleted file mode 100644 index f5d84552960a348db3935e457adc4b6fba249d17..0000000000000000000000000000000000000000 Binary files a/substrate/frame/contracts/benchmarks/ink_erc20_test.wasm and /dev/null differ diff --git a/substrate/frame/contracts/benchmarks/solang_erc20.json b/substrate/frame/contracts/benchmarks/solang_erc20.json deleted file mode 100644 index 9d8fd5ce70e70edb0fdb96439be847369e6ae7e0..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/benchmarks/solang_erc20.json +++ /dev/null @@ -1,581 +0,0 @@ -{ - "contract": { - "authors": [ - "unknown" - ], - "name": "ERC20PresetFixedSupply", - "version": "0.0.1" - }, - "metadataVersion": "0.1.0", - "source": { - "compiler": "solang 0.1.7", - "hash": "0x9c55e342566e89c741eb641eec3af796836da750fc930c55bccc0604a47ef700", - "language": "Solidity 0.1.7" - }, - "spec": { - "constructors": [ - { - "args": [ - { - "name": "name", - "type": { - "display_name": [ - "String" - ], - "type": 2 - } - }, - { - "name": "symbol", - "type": { - "display_name": [ - "String" - ], - "type": 2 - } - }, - { - "name": "initialSupply", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - }, - { - "name": "owner", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - } - ], - "docs": [ - "" - ], - "name": "new", - "selector": "0xa6f1f5e1" - } - ], - "events": [ - { - "args": [ - { - "indexed": true, - "name": "owner", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "indexed": true, - "name": "spender", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "indexed": false, - "name": "value", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "name": "Approval" - }, - { - "args": [ - { - "indexed": true, - "name": "from", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "indexed": true, - "name": "to", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "indexed": false, - "name": "value", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "name": "Transfer" - } - ], - "messages": [ - { - "args": [ - { - "name": "account", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "amount", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "mutates": true, - "name": "burnFrom", - "payable": false, - "return_type": null, - "selector": "0x0f1354f3" - }, - { - "args": [ - { - "name": "account", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - } - ], - "docs": [ - "" - ], - "mutates": false, - "name": "balanceOf", - "payable": false, - "return_type": { - "display_name": [ - "u256" - ], - "type": 1 - }, - "selector": "0x6c7f1542" - }, - { - "args": [], - "docs": [ - "" - ], - "mutates": false, - "name": "totalSupply", - "payable": false, - "return_type": { - "display_name": [ - "u256" - ], - "type": 1 - }, - "selector": "0x18160ddd" - }, - { - "args": [], - "docs": [ - "" - ], - "mutates": false, - "name": "decimals", - "payable": false, - "return_type": { - "display_name": [ - "u8" - ], - "type": 3 - }, - "selector": "0x313ce567" - }, - { - "args": [ - { - "name": "owner", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "spender", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - } - ], - "docs": [ - "" - ], - "mutates": false, - "name": "allowance", - "payable": false, - "return_type": { - "display_name": [ - "u256" - ], - "type": 1 - }, - "selector": "0xf2a9a8c7" - }, - { - "args": [], - "docs": [ - "" - ], - "mutates": false, - "name": "name", - "payable": false, - "return_type": { - "display_name": [ - "String" - ], - "type": 2 - }, - "selector": "0x06fdde03" - }, - { - "args": [ - { - "name": "spender", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "subtractedValue", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "mutates": true, - "name": "decreaseAllowance", - "payable": false, - "return_type": { - "display_name": [ - "bool" - ], - "type": 6 - }, - "selector": "0x4b76697b" - }, - { - "args": [ - { - "name": "sender", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "recipient", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "amount", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "mutates": true, - "name": "transferFrom", - "payable": false, - "return_type": { - "display_name": [ - "bool" - ], - "type": 6 - }, - "selector": "0x2fb840f5" - }, - { - "args": [], - "docs": [ - "" - ], - "mutates": false, - "name": "symbol", - "payable": false, - "return_type": { - "display_name": [ - "String" - ], - "type": 2 - }, - "selector": "0x95d89b41" - }, - { - "args": [ - { - "name": "spender", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "addedValue", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "mutates": true, - "name": "increaseAllowance", - "payable": false, - "return_type": { - "display_name": [ - "bool" - ], - "type": 6 - }, - "selector": "0xb936c899" - }, - { - "args": [ - { - "name": "recipient", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "amount", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "mutates": true, - "name": "transfer", - "payable": false, - "return_type": { - "display_name": [ - "bool" - ], - "type": 6 - }, - "selector": "0x6a467394" - }, - { - "args": [ - { - "name": "spender", - "type": { - "display_name": [ - "AccountId" - ], - "type": 5 - } - }, - { - "name": "amount", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "mutates": true, - "name": "approve", - "payable": false, - "return_type": { - "display_name": [ - "bool" - ], - "type": 6 - }, - "selector": "0x47144421" - }, - { - "args": [ - { - "name": "amount", - "type": { - "display_name": [ - "u256" - ], - "type": 1 - } - } - ], - "docs": [ - "" - ], - "mutates": true, - "name": "burn", - "payable": false, - "return_type": null, - "selector": "0x42966c68" - } - ] - }, - "storage": { - "struct": { - "fields": [ - { - "layout": { - "cell": { - "key": "0x0000000000000000000000000000000000000000000000000000000000000002", - "ty": 1 - } - }, - "name": "_totalSupply" - }, - { - "layout": { - "cell": { - "key": "0x0000000000000000000000000000000000000000000000000000000000000003", - "ty": 2 - } - }, - "name": "_name" - }, - { - "layout": { - "cell": { - "key": "0x0000000000000000000000000000000000000000000000000000000000000004", - "ty": 2 - } - }, - "name": "_symbol" - } - ] - } - }, - "types": [ - { - "def": { - "primitive": "u256" - } - }, - { - "def": { - "primitive": "str" - } - }, - { - "def": { - "primitive": "u8" - } - }, - { - "def": { - "array": { - "len": 32, - "type": 3 - } - } - }, - { - "def": { - "composite": { - "fields": [ - { - "type": 4 - } - ] - } - }, - "path": [ - "AccountId" - ] - }, - { - "def": { - "primitive": "bool" - } - } - ] -} diff --git a/substrate/frame/contracts/benchmarks/solang_erc20.wasm b/substrate/frame/contracts/benchmarks/solang_erc20.wasm deleted file mode 100644 index 0796085d33249b78871f4a336623444a0ef94e85..0000000000000000000000000000000000000000 Binary files a/substrate/frame/contracts/benchmarks/solang_erc20.wasm and /dev/null differ diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 7fdf56a91fcc7c114b0cadd622e9d43e47088f33..9ca9e404c31000569b50ce641619121f68927e34 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -11,7 +11,6 @@ description = "Fixtures for testing contracts pallet." workspace = true [dependencies] -wat = "1" frame-system = { path = "../../system" } sp-runtime = { path = "../../../primitives/runtime" } anyhow = "1.0.0" diff --git a/substrate/frame/contracts/fixtures/contracts/call.rs b/substrate/frame/contracts/fixtures/contracts/call.rs index f7d9d862d7465937f71afff998aecdaa9aa1f4bd..535745ffc0bc505c5cc29dc5959fe31a3e1fe509 100644 --- a/substrate/frame/contracts/fixtures/contracts/call.rs +++ b/substrate/frame/contracts/fixtures/contracts/call.rs @@ -35,11 +35,13 @@ pub extern "C" fn call() { ); // Call the callee - api::call_v1( + api::call_v2( uapi::CallFlags::empty(), callee_addr, - 0u64, // How much gas to devote for the execution. 0 = all. - &0u64.to_le_bytes(), // value transferred to the contract. + 0u64, // How much ref_time to devote for the execution. 0 = all. + 0u64, // How much proof_size to devote for the execution. 0 = all. + None, // No deposit limit. + &0u64.to_le_bytes(), // Value transferred to the contract. callee_input, None, ) diff --git a/substrate/frame/contracts/fixtures/contracts/call_return_code.rs b/substrate/frame/contracts/fixtures/contracts/call_return_code.rs index 1256588d3b58554edf5b1d00e98572681087f2c7..3d5a1073eaecaedabcf774e336abea48ab0b9001 100644 --- a/substrate/frame/contracts/fixtures/contracts/call_return_code.rs +++ b/substrate/frame/contracts/fixtures/contracts/call_return_code.rs @@ -38,11 +38,13 @@ pub extern "C" fn call() { ); // Call the callee - let err_code = match api::call_v1( + let err_code = match api::call_v2( uapi::CallFlags::empty(), callee_addr, - 0u64, // How much gas to devote for the execution. 0 = all. - &100u64.to_le_bytes(), // value transferred to the contract. + 0u64, // How much ref_time to devote for the execution. 0 = all. + 0u64, // How much proof_size to devote for the execution. 0 = all. + None, // No deposit limit. + &100u64.to_le_bytes(), // Value transferred to the contract. input, None, ) { diff --git a/substrate/frame/contracts/fixtures/contracts/call_runtime_and_call.rs b/substrate/frame/contracts/fixtures/contracts/call_runtime_and_call.rs index fdeb6097e732f9e7cc717f1144a51953c138e7f7..1321d36dc7efa17151cff67cfcd6162c91eecaa6 100644 --- a/substrate/frame/contracts/fixtures/contracts/call_runtime_and_call.rs +++ b/substrate/frame/contracts/fixtures/contracts/call_runtime_and_call.rs @@ -39,11 +39,13 @@ pub extern "C" fn call() { api::call_runtime(call).unwrap(); // Call the callee - api::call_v1( + api::call_v2( uapi::CallFlags::empty(), callee_addr, - 0u64, // How much gas to devote for the execution. 0 = all. - &0u64.to_le_bytes(), // value transferred to the contract. + 0u64, // How much ref_time to devote for the execution. 0 = all. + 0u64, // How much proof_size to devote for the execution. 0 = all. + None, // No deposit limit. + &0u64.to_le_bytes(), // Value transferred to the contract. callee_input, None, ) diff --git a/substrate/frame/contracts/fixtures/contracts/call_with_limit.rs b/substrate/frame/contracts/fixtures/contracts/call_with_limit.rs index 5e98aa614e95acad471a4146c492ca12cee90da8..f0851f32c75bc13d7b89c1bf366595ef1dbd57ca 100644 --- a/substrate/frame/contracts/fixtures/contracts/call_with_limit.rs +++ b/substrate/frame/contracts/fixtures/contracts/call_with_limit.rs @@ -31,12 +31,13 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { input!( + 256, callee_addr: [u8; 32], ref_time: u64, proof_size: u64, + forwarded_input: [u8], ); - #[allow(deprecated)] api::call_v2( uapi::CallFlags::empty(), callee_addr, @@ -44,7 +45,7 @@ pub extern "C" fn call() { proof_size, None, // No deposit limit. &0u64.to_le_bytes(), // value transferred to the contract. - &[0u8; 0], // input data. + forwarded_input, None, ) .unwrap(); diff --git a/substrate/frame/contracts/fixtures/contracts/caller_contract.rs b/substrate/frame/contracts/fixtures/contracts/caller_contract.rs index c2629e9fa1971fea3da5a77f3c2d3bdfce3ce601..fffdb66a33d7979da3d81f53ec51e4308f5d355b 100644 --- a/substrate/frame/contracts/fixtures/contracts/caller_contract.rs +++ b/substrate/frame/contracts/fixtures/contracts/caller_contract.rs @@ -40,7 +40,6 @@ pub extern "C" fn call() { let reverted_input = [1u8, 34, 51, 68, 85, 102, 119]; // Fail to deploy the contract since it returns a non-zero exit status. - #[allow(deprecated)] let res = api::instantiate_v2( code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. @@ -55,7 +54,6 @@ pub extern "C" fn call() { assert!(matches!(res, Err(ReturnErrorCode::CalleeReverted))); // Fail to deploy the contract due to insufficient ref_time weight. - #[allow(deprecated)] let res = api::instantiate_v2( code_hash, 1u64, // too little ref_time weight 0u64, // How much proof_size weight to devote for the execution. 0 = all. @@ -65,7 +63,6 @@ pub extern "C" fn call() { assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); // Fail to deploy the contract due to insufficient proof_size weight. - #[allow(deprecated)] let res = api::instantiate_v2( code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. 1u64, // Too little proof_size weight @@ -78,7 +75,6 @@ pub extern "C" fn call() { let mut callee = [0u8; 32]; let callee = &mut &mut callee[..]; - #[allow(deprecated)] api::instantiate_v2( code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. @@ -94,7 +90,6 @@ pub extern "C" fn call() { assert_eq!(callee.len(), 32); // Call the new contract and expect it to return failing exit code. - #[allow(deprecated)] let res = api::call_v2( uapi::CallFlags::empty(), callee, @@ -108,11 +103,10 @@ pub extern "C" fn call() { assert!(matches!(res, Err(ReturnErrorCode::CalleeReverted))); // Fail to call the contract due to insufficient ref_time weight. - #[allow(deprecated)] let res = api::call_v2( uapi::CallFlags::empty(), callee, - 1u64, // too little ref_time weight + 1u64, // Too little ref_time weight. 0u64, // How much proof_size weight to devote for the execution. 0 = all. None, // No deposit limit. &value, @@ -122,7 +116,6 @@ pub extern "C" fn call() { assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); // Fail to call the contract due to insufficient proof_size weight. - #[allow(deprecated)] let res = api::call_v2( uapi::CallFlags::empty(), callee, @@ -137,7 +130,6 @@ pub extern "C" fn call() { // Call the contract successfully. let mut output = [0u8; 4]; - #[allow(deprecated)] api::call_v2( uapi::CallFlags::empty(), callee, diff --git a/substrate/frame/contracts/fixtures/contracts/caller_is_origin_n.rs b/substrate/frame/contracts/fixtures/contracts/caller_is_origin_n.rs new file mode 100644 index 0000000000000000000000000000000000000000..fd6f59802fa08408105070f37ae64569a32d38a7 --- /dev/null +++ b/substrate/frame/contracts/fixtures/contracts/caller_is_origin_n.rs @@ -0,0 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This fixture calls caller_is_origin `n` times. + +#![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!(n: u32, ); + + for _ in 0..n { + let _ = api::caller_is_origin(); + } +} diff --git a/substrate/frame/contracts/fixtures/contracts/chain_extension_temp_storage.rs b/substrate/frame/contracts/fixtures/contracts/chain_extension_temp_storage.rs index 1ab08efb3c7ea49ee1e016cb6136b428e86075a3..2e15fb02a12ca5f0cd4bee944af062961d66e8b2 100644 --- a/substrate/frame/contracts/fixtures/contracts/chain_extension_temp_storage.rs +++ b/substrate/frame/contracts/fixtures/contracts/chain_extension_temp_storage.rs @@ -50,11 +50,13 @@ pub extern "C" fn call() { output!(addr, [0u8; 32], api::address,); // call self - api::call_v1( + api::call_v2( uapi::CallFlags::ALLOW_REENTRY, addr, - 0u64, // How much gas to devote for the execution. 0 = all. - &0u64.to_le_bytes(), // value transferred to the contract. + 0u64, // How much ref_time to devote for the execution. 0 = all. + 0u64, // How much proof_size to devote for the execution. 0 = all. + None, // No deposit limit. + &0u64.to_le_bytes(), // Value transferred to the contract. input, None, ) diff --git a/substrate/frame/contracts/fixtures/contracts/create_storage_and_call.rs b/substrate/frame/contracts/fixtures/contracts/create_storage_and_call.rs index 8b79dd87dffd2f35c2c597f95f4e442a855f69ea..f8ce0ff4fb84831fbf258f489d0bc6935784ff43 100644 --- a/substrate/frame/contracts/fixtures/contracts/create_storage_and_call.rs +++ b/substrate/frame/contracts/fixtures/contracts/create_storage_and_call.rs @@ -40,14 +40,13 @@ pub extern "C" fn call() { api::set_storage(buffer, &[1u8; 4]); // Call the callee - #[allow(deprecated)] api::call_v2( uapi::CallFlags::empty(), callee, 0u64, // How much ref_time weight to devote for the execution. 0 = all. 0u64, // How much proof_size weight to devote for the execution. 0 = all. Some(deposit_limit), - &0u64.to_le_bytes(), // value transferred to the contract. + &0u64.to_le_bytes(), // Value transferred to the contract. input, None, ) diff --git a/substrate/frame/contracts/fixtures/contracts/create_storage_and_instantiate.rs b/substrate/frame/contracts/fixtures/contracts/create_storage_and_instantiate.rs index c68d99eff821e86ecfa399fc6804f1e3a7b2649c..fa3b9000a7ed6bd3f5f094d39b5d025a995a8b4c 100644 --- a/substrate/frame/contracts/fixtures/contracts/create_storage_and_instantiate.rs +++ b/substrate/frame/contracts/fixtures/contracts/create_storage_and_instantiate.rs @@ -40,7 +40,6 @@ pub extern "C" fn call() { let mut address = [0u8; 32]; let address = &mut &mut address[..]; - #[allow(deprecated)] api::instantiate_v2( code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. diff --git a/substrate/frame/contracts/fixtures/contracts/destroy_and_transfer.rs b/substrate/frame/contracts/fixtures/contracts/destroy_and_transfer.rs index cfcfd60f21eef1c543e249832f74bd75e5c4a8d3..62fb63b56020455ea775e802b95daeacaefd3658 100644 --- a/substrate/frame/contracts/fixtures/contracts/destroy_and_transfer.rs +++ b/substrate/frame/contracts/fixtures/contracts/destroy_and_transfer.rs @@ -34,7 +34,6 @@ pub extern "C" fn deploy() { let address = &mut &mut address[..]; let salt = [71u8, 17u8]; - #[allow(deprecated)] api::instantiate_v2( code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. @@ -60,7 +59,6 @@ pub extern "C" fn call() { api::get_storage(&ADDRESS_KEY, callee_addr).unwrap(); // Calling the destination contract with non-empty input data should fail. - #[allow(deprecated)] let res = api::call_v2( uapi::CallFlags::empty(), callee_addr, @@ -74,7 +72,6 @@ pub extern "C" fn call() { assert!(matches!(res, Err(uapi::ReturnErrorCode::CalleeTrapped))); // Call the destination contract regularly, forcing it to self-destruct. - #[allow(deprecated)] api::call_v2( uapi::CallFlags::empty(), callee_addr, diff --git a/substrate/frame/contracts/fixtures/contracts/instantiate_return_code.rs b/substrate/frame/contracts/fixtures/contracts/instantiate_return_code.rs index 67cd739d85a6942a046cfaf7cc45301d6570600f..de194abe4840ac5fc67b83c1a377d114e65dfc01 100644 --- a/substrate/frame/contracts/fixtures/contracts/instantiate_return_code.rs +++ b/substrate/frame/contracts/fixtures/contracts/instantiate_return_code.rs @@ -31,7 +31,6 @@ pub extern "C" fn call() { input!(buffer, 36, code_hash: [u8; 32],); let input = &buffer[32..]; - #[allow(deprecated)] let err_code = match api::instantiate_v2( code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. diff --git a/substrate/frame/contracts/fixtures/contracts/add_remove_delegate_dependency.rs b/substrate/frame/contracts/fixtures/contracts/locking_delegate_dependency.rs similarity index 83% rename from substrate/frame/contracts/fixtures/contracts/add_remove_delegate_dependency.rs rename to substrate/frame/contracts/fixtures/contracts/locking_delegate_dependency.rs index 759ff7993740479f9e89b3c047eca27de74dbcc4..bb76c942aad18c511ab2e88bf1597101b307c2b4 100644 --- a/substrate/frame/contracts/fixtures/contracts/add_remove_delegate_dependency.rs +++ b/substrate/frame/contracts/fixtures/contracts/locking_delegate_dependency.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! This contract tests the behavior of adding / removing delegate_dependencies when delegate +//! This contract tests the behavior of locking / unlocking delegate_dependencies when delegate //! calling into a contract. #![no_std] #![no_main] @@ -34,15 +34,13 @@ fn load_input(delegate_call: bool) { ); match action { - // 1 = Add delegate dependency + // 1 = Lock delegate dependency 1 => { - #[allow(deprecated)] - api::add_delegate_dependency(code_hash); + api::lock_delegate_dependency(code_hash); }, - // 2 = Remove delegate dependency + // 2 = Unlock delegate dependency 2 => { - #[allow(deprecated)] - api::remove_delegate_dependency(code_hash); + api::unlock_delegate_dependency(code_hash); }, // 3 = Terminate 3 => { diff --git a/substrate/frame/contracts/fixtures/contracts/recurse.rs b/substrate/frame/contracts/fixtures/contracts/recurse.rs new file mode 100644 index 0000000000000000000000000000000000000000..b1ded608c2fc417323580257b74835a0aaee9aa3 --- /dev/null +++ b/substrate/frame/contracts/fixtures/contracts/recurse.rs @@ -0,0 +1,53 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This fixture calls itself as many times as passed as argument. + +#![no_std] +#![no_main] + +use common::{input, 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!(calls_left: u32, ); + + // own address + output!(addr, [0u8; 32], api::address,); + + if calls_left == 0 { + return + } + + api::call_v2( + uapi::CallFlags::ALLOW_REENTRY, + addr, + 0u64, // How much ref_time to devote for the execution. 0 = all. + 0u64, // How much deposit_limit to devote for the execution. 0 = all. + None, // No deposit limit. + &0u64.to_le_bytes(), // Value transferred to the contract. + &(calls_left - 1).to_le_bytes(), + None, + ) + .unwrap(); +} diff --git a/substrate/frame/contracts/fixtures/contracts/reentrance_count_call.rs b/substrate/frame/contracts/fixtures/contracts/reentrance_count_call.rs index 9812dce2e818d29a352927d2b47e301b06683dae..0acfe017f8df9094ef14aa9e6947b56e183d25be 100644 --- a/substrate/frame/contracts/fixtures/contracts/reentrance_count_call.rs +++ b/substrate/frame/contracts/fixtures/contracts/reentrance_count_call.rs @@ -42,11 +42,13 @@ pub extern "C" fn call() { if expected_reentrance_count != 5 { let count = (expected_reentrance_count + 1).to_le_bytes(); - api::call_v1( + api::call_v2( uapi::CallFlags::ALLOW_REENTRY, addr, - 0u64, // How much gas to devote for the execution. 0 = all. - &0u64.to_le_bytes(), // value transferred to the contract. + 0u64, // How much ref_time to devote for the execution. 0 = all. + 0u64, // How much proof_size to devote for the execution. 0 = all. + None, // No deposit limit. + &0u64.to_le_bytes(), // Value transferred to the contract. &count, None, ) diff --git a/substrate/frame/contracts/fixtures/contracts/self_destruct.rs b/substrate/frame/contracts/fixtures/contracts/self_destruct.rs index 94c3ac387a0a65228674efa93a477543b807661c..d3836d2d8c734214a67333dba9293067b4b5d9b1 100644 --- a/substrate/frame/contracts/fixtures/contracts/self_destruct.rs +++ b/substrate/frame/contracts/fixtures/contracts/self_destruct.rs @@ -37,10 +37,12 @@ pub extern "C" fn call() { if !input.is_empty() { output!(addr, [0u8; 32], api::address,); - api::call_v1( + api::call_v2( uapi::CallFlags::ALLOW_REENTRY, addr, - 0u64, // How much gas to devote for the execution. 0 = all. + 0u64, // How much ref_time to devote for the execution. 0 = all. + 0u64, // How much proof_size to devote for the execution. 0 = all. + None, // No deposit limit. &0u64.to_le_bytes(), // Value to transfer. &[0u8; 0], None, diff --git a/substrate/frame/contracts/fixtures/contracts/xcm_execute.rs b/substrate/frame/contracts/fixtures/contracts/xcm_execute.rs index 09d0b6cf972815e093f066a506e3d06e5b447791..1d570ffead71845c77d664bf5b911bf66794e907 100644 --- a/substrate/frame/contracts/fixtures/contracts/xcm_execute.rs +++ b/substrate/frame/contracts/fixtures/contracts/xcm_execute.rs @@ -30,10 +30,11 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { input!(512, msg: [u8],); - let mut outcome = [0u8; 512]; - let outcome = &mut &mut outcome[..]; - #[allow(deprecated)] - api::xcm_execute(msg, outcome).unwrap(); - api::return_value(uapi::ReturnFlags::empty(), outcome); + let err_code = match api::xcm_execute(msg) { + Ok(_) => 0u32, + Err(code) => code as u32, + }; + + api::return_value(uapi::ReturnFlags::empty(), &err_code.to_le_bytes()); } diff --git a/substrate/frame/contracts/fixtures/data/invalid_contract_no_memory.wat b/substrate/frame/contracts/fixtures/data/invalid_contract_no_memory.wat deleted file mode 100644 index 0aeefbcb7ebfe27f55fb84de0f14a3c7ec12b05c..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/fixtures/data/invalid_contract_no_memory.wat +++ /dev/null @@ -1,5 +0,0 @@ -;; A valid contract which does nothing at all -(module - (func (export "deploy")) - (func (export "call")) -) diff --git a/substrate/frame/contracts/fixtures/data/invalid_module.wat b/substrate/frame/contracts/fixtures/data/invalid_module.wat deleted file mode 100644 index e4a72f74273f9350420f737e0974516b3e5c4132..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/fixtures/data/invalid_module.wat +++ /dev/null @@ -1,8 +0,0 @@ -;; An invalid module -(module - (func (export "deploy")) - (func (export "call") - ;; imbalanced stack - (i32.const 7) - ) -) diff --git a/substrate/frame/contracts/fixtures/data/run_out_of_gas_start_fn.wat b/substrate/frame/contracts/fixtures/data/run_out_of_gas_start_fn.wat deleted file mode 100644 index 6591d7ede78c20e0d19c7c60c183b4c58e98d2dc..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/fixtures/data/run_out_of_gas_start_fn.wat +++ /dev/null @@ -1,10 +0,0 @@ -(module - (import "env" "memory" (memory 1 1)) - (start $start) - (func $start - (loop $inf (br $inf)) ;; just run out of gas - (unreachable) - ) - (func (export "call")) - (func (export "deploy")) -) diff --git a/substrate/frame/contracts/fixtures/data/seal_input_noop.wat b/substrate/frame/contracts/fixtures/data/seal_input_noop.wat deleted file mode 100644 index 7b5a1e32af4d61ba8dfecdc978e5f4d3a09e1480..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/fixtures/data/seal_input_noop.wat +++ /dev/null @@ -1,14 +0,0 @@ -;; Everything prepared for the host function call, but no call is performed. -(module - (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "env" "memory" (memory 1 1)) - - ;; [0, 8) buffer to write input - - ;; [8, 12) size of the input buffer - (data (i32.const 8) "\04") - - (func (export "call")) - - (func (export "deploy")) -) diff --git a/substrate/frame/contracts/fixtures/data/seal_input_once.wat b/substrate/frame/contracts/fixtures/data/seal_input_once.wat deleted file mode 100644 index 919a03a9b6903df3ff4917347b9c40a2d260b8f1..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/fixtures/data/seal_input_once.wat +++ /dev/null @@ -1,22 +0,0 @@ -;; Stores a value of the passed size. The host function is called once. -(module - (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "env" "memory" (memory 1 1)) - - ;; [0, 8) buffer to write input - - ;; [8, 12) size of the input buffer - (data (i32.const 8) "\04") - - (func (export "call") - ;; instructions to consume engine fuel - (drop - (i32.const 42) - ) - - (call $seal_input (i32.const 0) (i32.const 8)) - - ) - - (func (export "deploy")) -) diff --git a/substrate/frame/contracts/fixtures/data/seal_input_twice.wat b/substrate/frame/contracts/fixtures/data/seal_input_twice.wat deleted file mode 100644 index 3a8be814efb045078494294961686931c4cd7ab4..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/fixtures/data/seal_input_twice.wat +++ /dev/null @@ -1,28 +0,0 @@ -;; Stores a value of the passed size. The host function is called twice. -(module - (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "env" "memory" (memory 1 1)) - - ;; [0, 8) buffer to write input - - ;; [8, 12) size of the input buffer - (data (i32.const 8) "\04") - - (func (export "call") - ;; instructions to consume engine fuel - (drop - (i32.const 42) - ) - - (call $seal_input (i32.const 0) (i32.const 8)) - - ;; instructions to consume engine fuel - (drop - (i32.const 42) - ) - - (call $seal_input (i32.const 0) (i32.const 8)) - ) - - (func (export "deploy")) -) diff --git a/substrate/frame/contracts/fixtures/src/lib.rs b/substrate/frame/contracts/fixtures/src/lib.rs index e0d9d4f8bd5b1512f7998d497adacf695c5092e1..56a8e2321c5c3cc2181cbfeb676700993e3f0a77 100644 --- a/substrate/frame/contracts/fixtures/src/lib.rs +++ b/substrate/frame/contracts/fixtures/src/lib.rs @@ -16,34 +16,7 @@ // limitations under the License. use sp_runtime::traits::Hash; -use std::{env::var, fs, path::PathBuf}; - -fn wat_root_dir() -> PathBuf { - match (var("CARGO_MANIFEST_DIR"), var("CARGO_PKG_NAME")) { - // When `CARGO_MANIFEST_DIR` is not set, Rust resolves relative paths from the root folder - (Err(_), _) => "substrate/frame/contracts/fixtures/data".into(), - (Ok(path), Ok(s)) if s == "pallet-contracts" => PathBuf::from(path).join("fixtures/data"), - (Ok(path), Ok(s)) if s == "pallet-contracts-mock-network" => - PathBuf::from(path).parent().unwrap().join("fixtures/data"), - (Ok(_), pkg_name) => panic!("Failed to resolve fixture dir for tests from {pkg_name:?}."), - } -} - -/// Load a given wasm module represented by a .wat file and returns a wasm binary contents along -/// with it's hash. -/// -/// The fixture files are located under the `fixtures/` directory. -fn legacy_compile_module( - fixture_name: &str, -) -> anyhow::Result<(Vec, ::Output)> -where - T: frame_system::Config, -{ - let fixture_path = wat_root_dir().join(format!("{fixture_name}.wat")); - let wasm_binary = wat::parse_file(fixture_path)?; - let code_hash = T::Hashing::hash(&wasm_binary); - Ok((wasm_binary, code_hash)) -} +use std::{fs, path::PathBuf}; /// Load a given wasm module and returns a wasm binary contents along with it's hash. /// Use the legacy compile_module as fallback, if the rust fixture does not exist yet. @@ -53,15 +26,11 @@ pub fn compile_module( where T: frame_system::Config, { - let out_dir: std::path::PathBuf = env!("OUT_DIR").into(); + let out_dir: PathBuf = env!("OUT_DIR").into(); let fixture_path = out_dir.join(format!("{fixture_name}.wasm")); - match fs::read(fixture_path) { - Ok(wasm_binary) => { - let code_hash = T::Hashing::hash(&wasm_binary); - Ok((wasm_binary, code_hash)) - }, - Err(_) => legacy_compile_module::(fixture_name), - } + let binary = fs::read(fixture_path)?; + let code_hash = T::Hashing::hash(&binary); + Ok((binary, code_hash)) } #[cfg(test)] diff --git a/substrate/frame/contracts/mock-network/src/lib.rs b/substrate/frame/contracts/mock-network/src/lib.rs index eea9dde062c83172dbc106333f053657a7267cda..8a17a3f2fa781703f1393f2d69ca955384a080a2 100644 --- a/substrate/frame/contracts/mock-network/src/lib.rs +++ b/substrate/frame/contracts/mock-network/src/lib.rs @@ -26,7 +26,8 @@ use crate::primitives::{AccountId, UNITS}; use sp_runtime::BuildStorage; use xcm::latest::prelude::*; use xcm_executor::traits::ConvertLocation; -use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; +pub use xcm_simulator::TestExt; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain}; // Accounts pub const ADMIN: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index 53839f1fca037e370a598efa490cd2f226ac5b10..7a60a66b3145dd7268f20924cd53ec81f2d32447 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -37,13 +37,11 @@ use sp_runtime::traits::{Get, IdentityLookup, MaybeEquivalence}; use sp_std::prelude::*; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, - FrameTransactionalProcessor, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, - ParentAsSuperuser, ParentIsPreset, SignedAccountId32AsNative, SignedToAccountId32, + FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete, NativeAsset, + NoChecking, ParentAsSuperuser, ParentIsPreset, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, WithComputedOrigin, }; use xcm_executor::{traits::JustTry, Config, XcmExecutor}; @@ -184,9 +182,8 @@ pub fn estimate_fee_for_weight(weight: Weight) -> u128 { units_per_mb * (weight.proof_size() as u128) / (WEIGHT_PROOF_SIZE_PER_MB as u128) } -#[allow(deprecated)] pub type LocalBalancesTransactor = - XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + FungibleAdapter, SovereignAccountOf, AccountId, ()>; pub struct FromLocationToAsset(PhantomData<(Location, AssetId)>); impl MaybeEquivalence diff --git a/substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs b/substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs index dadba394e26453366d0b90ce8ff18931ab00743f..3c06131dd6088a2b044b68cfbf3b4a918eb37e3e 100644 --- a/substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs +++ b/substrate/frame/contracts/mock-network/src/parachain/contracts_config.rs @@ -25,7 +25,7 @@ use frame_support::{ traits::{ConstBool, ConstU32, Contains, Randomness}, weights::Weight, }; -use frame_system::pallet_prelude::BlockNumberFor; +use frame_system::{pallet_prelude::BlockNumberFor, EnsureSigned}; use pallet_xcm::BalanceOf; use sp_runtime::{traits::Convert, Perbill}; @@ -90,9 +90,12 @@ impl pallet_contracts::Config for Runtime { type Schedule = Schedule; type Time = super::Timestamp; type UnsafeUnstableInterface = ConstBool; + type UploadOrigin = EnsureSigned; + type InstantiateOrigin = EnsureSigned; type WeightInfo = (); type WeightPrice = Self; type Debug = (); type Environment = (); + type ApiVersion = (); type Xcm = pallet_xcm::Pallet; } diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index ce7e22dce2f0ccba24a6860408b0fc0c112eb3b9..6eb9b4e53855c0c62e65392a1dd0a63adc239b0b 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -29,13 +29,11 @@ use sp_runtime::traits::IdentityLookup; use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared}; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, DescribeAllTerminal, DescribeFamily, FixedRateOfFungible, - FixedWeightBounds, FrameTransactionalProcessor, HashedDescription, IsConcrete, + FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, WithComputedOrigin, }; use xcm_executor::{Config, XcmExecutor}; @@ -119,9 +117,8 @@ pub type SovereignAccountOf = ( ChildParachainConvertsVia, ); -#[allow(deprecated)] pub type LocalBalancesTransactor = - XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + FungibleAdapter, SovereignAccountOf, AccountId, ()>; pub type AssetTransactors = LocalBalancesTransactor; diff --git a/substrate/frame/contracts/mock-network/src/tests.rs b/substrate/frame/contracts/mock-network/src/tests.rs index c25373bcbe3aeaaad5d0ac7396e70ed61a4729c6..d22221fe8ee051182471249182d54b02b7f47c2c 100644 --- a/substrate/frame/contracts/mock-network/src/tests.rs +++ b/substrate/frame/contracts/mock-network/src/tests.rs @@ -21,7 +21,6 @@ use crate::{ primitives::{AccountId, CENTS}, relay_chain, MockNet, ParaA, ParachainBalances, Relay, ALICE, BOB, INITIAL_BALANCE, }; -use assert_matches::assert_matches; use codec::{Decode, Encode}; use frame_support::{ assert_err, @@ -31,11 +30,18 @@ use frame_support::{ use pallet_balances::{BalanceLock, Reasons}; use pallet_contracts::{Code, CollectEvents, DebugInfo, Determinism}; use pallet_contracts_fixtures::compile_module; +use pallet_contracts_uapi::ReturnErrorCode; use xcm::{v4::prelude::*, VersionedLocation, VersionedXcm}; use xcm_simulator::TestExt; type ParachainContracts = pallet_contracts::Pallet; +macro_rules! assert_return_code { + ( $x:expr , $y:expr $(,)? ) => {{ + assert_eq!(u32::from_le_bytes($x.data[..].try_into().unwrap()), $y as u32); + }}; +} + /// Instantiate the tests contract, and fund it with some balance and assets. fn instantiate_test_contract(name: &str) -> AccountId { let (wasm, _) = compile_module::(name).unwrap(); @@ -100,19 +106,57 @@ fn test_xcm_execute() { DebugInfo::UnsafeDebug, CollectEvents::UnsafeCollect, Determinism::Enforced, - ) - .result - .unwrap(); + ); - let mut data = &result.data[..]; - let outcome = Outcome::decode(&mut data).expect("Failed to decode xcm_execute Outcome"); - assert_matches!(outcome, Outcome::Complete { .. }); + assert_eq!(result.gas_consumed, result.gas_required); + assert_return_code!(&result.result.unwrap(), ReturnErrorCode::Success); // Check if the funds are subtracted from the account of Alice and added to the account of // Bob. let initial = INITIAL_BALANCE; - assert_eq!(parachain::Assets::balance(0, contract_addr), initial); assert_eq!(ParachainBalances::free_balance(BOB), initial + amount); + assert_eq!(ParachainBalances::free_balance(&contract_addr), initial - amount); + }); +} + +#[test] +fn test_xcm_execute_incomplete() { + MockNet::reset(); + + let contract_addr = instantiate_test_contract("xcm_execute"); + let amount = 10 * CENTS; + + // Execute XCM instructions through the contract. + ParaA::execute_with(|| { + // The XCM used to transfer funds to Bob. + let message: Xcm<()> = Xcm(vec![ + WithdrawAsset(vec![(Here, amount).into()].into()), + // This will fail as the contract does not have enough balance to complete both + // withdrawals. + WithdrawAsset(vec![(Here, INITIAL_BALANCE).into()].into()), + DepositAsset { + assets: All.into(), + beneficiary: AccountId32 { network: None, id: BOB.clone().into() }.into(), + }, + ]); + + let result = ParachainContracts::bare_call( + ALICE, + contract_addr.clone(), + 0, + Weight::MAX, + None, + VersionedXcm::V4(message).encode(), + DebugInfo::UnsafeDebug, + CollectEvents::UnsafeCollect, + Determinism::Enforced, + ); + + assert_eq!(result.gas_consumed, result.gas_required); + assert_return_code!(&result.result.unwrap(), ReturnErrorCode::XcmExecutionFailed); + + assert_eq!(ParachainBalances::free_balance(BOB), INITIAL_BALANCE); + assert_eq!(ParachainBalances::free_balance(&contract_addr), INITIAL_BALANCE - amount); }); } @@ -182,17 +226,10 @@ fn test_xcm_execute_reentrant_call() { DebugInfo::UnsafeDebug, CollectEvents::UnsafeCollect, Determinism::Enforced, - ) - .result - .unwrap(); - - let mut data = &result.data[..]; - let outcome = Outcome::decode(&mut data).expect("Failed to decode xcm_execute Outcome"); - assert_matches!( - outcome, - Outcome::Incomplete { used: _, error: XcmError::ExpectationFalse } ); + assert_return_code!(&result.result.unwrap(), ReturnErrorCode::XcmExecutionFailed); + // Funds should not change hands as the XCM transact failed. assert_eq!(ParachainBalances::free_balance(BOB), INITIAL_BALANCE); }); diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index ed6175ee8cdfdf34fff9faa0ca00341c65191ee7..4080cd0442dbc516231dc983a3b6609a211523db 100644 --- a/substrate/frame/contracts/proc-macro/Cargo.toml +++ b/substrate/frame/contracts/proc-macro/Cargo.toml @@ -19,5 +19,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = { version = "2.0.48", features = ["full"] } +quote = { workspace = true } +syn = { features = ["full"], workspace = true } diff --git a/substrate/frame/contracts/proc-macro/src/lib.rs b/substrate/frame/contracts/proc-macro/src/lib.rs index 403db15ac2cbcf796280a29ba4c7a91e3047b21e..1794d09d5ad28e08bf9579bed4f311f469be832c 100644 --- a/substrate/frame/contracts/proc-macro/src/lib.rs +++ b/substrate/frame/contracts/proc-macro/src/lib.rs @@ -497,9 +497,14 @@ fn expand_docs(def: &EnvDef) -> TokenStream2 { 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 stable_api_count = def.host_funcs.iter().filter(|f| f.is_stable).count(); quote! { pub struct Env; + + #[cfg(test)] + pub const STABLE_API_COUNT: usize = #stable_api_count; + #impls /// Documentation of the API (host functions) available to contracts. /// @@ -638,37 +643,34 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) }; let sync_gas_before = if expand_blocks { quote! { - // Gas left in the gas meter right before switching to engine execution. - let __gas_before__ = { - let engine_consumed_total = + // Write gas from wasmi into pallet-contracts before entering the host function. + let __gas_left_before__ = { + let executor_total = __caller__.fuel_consumed().expect("Fuel metering is enabled; qed"); - let gas_meter = __caller__.data_mut().ext().gas_meter_mut(); - gas_meter - .charge_fuel(engine_consumed_total) + __caller__ + .data_mut() + .ext() + .gas_meter_mut() + .sync_from_executor(executor_total) .map_err(TrapReason::from) .map_err(#into_host)? - .ref_time() }; } } else { quote! { } }; - // Gas left in the gas meter right after returning from engine execution. + // Write gas from pallet-contracts into wasmi after leaving the host function. let sync_gas_after = if expand_blocks { quote! { - let mut gas_after = __caller__.data_mut().ext().gas_meter().gas_left().ref_time(); - let mut host_consumed = __gas_before__.saturating_sub(gas_after); - // Possible undercharge of at max 1 fuel here, if host consumed less than `instruction_weights.base` - // Not a problem though, as soon as host accounts its spent gas properly. - let fuel_consumed = host_consumed - .checked_div(__caller__.data_mut().ext().schedule().instruction_weights.base as u64) - .ok_or(Error::::InvalidSchedule) - .map_err(TrapReason::from) - .map_err(#into_host)?; + let fuel_consumed = __caller__ + .data_mut() + .ext() + .gas_meter_mut() + .sync_to_executor(__gas_left_before__) + .map_err(TrapReason::from)?; __caller__ - .consume_fuel(fuel_consumed) - .map_err(|_| TrapReason::from(Error::::OutOfGas)) - .map_err(#into_host)?; + .consume_fuel(fuel_consumed.into()) + .map_err(|_| TrapReason::from(Error::::OutOfGas))?; } } else { quote! { } diff --git a/substrate/frame/contracts/src/benchmarking/code.rs b/substrate/frame/contracts/src/benchmarking/code.rs index 0b6ab6b3c0e1b99b2dfb34642568d29cc9dfdd91..96ce11f8c4183a53d7e8e75fc0f6d826e861c54b 100644 --- a/substrate/frame/contracts/src/benchmarking/code.rs +++ b/substrate/frame/contracts/src/benchmarking/code.rs @@ -26,13 +26,13 @@ use crate::Config; use frame_support::traits::Get; -use sp_runtime::traits::Hash; +use sp_runtime::{traits::Hash, Saturating}; use sp_std::{borrow::ToOwned, prelude::*}; use wasm_instrument::parity_wasm::{ builder, elements::{ - self, BlockType, CustomSection, External, FuncBody, Instruction, Instructions, Local, - Module, Section, ValueType, + self, BlockType, CustomSection, FuncBody, Instruction, Instructions, Local, Section, + ValueType, }, }; @@ -238,24 +238,6 @@ impl From for WasmModule { } impl WasmModule { - /// Uses the supplied wasm module. - pub fn from_code(code: &[u8]) -> Self { - let module = Module::from_bytes(code).unwrap(); - let limits = *module - .import_section() - .unwrap() - .entries() - .iter() - .find_map(|e| if let External::Memory(mem) = e.external() { Some(mem) } else { None }) - .unwrap() - .limits(); - let code = module.into_bytes().unwrap(); - let hash = T::Hashing::hash(&code); - let memory = - ImportedMemory { min_pages: limits.initial(), max_pages: limits.maximum().unwrap() }; - Self { code: code.into(), hash, memory: Some(memory) } - } - /// Creates a wasm module with an empty `call` and `deploy` function and nothing else. pub fn dummy() -> Self { ModuleDefinition::default().into() @@ -280,22 +262,25 @@ impl WasmModule { /// `instantiate_with_code` for different sizes of wasm modules. The generated module maximizes /// instrumentation runtime by nesting blocks as deeply as possible given the byte budget. /// `code_location`: Whether to place the code into `deploy` or `call`. - pub fn sized(target_bytes: u32, code_location: Location) -> Self { + pub fn sized(target_bytes: u32, code_location: Location, use_float: bool) -> Self { use self::elements::Instruction::{End, GetLocal, If, Return}; // Base size of a contract is 63 bytes and each expansion adds 6 bytes. // We do one expansion less to account for the code section and function body // size fields inside the binary wasm module representation which are leb128 encoded // and therefore grow in size when the contract grows. We are not allowed to overshoot // because of the maximum code size that is enforced by `instantiate_with_code`. - let expansions = (target_bytes.saturating_sub(63) / 6).saturating_sub(1); + let mut expansions = (target_bytes.saturating_sub(63) / 6).saturating_sub(1); const EXPANSION: [Instruction; 4] = [GetLocal(0), If(BlockType::NoResult), Return, End]; + let mut locals = vec![Local::new(1, ValueType::I32)]; + if use_float { + locals.push(Local::new(1, ValueType::F32)); + locals.push(Local::new(2, ValueType::F32)); + locals.push(Local::new(3, ValueType::F32)); + expansions.saturating_dec(); + } let mut module = ModuleDefinition { memory: Some(ImportedMemory::max::()), ..Default::default() }; - let body = Some(body::repeated_with_locals( - &[Local::new(1, ValueType::I32)], - expansions, - &EXPANSION, - )); + let body = Some(body::repeated_with_locals(&locals, expansions, &EXPANSION)); match code_location { Location::Call => module.call_body = body, Location::Deploy => module.deploy_body = body, diff --git a/substrate/frame/contracts/src/benchmarking/mod.rs b/substrate/frame/contracts/src/benchmarking/mod.rs index e387c28b6714c02d5ee5831cf5b5030bf90660d5..794777ef05cfae248542c61a811875925deaed45 100644 --- a/substrate/frame/contracts/src/benchmarking/mod.rs +++ b/substrate/frame/contracts/src/benchmarking/mod.rs @@ -29,7 +29,7 @@ use self::{ sandbox::Sandbox, }; use crate::{ - exec::{AccountIdOf, Key}, + exec::Key, migration::{ codegen::LATEST_MIGRATION_VERSION, v09, v10, v11, v12, v13, v14, v15, MigrationStep, }, @@ -184,24 +184,6 @@ fn caller_funding() -> BalanceOf { BalanceOf::::max_value() / 10_000u32.into() } -/// Load the specified contract file from disk by including it into the runtime. -/// -/// We need to load a different version of ink! contracts when the benchmark is run as -/// a test. This is because ink! contracts depend on the sizes of types that are defined -/// differently in the test environment. Solang is more lax in that regard. -macro_rules! load_benchmark { - ($name:expr) => {{ - #[cfg(not(test))] - { - include_bytes!(concat!("../../benchmarks/", $name, ".wasm")) - } - #[cfg(test)] - { - include_bytes!(concat!("../../benchmarks/", $name, "_test.wasm")) - } - }}; -} - benchmarks! { where_clause { where as codec::HasCompact>::Type: Clone + Eq + PartialEq + sp_std::fmt::Debug + scale_info::TypeInfo + codec::Encode, @@ -380,7 +362,7 @@ benchmarks! { call_with_code_per_byte { let c in 0 .. T::MaxCodeLen::get(); let instance = Contract::::with_caller( - whitelisted_caller(), WasmModule::sized(c, Location::Deploy), vec![], + whitelisted_caller(), WasmModule::sized(c, Location::Deploy, false), vec![], )?; let value = Pallet::::min_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); @@ -407,7 +389,7 @@ benchmarks! { let value = Pallet::::min_balance(); let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); - let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); + let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call, false); let origin = RawOrigin::Signed(caller.clone()); let addr = Contracts::::contract_address(&caller, &hash, &input, &salt); }: _(origin, value, Weight::MAX, None, code, input, salt) @@ -486,19 +468,36 @@ benchmarks! { // It creates a maximum number of metering blocks per byte. // `c`: Size of the code in bytes. #[pov_mode = Measured] - upload_code { + upload_code_determinism_enforced { let c in 0 .. T::MaxCodeLen::get(); let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); - let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); + let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call, false); let origin = RawOrigin::Signed(caller.clone()); - }: _(origin, code, None, Determinism::Enforced) + }: upload_code(origin, code, None, Determinism::Enforced) verify { // uploading the code reserves some balance in the callers account assert!(T::Currency::total_balance_on_hold(&caller) > 0u32.into()); assert!(>::code_exists(&hash)); } + // Uploading code with [`Determinism::Relaxed`] should be more expensive than uploading code with [`Determinism::Enforced`], + // as we always try to save the code with [`Determinism::Enforced`] first. + #[pov_mode = Measured] + upload_code_determinism_relaxed { + let c in 0 .. T::MaxCodeLen::get(); + let caller = whitelisted_caller(); + T::Currency::set_balance(&caller, caller_funding::()); + let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call, true); + let origin = RawOrigin::Signed(caller.clone()); + }: upload_code(origin, code, None, Determinism::Relaxed) + verify { + assert!(T::Currency::total_balance_on_hold(&caller) > 0u32.into()); + assert!(>::code_exists(&hash)); + // Ensure that the benchmark follows the most expensive path, i.e., the code is saved with [`Determinism::Relaxed`] after trying to save it with [`Determinism::Enforced`]. + assert_eq!(CodeInfoOf::::get(&hash).unwrap().determinism(), Determinism::Relaxed); + } + // Removing code does not depend on the size of the contract because all the information // needed to verify the removal claim (refcount, owner) is stored in a separate storage // item (`CodeInfoOf`). @@ -913,7 +912,7 @@ benchmarks! { }, ImportedFunction { module: "seal0", - name: "add_delegate_dependency", + name: "lock_delegate_dependency", params: vec![ValueType::I32], return_type: None, } @@ -928,7 +927,7 @@ benchmarks! { value: code_hashes_bytes, }, ], - deploy_body: Some(body::repeated_dyn(r, vec![ + deploy_body: Some(body::repeated_dyn(T::MaxDelegateDependencies::get(), vec![ Counter(beneficiary_len as u32, code_hash_len as u32), // code_hash_ptr Regular(Instruction::Call(1)), ])), @@ -944,6 +943,7 @@ benchmarks! { assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); assert_eq!(T::Currency::balance(&instance.account_id), Pallet::::min_balance() * 2u32.into()); assert_ne!(T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &instance.account_id), 0u32.into()); + assert_eq!(ContractInfoOf::::get(&instance.account_id).unwrap().delegate_dependencies_count() as u32, T::MaxDelegateDependencies::get()); }: call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![]) verify { if r > 0 { @@ -2420,7 +2420,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[pov_mode = Measured] - add_delegate_dependency { + lock_delegate_dependency { let r in 0 .. T::MaxDelegateDependencies::get(); let code_hashes = (0..r) .map(|i| { @@ -2438,7 +2438,7 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "seal0", - name: "add_delegate_dependency", + name: "lock_delegate_dependency", params: vec![ValueType::I32], return_type: None, }], @@ -2458,7 +2458,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - remove_delegate_dependency { + unlock_delegate_dependency { let r in 0 .. T::MaxDelegateDependencies::get(); let code_hashes = (0..r) .map(|i| { @@ -2477,12 +2477,12 @@ benchmarks! { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "seal0", - name: "remove_delegate_dependency", + name: "unlock_delegate_dependency", params: vec![ValueType::I32], return_type: None, }, ImportedFunction { module: "seal0", - name: "add_delegate_dependency", + name: "lock_delegate_dependency", params: vec![ValueType::I32], return_type: None }], @@ -2643,86 +2643,6 @@ benchmarks! { "); }: {} - // Execute one erc20 transfer using the ink! erc20 example contract. - #[extra] - #[pov_mode = Measured] - ink_erc20_transfer { - let code = load_benchmark!("ink_erc20"); - let data = { - let new: ([u8; 4], BalanceOf) = ([0x9b, 0xae, 0x9d, 0x5e], 1000u32.into()); - new.encode() - }; - let instance = Contract::::new( - WasmModule::from_code(code), data, - )?; - let data = { - let transfer: ([u8; 4], AccountIdOf, BalanceOf) = ( - [0x84, 0xa1, 0x5d, 0xa1], - account::("receiver", 0, 0), - 1u32.into(), - ); - transfer.encode() - }; - }: { - >::bare_call( - instance.caller, - instance.account_id, - 0u32.into(), - Weight::MAX, - None, - data, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result?; - } - - // Execute one erc20 transfer using the open zeppelin erc20 contract compiled with solang. - #[extra] - #[pov_mode = Measured] - solang_erc20_transfer { - let code = include_bytes!("../../benchmarks/solang_erc20.wasm"); - let caller = account::("instantiator", 0, 0); - let mut balance = [0u8; 32]; - balance[0] = 100; - let data = { - let new: ([u8; 4], &str, &str, [u8; 32], AccountIdOf) = ( - [0xa6, 0xf1, 0xf5, 0xe1], - "KSM", - "K", - balance, - caller.clone(), - ); - new.encode() - }; - let instance = Contract::::with_caller( - caller, WasmModule::from_code(code), data, - )?; - balance[0] = 1; - let data = { - let transfer: ([u8; 4], AccountIdOf, [u8; 32]) = ( - [0x6a, 0x46, 0x73, 0x94], - account::("receiver", 0, 0), - balance, - ); - transfer.encode() - }; - }: { - >::bare_call( - instance.caller, - instance.account_id, - 0u32.into(), - Weight::MAX, - None, - data, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result?; - } - impl_benchmark_test_suite!( Contracts, crate::tests::ExtBuilder::default().build(), diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 2183d6b96cc5d4f84cbfa6777e0c1b0bbeec4f86..7da321af547d5b8f5539673f7540c328299945b6 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -287,6 +287,9 @@ pub trait Ext: sealing::Sealed { /// Returns `true` if debug message recording is enabled. Otherwise `false` is returned. fn append_debug_buffer(&mut self, msg: &str) -> bool; + /// Returns `true` if debug message recording is enabled. Otherwise `false` is returned. + fn debug_buffer_enabled(&self) -> bool; + /// Call some dispatchable and return the result. fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo; @@ -345,20 +348,20 @@ pub trait Ext: sealing::Sealed { /// - [`Error::::MaxDelegateDependenciesReached`] /// - [`Error::::CannotAddSelfAsDelegateDependency`] /// - [`Error::::DelegateDependencyAlreadyExists`] - fn add_delegate_dependency( + fn lock_delegate_dependency( &mut self, code_hash: CodeHash, ) -> Result<(), DispatchError>; /// Removes a delegate dependency from [`ContractInfo`]'s `delegate_dependencies` field. /// - /// This is the counterpart of [`Self::add_delegate_dependency`]. It decreases the reference - /// count and refunds the deposit that was charged by [`Self::add_delegate_dependency`]. + /// This is the counterpart of [`Self::lock_delegate_dependency`]. It decreases the reference + /// count and refunds the deposit that was charged by [`Self::lock_delegate_dependency`]. /// /// # Errors /// /// - [`Error::::DelegateDependencyNotFound`] - fn remove_delegate_dependency( + fn unlock_delegate_dependency( &mut self, code_hash: &CodeHash, ) -> Result<(), DispatchError>; @@ -834,7 +837,7 @@ where contract_info: CachedContract::Cached(contract_info), account_id, entry_point, - nested_gas: gas_meter.nested(gas_limit)?, + nested_gas: gas_meter.nested(gas_limit), nested_storage: storage_meter.nested(deposit_limit), allows_reentry: true, }; @@ -1429,6 +1432,10 @@ where self.top_frame_mut().nested_storage.charge(diff) } + fn debug_buffer_enabled(&self) -> bool { + self.debug_message.is_some() + } + fn append_debug_buffer(&mut self, msg: &str) -> bool { if let Some(buffer) = &mut self.debug_message { buffer @@ -1547,7 +1554,7 @@ where }); } - fn add_delegate_dependency( + fn lock_delegate_dependency( &mut self, code_hash: CodeHash, ) -> Result<(), DispatchError> { @@ -1558,7 +1565,7 @@ where let code_info = CodeInfoOf::::get(code_hash).ok_or(Error::::CodeNotFound)?; let deposit = T::CodeHashLockupDepositPercent::get().mul_ceil(code_info.deposit()); - info.add_delegate_dependency(code_hash, deposit)?; + info.lock_delegate_dependency(code_hash, deposit)?; Self::increment_refcount(code_hash)?; frame .nested_storage @@ -1566,14 +1573,14 @@ where Ok(()) } - fn remove_delegate_dependency( + fn unlock_delegate_dependency( &mut self, code_hash: &CodeHash, ) -> Result<(), DispatchError> { let frame = self.top_frame_mut(); let info = frame.contract_info.get(&frame.account_id); - let deposit = info.remove_delegate_dependency(code_hash)?; + let deposit = info.unlock_delegate_dependency(code_hash)?; Self::decrement_refcount(*code_hash); frame .nested_storage diff --git a/substrate/frame/contracts/src/gas.rs b/substrate/frame/contracts/src/gas.rs index f78fb03a401db005bb11197bea605e4d615d8262..b9d91f38f16f957ae6bc40ef08010ecf146dbf03 100644 --- a/substrate/frame/contracts/src/gas.rs +++ b/substrate/frame/contracts/src/gas.rs @@ -23,7 +23,7 @@ use frame_support::{ DefaultNoBound, }; use sp_core::Get; -use sp_runtime::{traits::Zero, DispatchError}; +use sp_runtime::{traits::Zero, DispatchError, Saturating}; #[cfg(test)] use std::{any::Any, fmt::Debug}; @@ -37,6 +37,24 @@ impl ChargedAmount { } } +/// Used to capture the gas left before entering a host function. +/// +/// Has to be consumed in order to sync back the gas after leaving the host function. +#[must_use] +pub struct RefTimeLeft(u64); + +/// Resource that needs to be synced to the executor. +/// +/// Wrapped to make sure that the resource will be synced back the the executor. +#[must_use] +pub struct Syncable(u64); + +impl From for u64 { + fn from(from: Syncable) -> u64 { + from.0 + } +} + #[cfg(not(test))] pub trait TestAuxiliaries {} #[cfg(not(test))] @@ -63,6 +81,11 @@ pub trait Token: Copy + Clone + TestAuxiliaries { /// while calculating the amount. In this case it is ok to use saturating operations /// since on overflow they will return `max_value` which should consume all gas. fn weight(&self) -> Weight; + + /// Returns true if this token is expected to influence the lowest gas limit. + fn influence_lowest_gas_limit(&self) -> bool { + true + } } /// A wrapper around a type-erased trait object of what used to be a `Token`. @@ -79,8 +102,13 @@ pub struct GasMeter { gas_left: Weight, /// Due to `adjust_gas` and `nested` the `gas_left` can temporarily dip below its final value. gas_left_lowest: Weight, - /// Amount of fuel consumed by the engine from the last host function call. - engine_consumed: u64, + /// The amount of resources that was consumed by the execution engine. + /// + /// This should be equivalent to `self.gas_consumed().ref_time()` but expressed in whatever + /// unit the execution engine uses to track resource consumption. We have to track it + /// separately in order to avoid the loss of precision that happens when converting from + /// ref_time to the execution engine unit. + executor_consumed: u64, _phantom: PhantomData, #[cfg(test)] tokens: Vec, @@ -92,7 +120,7 @@ impl GasMeter { gas_limit, gas_left: gas_limit, gas_left_lowest: gas_limit, - engine_consumed: Default::default(), + executor_consumed: 0, _phantom: PhantomData, #[cfg(test)] tokens: Vec::new(), @@ -104,9 +132,7 @@ impl GasMeter { /// # Note /// /// Passing `0` as amount is interpreted as "all remaining gas". - pub fn nested(&mut self, amount: Weight) -> Result { - // NOTE that it is ok to allocate all available gas since it still ensured - // by `charge` that it doesn't reach zero. + pub fn nested(&mut self, amount: Weight) -> Self { let amount = Weight::from_parts( if amount.ref_time().is_zero() { self.gas_left().ref_time() @@ -118,33 +144,17 @@ impl GasMeter { } else { amount.proof_size() }, - ); - self.gas_left = self.gas_left.checked_sub(&amount).ok_or_else(|| >::OutOfGas)?; - Ok(GasMeter::new(amount)) + ) + .min(self.gas_left); + self.gas_left -= amount; + GasMeter::new(amount) } /// Absorb the remaining gas of a nested meter after we are done using it. pub fn absorb_nested(&mut self, nested: Self) { - if self.gas_left.ref_time().is_zero() { - // All of the remaining gas was inherited by the nested gas meter. When absorbing - // we can therefore safely inherit the lowest gas that the nested gas meter experienced - // as long as it is lower than the lowest gas that was experienced by the parent. - // We cannot call `self.gas_left_lowest()` here because in the state that this - // code is run the parent gas meter has `0` gas left. - *self.gas_left_lowest.ref_time_mut() = - nested.gas_left_lowest().ref_time().min(self.gas_left_lowest.ref_time()); - } else { - // The nested gas meter was created with a fixed amount that did not consume all of the - // parents (self) gas. The lowest gas that self will experience is when the nested - // gas was pre charged with the fixed amount. - *self.gas_left_lowest.ref_time_mut() = self.gas_left_lowest().ref_time(); - } - if self.gas_left.proof_size().is_zero() { - *self.gas_left_lowest.proof_size_mut() = - nested.gas_left_lowest().proof_size().min(self.gas_left_lowest.proof_size()); - } else { - *self.gas_left_lowest.proof_size_mut() = self.gas_left_lowest().proof_size(); - } + self.gas_left_lowest = (self.gas_left + nested.gas_limit) + .saturating_sub(nested.gas_required()) + .min(self.gas_left_lowest); self.gas_left += nested.gas_left; } @@ -178,37 +188,48 @@ impl GasMeter { /// This is when a maximum a priori amount was charged and then should be partially /// refunded to match the actual amount. pub fn adjust_gas>(&mut self, charged_amount: ChargedAmount, token: Tok) { - self.gas_left_lowest = self.gas_left_lowest(); + if token.influence_lowest_gas_limit() { + self.gas_left_lowest = self.gas_left_lowest(); + } let adjustment = charged_amount.0.saturating_sub(token.weight()); self.gas_left = self.gas_left.saturating_add(adjustment).min(self.gas_limit); } - /// This method is used for gas syncs with the engine. + /// Hand over the gas metering responsibility from the executor to this meter. /// - /// Updates internal `engine_comsumed` tracker of engine fuel consumption. + /// Needs to be called when entering a host function to update this meter with the + /// gas that was tracked by the executor. It tracks the latest seen total value + /// in order to compute the delta that needs to be charged. + pub fn sync_from_executor( + &mut self, + executor_total: u64, + ) -> Result { + let chargable_reftime = executor_total + .saturating_sub(self.executor_consumed) + .saturating_mul(u64::from(T::Schedule::get().instruction_weights.base)); + self.executor_consumed = executor_total; + self.gas_left + .checked_reduce(Weight::from_parts(chargable_reftime, 0)) + .ok_or_else(|| Error::::OutOfGas)?; + Ok(RefTimeLeft(self.gas_left.ref_time())) + } + + /// Hand over the gas metering responsibility from this meter to the executor. /// - /// Charges self with the `ref_time` Weight corresponding to wasmi fuel consumed on the engine - /// side since last sync. Passed value is scaled by multiplying it by the weight of a basic - /// operation, as such an operation in wasmi engine costs 1. + /// Needs to be called when leaving a host function in order to calculate how much + /// gas needs to be charged from the **executor**. It updates the last seen executor + /// total value so that it is correct when `sync_from_executor` is called the next time. /// - /// Returns the updated `gas_left` `Weight` value from the meter. - /// Normally this would never fail, as engine should fail first when out of gas. - pub fn charge_fuel(&mut self, wasmi_fuel_total: u64) -> Result { - // Take the part consumed since the last update. - let wasmi_fuel = wasmi_fuel_total.saturating_sub(self.engine_consumed); - if !wasmi_fuel.is_zero() { - self.engine_consumed = wasmi_fuel_total; - let reftime_consumed = - wasmi_fuel.saturating_mul(T::Schedule::get().instruction_weights.base as u64); - let ref_time_left = self - .gas_left - .ref_time() - .checked_sub(reftime_consumed) - .ok_or_else(|| Error::::OutOfGas)?; - - *(self.gas_left.ref_time_mut()) = ref_time_left; - } - Ok(self.gas_left) + /// It is important that this does **not** actually sync with the executor. That has + /// to be done by the caller. + pub fn sync_to_executor(&mut self, before: RefTimeLeft) -> Result { + let chargable_executor_resource = before + .0 + .saturating_sub(self.gas_left().ref_time()) + .checked_div(u64::from(T::Schedule::get().instruction_weights.base)) + .ok_or(Error::::InvalidSchedule)?; + self.executor_consumed.saturating_accrue(chargable_executor_resource); + Ok(Syncable(chargable_executor_resource)) } /// Returns the amount of gas that is required to run the same call. diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 533085f2b874f6cc1d6c122fa6db5c8498c3db0c..de84d5220c548a29cf046c85b8fea0520a5d3e91 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -214,6 +214,27 @@ pub struct Environment { block_number: EnvironmentType>, } +/// Defines the current version of the HostFn APIs. +/// This is used to communicate the available APIs in pallet-contracts. +/// +/// The version is bumped any time a new HostFn is added or stabilized. +#[derive(Encode, Decode, TypeInfo)] +pub struct ApiVersion(u16); +impl Default for ApiVersion { + fn default() -> Self { + Self(2) + } +} + +#[test] +fn api_version_is_up_to_date() { + assert_eq!( + 109, + crate::wasm::STABLE_API_COUNT, + "Stable API count has changed. Bump the returned value of ApiVersion::default() and update the test." + ); +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -222,7 +243,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; use sp_runtime::Perbill; - /// The current storage version. + /// The in-code storage version. pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(15); #[pallet::pallet] @@ -325,7 +346,7 @@ pub mod pallet { type DepositPerItem: Get>; /// The percentage of the storage deposit that should be held for using a code hash. - /// Instantiating a contract, or calling [`chain_extension::Ext::add_delegate_dependency`] + /// Instantiating a contract, or calling [`chain_extension::Ext::lock_delegate_dependency`] /// protects the code from being removed. In order to prevent abuse these actions are /// protected with a percentage of the code deposit. #[pallet::constant] @@ -347,7 +368,7 @@ pub mod pallet { type MaxStorageKeyLen: Get; /// The maximum number of delegate_dependencies that a contract can lock with - /// [`chain_extension::Ext::add_delegate_dependency`]. + /// [`chain_extension::Ext::lock_delegate_dependency`]. #[pallet::constant] type MaxDelegateDependencies: Get; @@ -367,6 +388,24 @@ pub mod pallet { #[pallet::constant] type MaxDebugBufferLen: Get; + /// Origin allowed to upload code. + /// + /// By default, it is safe to set this to `EnsureSigned`, allowing anyone to upload contract + /// code. + type UploadOrigin: EnsureOrigin; + + /// Origin allowed to instantiate code. + /// + /// # Note + /// + /// This is not enforced when a contract instantiates another contract. The + /// [`Self::UploadOrigin`] should make sure that no code is deployed that does unwanted + /// instantiations. + /// + /// By default, it is safe to set this to `EnsureSigned`, allowing anyone to instantiate + /// contract code. + type InstantiateOrigin: EnsureOrigin; + /// Overarching hold reason. type RuntimeHoldReason: From; @@ -402,6 +441,12 @@ pub mod pallet { #[pallet::constant] type Environment: Get>; + /// The version of the HostFn APIs that are available in the runtime. + /// + /// Only valid value is `()`. + #[pallet::constant] + type ApiVersion: Get; + /// A type that exposes XCM APIs, allowing contracts to interact with other parachains, and /// execute XCM programs. type Xcm: xcm_builder::Controller< @@ -609,8 +654,17 @@ 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`]. + /// + /// Use [`Determinism::Relaxed`] exclusively for non-deterministic code. If the uploaded + /// code is deterministic, specifying [`Determinism::Relaxed`] will be disregarded and + /// result in higher gas costs. #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))] + #[pallet::weight( + match determinism { + Determinism::Enforced => T::WeightInfo::upload_code_determinism_enforced(code.len() as u32), + Determinism::Relaxed => T::WeightInfo::upload_code_determinism_relaxed(code.len() as u32), + } + )] pub fn upload_code( origin: OriginFor, code: Vec, @@ -618,7 +672,7 @@ pub mod pallet { determinism: Determinism, ) -> DispatchResult { Migration::::ensure_migrated()?; - let origin = ensure_signed(origin)?; + let origin = T::UploadOrigin::ensure_origin(origin)?; Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into), determinism) .map(|_| ()) } @@ -767,11 +821,17 @@ pub mod pallet { salt: Vec, ) -> DispatchResultWithPostInfo { Migration::::ensure_migrated()?; - let origin = ensure_signed(origin)?; + + // These two origins will usually be the same; however, we treat them as separate since + // it is possible for the `Success` value of `UploadOrigin` and `InstantiateOrigin` to + // differ. + let upload_origin = T::UploadOrigin::ensure_origin(origin.clone())?; + let instantiate_origin = T::InstantiateOrigin::ensure_origin(origin)?; + let code_len = code.len() as u32; let (module, upload_deposit) = Self::try_upload_code( - origin.clone(), + upload_origin, code, storage_deposit_limit.clone().map(Into::into), Determinism::Enforced, @@ -785,7 +845,7 @@ pub mod pallet { let data_len = data.len() as u32; let salt_len = salt.len() as u32; let common = CommonInput { - origin: Origin::from_account_id(origin), + origin: Origin::from_account_id(instantiate_origin), value, data, gas_limit, @@ -826,10 +886,11 @@ pub mod pallet { salt: Vec, ) -> DispatchResultWithPostInfo { Migration::::ensure_migrated()?; + let origin = T::InstantiateOrigin::ensure_origin(origin)?; let data_len = data.len() as u32; let salt_len = salt.len() as u32; let common = CommonInput { - origin: Origin::from_runtime_origin(origin)?, + origin: Origin::from_account_id(origin), value, data, gas_limit, diff --git a/substrate/frame/contracts/src/migration.rs b/substrate/frame/contracts/src/migration.rs index 6d61cb6b1e1af158b9d4942efabc73267f8e44f7..f30ae1ebfadee55eeca000e74b4aac76f93f7551 100644 --- a/substrate/frame/contracts/src/migration.rs +++ b/substrate/frame/contracts/src/migration.rs @@ -263,10 +263,10 @@ impl Migration { impl OnRuntimeUpgrade for Migration { fn on_runtime_upgrade() -> Weight { let name = >::name(); - let current_version = >::current_storage_version(); + let in_code_version = >::in_code_storage_version(); let on_chain_version = >::on_chain_storage_version(); - if on_chain_version == current_version { + if on_chain_version == in_code_version { log::warn!( target: LOG_TARGET, "{name}: No Migration performed storage_version = latest_version = {:?}", @@ -289,7 +289,7 @@ impl OnRuntimeUpgrade for Migration OnRuntimeUpgrade for Migration>::on_chain_storage_version(); - let current_version = >::current_storage_version(); + let in_code_version = >::in_code_storage_version(); - if on_chain_version == current_version { + if on_chain_version == in_code_version { return Ok(Default::default()) } log::debug!( target: LOG_TARGET, - "Requested migration of {} from {:?}(on-chain storage version) to {:?}(current storage version)", - >::name(), on_chain_version, current_version + "Requested migration of {} from {:?}(on-chain storage version) to {:?}(in-code storage version)", + >::name(), on_chain_version, in_code_version ); ensure!( - T::Migrations::is_upgrade_supported(on_chain_version, current_version), - "Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, current storage version)" + T::Migrations::is_upgrade_supported(on_chain_version, in_code_version), + "Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, in-code storage version)" ); Ok(Default::default()) @@ -421,7 +421,7 @@ impl Migration { }, StepResult::Completed { steps_done } => { in_progress_version.put::>(); - if >::current_storage_version() != in_progress_version { + if >::in_code_storage_version() != in_progress_version { log::info!( target: LOG_TARGET, "{name}: Next migration is {:?},", diff --git a/substrate/frame/contracts/src/migration/v09.rs b/substrate/frame/contracts/src/migration/v09.rs index 98fcccc2c0becedccd4bd15eed98b36fd52662ee..f19bff9d6747f8359558e2c2d5a289fad668bfaa 100644 --- a/substrate/frame/contracts/src/migration/v09.rs +++ b/substrate/frame/contracts/src/migration/v09.rs @@ -28,7 +28,7 @@ use frame_support::{pallet_prelude::*, storage_alias, DefaultNoBound, Identity}; use sp_runtime::TryRuntimeError; use sp_std::prelude::*; -mod old { +mod v8 { use super::*; #[derive(Encode, Decode)] @@ -50,14 +50,14 @@ mod old { #[cfg(feature = "runtime-benchmarks")] pub fn store_old_dummy_code(len: usize) { use sp_runtime::traits::Hash; - let module = old::PrefabWasmModule { + let module = v8::PrefabWasmModule { instruction_weights_version: 0, initial: 0, maximum: 0, code: vec![42u8; len], }; let hash = T::Hashing::hash(&module.code); - old::CodeStorage::::insert(hash, module); + v8::CodeStorage::::insert(hash, module); } #[derive(Encode, Decode)] @@ -89,9 +89,9 @@ impl MigrationStep for Migration { fn step(&mut self) -> (IsFinished, Weight) { let mut iter = if let Some(last_key) = self.last_code_hash.take() { - old::CodeStorage::::iter_from(old::CodeStorage::::hashed_key_for(last_key)) + v8::CodeStorage::::iter_from(v8::CodeStorage::::hashed_key_for(last_key)) } else { - old::CodeStorage::::iter() + v8::CodeStorage::::iter() }; if let Some((key, old)) = iter.next() { @@ -115,7 +115,7 @@ impl MigrationStep for Migration { #[cfg(feature = "try-runtime")] fn pre_upgrade_step() -> Result, TryRuntimeError> { - let sample: Vec<_> = old::CodeStorage::::iter().take(100).collect(); + let sample: Vec<_> = v8::CodeStorage::::iter().take(100).collect(); log::debug!(target: LOG_TARGET, "Taking sample of {} contract codes", sample.len()); Ok(sample.encode()) @@ -123,7 +123,7 @@ impl MigrationStep for Migration { #[cfg(feature = "try-runtime")] fn post_upgrade_step(state: Vec) -> Result<(), TryRuntimeError> { - let sample = , old::PrefabWasmModule)> as Decode>::decode(&mut &state[..]) + let sample = , v8::PrefabWasmModule)> as Decode>::decode(&mut &state[..]) .expect("pre_upgrade_step provides a valid state; qed"); log::debug!(target: LOG_TARGET, "Validating sample of {} contract codes", sample.len()); diff --git a/substrate/frame/contracts/src/migration/v10.rs b/substrate/frame/contracts/src/migration/v10.rs index d64673aac7d268df80adb955ff3d5c5fd16c5681..1bee86e6a773a9b0d7720438644a4ae84d9bd332 100644 --- a/substrate/frame/contracts/src/migration/v10.rs +++ b/substrate/frame/contracts/src/migration/v10.rs @@ -47,7 +47,7 @@ use sp_runtime::{ }; use sp_std::prelude::*; -mod old { +mod v9 { use super::*; pub type BalanceOf = ( ) where OldCurrency: ReservableCurrency<::AccountId> + 'static, { - let info = old::ContractInfo { + let info = v9::ContractInfo { trie_id: info.trie_id, code_hash: info.code_hash, storage_bytes: Default::default(), @@ -94,7 +94,7 @@ pub fn store_old_contract_info( storage_item_deposit: Default::default(), storage_base_deposit: Default::default(), }; - old::ContractInfoOf::::insert(account, info); + v9::ContractInfoOf::::insert(account, info); } #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen)] @@ -120,9 +120,9 @@ where pub code_hash: CodeHash, storage_bytes: u32, storage_items: u32, - pub storage_byte_deposit: old::BalanceOf, - storage_item_deposit: old::BalanceOf, - storage_base_deposit: old::BalanceOf, + pub storage_byte_deposit: v9::BalanceOf, + storage_item_deposit: v9::BalanceOf, + storage_base_deposit: v9::BalanceOf, } #[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)] @@ -152,7 +152,7 @@ fn deposit_address( impl MigrationStep for Migration where OldCurrency: ReservableCurrency<::AccountId> - + Inspect<::AccountId, Balance = old::BalanceOf>, + + Inspect<::AccountId, Balance = v9::BalanceOf>, { const VERSION: u16 = 10; @@ -162,11 +162,11 @@ where fn step(&mut self) -> (IsFinished, Weight) { let mut iter = if let Some(last_account) = self.last_account.take() { - old::ContractInfoOf::::iter_from( - old::ContractInfoOf::::hashed_key_for(last_account), + v9::ContractInfoOf::::iter_from( + v9::ContractInfoOf::::hashed_key_for(last_account), ) } else { - old::ContractInfoOf::::iter() + v9::ContractInfoOf::::iter() }; if let Some((account, contract)) = iter.next() { @@ -276,7 +276,7 @@ where #[cfg(feature = "try-runtime")] fn pre_upgrade_step() -> Result, TryRuntimeError> { - let sample: Vec<_> = old::ContractInfoOf::::iter().take(10).collect(); + let sample: Vec<_> = v9::ContractInfoOf::::iter().take(10).collect(); log::debug!(target: LOG_TARGET, "Taking sample of {} contracts", sample.len()); Ok(sample.encode()) @@ -284,7 +284,7 @@ where #[cfg(feature = "try-runtime")] fn post_upgrade_step(state: Vec) -> Result<(), TryRuntimeError> { - let sample = )> as Decode>::decode( + let sample = )> as Decode>::decode( &mut &state[..], ) .expect("pre_upgrade_step provides a valid state; qed"); diff --git a/substrate/frame/contracts/src/migration/v11.rs b/substrate/frame/contracts/src/migration/v11.rs index a5b11f6e08977fbbeb737bc2650ad318ddac97c8..9bfbb25edfb44a8072d2d0073ec4cdb4d27cc360 100644 --- a/substrate/frame/contracts/src/migration/v11.rs +++ b/substrate/frame/contracts/src/migration/v11.rs @@ -29,7 +29,7 @@ use sp_runtime::TryRuntimeError; use codec::{Decode, Encode}; use frame_support::{pallet_prelude::*, storage_alias, DefaultNoBound}; use sp_std::{marker::PhantomData, prelude::*}; -mod old { +mod v10 { use super::*; #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] @@ -51,11 +51,11 @@ pub struct DeletionQueueManager { #[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime"))] pub fn fill_old_queue(len: usize) { - let queue: Vec = - core::iter::repeat_with(|| old::DeletedContract { trie_id: Default::default() }) + let queue: Vec = + core::iter::repeat_with(|| v10::DeletedContract { trie_id: Default::default() }) .take(len) .collect(); - old::DeletionQueue::::set(Some(queue)); + v10::DeletionQueue::::set(Some(queue)); } #[storage_alias] @@ -80,7 +80,7 @@ impl MigrationStep for Migration { } fn step(&mut self) -> (IsFinished, Weight) { - let Some(old_queue) = old::DeletionQueue::::take() else { + let Some(old_queue) = v10::DeletionQueue::::take() else { return (IsFinished::Yes, Weight::zero()) }; let len = old_queue.len(); @@ -106,7 +106,7 @@ impl MigrationStep for Migration { #[cfg(feature = "try-runtime")] fn pre_upgrade_step() -> Result, TryRuntimeError> { - let old_queue = old::DeletionQueue::::take().unwrap_or_default(); + let old_queue = v10::DeletionQueue::::take().unwrap_or_default(); if old_queue.is_empty() { let len = 10u32; diff --git a/substrate/frame/contracts/src/migration/v12.rs b/substrate/frame/contracts/src/migration/v12.rs index 7dee31503101ba753b0e807d11621be711d4b58b..d9128286df389f84b451660e8d00f4a886b629d4 100644 --- a/substrate/frame/contracts/src/migration/v12.rs +++ b/substrate/frame/contracts/src/migration/v12.rs @@ -34,7 +34,7 @@ use sp_runtime::TryRuntimeError; use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128, Saturating}; use sp_std::prelude::*; -mod old { +mod v11 { use super::*; pub type BalanceOf = , #[codec(compact)] - deposit: old::BalanceOf, + deposit: v11::BalanceOf, #[codec(compact)] refcount: u64, determinism: Determinism, @@ -112,17 +112,17 @@ where let hash = T::Hashing::hash(&code); PristineCode::::insert(hash, code.clone()); - let module = old::PrefabWasmModule { + let module = v11::PrefabWasmModule { instruction_weights_version: Default::default(), initial: Default::default(), maximum: Default::default(), code, determinism: Determinism::Enforced, }; - old::CodeStorage::::insert(hash, module); + v11::CodeStorage::::insert(hash, module); - let info = old::OwnerInfo { owner: account, deposit: u32::MAX.into(), refcount: u64::MAX }; - old::OwnerInfoOf::::insert(hash, info); + let info = v11::OwnerInfo { owner: account, deposit: u32::MAX.into(), refcount: u64::MAX }; + v11::OwnerInfoOf::::insert(hash, info); } #[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)] @@ -148,16 +148,16 @@ where fn step(&mut self) -> (IsFinished, Weight) { let mut iter = if let Some(last_key) = self.last_code_hash.take() { - old::OwnerInfoOf::::iter_from( - old::OwnerInfoOf::::hashed_key_for(last_key), + v11::OwnerInfoOf::::iter_from( + v11::OwnerInfoOf::::hashed_key_for(last_key), ) } else { - old::OwnerInfoOf::::iter() + v11::OwnerInfoOf::::iter() }; if let Some((hash, old_info)) = iter.next() { log::debug!(target: LOG_TARGET, "Migrating OwnerInfo for code_hash {:?}", hash); - let module = old::CodeStorage::::take(hash) + let module = v11::CodeStorage::::take(hash) .expect(format!("No PrefabWasmModule found for code_hash: {:?}", hash).as_str()); let code_len = module.code.len(); @@ -184,7 +184,7 @@ where let bytes_before = module .encoded_size() .saturating_add(code_len) - .saturating_add(old::OwnerInfo::::max_encoded_len()) + .saturating_add(v11::OwnerInfo::::max_encoded_len()) as u32; let items_before = 3u32; let deposit_expected_before = price_per_byte @@ -241,10 +241,10 @@ where fn pre_upgrade_step() -> Result, TryRuntimeError> { let len = 100; log::debug!(target: LOG_TARGET, "Taking sample of {} OwnerInfo(s)", len); - let sample: Vec<_> = old::OwnerInfoOf::::iter() + let sample: Vec<_> = v11::OwnerInfoOf::::iter() .take(len) .map(|(k, v)| { - let module = old::CodeStorage::::get(k) + let module = v11::CodeStorage::::get(k) .expect("No PrefabWasmModule found for code_hash: {:?}"); let info: CodeInfo = CodeInfo { determinism: module.determinism, @@ -258,9 +258,9 @@ where .collect(); let storage: u32 = - old::CodeStorage::::iter().map(|(_k, v)| v.encoded_size() as u32).sum(); - let mut deposit: old::BalanceOf = Default::default(); - old::OwnerInfoOf::::iter().for_each(|(_k, v)| deposit += v.deposit); + v11::CodeStorage::::iter().map(|(_k, v)| v.encoded_size() as u32).sum(); + let mut deposit: v11::BalanceOf = Default::default(); + v11::OwnerInfoOf::::iter().for_each(|(_k, v)| deposit += v.deposit); Ok((sample, deposit, storage).encode()) } @@ -269,7 +269,7 @@ where fn post_upgrade_step(state: Vec) -> Result<(), TryRuntimeError> { let state = <( Vec<(CodeHash, CodeInfo)>, - old::BalanceOf, + v11::BalanceOf, u32, ) as Decode>::decode(&mut &state[..]) .unwrap(); @@ -283,7 +283,7 @@ where ensure!(info.refcount == old.refcount, "invalid refcount"); } - if let Some((k, _)) = old::CodeStorage::::iter().next() { + if let Some((k, _)) = v11::CodeStorage::::iter().next() { log::warn!( target: LOG_TARGET, "CodeStorage is still NOT empty, found code_hash: {:?}", @@ -292,7 +292,7 @@ where } else { log::debug!(target: LOG_TARGET, "CodeStorage is empty."); } - if let Some((k, _)) = old::OwnerInfoOf::::iter().next() { + if let Some((k, _)) = v11::OwnerInfoOf::::iter().next() { log::warn!( target: LOG_TARGET, "OwnerInfoOf is still NOT empty, found code_hash: {:?}", @@ -302,7 +302,7 @@ where log::debug!(target: LOG_TARGET, "OwnerInfoOf is empty."); } - let mut deposit: old::BalanceOf = Default::default(); + let mut deposit: v11::BalanceOf = Default::default(); let mut items = 0u32; let mut storage_info = 0u32; CodeInfoOf::::iter().for_each(|(_k, v)| { diff --git a/substrate/frame/contracts/src/migration/v13.rs b/substrate/frame/contracts/src/migration/v13.rs index dd2eb12eb62a5daf92cec8b5910c03f6d81ae0c0..498c44d53abce9730e9833fcbd27e1b2dbb2fe38 100644 --- a/substrate/frame/contracts/src/migration/v13.rs +++ b/substrate/frame/contracts/src/migration/v13.rs @@ -28,7 +28,7 @@ use frame_support::{pallet_prelude::*, storage_alias, DefaultNoBound}; use sp_runtime::BoundedBTreeMap; use sp_std::prelude::*; -mod old { +mod v12 { use super::*; #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -59,7 +59,7 @@ pub fn store_old_contract_info(account: T::AccountId, info: crate::Co let entropy = (b"contract_depo_v1", account.clone()).using_encoded(T::Hashing::hash); let deposit_account = Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) .expect("infinite length input; no invalid inputs for type; qed"); - let info = old::ContractInfo { + let info = v12::ContractInfo { trie_id: info.trie_id.clone(), deposit_account, code_hash: info.code_hash, @@ -69,7 +69,7 @@ pub fn store_old_contract_info(account: T::AccountId, info: crate::Co storage_item_deposit: Default::default(), storage_base_deposit: Default::default(), }; - old::ContractInfoOf::::insert(account, info); + v12::ContractInfoOf::::insert(account, info); } #[storage_alias] @@ -104,11 +104,11 @@ impl MigrationStep for Migration { fn step(&mut self) -> (IsFinished, Weight) { let mut iter = if let Some(last_account) = self.last_account.take() { - old::ContractInfoOf::::iter_from(old::ContractInfoOf::::hashed_key_for( + v12::ContractInfoOf::::iter_from(v12::ContractInfoOf::::hashed_key_for( last_account, )) } else { - old::ContractInfoOf::::iter() + v12::ContractInfoOf::::iter() }; if let Some((key, old)) = iter.next() { diff --git a/substrate/frame/contracts/src/migration/v14.rs b/substrate/frame/contracts/src/migration/v14.rs index 94534d05fdf889d05227149efd57ede584ecb013..09da09e5bcfb1f9ab4396a651e67519a75e09df2 100644 --- a/substrate/frame/contracts/src/migration/v14.rs +++ b/substrate/frame/contracts/src/migration/v14.rs @@ -44,7 +44,7 @@ use sp_runtime::{traits::Zero, Saturating}; #[cfg(feature = "try-runtime")] use sp_std::collections::btree_map::BTreeMap; -mod old { +mod v13 { use super::*; pub type BalanceOf = , #[codec(compact)] - pub deposit: old::BalanceOf, + pub deposit: v13::BalanceOf, #[codec(compact)] pub refcount: u64, pub determinism: Determinism, @@ -86,14 +86,14 @@ where let code = vec![42u8; len as usize]; let hash = T::Hashing::hash(&code); - let info = old::CodeInfo { + let info = v13::CodeInfo { owner: account, deposit: 10_000u32.into(), refcount: u64::MAX, determinism: Determinism::Enforced, code_len: len, }; - old::CodeInfoOf::::insert(hash, info); + v13::CodeInfoOf::::insert(hash, info); } #[cfg(feature = "try-runtime")] @@ -105,9 +105,9 @@ where OldCurrency: ReservableCurrency<::AccountId>, { /// Total reserved balance as code upload deposit for the owner. - reserved: old::BalanceOf, + reserved: v13::BalanceOf, /// Total balance of the owner. - total: old::BalanceOf, + total: v13::BalanceOf, } #[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)] @@ -134,11 +134,11 @@ where fn step(&mut self) -> (IsFinished, Weight) { let mut iter = if let Some(last_hash) = self.last_code_hash.take() { - old::CodeInfoOf::::iter_from( - old::CodeInfoOf::::hashed_key_for(last_hash), + v13::CodeInfoOf::::iter_from( + v13::CodeInfoOf::::hashed_key_for(last_hash), ) } else { - old::CodeInfoOf::::iter() + v13::CodeInfoOf::::iter() }; if let Some((hash, code_info)) = iter.next() { @@ -194,7 +194,7 @@ where #[cfg(feature = "try-runtime")] fn pre_upgrade_step() -> Result, TryRuntimeError> { - let info: Vec<_> = old::CodeInfoOf::::iter().collect(); + let info: Vec<_> = v13::CodeInfoOf::::iter().collect(); let mut owner_balance_allocation = BTreeMap::, BalanceAllocation>::new(); diff --git a/substrate/frame/contracts/src/migration/v15.rs b/substrate/frame/contracts/src/migration/v15.rs index 180fe855ca66728ba18b17555363eeac11a340ba..c77198d6fea0f6b7c305d40b981330cbb50e355d 100644 --- a/substrate/frame/contracts/src/migration/v15.rs +++ b/substrate/frame/contracts/src/migration/v15.rs @@ -46,7 +46,7 @@ use sp_runtime::{traits::Zero, Saturating}; #[cfg(feature = "try-runtime")] use sp_std::vec::Vec; -mod old { +mod v14 { use super::*; #[derive( @@ -81,7 +81,7 @@ pub fn store_old_contract_info(account: T::AccountId, info: crate::Co let entropy = (b"contract_depo_v1", account.clone()).using_encoded(T::Hashing::hash); let deposit_account = Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) .expect("infinite length input; no invalid inputs for type; qed"); - let info = old::ContractInfo { + let info = v14::ContractInfo { trie_id: info.trie_id.clone(), deposit_account, code_hash: info.code_hash, @@ -92,7 +92,7 @@ pub fn store_old_contract_info(account: T::AccountId, info: crate::Co storage_base_deposit: info.storage_base_deposit(), delegate_dependencies: info.delegate_dependencies().clone(), }; - old::ContractInfoOf::::insert(account, info); + v14::ContractInfoOf::::insert(account, info); } #[derive(Encode, Decode, CloneNoBound, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -127,11 +127,11 @@ impl MigrationStep for Migration { fn step(&mut self) -> (IsFinished, Weight) { let mut iter = if let Some(last_account) = self.last_account.take() { - old::ContractInfoOf::::iter_from(old::ContractInfoOf::::hashed_key_for( + v14::ContractInfoOf::::iter_from(v14::ContractInfoOf::::hashed_key_for( last_account, )) } else { - old::ContractInfoOf::::iter() + v14::ContractInfoOf::::iter() }; if let Some((account, old_contract)) = iter.next() { @@ -243,11 +243,11 @@ impl MigrationStep for Migration { #[cfg(feature = "try-runtime")] fn pre_upgrade_step() -> Result, TryRuntimeError> { - let sample: Vec<_> = old::ContractInfoOf::::iter().take(100).collect(); + let sample: Vec<_> = v14::ContractInfoOf::::iter().take(100).collect(); log::debug!(target: LOG_TARGET, "Taking sample of {} contracts", sample.len()); - let state: Vec<(T::AccountId, old::ContractInfo, BalanceOf, BalanceOf)> = sample + let state: Vec<(T::AccountId, v14::ContractInfo, BalanceOf, BalanceOf)> = sample .iter() .map(|(account, contract)| { ( @@ -265,7 +265,7 @@ impl MigrationStep for Migration { #[cfg(feature = "try-runtime")] fn post_upgrade_step(state: Vec) -> Result<(), TryRuntimeError> { let sample = - , BalanceOf, BalanceOf)> as Decode>::decode( + , BalanceOf, BalanceOf)> as Decode>::decode( &mut &state[..], ) .expect("pre_upgrade_step provides a valid state; qed"); diff --git a/substrate/frame/contracts/src/schedule.rs b/substrate/frame/contracts/src/schedule.rs index 63641832315eeb59928973aff221989800cd0579..b2e3801deaec1a36aef589427a6bf9dd324183b8 100644 --- a/substrate/frame/contracts/src/schedule.rs +++ b/substrate/frame/contracts/src/schedule.rs @@ -39,11 +39,7 @@ use serde::{Deserialize, Serialize}; /// fn create_schedule() -> Schedule { /// Schedule { /// limits: Limits { -/// globals: 3, -/// parameters: 3, /// memory_pages: 16, -/// table_size: 3, -/// br_table_size: 3, /// .. Default::default() /// }, /// instruction_weights: InstructionWeights { @@ -77,38 +73,9 @@ pub struct Limits { /// The maximum number of topics supported by an event. pub event_topics: u32, - /// Maximum number of globals a module is allowed to declare. - /// - /// Globals are not limited through the linear memory limit `memory_pages`. - pub globals: u32, - - /// Maximum number of locals a function can have. - /// - /// As wasm engine initializes each of the local, we need to limit their number to confine - /// execution costs. - pub locals: u32, - - /// Maximum numbers of parameters a function can have. - /// - /// Those need to be limited to prevent a potentially exploitable interaction with - /// the stack height instrumentation: The costs of executing the stack height - /// instrumentation for an indirectly called function scales linearly with the amount - /// of parameters of this function. Because the stack height instrumentation itself is - /// is not weight metered its costs must be static (via this limit) and included in - /// the costs of the instructions that cause them (call, call_indirect). - pub parameters: u32, - /// Maximum number of memory pages allowed for a contract. pub memory_pages: u32, - /// Maximum number of elements allowed in a table. - /// - /// Currently, the only type of element that is allowed in a table is funcref. - pub table_size: u32, - - /// Maximum number of elements that can appear as immediate value to the br_table instruction. - pub br_table_size: u32, - /// The maximum length of a subject in bytes used for PRNG generation. pub subject_len: u32, @@ -331,11 +298,11 @@ pub struct HostFnWeights { /// Weight of calling `instantiation_nonce`. pub instantiation_nonce: Weight, - /// Weight of calling `add_delegate_dependency`. - pub add_delegate_dependency: Weight, + /// Weight of calling `lock_delegate_dependency`. + pub lock_delegate_dependency: Weight, - /// Weight of calling `remove_delegate_dependency`. - pub remove_delegate_dependency: Weight, + /// Weight of calling `unlock_delegate_dependency`. + pub unlock_delegate_dependency: Weight, /// The type parameter is used in the default implementation. #[codec(skip)] @@ -370,13 +337,7 @@ impl Default for Limits { fn default() -> Self { Self { event_topics: 4, - globals: 256, - locals: 1024, - parameters: 128, memory_pages: 16, - // 4k function pointers (This is in count not bytes). - table_size: 4096, - br_table_size: 256, subject_len: 32, payload_len: 16 * 1024, runtime_memory: 1024 * 1024 * 128, @@ -474,8 +435,8 @@ impl Default for HostFnWeights { reentrance_count: cost!(seal_reentrance_count), account_reentrance_count: cost!(seal_account_reentrance_count), instantiation_nonce: cost!(seal_instantiation_nonce), - add_delegate_dependency: cost!(add_delegate_dependency), - remove_delegate_dependency: cost!(remove_delegate_dependency), + lock_delegate_dependency: cost!(lock_delegate_dependency), + unlock_delegate_dependency: cost!(unlock_delegate_dependency), _phantom: PhantomData, } } diff --git a/substrate/frame/contracts/src/storage.rs b/substrate/frame/contracts/src/storage.rs index d4d261f4ec1ffcfc68c5245864b00ea2f47928ed..e99afd5d42ee4684adc874d68bdba325feb58358 100644 --- a/substrate/frame/contracts/src/storage.rs +++ b/substrate/frame/contracts/src/storage.rs @@ -66,7 +66,7 @@ pub struct ContractInfo { storage_base_deposit: BalanceOf, /// Map of code hashes and deposit balances. /// - /// Tracks the code hash and deposit held for adding delegate dependencies. Dependencies added + /// Tracks the code hash and deposit held for locking delegate dependencies. Dependencies added /// to the map can not be removed from the chain state and can be safely used for delegate /// calls. delegate_dependencies: BoundedBTreeMap, BalanceOf, T::MaxDelegateDependencies>, @@ -108,6 +108,11 @@ impl ContractInfo { Ok(contract) } + /// Returns the number of locked delegate dependencies. + pub fn delegate_dependencies_count(&self) -> usize { + self.delegate_dependencies.len() + } + /// Associated child trie unique id is built from the hash part of the trie id. pub fn child_trie_info(&self) -> ChildInfo { ChildInfo::new_default(self.trie_id.as_ref()) @@ -233,7 +238,7 @@ impl ContractInfo { /// /// Returns an error if the maximum number of delegate_dependencies is reached or if /// the delegate dependency already exists. - pub fn add_delegate_dependency( + pub fn lock_delegate_dependency( &mut self, code_hash: CodeHash, amount: BalanceOf, @@ -249,7 +254,7 @@ impl ContractInfo { /// dependency. /// /// Returns an error if the entry doesn't exist. - pub fn remove_delegate_dependency( + pub fn unlock_delegate_dependency( &mut self, code_hash: &CodeHash, ) -> Result, DispatchError> { @@ -322,7 +327,8 @@ impl ContractInfo { KillStorageResult::SomeRemaining(_) => return weight_limit, KillStorageResult::AllRemoved(keys_removed) => { entry.remove(); - remaining_key_budget = remaining_key_budget.saturating_sub(keys_removed); + // charge at least one key even if none were removed. + remaining_key_budget = remaining_key_budget.saturating_sub(keys_removed.max(1)); }, }; } diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 5711d3ccc83a527fae49f4ea6397a5a4b5fe54a9..4c1f65e28d5f73e04db8e1ffd301e12f9fe0c8f9 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -35,16 +35,17 @@ use crate::{ tests::test_utils::{get_contract, get_contract_checked}, wasm::{Determinism, ReturnErrorCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Code, CodeHash, CodeInfoOf, CollectEvents, Config, ContractInfo, ContractInfoOf, - DebugInfo, DefaultAddressGenerator, DeletionQueueCounter, Error, HoldReason, + Array, BalanceOf, Code, CodeHash, CodeInfoOf, CollectEvents, Config, ContractInfo, + ContractInfoOf, DebugInfo, DefaultAddressGenerator, DeletionQueueCounter, Error, HoldReason, MigrationInProgress, Origin, Pallet, PristineCode, Schedule, }; use assert_matches::assert_matches; -use codec::Encode; +use codec::{Decode, Encode}; use frame_support::{ assert_err, assert_err_ignore_postinfo, assert_err_with_weight, assert_noop, assert_ok, derive_impl, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, + pallet_prelude::EnsureOrigin, parameter_types, storage::child, traits::{ @@ -217,8 +218,6 @@ impl ChainExtension for TestExtension { where E: Ext, { - use codec::Decode; - let func_id = env.func_id(); let id = env.ext_id() as u32 | func_id as u32; match func_id { @@ -334,29 +333,10 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; type AccountId = AccountId32; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_insecure_randomness_collective_flip::Config for Test {} impl pallet_balances::Config for Test { @@ -455,6 +435,33 @@ impl Contains for TestFilter { } } +parameter_types! { + pub static UploadAccount: Option<::AccountId> = None; + pub static InstantiateAccount: Option<::AccountId> = None; +} + +pub struct EnsureAccount(sp_std::marker::PhantomData<(T, A)>); +impl>>> + EnsureOrigin<::RuntimeOrigin> for EnsureAccount +where + ::AccountId: From, +{ + type Success = T::AccountId; + + fn try_origin(o: T::RuntimeOrigin) -> Result { + let who = as EnsureOrigin<_>>::try_origin(o.clone())?; + if matches!(A::get(), Some(a) if who != a) { + return Err(o) + } + + Ok(who) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Err(()) + } +} parameter_types! { pub static UnstableInterface: bool = true; } @@ -479,6 +486,8 @@ impl Config for Test { type MaxCodeLen = ConstU32<{ 123 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; type UnsafeUnstableInterface = UnstableInterface; + type UploadOrigin = EnsureAccount; + type InstantiateOrigin = EnsureAccount; type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; type RuntimeHoldReason = RuntimeHoldReason; type Migrations = crate::migration::codegen::BenchMigrations; @@ -486,6 +495,7 @@ impl Config for Test { type MaxDelegateDependencies = MaxDelegateDependencies; type Debug = TestDebug; type Environment = (); + type ApiVersion = (); type Xcm = (); } @@ -842,27 +852,6 @@ fn deposit_event_max_value_limit() { }); } -// Fail out of fuel (ref_time weight) inside the start function. -#[test] -fn run_out_of_fuel_start_fun() { - let (wasm, _code_hash) = compile_module::("run_out_of_gas_start_fn").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 0, - Weight::from_parts(1_000_000_000_000, u64::MAX), - None, - wasm, - vec![], - vec![], - ), - Error::::OutOfGas, - ); - }); -} - // Fail out of fuel (ref_time weight) in the engine. #[test] fn run_out_of_fuel_engine() { @@ -946,50 +935,15 @@ fn run_out_of_fuel_host() { #[test] fn gas_syncs_work() { - let (wasm0, _code_hash) = compile_module::("seal_input_noop").unwrap(); - let (wasm1, _code_hash) = compile_module::("seal_input_once").unwrap(); - let (wasm2, _code_hash) = compile_module::("seal_input_twice").unwrap(); + 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); - // Instantiate noop contract. - let addr0 = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm0), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - - // Instantiate 1st contract. - let addr1 = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm1), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - - // Instantiate 2nd contract. - let addr2 = Contracts::bare_instantiate( + let addr = Contracts::bare_instantiate( ALICE, 0, GAS_LIMIT, None, - Code::Upload(wasm2), + Code::Upload(code), vec![], vec![], DebugInfo::Skip, @@ -1001,11 +955,11 @@ fn gas_syncs_work() { let result = Contracts::bare_call( ALICE, - addr0, + addr.clone(), 0, GAS_LIMIT, None, - 1u8.to_le_bytes().to_vec(), + 0u32.encode(), DebugInfo::Skip, CollectEvents::Skip, Determinism::Enforced, @@ -1015,27 +969,28 @@ fn gas_syncs_work() { let result = Contracts::bare_call( ALICE, - addr1, + addr.clone(), 0, GAS_LIMIT, None, - 1u8.to_le_bytes().to_vec(), + 1u32.encode(), DebugInfo::Skip, CollectEvents::Skip, Determinism::Enforced, ); assert_ok!(result.result); let gas_consumed_once = result.gas_consumed.ref_time(); - let host_consumed_once = ::Schedule::get().host_fn_weights.input.ref_time(); + let host_consumed_once = + ::Schedule::get().host_fn_weights.caller_is_origin.ref_time(); let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; let result = Contracts::bare_call( ALICE, - addr2, + addr, 0, GAS_LIMIT, None, - 1u8.to_le_bytes().to_vec(), + 2u32.encode(), DebugInfo::Skip, CollectEvents::Skip, Determinism::Enforced, @@ -2924,12 +2879,13 @@ fn debug_message_invalid_utf8() { } #[test] -fn gas_estimation_nested_call_fixed_limit() { +fn gas_estimation_for_subcalls() { let (caller_code, _caller_hash) = compile_module::("call_with_limit").unwrap(); - let (callee_code, _callee_hash) = compile_module::("dummy").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, 1000 * min_balance); + let _ = ::Currency::set_balance(&ALICE, 2_000 * min_balance); let addr_caller = Contracts::bare_instantiate( ALICE, @@ -2938,7 +2894,7 @@ fn gas_estimation_nested_call_fixed_limit() { None, Code::Upload(caller_code), vec![], - vec![0], + vec![], DebugInfo::Skip, CollectEvents::Skip, ) @@ -2946,14 +2902,14 @@ fn gas_estimation_nested_call_fixed_limit() { .unwrap() .account_id; - let addr_callee = Contracts::bare_instantiate( + let addr_dummy = Contracts::bare_instantiate( ALICE, min_balance * 100, GAS_LIMIT, None, - Code::Upload(callee_code), + Code::Upload(dummy_code), + vec![], vec![], - vec![1], DebugInfo::Skip, CollectEvents::Skip, ) @@ -2961,68 +2917,136 @@ fn gas_estimation_nested_call_fixed_limit() { .unwrap() .account_id; - let input: Vec = AsRef::<[u8]>::as_ref(&addr_callee) - .iter() - .cloned() - .chain((GAS_LIMIT / 5).ref_time().to_le_bytes()) - .chain((GAS_LIMIT / 5).proof_size().to_le_bytes()) - .collect(); - - // Call in order to determine the gas that is required for this call - let result = Contracts::bare_call( + let addr_call_runtime = Contracts::bare_instantiate( ALICE, - addr_caller.clone(), - 0, + min_balance * 100, GAS_LIMIT, None, - input.clone(), + Code::Upload(call_runtime_code), + vec![], + vec![], DebugInfo::Skip, CollectEvents::Skip, - Determinism::Enforced, - ); - assert_ok!(&result.result); + ) + .result + .unwrap() + .account_id; - // We have a subcall with a fixed gas limit. This constitutes precharging. - assert!(result.gas_required.all_gt(result.gas_consumed)); + // 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), + ]; - // Make the same call using the estimated gas. Should succeed. - assert_ok!( - Contracts::bare_call( - ALICE, - addr_caller.clone(), - 0, - result.gas_required, - Some(result.storage_deposit.charge_or_zero()), - input.clone(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - ); + // 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(); - // Make the same call using proof_size but less than estimated. Should fail with OutOfGas. - let result = Contracts::bare_call( - ALICE, - addr_caller, - 0, - result.gas_required.sub_proof_size(1), - Some(result.storage_deposit.charge_or_zero()), - input, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result; - assert_err!(result, >::OutOfGas); + // 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), + ]; + + 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 = Contracts::bare_call( + ALICE, + addr_caller.clone(), + 0, + GAS_LIMIT, + None, + input.clone(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ); + assert_ok!(&result.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.gas_required.all_gt(result.gas_consumed)); + >::ContractTrapped.into() + } else { + assert_eq!(result.gas_required, result.gas_consumed); + >::OutOfGas.into() + }; + + // Make the same call using the estimated gas. Should succeed. + assert_ok!( + Contracts::bare_call( + ALICE, + addr_caller.clone(), + 0, + result.gas_required, + Some(result.storage_deposit.charge_or_zero()), + input.clone(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + ); + + // Check that it fails with too little ref_time + assert_err!( + Contracts::bare_call( + ALICE, + addr_caller.clone(), + 0, + result.gas_required.sub_ref_time(1), + Some(result.storage_deposit.charge_or_zero()), + input.clone(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result, + error, + ); + + // Check that it fails with too little proof_size + assert_err!( + Contracts::bare_call( + ALICE, + addr_caller.clone(), + 0, + result.gas_required.sub_proof_size(1), + Some(result.storage_deposit.charge_or_zero()), + input, + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result, + error, + ); + } + } }); } #[test] fn gas_estimation_call_runtime() { - use codec::Decode; 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); @@ -3043,25 +3067,11 @@ fn gas_estimation_call_runtime() { .unwrap() .account_id; - Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(callee_code), - vec![], - vec![1], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap(); - // 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, 0), - actual_weight: Weight::from_parts(100, 0), + pre_charge: Weight::from_parts(10_000_000, 1_000), + actual_weight: Weight::from_parts(100, 100), }); let result = Contracts::bare_call( ALICE, @@ -3077,7 +3087,7 @@ fn gas_estimation_call_runtime() { // 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.ref_time() > result.gas_consumed.ref_time()); + assert!(result.gas_required.all_gt(result.gas_consumed)); // Make the same call using the required gas. Should succeed. assert_ok!( @@ -4388,96 +4398,6 @@ fn contract_reverted() { }); } -#[test] -fn code_rejected_error_works() { - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let (wasm, _) = compile_module::("invalid_module").unwrap(); - assert_noop!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - wasm.clone(), - None, - Determinism::Enforced - ), - >::CodeRejected, - ); - let result = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - ); - assert_err!(result.result, >::CodeRejected); - assert_eq!( - std::str::from_utf8(&result.debug_message).unwrap(), - "Can't load the module into wasmi!" - ); - - let (wasm, _) = compile_module::("invalid_contract_no_call").unwrap(); - assert_noop!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - wasm.clone(), - None, - Determinism::Enforced - ), - >::CodeRejected, - ); - - let result = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - ); - assert_err!(result.result, >::CodeRejected); - assert_eq!( - std::str::from_utf8(&result.debug_message).unwrap(), - "call function isn't exported" - ); - - let (wasm, _) = compile_module::("invalid_contract_no_memory").unwrap(); - assert_noop!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - wasm.clone(), - None, - Determinism::Enforced - ), - >::CodeRejected, - ); - - let result = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - ); - assert_err!(result.result, >::CodeRejected); - assert_eq!( - std::str::from_utf8(&result.debug_message).unwrap(), - "No memory import found in the module" - ); - }); -} - #[test] fn set_code_hash() { let (wasm, code_hash) = compile_module::("set_code_hash").unwrap(); @@ -5120,6 +5040,26 @@ fn deposit_limit_honors_min_leftover() { }); } +#[test] +fn upload_should_enforce_deterministic_mode_when_possible() { + let upload = |fixture, determinism| { + let (wasm, code_hash) = compile_module::(fixture).unwrap(); + ExtBuilder::default() + .build() + .execute_with(|| -> Result { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + Contracts::bare_upload_code(ALICE, wasm, None, determinism)?; + let info = CodeInfoOf::::get(code_hash).unwrap(); + Ok(info.determinism()) + }) + }; + + assert_eq!(upload("dummy", Determinism::Enforced), Ok(Determinism::Enforced)); + assert_eq!(upload("dummy", Determinism::Relaxed), Ok(Determinism::Enforced)); + assert_eq!(upload("float_instruction", Determinism::Relaxed), Ok(Determinism::Relaxed)); + assert!(upload("float_instruction", Determinism::Enforced).is_err()); +} + #[test] fn cannot_instantiate_indeterministic_code() { let (wasm, code_hash) = compile_module::("float_instruction").unwrap(); @@ -5372,21 +5312,21 @@ fn delegate_call_indeterministic_code() { } #[test] -fn add_remove_delegate_dependency_works() { +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)); MAX_DELEGATE_DEPENDENCIES.with(|c| *c.borrow_mut() = 1); let (wasm_caller, self_code_hash) = - compile_module::("add_remove_delegate_dependency").unwrap(); + compile_module::("locking_delegate_dependency").unwrap(); let (wasm_callee, code_hash) = compile_module::("dummy").unwrap(); let (wasm_other, other_code_hash) = compile_module::("call").unwrap(); - // Define inputs with various actions to test adding / removing delegate_dependencies. + // Define inputs with various actions to test locking / unlocking delegate_dependencies. // See the contract for more details. let noop_input = (0u32, code_hash); - let add_delegate_dependency_input = (1u32, code_hash); - let remove_delegate_dependency_input = (2u32, code_hash); + let lock_delegate_dependency_input = (1u32, code_hash); + let unlock_delegate_dependency_input = (2u32, code_hash); let terminate_input = (3u32, code_hash); // Instantiate the caller contract with the given input. @@ -5423,9 +5363,9 @@ fn add_remove_delegate_dependency_works() { ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { let _ = Balances::set_balance(&ALICE, 1_000_000); - // Instantiate with add_delegate_dependency should fail since the code is not yet on chain. + // Instantiate with lock_delegate_dependency should fail since the code is not yet on chain. assert_err!( - instantiate(&add_delegate_dependency_input).result, + instantiate(&lock_delegate_dependency_input).result, Error::::CodeNotFound ); @@ -5435,7 +5375,7 @@ fn add_remove_delegate_dependency_works() { .unwrap(); // Instantiate should now work. - let addr_caller = instantiate(&add_delegate_dependency_input).result.unwrap().account_id; + let addr_caller = instantiate(&lock_delegate_dependency_input).result.unwrap().account_id; // There should be a dependency and a deposit. let contract = test_utils::get_contract(&addr_caller); @@ -5456,27 +5396,27 @@ fn add_remove_delegate_dependency_works() { >::CodeInUse ); - // Adding an already existing dependency should fail. + // Locking an already existing dependency should fail. assert_err!( - call(&addr_caller, &add_delegate_dependency_input).result, + call(&addr_caller, &lock_delegate_dependency_input).result, Error::::DelegateDependencyAlreadyExists ); - // Adding a dependency to self should fail. + // Locking self should fail. assert_err!( call(&addr_caller, &(1u32, self_code_hash)).result, Error::::CannotAddSelfAsDelegateDependency ); - // Adding more than the maximum allowed delegate_dependencies should fail. + // Locking more than the maximum allowed delegate_dependencies should fail. Contracts::bare_upload_code(ALICE, wasm_other, None, Determinism::Enforced).unwrap(); assert_err!( call(&addr_caller, &(1u32, other_code_hash)).result, Error::::MaxDelegateDependenciesReached ); - // Removing dependency should work. - assert_ok!(call(&addr_caller, &remove_delegate_dependency_input).result); + // Unlocking dependency should work. + assert_ok!(call(&addr_caller, &unlock_delegate_dependency_input).result); // Dependency should be removed, and deposit should be returned. let contract = test_utils::get_contract(&addr_caller); @@ -5491,18 +5431,18 @@ fn add_remove_delegate_dependency_works() { // Removing an unexisting dependency should fail. assert_err!( - call(&addr_caller, &remove_delegate_dependency_input).result, + call(&addr_caller, &unlock_delegate_dependency_input).result, Error::::DelegateDependencyNotFound ); - // Adding a dependency with a storage limit too low should fail. + // Locking a dependency with a storage limit too low should fail. DEFAULT_DEPOSIT_LIMIT.with(|c| *c.borrow_mut() = dependency_deposit - 1); assert_err!( - call(&addr_caller, &add_delegate_dependency_input).result, + call(&addr_caller, &lock_delegate_dependency_input).result, Error::::StorageDepositLimitExhausted ); - // Since we removed the dependency we should now be able to remove the code. + // Since we unlocked the dependency we should now be able to remove the code. assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); // Calling should fail since the delegated contract is not on chain anymore. @@ -5511,7 +5451,7 @@ fn add_remove_delegate_dependency_works() { // Restore initial deposit limit and add the dependency back. DEFAULT_DEPOSIT_LIMIT.with(|c| *c.borrow_mut() = 10_000_000); Contracts::bare_upload_code(ALICE, wasm_callee, None, Determinism::Enforced).unwrap(); - call(&addr_caller, &add_delegate_dependency_input).result.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); @@ -5889,7 +5829,106 @@ fn root_cannot_instantiate() { vec![], vec![], ), - DispatchError::RootNotAllowed + 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(), + None, + Determinism::Enforced, + ), + DispatchError::BadOrigin + ); + + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(BOB), + wasm.clone(), + None, + Determinism::Enforced, + ), + DispatchError::BadOrigin + ); + + // Only alice is allowed to upload contract code. + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + None, + Determinism::Enforced, + )); + }); +} + +#[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!( + Contracts::instantiate_with_code( + RuntimeOrigin::root(), + 0, + GAS_LIMIT, + None, + code.clone(), + vec![], + vec![], + ), + DispatchError::BadOrigin + ); + + assert_err_ignore_postinfo!( + Contracts::instantiate_with_code( + RuntimeOrigin::signed(BOB), + 0, + GAS_LIMIT, + None, + code.clone(), + vec![], + vec![], + ), + DispatchError::BadOrigin + ); + + // Only Alice can instantiate + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + code, + vec![], + vec![], + ),); + + // Bob cannot instantiate with either `instantiate_with_code` or `instantiate`. + assert_err_ignore_postinfo!( + Contracts::instantiate( + RuntimeOrigin::signed(BOB), + 0, + GAS_LIMIT, + None, + code_hash, + vec![], + vec![], + ), + DispatchError::BadOrigin ); }); } @@ -5943,3 +5982,53 @@ fn balance_api_returns_free_balance() { ); }); } + +#[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 addr = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(code), + vec![], + vec![], + DebugInfo::Skip, + CollectEvents::Skip, + ) + .result + .unwrap() + .account_id; + + let max_call_depth = ::CallStack::size() as u32; + let [gas_0, gas_1, gas_2, gas_max] = { + [0u32, 1u32, 2u32, max_call_depth] + .iter() + .map(|i| { + let result = Contracts::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + i.encode(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ); + assert_ok!(result.result); + result.gas_consumed + }) + .collect::>() + .try_into() + .unwrap() + }; + + let gas_per_recursion = gas_2.checked_sub(&gas_1).unwrap(); + assert_eq!(gas_max, gas_0 + gas_per_recursion * max_call_depth as u64); + }); +} diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index d00ec2e47521b12c8082b5a0fd2001fbf5562948..af287a6f2dff946fa5d3e688ff8a71d9db4c22a3 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -21,6 +21,9 @@ mod prepare; mod runtime; +#[cfg(test)] +pub use runtime::STABLE_API_COUNT; + #[cfg(doc)] pub use crate::wasm::runtime::api_doc; @@ -313,6 +316,11 @@ impl CodeInfo { } } + /// Returns the determinism of the module. + pub fn determinism(&self) -> Determinism { + self.determinism + } + /// Returns reference count of the module. pub fn refcount(&self) -> u64 { self.refcount @@ -386,7 +394,7 @@ impl Executable for WasmBlob { let engine_consumed_total = store.fuel_consumed().expect("Fuel metering is enabled; qed"); let gas_meter = store.data_mut().ext().gas_meter_mut(); - gas_meter.charge_fuel(engine_consumed_total)?; + let _ = gas_meter.sync_from_executor(engine_consumed_total)?; store.into_data().to_execution_result(result) }; @@ -687,6 +695,10 @@ mod tests { &mut self.gas_meter } fn charge_storage(&mut self, _diff: &crate::storage::meter::Diff) {} + + fn debug_buffer_enabled(&self) -> bool { + true + } fn append_debug_buffer(&mut self, msg: &str) -> bool { self.debug_buffer.extend(msg.as_bytes()); true @@ -729,14 +741,14 @@ mod tests { Ok(()) } fn decrement_refcount(_code_hash: CodeHash) {} - fn add_delegate_dependency( + fn lock_delegate_dependency( &mut self, code: CodeHash, ) -> Result<(), DispatchError> { self.delegate_dependencies.borrow_mut().insert(code); Ok(()) } - fn remove_delegate_dependency( + fn unlock_delegate_dependency( &mut self, code: &CodeHash, ) -> Result<(), DispatchError> { @@ -1817,17 +1829,6 @@ mod tests { assert!(weight_left.all_gt(actual_left), "gas_left must be greater than final"); } - /// Test that [`frame_support::weights::OldWeight`] en/decodes the same as our - /// [`crate::OldWeight`]. - #[test] - fn old_weight_decode() { - #![allow(deprecated)] - let sp = frame_support::weights::OldWeight(42).encode(); - let our = crate::OldWeight::decode(&mut &*sp).unwrap(); - - assert_eq!(our, 42); - } - const CODE_VALUE_TRANSFERRED: &str = r#" (module (import "seal0" "seal_value_transferred" (func $seal_value_transferred (param i32 i32))) @@ -3395,16 +3396,16 @@ mod tests { } #[test] - fn add_remove_delegate_dependency() { - const CODE_ADD_REMOVE_DELEGATE_DEPENDENCY: &str = r#" + fn lock_unlock_delegate_dependency() { + const CODE_LOCK_UNLOCK_DELEGATE_DEPENDENCY: &str = r#" (module - (import "seal0" "add_delegate_dependency" (func $add_delegate_dependency (param i32))) - (import "seal0" "remove_delegate_dependency" (func $remove_delegate_dependency (param i32))) + (import "seal0" "lock_delegate_dependency" (func $lock_delegate_dependency (param i32))) + (import "seal0" "unlock_delegate_dependency" (func $unlock_delegate_dependency (param i32))) (import "env" "memory" (memory 1 1)) (func (export "call") - (call $add_delegate_dependency (i32.const 0)) - (call $add_delegate_dependency (i32.const 32)) - (call $remove_delegate_dependency (i32.const 32)) + (call $lock_delegate_dependency (i32.const 0)) + (call $lock_delegate_dependency (i32.const 32)) + (call $unlock_delegate_dependency (i32.const 32)) ) (func (export "deploy")) @@ -3422,7 +3423,7 @@ mod tests { ) "#; let mut mock_ext = MockExt::default(); - assert_ok!(execute(&CODE_ADD_REMOVE_DELEGATE_DEPENDENCY, vec![], &mut mock_ext)); + assert_ok!(execute(&CODE_LOCK_UNLOCK_DELEGATE_DEPENDENCY, vec![], &mut mock_ext)); let delegate_dependencies: Vec<_> = mock_ext.delegate_dependencies.into_inner().into_iter().collect(); assert_eq!(delegate_dependencies.len(), 1); @@ -3444,4 +3445,22 @@ mod tests { runtime.read_sandbox_memory_as(&memory, 0u32).unwrap(); assert_eq!(decoded.into_inner(), data); } + + #[test] + fn run_out_of_gas_in_start_fn() { + const CODE: &str = r#" +(module + (import "env" "memory" (memory 1 1)) + (start $start) + (func $start + (loop $inf (br $inf)) ;; just run out of gas + (unreachable) + ) + (func (export "call")) + (func (export "deploy")) +) +"#; + let mut mock_ext = MockExt::default(); + assert_err!(execute(&CODE, vec![], &mut mock_ext), >::OutOfGas); + } } diff --git a/substrate/frame/contracts/src/wasm/prepare.rs b/substrate/frame/contracts/src/wasm/prepare.rs index dfe8c4f8f9b91fe5e7d73032282fe50effd51d38..5efea8c3a23b319ff86fa38089ef04e1dcdc6681 100644 --- a/substrate/frame/contracts/src/wasm/prepare.rs +++ b/substrate/frame/contracts/src/wasm/prepare.rs @@ -79,7 +79,10 @@ impl LoadedModule { } let engine = Engine::new(&config); - let module = Module::new(&engine, code).map_err(|_| "Can't load the module into wasmi!")?; + let module = Module::new(&engine, code).map_err(|err| { + log::debug!(target: LOG_TARGET, "Module creation failed: {:?}", err); + "Can't load the module into wasmi!" + })?; // Return a `LoadedModule` instance with // __valid__ module. @@ -220,7 +223,7 @@ impl LoadedModule { fn validate( code: &[u8], schedule: &Schedule, - determinism: Determinism, + determinism: &mut Determinism, ) -> Result<(), (DispatchError, &'static str)> where E: Environment<()>, @@ -229,7 +232,17 @@ where (|| { // We check that the module is generally valid, // and does not have restricted WebAssembly features, here. - let contract_module = LoadedModule::new::(code, determinism, None)?; + let contract_module = match *determinism { + Determinism::Relaxed => + if let Ok(module) = LoadedModule::new::(code, Determinism::Enforced, None) { + *determinism = Determinism::Enforced; + module + } else { + LoadedModule::new::(code, Determinism::Relaxed, None)? + }, + Determinism::Enforced => LoadedModule::new::(code, Determinism::Enforced, None)?, + }; + // The we check that module satisfies constraints the pallet puts on contracts. contract_module.scan_exports()?; contract_module.scan_imports::(schedule)?; @@ -252,7 +265,7 @@ where &code, (), schedule, - determinism, + *determinism, stack_limits, AllowDeprecatedInterface::No, ) @@ -276,13 +289,13 @@ pub fn prepare( code: CodeVec, schedule: &Schedule, owner: AccountIdOf, - determinism: Determinism, + mut determinism: Determinism, ) -> Result, (DispatchError, &'static str)> where E: Environment<()>, T: Config, { - validate::(code.as_ref(), schedule, determinism)?; + validate::(code.as_ref(), schedule, &mut determinism)?; // Calculate deposit for storing contract code and `code_info` in two different storage items. let code_len = code.len() as u32; @@ -384,12 +397,7 @@ mod tests { let wasm = wat::parse_str($wat).unwrap().try_into().unwrap(); let schedule = Schedule { limits: Limits { - globals: 3, - locals: 3, - parameters: 3, memory_pages: 16, - table_size: 3, - br_table_size: 3, .. Default::default() }, .. Default::default() diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 3af0d04a3ad1378aa6826382b8babc9d5bf90a5a..7d43d30ba580dee2f69bdbe3b51638e9d98e61cb 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -21,7 +21,6 @@ use crate::{ exec::{ExecError, ExecResult, Ext, Key, TopicOf}, gas::{ChargedAmount, Token}, primitives::ExecReturnValue, - schedule::HostFnWeights, BalanceOf, CodeHash, Config, DebugBufferVec, Error, SENTINEL, }; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; @@ -235,6 +234,8 @@ pub enum RuntimeCosts { ChainExtension(Weight), /// Weight charged for calling into the runtime. CallRuntime(Weight), + /// Weight charged for calling xcm_execute. + CallXcmExecute(Weight), /// Weight of calling `seal_set_code_hash` SetCodeHash, /// Weight of calling `ecdsa_to_eth_address` @@ -245,16 +246,24 @@ pub enum RuntimeCosts { AccountEntranceCount, /// Weight of calling `instantiation_nonce` InstantationNonce, - /// Weight of calling `add_delegate_dependency` - AddDelegateDependency, - /// Weight of calling `remove_delegate_dependency` - RemoveDelegateDependency, + /// Weight of calling `lock_delegate_dependency` + LockDelegateDependency, + /// Weight of calling `unlock_delegate_dependency` + UnlockDelegateDependency, } -impl RuntimeCosts { - fn token(&self, s: &HostFnWeights) -> RuntimeToken { +impl Token for RuntimeCosts { + fn influence_lowest_gas_limit(&self) -> bool { + match self { + &Self::CallXcmExecute(_) => false, + _ => true, + } + } + + fn weight(&self) -> Weight { + let s = T::Schedule::get().host_fn_weights; use self::RuntimeCosts::*; - let weight = match *self { + match *self { CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()), CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, @@ -323,20 +332,14 @@ impl RuntimeCosts { Sr25519Verify(len) => s .sr25519_verify .saturating_add(s.sr25519_verify_per_byte.saturating_mul(len.into())), - ChainExtension(weight) => weight, - CallRuntime(weight) => weight, + ChainExtension(weight) | CallRuntime(weight) | CallXcmExecute(weight) => weight, SetCodeHash => s.set_code_hash, EcdsaToEthAddress => s.ecdsa_to_eth_address, ReentrantCount => s.reentrance_count, AccountEntranceCount => s.account_reentrance_count, InstantationNonce => s.instantiation_nonce, - AddDelegateDependency => s.add_delegate_dependency, - RemoveDelegateDependency => s.remove_delegate_dependency, - }; - RuntimeToken { - #[cfg(test)] - _created_from: *self, - weight, + LockDelegateDependency => s.lock_delegate_dependency, + UnlockDelegateDependency => s.unlock_delegate_dependency, } } } @@ -347,25 +350,10 @@ impl RuntimeCosts { /// a function won't work out. macro_rules! charge_gas { ($runtime:expr, $costs:expr) => {{ - let token = $costs.token(&$runtime.ext.schedule().host_fn_weights); - $runtime.ext.gas_meter_mut().charge(token) + $runtime.ext.gas_meter_mut().charge($costs) }}; } -#[cfg_attr(test, derive(Debug, PartialEq, Eq))] -#[derive(Copy, Clone)] -struct RuntimeToken { - #[cfg(test)] - _created_from: RuntimeCosts, - weight: Weight, -} - -impl Token for RuntimeToken { - fn weight(&self) -> Weight { - self.weight - } -} - /// The kind of call that should be performed. enum CallType { /// Execute another instantiated contract @@ -506,28 +494,25 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { /// This is when a maximum a priori amount was charged and then should be partially /// refunded to match the actual amount. pub fn adjust_gas(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) { - let token = actual_costs.token(&self.ext.schedule().host_fn_weights); - self.ext.gas_meter_mut().adjust_gas(charged, token); + self.ext.gas_meter_mut().adjust_gas(charged, actual_costs); } /// Charge, Run and adjust gas, for executing the given dispatchable. - fn call_dispatchable< - ErrorReturnCode: Get, - F: FnOnce(&mut Self) -> DispatchResultWithPostInfo, - >( + fn call_dispatchable>( &mut self, dispatch_info: DispatchInfo, - run: F, + runtime_cost: impl Fn(Weight) -> RuntimeCosts, + run: impl FnOnce(&mut Self) -> DispatchResultWithPostInfo, ) -> Result { use frame_support::dispatch::extract_actual_weight; - let charged = self.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; + let charged = self.charge_gas(runtime_cost(dispatch_info.weight))?; let result = run(self); let actual_weight = extract_actual_weight(&result, &dispatch_info); - self.adjust_gas(charged, RuntimeCosts::CallRuntime(actual_weight)); + self.adjust_gas(charged, runtime_cost(actual_weight)); match result { Ok(_) => Ok(ReturnErrorCode::Success), Err(e) => { - if self.ext.append_debug_buffer("") { + if self.ext.debug_buffer_enabled() { self.ext.append_debug_buffer("call failed with: "); self.ext.append_debug_buffer(e.into()); }; @@ -1002,7 +987,6 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { // for every function. #[define_env(doc)] pub mod env { - /// Set the value at the given key in the contract storage. /// See [`pallet_contracts_uapi::HostFn::set_storage`] #[prefixed_alias] @@ -1231,7 +1215,6 @@ pub mod env { /// Make a call to another contract. /// See [`pallet_contracts_uapi::HostFn::call_v2`]. #[version(2)] - #[unstable] fn call( ctx: _, memory: _, @@ -1368,7 +1351,6 @@ pub mod env { /// Instantiate a contract with the specified code hash. /// See [`pallet_contracts_uapi::HostFn::instantiate_v2`]. #[version(2)] - #[unstable] fn instantiate( ctx: _, memory: _, @@ -2113,9 +2095,11 @@ pub mod env { ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; let call: ::RuntimeCall = ctx.read_sandbox_memory_as_unbounded(memory, call_ptr, call_len)?; - ctx.call_dispatchable::(call.get_dispatch_info(), |ctx| { - ctx.ext.call_runtime(call) - }) + ctx.call_dispatchable::( + call.get_dispatch_info(), + RuntimeCosts::CallRuntime, + |ctx| ctx.ext.call_runtime(call), + ) } /// Execute an XCM program locally, using the contract's address as the origin. @@ -2126,7 +2110,6 @@ pub mod env { memory: _, msg_ptr: u32, msg_len: u32, - output_ptr: u32, ) -> Result { use frame_support::dispatch::DispatchInfo; use xcm::VersionedXcm; @@ -2135,26 +2118,27 @@ pub mod env { ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; let message: VersionedXcm> = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; + ensure_executable::(&message)?; 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() }; - ensure_executable::(&message)?; - ctx.call_dispatchable::(dispatch_info, |ctx| { - let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); - let outcome = <::Xcm>::execute( - origin, - Box::new(message), - weight.saturating_sub(execute_weight), - )?; + ctx.call_dispatchable::( + dispatch_info, + RuntimeCosts::CallXcmExecute, + |ctx| { + let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); + let weight_used = <::Xcm>::execute( + origin, + Box::new(message), + weight.saturating_sub(execute_weight), + )?; - ctx.write_sandbox_memory(memory, output_ptr, &outcome.encode())?; - let pre_dispatch_weight = - <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); - Ok(Some(outcome.weight_used().saturating_add(pre_dispatch_weight)).into()) - }) + Ok(Some(weight_used.saturating_add(execute_weight)).into()) + }, + ) } /// Send an XCM program from the contract to the specified destination. @@ -2319,22 +2303,20 @@ pub mod env { } /// Adds a new delegate dependency to the contract. - /// See [`pallet_contracts_uapi::HostFn::add_delegate_dependency`]. - #[unstable] - fn add_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { - ctx.charge_gas(RuntimeCosts::AddDelegateDependency)?; + /// See [`pallet_contracts_uapi::HostFn::lock_delegate_dependency`]. + fn lock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { + ctx.charge_gas(RuntimeCosts::LockDelegateDependency)?; let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?; - ctx.ext.add_delegate_dependency(code_hash)?; + ctx.ext.lock_delegate_dependency(code_hash)?; Ok(()) } /// Removes the delegate dependency from the contract. - /// see [`pallet_contracts_uapi::HostFn::remove_delegate_dependency`]. - #[unstable] - fn remove_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { - ctx.charge_gas(RuntimeCosts::RemoveDelegateDependency)?; + /// see [`pallet_contracts_uapi::HostFn::unlock_delegate_dependency`]. + fn unlock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { + ctx.charge_gas(RuntimeCosts::UnlockDelegateDependency)?; let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?; - ctx.ext.remove_delegate_dependency(&code_hash)?; + ctx.ext.unlock_delegate_dependency(&code_hash)?; Ok(()) } } diff --git a/substrate/frame/contracts/src/weights.rs b/substrate/frame/contracts/src/weights.rs index fa9df922a7cbb9711c7b1315cf680a30fc4c5ebb..6e09120c1413a28e456e9114dcc0cf3d6be1c781 100644 --- a/substrate/frame/contracts/src/weights.rs +++ b/substrate/frame/contracts/src/weights.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_contracts` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-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-03-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-j8vvqcjr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-p5qp1txx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -67,7 +67,8 @@ pub trait WeightInfo { fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight; fn instantiate(i: u32, s: u32, ) -> Weight; fn call() -> Weight; - fn upload_code(c: u32, ) -> Weight; + fn upload_code_determinism_enforced(c: u32, ) -> Weight; + fn upload_code_determinism_relaxed(c: u32, ) -> Weight; fn remove_code() -> Weight; fn set_code() -> Weight; fn seal_caller(r: u32, ) -> Weight; @@ -124,8 +125,8 @@ pub trait WeightInfo { fn seal_ecdsa_recover(r: u32, ) -> Weight; fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight; fn seal_set_code_hash(r: u32, ) -> Weight; - fn add_delegate_dependency(r: u32, ) -> Weight; - fn remove_delegate_dependency(r: u32, ) -> Weight; + fn lock_delegate_dependency(r: u32, ) -> Weight; + fn unlock_delegate_dependency(r: u32, ) -> Weight; fn seal_reentrance_count(r: u32, ) -> Weight; fn seal_account_reentrance_count(r: u32, ) -> Weight; fn seal_instantiation_nonce(r: u32, ) -> Weight; @@ -141,8 +142,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 1_997_000 picoseconds. - Weight::from_parts(2_130_000, 1627) + // Minimum execution time: 2_054_000 picoseconds. + Weight::from_parts(2_178_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -152,10 +153,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 12_276_000 picoseconds. - Weight::from_parts(1_593_881, 442) - // Standard Error: 1_135 - .saturating_add(Weight::from_parts(1_109_302, 0).saturating_mul(k.into())) + // Minimum execution time: 12_119_000 picoseconds. + Weight::from_parts(12_536_000, 442) + // Standard Error: 1_254 + .saturating_add(Weight::from_parts(1_161_885, 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 +170,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_176_000 picoseconds. - Weight::from_parts(8_555_388, 6149) + // Minimum execution time: 8_146_000 picoseconds. + Weight::from_parts(8_560_745, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_184, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_182, 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 +186,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_270_000 picoseconds. - Weight::from_parts(16_779_000, 6450) + // Minimum execution time: 16_183_000 picoseconds. + Weight::from_parts(16_825_000, 6450) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -199,10 +200,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_572_000 picoseconds. - Weight::from_parts(1_950_905, 3635) - // Standard Error: 1_597 - .saturating_add(Weight::from_parts(1_123_190, 0).saturating_mul(k.into())) + // Minimum execution time: 3_645_000 picoseconds. + Weight::from_parts(604_365, 3635) + // Standard Error: 1_013 + .saturating_add(Weight::from_parts(1_100_277, 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()))) @@ -212,6 +213,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553053f13fd319a03c211337c76e0fe776df` (r:2 w:0) /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:0 w:1) @@ -219,13 +222,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 125952]`. fn v12_migration_step(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `325 + c * (1 ±0)` - // Estimated: `6263 + c * (1 ±0)` - // Minimum execution time: 16_873_000 picoseconds. - Weight::from_parts(16_790_402, 6263) + // Measured: `328 + c * (1 ±0)` + // Estimated: `6266 + c * (1 ±0)` + // Minimum execution time: 19_500_000 picoseconds. + Weight::from_parts(20_074_895, 6266) // Standard Error: 1 - .saturating_add(Weight::from_parts(396, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_parts(422, 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())) } @@ -235,8 +238,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 11_904_000 picoseconds. - Weight::from_parts(12_785_000, 6380) + // Minimum execution time: 12_530_000 picoseconds. + Weight::from_parts(13_362_000, 6380) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -245,13 +248,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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 44_920_000 picoseconds. - Weight::from_parts(46_163_000, 6292) + // Minimum execution time: 44_275_000 picoseconds. + Weight::from_parts(45_718_000, 6292) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -263,8 +266,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 53_864_000 picoseconds. - Weight::from_parts(55_139_000, 6534) + // Minimum execution time: 55_095_000 picoseconds. + Weight::from_parts(58_009_000, 6534) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -274,8 +277,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_375_000 picoseconds. - Weight::from_parts(2_487_000, 1627) + // Minimum execution time: 2_455_000 picoseconds. + Weight::from_parts(2_608_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -287,8 +290,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 11_580_000 picoseconds. - Weight::from_parts(11_980_000, 3631) + // Minimum execution time: 11_207_000 picoseconds. + Weight::from_parts(11_802_000, 3631) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -298,8 +301,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_557_000 picoseconds. - Weight::from_parts(4_807_000, 3607) + // Minimum execution time: 4_581_000 picoseconds. + Weight::from_parts(4_781_000, 3607) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -310,8 +313,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 6_253_000 picoseconds. - Weight::from_parts(6_479_000, 3632) + // Minimum execution time: 5_887_000 picoseconds. + Weight::from_parts(6_393_000, 3632) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -322,13 +325,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_166_000 picoseconds. - Weight::from_parts(6_545_000, 3607) + // Minimum execution time: 6_025_000 picoseconds. + Weight::from_parts(6_298_000, 3607) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -344,22 +349,24 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `801 + c * (1 ±0)` - // Estimated: `6739 + c * (1 ±0)` - // Minimum execution time: 282_232_000 picoseconds. - Weight::from_parts(266_148_573, 6739) - // Standard Error: 69 - .saturating_add(Weight::from_parts(34_592, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `804 + c * (1 ±0)` + // Estimated: `9217 + c * (1 ±0)` + // Minimum execution time: 294_976_000 picoseconds. + Weight::from_parts(277_235_948, 9217) + // Standard Error: 65 + .saturating_add(Weight::from_parts(34_445, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// 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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:3 w:3) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) @@ -377,17 +384,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `323` - // Estimated: `8737` - // Minimum execution time: 3_760_879_000 picoseconds. - Weight::from_parts(794_812_431, 8737) - // Standard Error: 149 - .saturating_add(Weight::from_parts(101_881, 0).saturating_mul(c.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_404, 0).saturating_mul(i.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_544, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) + // Measured: `326` + // Estimated: `8740` + // Minimum execution time: 3_864_558_000 picoseconds. + Weight::from_parts(421_676_889, 8740) + // Standard Error: 188 + .saturating_add(Weight::from_parts(103_788, 0).saturating_mul(c.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_715, 0).saturating_mul(i.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_774, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) @@ -396,6 +403,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, 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) @@ -407,24 +416,26 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `6504` - // Minimum execution time: 1_953_162_000 picoseconds. - Weight::from_parts(374_252_840, 6504) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_630, 0).saturating_mul(i.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_650, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(10_u64)) + // Measured: `563` + // Estimated: `8982` + // Minimum execution time: 2_069_276_000 picoseconds. + Weight::from_parts(377_210_279, 8982) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_719, 0).saturating_mul(i.into())) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_728, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -439,41 +450,67 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `826` - // Estimated: `6766` - // Minimum execution time: 187_899_000 picoseconds. - Weight::from_parts(195_510_000, 6766) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `829` + // Estimated: `9244` + // Minimum execution time: 199_037_000 picoseconds. + Weight::from_parts(213_931_000, 9244) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// 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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, 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]`. - fn upload_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3607` - // Minimum execution time: 254_800_000 picoseconds. - Weight::from_parts(285_603_050, 3607) - // Standard Error: 62 - .saturating_add(Weight::from_parts(66_212, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + fn upload_code_determinism_enforced(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `6085` + // Minimum execution time: 278_482_000 picoseconds. + Weight::from_parts(262_753_879, 6085) + // Standard Error: 112 + .saturating_add(Weight::from_parts(66_129, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// 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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Storage: `System::EventTopics` (r:1 w:1) + /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, 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]`. + fn upload_code_determinism_relaxed(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `6085` + // Minimum execution time: 286_902_000 picoseconds. + Weight::from_parts(269_003_959, 6085) + // Standard Error: 123 + .saturating_add(Weight::from_parts(66_629, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) + /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// 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`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -482,8 +519,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 43_553_000 picoseconds. - Weight::from_parts(45_036_000, 3780) + // Minimum execution time: 44_128_000 picoseconds. + Weight::from_parts(46_044_000, 3780) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -499,8 +536,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 33_223_000 picoseconds. - Weight::from_parts(34_385_000, 8967) + // Minimum execution time: 33_567_000 picoseconds. + Weight::from_parts(35_057_000, 8967) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -508,6 +545,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -521,13 +560,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `866 + r * (6 ±0)` - // Estimated: `6806 + r * (6 ±0)` - // Minimum execution time: 254_213_000 picoseconds. - Weight::from_parts(273_464_980, 6806) - // Standard Error: 1_362 - .saturating_add(Weight::from_parts(322_619, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `869 + r * (6 ±0)` + // Estimated: `9284 + r * (6 ±0)` + // Minimum execution time: 272_376_000 picoseconds. + Weight::from_parts(284_162_161, 9284) + // Standard Error: 501 + .saturating_add(Weight::from_parts(341_575, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -535,6 +574,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -548,13 +589,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `922 + r * (209 ±0)` - // Estimated: `6826 + r * (2684 ±0)` - // Minimum execution time: 250_273_000 picoseconds. - Weight::from_parts(122_072_782, 6826) - // Standard Error: 5_629 - .saturating_add(Weight::from_parts(3_490_256, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `925 + r * (209 ±0)` + // Estimated: `9304 + r * (2684 ±0)` + // Minimum execution time: 256_990_000 picoseconds. + Weight::from_parts(107_167_044, 9304) + // Standard Error: 7_545 + .saturating_add(Weight::from_parts(3_628_112, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2684).saturating_mul(r.into())) @@ -563,6 +604,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -576,13 +619,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (213 ±0)` - // Estimated: `6830 + r * (2688 ±0)` - // Minimum execution time: 255_187_000 picoseconds. - Weight::from_parts(118_082_505, 6830) - // Standard Error: 6_302 - .saturating_add(Weight::from_parts(4_246_968, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `924 + r * (213 ±0)` + // Estimated: `9308 + r * (2688 ±0)` + // Minimum execution time: 272_889_000 picoseconds. + Weight::from_parts(110_341_799, 9308) + // Standard Error: 7_881 + .saturating_add(Weight::from_parts(4_427_043, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2688).saturating_mul(r.into())) @@ -591,6 +634,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -604,13 +649,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (6 ±0)` - // Estimated: `6815 + r * (6 ±0)` - // Minimum execution time: 256_833_000 picoseconds. - Weight::from_parts(273_330_216, 6815) - // Standard Error: 881 - .saturating_add(Weight::from_parts(400_105, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `876 + r * (6 ±0)` + // Estimated: `9293 + r * (6 ±0)` + // Minimum execution time: 275_027_000 picoseconds. + Weight::from_parts(283_302_223, 9293) + // Standard Error: 1_179 + .saturating_add(Weight::from_parts(436_023, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -618,6 +663,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -631,18 +678,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (3 ±0)` - // Estimated: `6804 + r * (3 ±0)` - // Minimum execution time: 244_193_000 picoseconds. - Weight::from_parts(271_221_908, 6804) - // Standard Error: 442 - .saturating_add(Weight::from_parts(176_480, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `866 + r * (3 ±0)` + // Estimated: `9282 + r * (3 ±0)` + // Minimum execution time: 270_137_000 picoseconds. + Weight::from_parts(282_756_362, 9282) + // Standard Error: 384 + .saturating_add(Weight::from_parts(171_660, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -656,13 +705,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_root(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `753 + r * (3 ±0)` - // Estimated: `6693 + r * (3 ±0)` - // Minimum execution time: 232_603_000 picoseconds. - Weight::from_parts(260_577_368, 6693) - // Standard Error: 365 - .saturating_add(Weight::from_parts(158_126, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(7_u64)) + // Measured: `756 + r * (3 ±0)` + // Estimated: `9171 + r * (3 ±0)` + // Minimum execution time: 255_131_000 picoseconds. + Weight::from_parts(269_207_006, 9171) + // Standard Error: 542 + .saturating_add(Weight::from_parts(161_597, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } @@ -670,6 +719,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -683,13 +734,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `867 + r * (6 ±0)` - // Estimated: `6807 + r * (6 ±0)` - // Minimum execution time: 247_564_000 picoseconds. - Weight::from_parts(275_108_914, 6807) - // Standard Error: 505 - .saturating_add(Weight::from_parts(315_065, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `870 + r * (6 ±0)` + // Estimated: `9285 + r * (6 ±0)` + // Minimum execution time: 272_172_000 picoseconds. + Weight::from_parts(283_747_134, 9285) + // Standard Error: 885 + .saturating_add(Weight::from_parts(343_968, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -697,6 +748,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -710,13 +763,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (6 ±0)` - // Estimated: `6806 + r * (6 ±0)` - // Minimum execution time: 258_799_000 picoseconds. - Weight::from_parts(274_338_256, 6806) - // Standard Error: 632 - .saturating_add(Weight::from_parts(355_032, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `866 + r * (6 ±0)` + // Estimated: `9284 + r * (6 ±0)` + // Minimum execution time: 263_220_000 picoseconds. + Weight::from_parts(277_062_382, 9284) + // Standard Error: 1_783 + .saturating_add(Weight::from_parts(399_631, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -724,6 +777,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:2 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -737,13 +792,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1007 + r * (6 ±0)` - // Estimated: `6931 + r * (6 ±0)` - // Minimum execution time: 253_335_000 picoseconds. - Weight::from_parts(273_013_859, 6931) - // Standard Error: 2_007 - .saturating_add(Weight::from_parts(1_540_735, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1010 + r * (6 ±0)` + // Estimated: `9409 + r * (6 ±0)` + // Minimum execution time: 253_218_000 picoseconds. + Weight::from_parts(282_251_452, 9409) + // Standard Error: 2_367 + .saturating_add(Weight::from_parts(1_604_060, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -751,6 +806,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -764,13 +821,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (6 ±0)` - // Estimated: `6823 + r * (6 ±0)` - // Minimum execution time: 252_325_000 picoseconds. - Weight::from_parts(274_733_944, 6823) - // Standard Error: 603 - .saturating_add(Weight::from_parts(314_467, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `880 + r * (6 ±0)` + // Estimated: `9301 + r * (6 ±0)` + // Minimum execution time: 271_797_000 picoseconds. + Weight::from_parts(288_594_393, 9301) + // Standard Error: 846 + .saturating_add(Weight::from_parts(335_063, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -778,6 +835,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -791,13 +850,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (6 ±0)` - // Estimated: `6816 + r * (6 ±0)` - // Minimum execution time: 250_698_000 picoseconds. - Weight::from_parts(271_707_578, 6816) - // Standard Error: 952 - .saturating_add(Weight::from_parts(318_412, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `878 + r * (6 ±0)` + // Estimated: `9294 + r * (6 ±0)` + // Minimum execution time: 254_997_000 picoseconds. + Weight::from_parts(284_331_894, 9294) + // Standard Error: 885 + .saturating_add(Weight::from_parts(337_073, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -805,6 +864,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -818,13 +879,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872 + r * (6 ±0)` - // Estimated: `6819 + r * (6 ±0)` - // Minimum execution time: 251_854_000 picoseconds. - Weight::from_parts(272_002_212, 6819) - // Standard Error: 622 - .saturating_add(Weight::from_parts(313_353, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `875 + r * (6 ±0)` + // Estimated: `9297 + r * (6 ±0)` + // Minimum execution time: 273_845_000 picoseconds. + Weight::from_parts(285_291_242, 9297) + // Standard Error: 690 + .saturating_add(Weight::from_parts(332_783, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -832,6 +893,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -845,13 +908,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (6 ±0)` - // Estimated: `6804 + r * (6 ±0)` - // Minimum execution time: 252_010_000 picoseconds. - Weight::from_parts(270_387_000, 6804) - // Standard Error: 659 - .saturating_add(Weight::from_parts(325_856, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `866 + r * (6 ±0)` + // Estimated: `9282 + r * (6 ±0)` + // Minimum execution time: 268_302_000 picoseconds. + Weight::from_parts(280_463_257, 9282) + // Standard Error: 1_035 + .saturating_add(Weight::from_parts(345_811, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -859,6 +922,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -874,13 +939,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `937 + r * (14 ±0)` - // Estimated: `6872 + r * (14 ±0)` - // Minimum execution time: 247_933_000 picoseconds. - Weight::from_parts(281_550_162, 6872) - // Standard Error: 660 - .saturating_add(Weight::from_parts(1_090_869, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `940 + r * (14 ±0)` + // Estimated: `9350 + r * (14 ±0)` + // Minimum execution time: 263_433_000 picoseconds. + Weight::from_parts(290_098_370, 9350) + // Standard Error: 1_905 + .saturating_add(Weight::from_parts(805_299, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 14).saturating_mul(r.into())) } @@ -888,6 +953,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -901,13 +968,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `865 + r * (6 ±0)` - // Estimated: `6807 + r * (6 ±0)` - // Minimum execution time: 251_158_000 picoseconds. - Weight::from_parts(274_623_152, 6807) - // Standard Error: 491 - .saturating_add(Weight::from_parts(263_916, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `868 + r * (6 ±0)` + // Estimated: `9285 + r * (6 ±0)` + // Minimum execution time: 273_588_000 picoseconds. + Weight::from_parts(287_133_565, 9285) + // Standard Error: 799 + .saturating_add(Weight::from_parts(254_114, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -915,6 +982,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -928,19 +997,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `869` - // Estimated: `6809` - // Minimum execution time: 263_205_000 picoseconds. - Weight::from_parts(216_792_893, 6809) - // Standard Error: 23 - .saturating_add(Weight::from_parts(989, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `872` + // Estimated: `9287` + // Minimum execution time: 257_843_000 picoseconds. + Weight::from_parts(228_177_495, 9287) + // Standard Error: 24 + .saturating_add(Weight::from_parts(985, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -954,11 +1025,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `853 + r * (45 ±0)` - // Estimated: `6793 + r * (45 ±0)` - // Minimum execution time: 239_663_000 picoseconds. - Weight::from_parts(266_124_565, 6793) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `856 + r * (45 ±0)` + // Estimated: `9271 + r * (45 ±0)` + // Minimum execution time: 248_332_000 picoseconds. + Weight::from_parts(274_998_906, 9271) + // Standard Error: 949_561 + .saturating_add(Weight::from_parts(5_570_693, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) } @@ -966,6 +1039,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -979,19 +1054,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863` - // Estimated: `6810` - // Minimum execution time: 241_763_000 picoseconds. - Weight::from_parts(266_535_552, 6810) - // Standard Error: 0 - .saturating_add(Weight::from_parts(320, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `866` + // Estimated: `9288` + // Minimum execution time: 272_055_000 picoseconds. + Weight::from_parts(282_280_090, 9288) + // Standard Error: 1 + .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:1 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:2) @@ -1005,28 +1082,30 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `Contracts::DeletionQueue` (r:0 w:1) /// Proof: `Contracts::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2972 + r * (316 ±0)` - // Estimated: `8912 + r * (5266 ±0)` - // Minimum execution time: 265_888_000 picoseconds. - Weight::from_parts(291_232_232, 8912) - // Standard Error: 845_475 - .saturating_add(Weight::from_parts(104_398_867, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(r.into()))) + // Measured: `2902 + r * (529 ±0)` + // Estimated: `11317 + r * (5479 ±0)` + // Minimum execution time: 274_842_000 picoseconds. + Weight::from_parts(299_824_497, 11317) + // Standard Error: 902_686 + .saturating_add(Weight::from_parts(106_562_902, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((10_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 5266).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 5479).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1042,13 +1121,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `944 + r * (10 ±0)` - // Estimated: `6885 + r * (10 ±0)` - // Minimum execution time: 248_500_000 picoseconds. - Weight::from_parts(282_353_053, 6885) - // Standard Error: 1_144 - .saturating_add(Weight::from_parts(1_193_841, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `947 + r * (10 ±0)` + // Estimated: `9363 + r * (10 ±0)` + // Minimum execution time: 255_393_000 picoseconds. + Weight::from_parts(309_814_338, 9363) + // Standard Error: 2_978 + .saturating_add(Weight::from_parts(1_203_507, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } @@ -1056,6 +1135,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1069,13 +1150,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (10 ±0)` - // Estimated: `6805 + r * (10 ±0)` - // Minimum execution time: 248_130_000 picoseconds. - Weight::from_parts(279_583_178, 6805) - // Standard Error: 971 - .saturating_add(Weight::from_parts(1_987_941, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `866 + r * (10 ±0)` + // Estimated: `9283 + r * (10 ±0)` + // Minimum execution time: 250_378_000 picoseconds. + Weight::from_parts(287_003_144, 9283) + // Standard Error: 2_726 + .saturating_add(Weight::from_parts(1_850_967, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } @@ -1083,6 +1164,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1097,15 +1180,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `880 + t * (32 ±0)` - // Estimated: `6825 + t * (2508 ±0)` - // Minimum execution time: 258_594_000 picoseconds. - Weight::from_parts(276_734_422, 6825) - // Standard Error: 102_093 - .saturating_add(Weight::from_parts(2_559_383, 0).saturating_mul(t.into())) - // Standard Error: 28 - .saturating_add(Weight::from_parts(501, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `883 + t * (32 ±0)` + // Estimated: `9303 + t * (2508 ±0)` + // Minimum execution time: 266_787_000 picoseconds. + Weight::from_parts(284_368_661, 9303) + // Standard Error: 121_315 + .saturating_add(Weight::from_parts(2_690_211, 0).saturating_mul(t.into())) + // Standard Error: 33 + .saturating_add(Weight::from_parts(789, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) @@ -1115,6 +1198,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1128,13 +1213,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `862 + r * (7 ±0)` - // Estimated: `6807 + r * (7 ±0)` - // Minimum execution time: 154_564_000 picoseconds. - Weight::from_parts(168_931_365, 6807) - // Standard Error: 349 - .saturating_add(Weight::from_parts(226_848, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `865 + r * (7 ±0)` + // Estimated: `9285 + r * (7 ±0)` + // Minimum execution time: 166_804_000 picoseconds. + Weight::from_parts(175_118_291, 9285) + // Standard Error: 398 + .saturating_add(Weight::from_parts(220_961, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) } @@ -1142,6 +1227,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1155,13 +1242,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125813` - // Estimated: `131755` - // Minimum execution time: 394_382_000 picoseconds. - Weight::from_parts(376_780_500, 131755) + // Measured: `125816` + // Estimated: `131758` + // Minimum execution time: 398_436_000 picoseconds. + Weight::from_parts(385_003_285, 131758) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_026, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(Weight::from_parts(1_038, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1169,13 +1256,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `924 + r * (292 ±0)` - // Estimated: `926 + r * (293 ±0)` - // Minimum execution time: 249_757_000 picoseconds. - Weight::from_parts(177_324_374, 926) - // Standard Error: 9_512 - .saturating_add(Weight::from_parts(6_176_717, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `927 + r * (292 ±0)` + // Estimated: `929 + r * (293 ±0)` + // Minimum execution time: 274_099_000 picoseconds. + Weight::from_parts(174_282_817, 929) + // Standard Error: 10_547 + .saturating_add(Weight::from_parts(6_262_173, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -1186,13 +1273,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1447` - // Estimated: `1430` - // Minimum execution time: 267_564_000 picoseconds. - Weight::from_parts(328_701_080, 1430) - // Standard Error: 61 - .saturating_add(Weight::from_parts(576, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Measured: `1450` + // Estimated: `1433` + // Minimum execution time: 274_061_000 picoseconds. + Weight::from_parts(334_755_333, 1433) + // Standard Error: 66 + .saturating_add(Weight::from_parts(771, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1200,13 +1287,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1253 + n * (1 ±0)` - // Estimated: `1253 + n * (1 ±0)` - // Minimum execution time: 266_347_000 picoseconds. - Weight::from_parts(289_824_718, 1253) - // Standard Error: 34 - .saturating_add(Weight::from_parts(184, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1256 + n * (1 ±0)` + // Estimated: `1256 + n * (1 ±0)` + // Minimum execution time: 272_657_000 picoseconds. + Weight::from_parts(299_061_594, 1256) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1215,13 +1300,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (288 ±0)` - // Estimated: `927 + r * (289 ±0)` - // Minimum execution time: 247_207_000 picoseconds. - Weight::from_parts(179_856_075, 927) - // Standard Error: 9_383 - .saturating_add(Weight::from_parts(6_053_198, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `924 + r * (288 ±0)` + // Estimated: `930 + r * (289 ±0)` + // Minimum execution time: 270_524_000 picoseconds. + Weight::from_parts(177_959_667, 930) + // Standard Error: 10_397 + .saturating_add(Weight::from_parts(6_270_181, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -1232,13 +1317,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_clear_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1249 + n * (1 ±0)` - // Estimated: `1249 + n * (1 ±0)` - // Minimum execution time: 262_655_000 picoseconds. - Weight::from_parts(289_482_543, 1249) - // Standard Error: 35 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1252 + n * (1 ±0)` + // Estimated: `1252 + n * (1 ±0)` + // Minimum execution time: 270_757_000 picoseconds. + Weight::from_parts(298_627_896, 1252) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1247,13 +1330,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (296 ±0)` - // Estimated: `923 + r * (297 ±0)` - // Minimum execution time: 247_414_000 picoseconds. - Weight::from_parts(203_317_182, 923) - // Standard Error: 7_191 - .saturating_add(Weight::from_parts(4_925_154, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `924 + r * (296 ±0)` + // Estimated: `926 + r * (297 ±0)` + // Minimum execution time: 268_082_000 picoseconds. + Weight::from_parts(202_583_730, 926) + // Standard Error: 9_029 + .saturating_add(Weight::from_parts(5_028_517, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 297).saturating_mul(r.into())) @@ -1263,13 +1346,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_get_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1265 + n * (1 ±0)` - // Estimated: `1265 + n * (1 ±0)` - // Minimum execution time: 258_910_000 picoseconds. - Weight::from_parts(283_086_514, 1265) - // Standard Error: 39 - .saturating_add(Weight::from_parts(980, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1268 + n * (1 ±0)` + // Estimated: `1268 + n * (1 ±0)` + // Minimum execution time: 274_100_000 picoseconds. + Weight::from_parts(296_981_515, 1268) + // Standard Error: 34 + .saturating_add(Weight::from_parts(578, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1278,13 +1361,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `932 + r * (288 ±0)` - // Estimated: `929 + r * (289 ±0)` - // Minimum execution time: 252_410_000 picoseconds. - Weight::from_parts(201_227_879, 929) - // Standard Error: 6_899 - .saturating_add(Weight::from_parts(4_774_983, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `935 + r * (288 ±0)` + // Estimated: `932 + r * (289 ±0)` + // Minimum execution time: 269_697_000 picoseconds. + Weight::from_parts(198_346_516, 932) + // Standard Error: 8_623 + .saturating_add(Weight::from_parts(4_964_116, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 289).saturating_mul(r.into())) @@ -1294,13 +1377,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_contains_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1252 + n * (1 ±0)` - // Estimated: `1252 + n * (1 ±0)` - // Minimum execution time: 259_053_000 picoseconds. - Weight::from_parts(283_392_084, 1252) - // Standard Error: 41 - .saturating_add(Weight::from_parts(213, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1255 + n * (1 ±0)` + // Estimated: `1255 + n * (1 ±0)` + // Minimum execution time: 264_210_000 picoseconds. + Weight::from_parts(291_387_652, 1255) + // Standard Error: 36 + .saturating_add(Weight::from_parts(524, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1309,13 +1392,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `914 + r * (296 ±0)` - // Estimated: `919 + r * (297 ±0)` - // Minimum execution time: 251_371_000 picoseconds. - Weight::from_parts(177_119_717, 919) - // Standard Error: 9_421 - .saturating_add(Weight::from_parts(6_226_005, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `917 + r * (296 ±0)` + // Estimated: `922 + r * (297 ±0)` + // Minimum execution time: 267_219_000 picoseconds. + Weight::from_parts(175_866_982, 922) + // Standard Error: 11_275 + .saturating_add(Weight::from_parts(6_424_755, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -1326,13 +1409,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_take_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1266 + n * (1 ±0)` - // Estimated: `1266 + n * (1 ±0)` - // Minimum execution time: 263_350_000 picoseconds. - Weight::from_parts(284_323_917, 1266) - // Standard Error: 31 - .saturating_add(Weight::from_parts(921, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1269 + n * (1 ±0)` + // Estimated: `1269 + n * (1 ±0)` + // Minimum execution time: 274_634_000 picoseconds. + Weight::from_parts(294_272_009, 1269) + // Standard Error: 36 + .saturating_add(Weight::from_parts(1_219, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1340,6 +1423,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1602 w:1601) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1353,13 +1438,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1415 + r * (45 ±0)` - // Estimated: `7307 + r * (2520 ±0)` - // Minimum execution time: 248_701_000 picoseconds. - Weight::from_parts(17_811_969, 7307) - // Standard Error: 35_154 - .saturating_add(Weight::from_parts(31_809_738, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1418 + r * (45 ±0)` + // Estimated: `9785 + r * (2520 ±0)` + // Minimum execution time: 266_833_000 picoseconds. + Weight::from_parts(186_049_741, 9785) + // Standard Error: 40_311 + .saturating_add(Weight::from_parts(31_365_585, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -1369,6 +1454,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -1382,13 +1469,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1260 + r * (245 ±0)` - // Estimated: `9440 + r * (2721 ±0)` - // Minimum execution time: 247_335_000 picoseconds. - Weight::from_parts(264_025_000, 9440) - // Standard Error: 121_299 - .saturating_add(Weight::from_parts(234_770_827, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) + // Measured: `1263 + r * (245 ±0)` + // Estimated: `9635 + r * (2721 ±0)` + // Minimum execution time: 272_140_000 picoseconds. + Weight::from_parts(275_009_000, 9635) + // Standard Error: 99_187 + .saturating_add(Weight::from_parts(240_702_479, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) @@ -1398,6 +1485,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:736 w:0) @@ -1412,12 +1501,12 @@ impl WeightInfo for SubstrateWeight { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (576 ±0)` - // Estimated: `6812 + r * (2637 ±3)` - // Minimum execution time: 261_011_000 picoseconds. - Weight::from_parts(264_554_000, 6812) - // Standard Error: 104_415 - .saturating_add(Weight::from_parts(231_627_084, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Estimated: `9290 + r * (2637 ±10)` + // Minimum execution time: 263_664_000 picoseconds. + Weight::from_parts(277_240_000, 9290) + // Standard Error: 169_147 + .saturating_add(Weight::from_parts(240_084_929, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -1427,6 +1516,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -1441,15 +1532,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1048576]`. fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1307 + t * (277 ±0)` - // Estimated: `12197 + t * (5227 ±0)` - // Minimum execution time: 445_561_000 picoseconds. - Weight::from_parts(62_287_490, 12197) - // Standard Error: 11_797_697 - .saturating_add(Weight::from_parts(357_530_529, 0).saturating_mul(t.into())) + // Measured: `1310 + t * (277 ±0)` + // Estimated: `12200 + t * (5227 ±0)` + // Minimum execution time: 464_644_000 picoseconds. + Weight::from_parts(40_377_313, 12200) + // Standard Error: 12_060_226 + .saturating_add(Weight::from_parts(380_635_982, 0).saturating_mul(t.into())) // Standard Error: 17 - .saturating_add(Weight::from_parts(970, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(Weight::from_parts(1_014, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) @@ -1459,6 +1550,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:801 w:800) @@ -1472,17 +1565,17 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1278 + r * (255 ±0)` - // Estimated: `9620 + r * (2731 ±0)` - // Minimum execution time: 621_897_000 picoseconds. - Weight::from_parts(631_687_000, 9620) - // Standard Error: 215_241 - .saturating_add(Weight::from_parts(350_527_831, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) + // Measured: `1281 + r * (255 ±0)` + // Estimated: `9623 + r * (2731 ±0)` + // Minimum execution time: 641_845_000 picoseconds. + Weight::from_parts(649_908_000, 9623) + // Standard Error: 278_514 + .saturating_add(Weight::from_parts(361_164_598, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(7_u64)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into()))) @@ -1492,6 +1585,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:1) @@ -1505,23 +1600,21 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1303 + t * (104 ±0)` - // Estimated: `12211 + t * (2549 ±1)` - // Minimum execution time: 2_181_184_000 picoseconds. - Weight::from_parts(1_194_190_111, 12211) - // Standard Error: 11_578_766 - .saturating_add(Weight::from_parts(6_361_884, 0).saturating_mul(t.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_025, 0).saturating_mul(i.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_158, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(16_u64)) + // Measured: `1306 + t * (104 ±0)` + // Estimated: `12214 + t * (2549 ±1)` + // Minimum execution time: 2_111_632_000 picoseconds. + Weight::from_parts(1_213_125_745, 12214) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_055, 0).saturating_mul(i.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_192, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(19_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) @@ -1531,6 +1624,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1544,13 +1639,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `862 + r * (8 ±0)` - // Estimated: `6801 + r * (8 ±0)` - // Minimum execution time: 241_609_000 picoseconds. - Weight::from_parts(268_716_874, 6801) - // Standard Error: 617 - .saturating_add(Weight::from_parts(377_753, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `865 + r * (8 ±0)` + // Estimated: `9279 + r * (8 ±0)` + // Minimum execution time: 264_227_000 picoseconds. + Weight::from_parts(281_015_995, 9279) + // Standard Error: 710 + .saturating_add(Weight::from_parts(365_734, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -1558,6 +1653,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1571,19 +1668,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `870` - // Estimated: `6808` - // Minimum execution time: 261_296_000 picoseconds. - Weight::from_parts(255_531_654, 6808) + // Measured: `873` + // Estimated: `9286` + // Minimum execution time: 270_709_000 picoseconds. + Weight::from_parts(268_416_051, 9286) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_081, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(Weight::from_parts(1_080, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1597,13 +1696,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (8 ±0)` - // Estimated: `6806 + r * (8 ±0)` - // Minimum execution time: 243_583_000 picoseconds. - Weight::from_parts(270_025_058, 6806) - // Standard Error: 560 - .saturating_add(Weight::from_parts(767_519, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `867 + r * (8 ±0)` + // Estimated: `9284 + r * (8 ±0)` + // Minimum execution time: 267_283_000 picoseconds. + Weight::from_parts(280_706_659, 9284) + // Standard Error: 540 + .saturating_add(Weight::from_parts(790_312, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -1611,6 +1710,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1624,19 +1725,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872` - // Estimated: `6814` - // Minimum execution time: 253_798_000 picoseconds. - Weight::from_parts(265_542_351, 6814) - // Standard Error: 0 - .saturating_add(Weight::from_parts(3_343, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `875` + // Estimated: `9292` + // Minimum execution time: 262_010_000 picoseconds. + Weight::from_parts(273_278_744, 9292) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_362, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1650,13 +1753,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (8 ±0)` - // Estimated: `6808 + r * (8 ±0)` - // Minimum execution time: 247_332_000 picoseconds. - Weight::from_parts(269_183_656, 6808) - // Standard Error: 665 - .saturating_add(Weight::from_parts(443_386, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `867 + r * (8 ±0)` + // Estimated: `9286 + r * (8 ±0)` + // Minimum execution time: 268_698_000 picoseconds. + Weight::from_parts(282_890_578, 9286) + // Standard Error: 622 + .saturating_add(Weight::from_parts(441_131, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -1664,6 +1767,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1677,19 +1782,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872` - // Estimated: `6813` - // Minimum execution time: 250_855_000 picoseconds. - Weight::from_parts(258_752_975, 6813) + // Measured: `875` + // Estimated: `9291` + // Minimum execution time: 252_846_000 picoseconds. + Weight::from_parts(267_657_561, 9291) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_202, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(Weight::from_parts(1_208, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1703,13 +1810,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (8 ±0)` - // Estimated: `6805 + r * (8 ±0)` - // Minimum execution time: 240_733_000 picoseconds. - Weight::from_parts(269_134_358, 6805) - // Standard Error: 512 - .saturating_add(Weight::from_parts(440_043, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `867 + r * (8 ±0)` + // Estimated: `9283 + r * (8 ±0)` + // Minimum execution time: 266_899_000 picoseconds. + Weight::from_parts(276_862_067, 9283) + // Standard Error: 1_249 + .saturating_add(Weight::from_parts(443_970, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -1717,6 +1824,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1730,19 +1839,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872` - // Estimated: `6811` - // Minimum execution time: 247_377_000 picoseconds. - Weight::from_parts(261_077_322, 6811) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_195, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `875` + // Estimated: `9289` + // Minimum execution time: 265_413_000 picoseconds. + Weight::from_parts(265_600_840, 9289) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1756,13 +1867,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `997 + n * (1 ±0)` - // Estimated: `6934 + n * (1 ±0)` - // Minimum execution time: 307_337_000 picoseconds. - Weight::from_parts(326_710_473, 6934) - // Standard Error: 9 - .saturating_add(Weight::from_parts(5_765, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `1000 + n * (1 ±0)` + // Estimated: `9412 + n * (1 ±0)` + // Minimum execution time: 328_341_000 picoseconds. + Weight::from_parts(341_038_581, 9412) + // Standard Error: 10 + .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1770,6 +1881,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1783,13 +1896,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `805 + r * (112 ±0)` - // Estimated: `6748 + r * (112 ±0)` - // Minimum execution time: 245_432_000 picoseconds. - Weight::from_parts(294_206_377, 6748) - // Standard Error: 7_229 - .saturating_add(Weight::from_parts(41_480_485, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `808 + r * (112 ±0)` + // Estimated: `9226 + r * (112 ±0)` + // Minimum execution time: 272_730_000 picoseconds. + Weight::from_parts(339_349_232, 9226) + // Standard Error: 13_004 + .saturating_add(Weight::from_parts(41_649_026, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) } @@ -1797,6 +1910,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1810,13 +1925,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `907 + r * (76 ±0)` - // Estimated: `6802 + r * (77 ±0)` - // Minimum execution time: 247_788_000 picoseconds. - Weight::from_parts(303_940_062, 6802) - // Standard Error: 10_671 - .saturating_add(Weight::from_parts(45_730_772, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `910 + r * (76 ±0)` + // Estimated: `9279 + r * (77 ±0)` + // Minimum execution time: 273_892_000 picoseconds. + Weight::from_parts(352_853_960, 9279) + // Standard Error: 16_745 + .saturating_add(Weight::from_parts(45_853_294, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) } @@ -1824,6 +1939,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1837,13 +1954,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (42 ±0)` - // Estimated: `6816 + r * (42 ±0)` - // Minimum execution time: 248_825_000 picoseconds. - Weight::from_parts(286_832_225, 6816) - // Standard Error: 5_274 - .saturating_add(Weight::from_parts(11_889_262, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `880 + r * (42 ±0)` + // Estimated: `9294 + r * (42 ±0)` + // Minimum execution time: 268_431_000 picoseconds. + Weight::from_parts(319_727_796, 9294) + // Standard Error: 10_276 + .saturating_add(Weight::from_parts(11_928_882, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) } @@ -1851,6 +1968,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) @@ -1865,12 +1984,12 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (965 ±0)` - // Estimated: `6807 + r * (3090 ±7)` - // Minimum execution time: 244_982_000 picoseconds. - Weight::from_parts(265_297_000, 6807) - // Standard Error: 39_895 - .saturating_add(Weight::from_parts(22_435_888, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Estimated: `9285 + r * (3090 ±7)` + // Minimum execution time: 275_482_000 picoseconds. + Weight::from_parts(279_155_000, 9285) + // Standard Error: 65_388 + .saturating_add(Weight::from_parts(26_634_187, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) @@ -1880,6 +1999,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -1891,24 +2012,26 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 32]`. - fn add_delegate_dependency(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `928 + r * (131 ±0)` - // Estimated: `6878 + r * (2606 ±0)` - // Minimum execution time: 246_455_000 picoseconds. - Weight::from_parts(275_334_919, 6878) - // Standard Error: 20_911 - .saturating_add(Weight::from_parts(6_427_525, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + fn lock_delegate_dependency(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `937 + r * (131 ±0)` + // Estimated: `9346 + r * (2607 ±0)` + // Minimum execution time: 270_001_000 picoseconds. + Weight::from_parts(286_792_689, 9346) + // Standard Error: 21_074 + .saturating_add(Weight::from_parts(6_465_885, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2606).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2607).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -1920,15 +2043,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 32]`. - fn remove_delegate_dependency(r: u32, ) -> Weight { + fn unlock_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `969 + r * (183 ±0)` + // Measured: `972 + r * (184 ±0)` // Estimated: `129453 + r * (2568 ±0)` - // Minimum execution time: 254_472_000 picoseconds. - Weight::from_parts(280_657_909, 129453) - // Standard Error: 20_131 - .saturating_add(Weight::from_parts(5_644_006, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 270_652_000 picoseconds. + Weight::from_parts(293_369_452, 129453) + // Standard Error: 24_321 + .saturating_add(Weight::from_parts(5_575_600, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -1938,6 +2061,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1951,13 +2076,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `858 + r * (3 ±0)` - // Estimated: `6804 + r * (3 ±0)` - // Minimum execution time: 250_535_000 picoseconds. - Weight::from_parts(270_318_376, 6804) - // Standard Error: 386 - .saturating_add(Weight::from_parts(174_627, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `861 + r * (3 ±0)` + // Estimated: `9282 + r * (3 ±0)` + // Minimum execution time: 267_749_000 picoseconds. + Weight::from_parts(280_373_341, 9282) + // Standard Error: 464 + .saturating_add(Weight::from_parts(170_398, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } @@ -1965,6 +2090,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1978,13 +2105,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2109 + r * (39 ±0)` - // Estimated: `7899 + r * (40 ±0)` - // Minimum execution time: 248_174_000 picoseconds. - Weight::from_parts(301_826_520, 7899) - // Standard Error: 801 - .saturating_add(Weight::from_parts(248_479, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `2112 + r * (39 ±0)` + // Estimated: `10377 + r * (40 ±0)` + // Minimum execution time: 270_260_000 picoseconds. + Weight::from_parts(337_969_172, 10377) + // Standard Error: 1_557 + .saturating_add(Weight::from_parts(305_735, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } @@ -1992,6 +2119,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2007,13 +2136,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `861 + r * (3 ±0)` - // Estimated: `6801 + r * (3 ±0)` - // Minimum execution time: 246_540_000 picoseconds. - Weight::from_parts(268_913_509, 6801) - // Standard Error: 378 - .saturating_add(Weight::from_parts(154_950, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `864 + r * (3 ±0)` + // Estimated: `9279 + r * (3 ±0)` + // Minimum execution time: 265_607_000 picoseconds. + Weight::from_parts(283_396_630, 9279) + // Standard Error: 449 + .saturating_add(Weight::from_parts(149_018, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } @@ -2022,10 +2151,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_777_000 picoseconds. - Weight::from_parts(1_707_601, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(15_392, 0).saturating_mul(r.into())) + // Minimum execution time: 1_813_000 picoseconds. + Weight::from_parts(1_264_945, 0) + // Standard Error: 19 + .saturating_add(Weight::from_parts(15_098, 0).saturating_mul(r.into())) } } @@ -2037,8 +2166,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 1_997_000 picoseconds. - Weight::from_parts(2_130_000, 1627) + // Minimum execution time: 2_054_000 picoseconds. + Weight::from_parts(2_178_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -2048,10 +2177,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 12_276_000 picoseconds. - Weight::from_parts(1_593_881, 442) - // Standard Error: 1_135 - .saturating_add(Weight::from_parts(1_109_302, 0).saturating_mul(k.into())) + // Minimum execution time: 12_119_000 picoseconds. + Weight::from_parts(12_536_000, 442) + // Standard Error: 1_254 + .saturating_add(Weight::from_parts(1_161_885, 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)) @@ -2065,10 +2194,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_176_000 picoseconds. - Weight::from_parts(8_555_388, 6149) + // Minimum execution time: 8_146_000 picoseconds. + Weight::from_parts(8_560_745, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_184, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_182, 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())) @@ -2081,8 +2210,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_270_000 picoseconds. - Weight::from_parts(16_779_000, 6450) + // Minimum execution time: 16_183_000 picoseconds. + Weight::from_parts(16_825_000, 6450) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2095,10 +2224,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_572_000 picoseconds. - Weight::from_parts(1_950_905, 3635) - // Standard Error: 1_597 - .saturating_add(Weight::from_parts(1_123_190, 0).saturating_mul(k.into())) + // Minimum execution time: 3_645_000 picoseconds. + Weight::from_parts(604_365, 3635) + // Standard Error: 1_013 + .saturating_add(Weight::from_parts(1_100_277, 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()))) @@ -2108,6 +2237,8 @@ impl WeightInfo for () { /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553053f13fd319a03c211337c76e0fe776df` (r:2 w:0) /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:0 w:1) @@ -2115,13 +2246,13 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 125952]`. fn v12_migration_step(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `325 + c * (1 ±0)` - // Estimated: `6263 + c * (1 ±0)` - // Minimum execution time: 16_873_000 picoseconds. - Weight::from_parts(16_790_402, 6263) + // Measured: `328 + c * (1 ±0)` + // Estimated: `6266 + c * (1 ±0)` + // Minimum execution time: 19_500_000 picoseconds. + Weight::from_parts(20_074_895, 6266) // Standard Error: 1 - .saturating_add(Weight::from_parts(396, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_parts(422, 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())) } @@ -2131,8 +2262,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 11_904_000 picoseconds. - Weight::from_parts(12_785_000, 6380) + // Minimum execution time: 12_530_000 picoseconds. + Weight::from_parts(13_362_000, 6380) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2141,13 +2272,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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 44_920_000 picoseconds. - Weight::from_parts(46_163_000, 6292) + // Minimum execution time: 44_275_000 picoseconds. + Weight::from_parts(45_718_000, 6292) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2159,8 +2290,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 53_864_000 picoseconds. - Weight::from_parts(55_139_000, 6534) + // Minimum execution time: 55_095_000 picoseconds. + Weight::from_parts(58_009_000, 6534) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -2170,8 +2301,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_375_000 picoseconds. - Weight::from_parts(2_487_000, 1627) + // Minimum execution time: 2_455_000 picoseconds. + Weight::from_parts(2_608_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2183,8 +2314,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 11_580_000 picoseconds. - Weight::from_parts(11_980_000, 3631) + // Minimum execution time: 11_207_000 picoseconds. + Weight::from_parts(11_802_000, 3631) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -2194,8 +2325,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_557_000 picoseconds. - Weight::from_parts(4_807_000, 3607) + // Minimum execution time: 4_581_000 picoseconds. + Weight::from_parts(4_781_000, 3607) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -2206,8 +2337,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 6_253_000 picoseconds. - Weight::from_parts(6_479_000, 3632) + // Minimum execution time: 5_887_000 picoseconds. + Weight::from_parts(6_393_000, 3632) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -2218,13 +2349,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_166_000 picoseconds. - Weight::from_parts(6_545_000, 3607) + // Minimum execution time: 6_025_000 picoseconds. + Weight::from_parts(6_298_000, 3607) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2240,22 +2373,24 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `801 + c * (1 ±0)` - // Estimated: `6739 + c * (1 ±0)` - // Minimum execution time: 282_232_000 picoseconds. - Weight::from_parts(266_148_573, 6739) - // Standard Error: 69 - .saturating_add(Weight::from_parts(34_592, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `804 + c * (1 ±0)` + // Estimated: `9217 + c * (1 ±0)` + // Minimum execution time: 294_976_000 picoseconds. + Weight::from_parts(277_235_948, 9217) + // Standard Error: 65 + .saturating_add(Weight::from_parts(34_445, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// 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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:3 w:3) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) @@ -2273,17 +2408,17 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `323` - // Estimated: `8737` - // Minimum execution time: 3_760_879_000 picoseconds. - Weight::from_parts(794_812_431, 8737) - // Standard Error: 149 - .saturating_add(Weight::from_parts(101_881, 0).saturating_mul(c.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_404, 0).saturating_mul(i.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_544, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) + // Measured: `326` + // Estimated: `8740` + // Minimum execution time: 3_864_558_000 picoseconds. + Weight::from_parts(421_676_889, 8740) + // Standard Error: 188 + .saturating_add(Weight::from_parts(103_788, 0).saturating_mul(c.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_715, 0).saturating_mul(i.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_774, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) @@ -2292,6 +2427,8 @@ impl WeightInfo for () { /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, 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) @@ -2303,24 +2440,26 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `6504` - // Minimum execution time: 1_953_162_000 picoseconds. - Weight::from_parts(374_252_840, 6504) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_630, 0).saturating_mul(i.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_650, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(10_u64)) + // Measured: `563` + // Estimated: `8982` + // Minimum execution time: 2_069_276_000 picoseconds. + Weight::from_parts(377_210_279, 8982) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_719, 0).saturating_mul(i.into())) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_728, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2335,41 +2474,67 @@ impl WeightInfo for () { /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `826` - // Estimated: `6766` - // Minimum execution time: 187_899_000 picoseconds. - Weight::from_parts(195_510_000, 6766) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `829` + // Estimated: `9244` + // Minimum execution time: 199_037_000 picoseconds. + Weight::from_parts(213_931_000, 9244) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// 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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, 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]`. - fn upload_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3607` - // Minimum execution time: 254_800_000 picoseconds. - Weight::from_parts(285_603_050, 3607) - // Standard Error: 62 - .saturating_add(Weight::from_parts(66_212, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + fn upload_code_determinism_enforced(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `6085` + // Minimum execution time: 278_482_000 picoseconds. + Weight::from_parts(262_753_879, 6085) + // Standard Error: 112 + .saturating_add(Weight::from_parts(66_129, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// 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(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Storage: `System::EventTopics` (r:1 w:1) + /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, 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]`. + fn upload_code_determinism_relaxed(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `6085` + // Minimum execution time: 286_902_000 picoseconds. + Weight::from_parts(269_003_959, 6085) + // Standard Error: 123 + .saturating_add(Weight::from_parts(66_629, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) + /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// 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`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -2378,8 +2543,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 43_553_000 picoseconds. - Weight::from_parts(45_036_000, 3780) + // Minimum execution time: 44_128_000 picoseconds. + Weight::from_parts(46_044_000, 3780) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2395,8 +2560,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 33_223_000 picoseconds. - Weight::from_parts(34_385_000, 8967) + // Minimum execution time: 33_567_000 picoseconds. + Weight::from_parts(35_057_000, 8967) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2404,6 +2569,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2417,13 +2584,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `866 + r * (6 ±0)` - // Estimated: `6806 + r * (6 ±0)` - // Minimum execution time: 254_213_000 picoseconds. - Weight::from_parts(273_464_980, 6806) - // Standard Error: 1_362 - .saturating_add(Weight::from_parts(322_619, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `869 + r * (6 ±0)` + // Estimated: `9284 + r * (6 ±0)` + // Minimum execution time: 272_376_000 picoseconds. + Weight::from_parts(284_162_161, 9284) + // Standard Error: 501 + .saturating_add(Weight::from_parts(341_575, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2431,6 +2598,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2444,13 +2613,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `922 + r * (209 ±0)` - // Estimated: `6826 + r * (2684 ±0)` - // Minimum execution time: 250_273_000 picoseconds. - Weight::from_parts(122_072_782, 6826) - // Standard Error: 5_629 - .saturating_add(Weight::from_parts(3_490_256, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `925 + r * (209 ±0)` + // Estimated: `9304 + r * (2684 ±0)` + // Minimum execution time: 256_990_000 picoseconds. + Weight::from_parts(107_167_044, 9304) + // Standard Error: 7_545 + .saturating_add(Weight::from_parts(3_628_112, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2684).saturating_mul(r.into())) @@ -2459,6 +2628,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2472,13 +2643,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (213 ±0)` - // Estimated: `6830 + r * (2688 ±0)` - // Minimum execution time: 255_187_000 picoseconds. - Weight::from_parts(118_082_505, 6830) - // Standard Error: 6_302 - .saturating_add(Weight::from_parts(4_246_968, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `924 + r * (213 ±0)` + // Estimated: `9308 + r * (2688 ±0)` + // Minimum execution time: 272_889_000 picoseconds. + Weight::from_parts(110_341_799, 9308) + // Standard Error: 7_881 + .saturating_add(Weight::from_parts(4_427_043, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2688).saturating_mul(r.into())) @@ -2487,6 +2658,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2500,13 +2673,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (6 ±0)` - // Estimated: `6815 + r * (6 ±0)` - // Minimum execution time: 256_833_000 picoseconds. - Weight::from_parts(273_330_216, 6815) - // Standard Error: 881 - .saturating_add(Weight::from_parts(400_105, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `876 + r * (6 ±0)` + // Estimated: `9293 + r * (6 ±0)` + // Minimum execution time: 275_027_000 picoseconds. + Weight::from_parts(283_302_223, 9293) + // Standard Error: 1_179 + .saturating_add(Weight::from_parts(436_023, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2514,6 +2687,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2527,18 +2702,20 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (3 ±0)` - // Estimated: `6804 + r * (3 ±0)` - // Minimum execution time: 244_193_000 picoseconds. - Weight::from_parts(271_221_908, 6804) - // Standard Error: 442 - .saturating_add(Weight::from_parts(176_480, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `866 + r * (3 ±0)` + // Estimated: `9282 + r * (3 ±0)` + // Minimum execution time: 270_137_000 picoseconds. + Weight::from_parts(282_756_362, 9282) + // Standard Error: 384 + .saturating_add(Weight::from_parts(171_660, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2552,13 +2729,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_root(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `753 + r * (3 ±0)` - // Estimated: `6693 + r * (3 ±0)` - // Minimum execution time: 232_603_000 picoseconds. - Weight::from_parts(260_577_368, 6693) - // Standard Error: 365 - .saturating_add(Weight::from_parts(158_126, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(7_u64)) + // Measured: `756 + r * (3 ±0)` + // Estimated: `9171 + r * (3 ±0)` + // Minimum execution time: 255_131_000 picoseconds. + Weight::from_parts(269_207_006, 9171) + // Standard Error: 542 + .saturating_add(Weight::from_parts(161_597, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } @@ -2566,6 +2743,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2579,13 +2758,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `867 + r * (6 ±0)` - // Estimated: `6807 + r * (6 ±0)` - // Minimum execution time: 247_564_000 picoseconds. - Weight::from_parts(275_108_914, 6807) - // Standard Error: 505 - .saturating_add(Weight::from_parts(315_065, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `870 + r * (6 ±0)` + // Estimated: `9285 + r * (6 ±0)` + // Minimum execution time: 272_172_000 picoseconds. + Weight::from_parts(283_747_134, 9285) + // Standard Error: 885 + .saturating_add(Weight::from_parts(343_968, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2593,6 +2772,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2606,13 +2787,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (6 ±0)` - // Estimated: `6806 + r * (6 ±0)` - // Minimum execution time: 258_799_000 picoseconds. - Weight::from_parts(274_338_256, 6806) - // Standard Error: 632 - .saturating_add(Weight::from_parts(355_032, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `866 + r * (6 ±0)` + // Estimated: `9284 + r * (6 ±0)` + // Minimum execution time: 263_220_000 picoseconds. + Weight::from_parts(277_062_382, 9284) + // Standard Error: 1_783 + .saturating_add(Weight::from_parts(399_631, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2620,6 +2801,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:2 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2633,13 +2816,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1007 + r * (6 ±0)` - // Estimated: `6931 + r * (6 ±0)` - // Minimum execution time: 253_335_000 picoseconds. - Weight::from_parts(273_013_859, 6931) - // Standard Error: 2_007 - .saturating_add(Weight::from_parts(1_540_735, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1010 + r * (6 ±0)` + // Estimated: `9409 + r * (6 ±0)` + // Minimum execution time: 253_218_000 picoseconds. + Weight::from_parts(282_251_452, 9409) + // Standard Error: 2_367 + .saturating_add(Weight::from_parts(1_604_060, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2647,6 +2830,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2660,13 +2845,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (6 ±0)` - // Estimated: `6823 + r * (6 ±0)` - // Minimum execution time: 252_325_000 picoseconds. - Weight::from_parts(274_733_944, 6823) - // Standard Error: 603 - .saturating_add(Weight::from_parts(314_467, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `880 + r * (6 ±0)` + // Estimated: `9301 + r * (6 ±0)` + // Minimum execution time: 271_797_000 picoseconds. + Weight::from_parts(288_594_393, 9301) + // Standard Error: 846 + .saturating_add(Weight::from_parts(335_063, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2674,6 +2859,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2687,13 +2874,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (6 ±0)` - // Estimated: `6816 + r * (6 ±0)` - // Minimum execution time: 250_698_000 picoseconds. - Weight::from_parts(271_707_578, 6816) - // Standard Error: 952 - .saturating_add(Weight::from_parts(318_412, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `878 + r * (6 ±0)` + // Estimated: `9294 + r * (6 ±0)` + // Minimum execution time: 254_997_000 picoseconds. + Weight::from_parts(284_331_894, 9294) + // Standard Error: 885 + .saturating_add(Weight::from_parts(337_073, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2701,6 +2888,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2714,13 +2903,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872 + r * (6 ±0)` - // Estimated: `6819 + r * (6 ±0)` - // Minimum execution time: 251_854_000 picoseconds. - Weight::from_parts(272_002_212, 6819) - // Standard Error: 622 - .saturating_add(Weight::from_parts(313_353, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `875 + r * (6 ±0)` + // Estimated: `9297 + r * (6 ±0)` + // Minimum execution time: 273_845_000 picoseconds. + Weight::from_parts(285_291_242, 9297) + // Standard Error: 690 + .saturating_add(Weight::from_parts(332_783, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2728,6 +2917,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2741,13 +2932,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (6 ±0)` - // Estimated: `6804 + r * (6 ±0)` - // Minimum execution time: 252_010_000 picoseconds. - Weight::from_parts(270_387_000, 6804) - // Standard Error: 659 - .saturating_add(Weight::from_parts(325_856, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `866 + r * (6 ±0)` + // Estimated: `9282 + r * (6 ±0)` + // Minimum execution time: 268_302_000 picoseconds. + Weight::from_parts(280_463_257, 9282) + // Standard Error: 1_035 + .saturating_add(Weight::from_parts(345_811, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2755,6 +2946,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2770,13 +2963,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `937 + r * (14 ±0)` - // Estimated: `6872 + r * (14 ±0)` - // Minimum execution time: 247_933_000 picoseconds. - Weight::from_parts(281_550_162, 6872) - // Standard Error: 660 - .saturating_add(Weight::from_parts(1_090_869, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `940 + r * (14 ±0)` + // Estimated: `9350 + r * (14 ±0)` + // Minimum execution time: 263_433_000 picoseconds. + Weight::from_parts(290_098_370, 9350) + // Standard Error: 1_905 + .saturating_add(Weight::from_parts(805_299, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 14).saturating_mul(r.into())) } @@ -2784,6 +2977,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2797,13 +2992,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `865 + r * (6 ±0)` - // Estimated: `6807 + r * (6 ±0)` - // Minimum execution time: 251_158_000 picoseconds. - Weight::from_parts(274_623_152, 6807) - // Standard Error: 491 - .saturating_add(Weight::from_parts(263_916, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `868 + r * (6 ±0)` + // Estimated: `9285 + r * (6 ±0)` + // Minimum execution time: 273_588_000 picoseconds. + Weight::from_parts(287_133_565, 9285) + // Standard Error: 799 + .saturating_add(Weight::from_parts(254_114, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } @@ -2811,6 +3006,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2824,19 +3021,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `869` - // Estimated: `6809` - // Minimum execution time: 263_205_000 picoseconds. - Weight::from_parts(216_792_893, 6809) - // Standard Error: 23 - .saturating_add(Weight::from_parts(989, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `872` + // Estimated: `9287` + // Minimum execution time: 257_843_000 picoseconds. + Weight::from_parts(228_177_495, 9287) + // Standard Error: 24 + .saturating_add(Weight::from_parts(985, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2850,11 +3049,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `853 + r * (45 ±0)` - // Estimated: `6793 + r * (45 ±0)` - // Minimum execution time: 239_663_000 picoseconds. - Weight::from_parts(266_124_565, 6793) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `856 + r * (45 ±0)` + // Estimated: `9271 + r * (45 ±0)` + // Minimum execution time: 248_332_000 picoseconds. + Weight::from_parts(274_998_906, 9271) + // Standard Error: 949_561 + .saturating_add(Weight::from_parts(5_570_693, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) } @@ -2862,6 +3063,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2875,19 +3078,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863` - // Estimated: `6810` - // Minimum execution time: 241_763_000 picoseconds. - Weight::from_parts(266_535_552, 6810) - // Standard Error: 0 - .saturating_add(Weight::from_parts(320, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `866` + // Estimated: `9288` + // Minimum execution time: 272_055_000 picoseconds. + Weight::from_parts(282_280_090, 9288) + // Standard Error: 1 + .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:1 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:2) @@ -2901,28 +3106,30 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `Contracts::DeletionQueue` (r:0 w:1) /// Proof: `Contracts::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2972 + r * (316 ±0)` - // Estimated: `8912 + r * (5266 ±0)` - // Minimum execution time: 265_888_000 picoseconds. - Weight::from_parts(291_232_232, 8912) - // Standard Error: 845_475 - .saturating_add(Weight::from_parts(104_398_867, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(r.into()))) + // Measured: `2902 + r * (529 ±0)` + // Estimated: `11317 + r * (5479 ±0)` + // Minimum execution time: 274_842_000 picoseconds. + Weight::from_parts(299_824_497, 11317) + // Standard Error: 902_686 + .saturating_add(Weight::from_parts(106_562_902, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((10_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 5266).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 5479).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2938,13 +3145,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `944 + r * (10 ±0)` - // Estimated: `6885 + r * (10 ±0)` - // Minimum execution time: 248_500_000 picoseconds. - Weight::from_parts(282_353_053, 6885) - // Standard Error: 1_144 - .saturating_add(Weight::from_parts(1_193_841, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `947 + r * (10 ±0)` + // Estimated: `9363 + r * (10 ±0)` + // Minimum execution time: 255_393_000 picoseconds. + Weight::from_parts(309_814_338, 9363) + // Standard Error: 2_978 + .saturating_add(Weight::from_parts(1_203_507, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } @@ -2952,6 +3159,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2965,13 +3174,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (10 ±0)` - // Estimated: `6805 + r * (10 ±0)` - // Minimum execution time: 248_130_000 picoseconds. - Weight::from_parts(279_583_178, 6805) - // Standard Error: 971 - .saturating_add(Weight::from_parts(1_987_941, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `866 + r * (10 ±0)` + // Estimated: `9283 + r * (10 ±0)` + // Minimum execution time: 250_378_000 picoseconds. + Weight::from_parts(287_003_144, 9283) + // Standard Error: 2_726 + .saturating_add(Weight::from_parts(1_850_967, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } @@ -2979,6 +3188,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2993,15 +3204,15 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `880 + t * (32 ±0)` - // Estimated: `6825 + t * (2508 ±0)` - // Minimum execution time: 258_594_000 picoseconds. - Weight::from_parts(276_734_422, 6825) - // Standard Error: 102_093 - .saturating_add(Weight::from_parts(2_559_383, 0).saturating_mul(t.into())) - // Standard Error: 28 - .saturating_add(Weight::from_parts(501, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `883 + t * (32 ±0)` + // Estimated: `9303 + t * (2508 ±0)` + // Minimum execution time: 266_787_000 picoseconds. + Weight::from_parts(284_368_661, 9303) + // Standard Error: 121_315 + .saturating_add(Weight::from_parts(2_690_211, 0).saturating_mul(t.into())) + // Standard Error: 33 + .saturating_add(Weight::from_parts(789, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) @@ -3011,6 +3222,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3024,13 +3237,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `862 + r * (7 ±0)` - // Estimated: `6807 + r * (7 ±0)` - // Minimum execution time: 154_564_000 picoseconds. - Weight::from_parts(168_931_365, 6807) - // Standard Error: 349 - .saturating_add(Weight::from_parts(226_848, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `865 + r * (7 ±0)` + // Estimated: `9285 + r * (7 ±0)` + // Minimum execution time: 166_804_000 picoseconds. + Weight::from_parts(175_118_291, 9285) + // Standard Error: 398 + .saturating_add(Weight::from_parts(220_961, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) } @@ -3038,6 +3251,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3051,13 +3266,13 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125813` - // Estimated: `131755` - // Minimum execution time: 394_382_000 picoseconds. - Weight::from_parts(376_780_500, 131755) + // Measured: `125816` + // Estimated: `131758` + // Minimum execution time: 398_436_000 picoseconds. + Weight::from_parts(385_003_285, 131758) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_026, 0).saturating_mul(i.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(Weight::from_parts(1_038, 0).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -3065,13 +3280,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `924 + r * (292 ±0)` - // Estimated: `926 + r * (293 ±0)` - // Minimum execution time: 249_757_000 picoseconds. - Weight::from_parts(177_324_374, 926) - // Standard Error: 9_512 - .saturating_add(Weight::from_parts(6_176_717, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `927 + r * (292 ±0)` + // Estimated: `929 + r * (293 ±0)` + // Minimum execution time: 274_099_000 picoseconds. + Weight::from_parts(174_282_817, 929) + // Standard Error: 10_547 + .saturating_add(Weight::from_parts(6_262_173, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -3082,13 +3297,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1447` - // Estimated: `1430` - // Minimum execution time: 267_564_000 picoseconds. - Weight::from_parts(328_701_080, 1430) - // Standard Error: 61 - .saturating_add(Weight::from_parts(576, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Measured: `1450` + // Estimated: `1433` + // Minimum execution time: 274_061_000 picoseconds. + Weight::from_parts(334_755_333, 1433) + // Standard Error: 66 + .saturating_add(Weight::from_parts(771, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -3096,13 +3311,11 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1253 + n * (1 ±0)` - // Estimated: `1253 + n * (1 ±0)` - // Minimum execution time: 266_347_000 picoseconds. - Weight::from_parts(289_824_718, 1253) - // Standard Error: 34 - .saturating_add(Weight::from_parts(184, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1256 + n * (1 ±0)` + // Estimated: `1256 + n * (1 ±0)` + // Minimum execution time: 272_657_000 picoseconds. + Weight::from_parts(299_061_594, 1256) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -3111,13 +3324,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (288 ±0)` - // Estimated: `927 + r * (289 ±0)` - // Minimum execution time: 247_207_000 picoseconds. - Weight::from_parts(179_856_075, 927) - // Standard Error: 9_383 - .saturating_add(Weight::from_parts(6_053_198, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `924 + r * (288 ±0)` + // Estimated: `930 + r * (289 ±0)` + // Minimum execution time: 270_524_000 picoseconds. + Weight::from_parts(177_959_667, 930) + // Standard Error: 10_397 + .saturating_add(Weight::from_parts(6_270_181, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -3128,13 +3341,11 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_clear_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1249 + n * (1 ±0)` - // Estimated: `1249 + n * (1 ±0)` - // Minimum execution time: 262_655_000 picoseconds. - Weight::from_parts(289_482_543, 1249) - // Standard Error: 35 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1252 + n * (1 ±0)` + // Estimated: `1252 + n * (1 ±0)` + // Minimum execution time: 270_757_000 picoseconds. + Weight::from_parts(298_627_896, 1252) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -3143,13 +3354,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (296 ±0)` - // Estimated: `923 + r * (297 ±0)` - // Minimum execution time: 247_414_000 picoseconds. - Weight::from_parts(203_317_182, 923) - // Standard Error: 7_191 - .saturating_add(Weight::from_parts(4_925_154, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `924 + r * (296 ±0)` + // Estimated: `926 + r * (297 ±0)` + // Minimum execution time: 268_082_000 picoseconds. + Weight::from_parts(202_583_730, 926) + // Standard Error: 9_029 + .saturating_add(Weight::from_parts(5_028_517, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 297).saturating_mul(r.into())) @@ -3159,13 +3370,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_get_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1265 + n * (1 ±0)` - // Estimated: `1265 + n * (1 ±0)` - // Minimum execution time: 258_910_000 picoseconds. - Weight::from_parts(283_086_514, 1265) - // Standard Error: 39 - .saturating_add(Weight::from_parts(980, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1268 + n * (1 ±0)` + // Estimated: `1268 + n * (1 ±0)` + // Minimum execution time: 274_100_000 picoseconds. + Weight::from_parts(296_981_515, 1268) + // Standard Error: 34 + .saturating_add(Weight::from_parts(578, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -3174,13 +3385,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `932 + r * (288 ±0)` - // Estimated: `929 + r * (289 ±0)` - // Minimum execution time: 252_410_000 picoseconds. - Weight::from_parts(201_227_879, 929) - // Standard Error: 6_899 - .saturating_add(Weight::from_parts(4_774_983, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `935 + r * (288 ±0)` + // Estimated: `932 + r * (289 ±0)` + // Minimum execution time: 269_697_000 picoseconds. + Weight::from_parts(198_346_516, 932) + // Standard Error: 8_623 + .saturating_add(Weight::from_parts(4_964_116, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 289).saturating_mul(r.into())) @@ -3190,13 +3401,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_contains_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1252 + n * (1 ±0)` - // Estimated: `1252 + n * (1 ±0)` - // Minimum execution time: 259_053_000 picoseconds. - Weight::from_parts(283_392_084, 1252) - // Standard Error: 41 - .saturating_add(Weight::from_parts(213, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1255 + n * (1 ±0)` + // Estimated: `1255 + n * (1 ±0)` + // Minimum execution time: 264_210_000 picoseconds. + Weight::from_parts(291_387_652, 1255) + // Standard Error: 36 + .saturating_add(Weight::from_parts(524, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -3205,13 +3416,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `914 + r * (296 ±0)` - // Estimated: `919 + r * (297 ±0)` - // Minimum execution time: 251_371_000 picoseconds. - Weight::from_parts(177_119_717, 919) - // Standard Error: 9_421 - .saturating_add(Weight::from_parts(6_226_005, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `917 + r * (296 ±0)` + // Estimated: `922 + r * (297 ±0)` + // Minimum execution time: 267_219_000 picoseconds. + Weight::from_parts(175_866_982, 922) + // Standard Error: 11_275 + .saturating_add(Weight::from_parts(6_424_755, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -3222,13 +3433,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_take_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1266 + n * (1 ±0)` - // Estimated: `1266 + n * (1 ±0)` - // Minimum execution time: 263_350_000 picoseconds. - Weight::from_parts(284_323_917, 1266) - // Standard Error: 31 - .saturating_add(Weight::from_parts(921, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1269 + n * (1 ±0)` + // Estimated: `1269 + n * (1 ±0)` + // Minimum execution time: 274_634_000 picoseconds. + Weight::from_parts(294_272_009, 1269) + // Standard Error: 36 + .saturating_add(Weight::from_parts(1_219, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -3236,6 +3447,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1602 w:1601) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3249,13 +3462,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1415 + r * (45 ±0)` - // Estimated: `7307 + r * (2520 ±0)` - // Minimum execution time: 248_701_000 picoseconds. - Weight::from_parts(17_811_969, 7307) - // Standard Error: 35_154 - .saturating_add(Weight::from_parts(31_809_738, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1418 + r * (45 ±0)` + // Estimated: `9785 + r * (2520 ±0)` + // Minimum execution time: 266_833_000 picoseconds. + Weight::from_parts(186_049_741, 9785) + // Standard Error: 40_311 + .saturating_add(Weight::from_parts(31_365_585, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -3265,6 +3478,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -3278,13 +3493,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1260 + r * (245 ±0)` - // Estimated: `9440 + r * (2721 ±0)` - // Minimum execution time: 247_335_000 picoseconds. - Weight::from_parts(264_025_000, 9440) - // Standard Error: 121_299 - .saturating_add(Weight::from_parts(234_770_827, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) + // Measured: `1263 + r * (245 ±0)` + // Estimated: `9635 + r * (2721 ±0)` + // Minimum execution time: 272_140_000 picoseconds. + Weight::from_parts(275_009_000, 9635) + // Standard Error: 99_187 + .saturating_add(Weight::from_parts(240_702_479, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) @@ -3294,6 +3509,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:736 w:0) @@ -3308,12 +3525,12 @@ impl WeightInfo for () { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (576 ±0)` - // Estimated: `6812 + r * (2637 ±3)` - // Minimum execution time: 261_011_000 picoseconds. - Weight::from_parts(264_554_000, 6812) - // Standard Error: 104_415 - .saturating_add(Weight::from_parts(231_627_084, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Estimated: `9290 + r * (2637 ±10)` + // Minimum execution time: 263_664_000 picoseconds. + Weight::from_parts(277_240_000, 9290) + // Standard Error: 169_147 + .saturating_add(Weight::from_parts(240_084_929, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -3323,6 +3540,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -3337,15 +3556,15 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 1048576]`. fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1307 + t * (277 ±0)` - // Estimated: `12197 + t * (5227 ±0)` - // Minimum execution time: 445_561_000 picoseconds. - Weight::from_parts(62_287_490, 12197) - // Standard Error: 11_797_697 - .saturating_add(Weight::from_parts(357_530_529, 0).saturating_mul(t.into())) + // Measured: `1310 + t * (277 ±0)` + // Estimated: `12200 + t * (5227 ±0)` + // Minimum execution time: 464_644_000 picoseconds. + Weight::from_parts(40_377_313, 12200) + // Standard Error: 12_060_226 + .saturating_add(Weight::from_parts(380_635_982, 0).saturating_mul(t.into())) // Standard Error: 17 - .saturating_add(Weight::from_parts(970, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(13_u64)) + .saturating_add(Weight::from_parts(1_014, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(t.into()))) @@ -3355,6 +3574,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:801 w:800) @@ -3368,17 +3589,17 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1278 + r * (255 ±0)` - // Estimated: `9620 + r * (2731 ±0)` - // Minimum execution time: 621_897_000 picoseconds. - Weight::from_parts(631_687_000, 9620) - // Standard Error: 215_241 - .saturating_add(Weight::from_parts(350_527_831, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) + // Measured: `1281 + r * (255 ±0)` + // Estimated: `9623 + r * (2731 ±0)` + // Minimum execution time: 641_845_000 picoseconds. + Weight::from_parts(649_908_000, 9623) + // Standard Error: 278_514 + .saturating_add(Weight::from_parts(361_164_598, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(7_u64)) .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(r.into()))) @@ -3388,6 +3609,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:1) @@ -3401,23 +3624,21 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1303 + t * (104 ±0)` - // Estimated: `12211 + t * (2549 ±1)` - // Minimum execution time: 2_181_184_000 picoseconds. - Weight::from_parts(1_194_190_111, 12211) - // Standard Error: 11_578_766 - .saturating_add(Weight::from_parts(6_361_884, 0).saturating_mul(t.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_025, 0).saturating_mul(i.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_158, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(16_u64)) + // Measured: `1306 + t * (104 ±0)` + // Estimated: `12214 + t * (2549 ±1)` + // Minimum execution time: 2_111_632_000 picoseconds. + Weight::from_parts(1_213_125_745, 12214) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_055, 0).saturating_mul(i.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_192, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(19_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) @@ -3427,6 +3648,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3440,13 +3663,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `862 + r * (8 ±0)` - // Estimated: `6801 + r * (8 ±0)` - // Minimum execution time: 241_609_000 picoseconds. - Weight::from_parts(268_716_874, 6801) - // Standard Error: 617 - .saturating_add(Weight::from_parts(377_753, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `865 + r * (8 ±0)` + // Estimated: `9279 + r * (8 ±0)` + // Minimum execution time: 264_227_000 picoseconds. + Weight::from_parts(281_015_995, 9279) + // Standard Error: 710 + .saturating_add(Weight::from_parts(365_734, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -3454,6 +3677,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3467,19 +3692,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `870` - // Estimated: `6808` - // Minimum execution time: 261_296_000 picoseconds. - Weight::from_parts(255_531_654, 6808) + // Measured: `873` + // Estimated: `9286` + // Minimum execution time: 270_709_000 picoseconds. + Weight::from_parts(268_416_051, 9286) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_081, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(Weight::from_parts(1_080, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3493,13 +3720,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (8 ±0)` - // Estimated: `6806 + r * (8 ±0)` - // Minimum execution time: 243_583_000 picoseconds. - Weight::from_parts(270_025_058, 6806) - // Standard Error: 560 - .saturating_add(Weight::from_parts(767_519, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `867 + r * (8 ±0)` + // Estimated: `9284 + r * (8 ±0)` + // Minimum execution time: 267_283_000 picoseconds. + Weight::from_parts(280_706_659, 9284) + // Standard Error: 540 + .saturating_add(Weight::from_parts(790_312, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -3507,6 +3734,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3520,19 +3749,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872` - // Estimated: `6814` - // Minimum execution time: 253_798_000 picoseconds. - Weight::from_parts(265_542_351, 6814) - // Standard Error: 0 - .saturating_add(Weight::from_parts(3_343, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `875` + // Estimated: `9292` + // Minimum execution time: 262_010_000 picoseconds. + Weight::from_parts(273_278_744, 9292) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_362, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3546,13 +3777,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (8 ±0)` - // Estimated: `6808 + r * (8 ±0)` - // Minimum execution time: 247_332_000 picoseconds. - Weight::from_parts(269_183_656, 6808) - // Standard Error: 665 - .saturating_add(Weight::from_parts(443_386, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `867 + r * (8 ±0)` + // Estimated: `9286 + r * (8 ±0)` + // Minimum execution time: 268_698_000 picoseconds. + Weight::from_parts(282_890_578, 9286) + // Standard Error: 622 + .saturating_add(Weight::from_parts(441_131, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -3560,6 +3791,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3573,19 +3806,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872` - // Estimated: `6813` - // Minimum execution time: 250_855_000 picoseconds. - Weight::from_parts(258_752_975, 6813) + // Measured: `875` + // Estimated: `9291` + // Minimum execution time: 252_846_000 picoseconds. + Weight::from_parts(267_657_561, 9291) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_202, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(Weight::from_parts(1_208, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3599,13 +3834,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (8 ±0)` - // Estimated: `6805 + r * (8 ±0)` - // Minimum execution time: 240_733_000 picoseconds. - Weight::from_parts(269_134_358, 6805) - // Standard Error: 512 - .saturating_add(Weight::from_parts(440_043, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `867 + r * (8 ±0)` + // Estimated: `9283 + r * (8 ±0)` + // Minimum execution time: 266_899_000 picoseconds. + Weight::from_parts(276_862_067, 9283) + // Standard Error: 1_249 + .saturating_add(Weight::from_parts(443_970, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } @@ -3613,6 +3848,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3626,19 +3863,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872` - // Estimated: `6811` - // Minimum execution time: 247_377_000 picoseconds. - Weight::from_parts(261_077_322, 6811) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_195, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `875` + // Estimated: `9289` + // Minimum execution time: 265_413_000 picoseconds. + Weight::from_parts(265_600_840, 9289) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3652,13 +3891,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `997 + n * (1 ±0)` - // Estimated: `6934 + n * (1 ±0)` - // Minimum execution time: 307_337_000 picoseconds. - Weight::from_parts(326_710_473, 6934) - // Standard Error: 9 - .saturating_add(Weight::from_parts(5_765, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `1000 + n * (1 ±0)` + // Estimated: `9412 + n * (1 ±0)` + // Minimum execution time: 328_341_000 picoseconds. + Weight::from_parts(341_038_581, 9412) + // Standard Error: 10 + .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -3666,6 +3905,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3679,13 +3920,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `805 + r * (112 ±0)` - // Estimated: `6748 + r * (112 ±0)` - // Minimum execution time: 245_432_000 picoseconds. - Weight::from_parts(294_206_377, 6748) - // Standard Error: 7_229 - .saturating_add(Weight::from_parts(41_480_485, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `808 + r * (112 ±0)` + // Estimated: `9226 + r * (112 ±0)` + // Minimum execution time: 272_730_000 picoseconds. + Weight::from_parts(339_349_232, 9226) + // Standard Error: 13_004 + .saturating_add(Weight::from_parts(41_649_026, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) } @@ -3693,6 +3934,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3706,13 +3949,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `907 + r * (76 ±0)` - // Estimated: `6802 + r * (77 ±0)` - // Minimum execution time: 247_788_000 picoseconds. - Weight::from_parts(303_940_062, 6802) - // Standard Error: 10_671 - .saturating_add(Weight::from_parts(45_730_772, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `910 + r * (76 ±0)` + // Estimated: `9279 + r * (77 ±0)` + // Minimum execution time: 273_892_000 picoseconds. + Weight::from_parts(352_853_960, 9279) + // Standard Error: 16_745 + .saturating_add(Weight::from_parts(45_853_294, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) } @@ -3720,6 +3963,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3733,13 +3978,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (42 ±0)` - // Estimated: `6816 + r * (42 ±0)` - // Minimum execution time: 248_825_000 picoseconds. - Weight::from_parts(286_832_225, 6816) - // Standard Error: 5_274 - .saturating_add(Weight::from_parts(11_889_262, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `880 + r * (42 ±0)` + // Estimated: `9294 + r * (42 ±0)` + // Minimum execution time: 268_431_000 picoseconds. + Weight::from_parts(319_727_796, 9294) + // Standard Error: 10_276 + .saturating_add(Weight::from_parts(11_928_882, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) } @@ -3747,6 +3992,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) @@ -3761,12 +4008,12 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (965 ±0)` - // Estimated: `6807 + r * (3090 ±7)` - // Minimum execution time: 244_982_000 picoseconds. - Weight::from_parts(265_297_000, 6807) - // Standard Error: 39_895 - .saturating_add(Weight::from_parts(22_435_888, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Estimated: `9285 + r * (3090 ±7)` + // Minimum execution time: 275_482_000 picoseconds. + Weight::from_parts(279_155_000, 9285) + // Standard Error: 65_388 + .saturating_add(Weight::from_parts(26_634_187, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) @@ -3776,6 +4023,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -3787,24 +4036,26 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 32]`. - fn add_delegate_dependency(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `928 + r * (131 ±0)` - // Estimated: `6878 + r * (2606 ±0)` - // Minimum execution time: 246_455_000 picoseconds. - Weight::from_parts(275_334_919, 6878) - // Standard Error: 20_911 - .saturating_add(Weight::from_parts(6_427_525, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + fn lock_delegate_dependency(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `937 + r * (131 ±0)` + // Estimated: `9346 + r * (2607 ±0)` + // Minimum execution time: 270_001_000 picoseconds. + Weight::from_parts(286_792_689, 9346) + // Standard Error: 21_074 + .saturating_add(Weight::from_parts(6_465_885, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2606).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2607).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -3816,15 +4067,15 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 32]`. - fn remove_delegate_dependency(r: u32, ) -> Weight { + fn unlock_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `969 + r * (183 ±0)` + // Measured: `972 + r * (184 ±0)` // Estimated: `129453 + r * (2568 ±0)` - // Minimum execution time: 254_472_000 picoseconds. - Weight::from_parts(280_657_909, 129453) - // Standard Error: 20_131 - .saturating_add(Weight::from_parts(5_644_006, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 270_652_000 picoseconds. + Weight::from_parts(293_369_452, 129453) + // Standard Error: 24_321 + .saturating_add(Weight::from_parts(5_575_600, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -3834,6 +4085,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3847,13 +4100,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `858 + r * (3 ±0)` - // Estimated: `6804 + r * (3 ±0)` - // Minimum execution time: 250_535_000 picoseconds. - Weight::from_parts(270_318_376, 6804) - // Standard Error: 386 - .saturating_add(Weight::from_parts(174_627, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `861 + r * (3 ±0)` + // Estimated: `9282 + r * (3 ±0)` + // Minimum execution time: 267_749_000 picoseconds. + Weight::from_parts(280_373_341, 9282) + // Standard Error: 464 + .saturating_add(Weight::from_parts(170_398, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } @@ -3861,6 +4114,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3874,13 +4129,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2109 + r * (39 ±0)` - // Estimated: `7899 + r * (40 ±0)` - // Minimum execution time: 248_174_000 picoseconds. - Weight::from_parts(301_826_520, 7899) - // Standard Error: 801 - .saturating_add(Weight::from_parts(248_479, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `2112 + r * (39 ±0)` + // Estimated: `10377 + r * (40 ±0)` + // Minimum execution time: 270_260_000 picoseconds. + Weight::from_parts(337_969_172, 10377) + // Standard Error: 1_557 + .saturating_add(Weight::from_parts(305_735, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } @@ -3888,6 +4143,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3903,13 +4160,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `861 + r * (3 ±0)` - // Estimated: `6801 + r * (3 ±0)` - // Minimum execution time: 246_540_000 picoseconds. - Weight::from_parts(268_913_509, 6801) - // Standard Error: 378 - .saturating_add(Weight::from_parts(154_950, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `864 + r * (3 ±0)` + // Estimated: `9279 + r * (3 ±0)` + // Minimum execution time: 265_607_000 picoseconds. + Weight::from_parts(283_396_630, 9279) + // Standard Error: 449 + .saturating_add(Weight::from_parts(149_018, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } @@ -3918,9 +4175,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_777_000 picoseconds. - Weight::from_parts(1_707_601, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(15_392, 0).saturating_mul(r.into())) + // Minimum execution time: 1_813_000 picoseconds. + Weight::from_parts(1_264_945, 0) + // Standard Error: 19 + .saturating_add(Weight::from_parts(15_098, 0).saturating_mul(r.into())) } } diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index eb8a9c61820922ce51d4ece5ac54609e0d4fe435..a5081af2a2d280cc1956dcf2dbb69de18588ccd4 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -23,6 +23,9 @@ scale = { package = "parity-scale-codec", version = "3.6.1", default-features = [target.'cfg(target_arch = "riscv32")'.dependencies] polkavm-derive = '0.5.0' +[package.metadata.docs.rs] +default-target = ["wasm32-unknown-unknown"] + [features] default = ["scale"] scale = ["dep:scale", "scale-info"] diff --git a/substrate/frame/contracts/uapi/src/host.rs b/substrate/frame/contracts/uapi/src/host.rs index c8b9ae8b2def9e253fd6523c0ac15faf6fd36f29..04f58895ab4f6ccebb6452ebeec20038ce7f0d78 100644 --- a/substrate/frame/contracts/uapi/src/host.rs +++ b/substrate/frame/contracts/uapi/src/host.rs @@ -93,7 +93,7 @@ pub trait HostFn { /// - `output`: A reference to the output data buffer to write the address. fn address(output: &mut &mut [u8]); - /// Adds a new delegate dependency to the contract. + /// Lock a new delegate dependency to the contract. /// /// Traps if the maximum number of delegate_dependencies is reached or if /// the delegate dependency already exists. @@ -102,10 +102,7 @@ pub trait HostFn { /// /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps /// otherwise. - #[deprecated( - note = "Unstable function. Behaviour can change without further notice. Use only for testing." - )] - fn add_delegate_dependency(code_hash: &[u8]); + fn lock_delegate_dependency(code_hash: &[u8]); /// Stores the *free* balance of the current account into the supplied buffer. /// @@ -142,6 +139,7 @@ pub trait HostFn { /// /// Equivalent to the newer [`Self::call_v2`] version but works with /// *ref_time* Weight only + #[deprecated(note = "Deprecated, use newer version instead")] fn call_v1( flags: CallFlags, callee: &[u8], @@ -178,14 +176,11 @@ pub trait HostFn { /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] /// - [NotCallable][`crate::ReturnErrorCode::NotCallable] - #[deprecated( - note = "Unstable function. Behaviour can change without further notice. Use only for testing." - )] fn call_v2( flags: CallFlags, callee: &[u8], ref_time_limit: u64, - proof_time_limit: u64, + proof_size_limit: u64, deposit: Option<&[u8]>, value: &[u8], input_data: &[u8], @@ -480,6 +475,7 @@ pub trait HostFn { /// /// Equivalent to the newer [`Self::instantiate_v2`] version but works /// with *ref_time* Weight only. + #[deprecated(note = "Deprecated, use newer version instead")] fn instantiate_v1( code_hash: &[u8], gas: u64, @@ -524,9 +520,6 @@ pub trait HostFn { /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] - #[deprecated( - note = "Unstable function. Behaviour can change without further notice. Use only for testing." - )] fn instantiate_v2( code_hash: &[u8], ref_time_limit: u64, @@ -602,10 +595,7 @@ pub trait HostFn { /// /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps /// otherwise. - #[deprecated( - note = "Unstable function. Behaviour can change without further notice. Use only for testing." - )] - fn remove_delegate_dependency(code_hash: &[u8]); + fn unlock_delegate_dependency(code_hash: &[u8]); /// Cease contract execution and save a data buffer as a result of the execution. /// @@ -792,7 +782,7 @@ pub trait HostFn { #[deprecated( note = "Unstable function. Behaviour can change without further notice. Use only for testing." )] - fn xcm_execute(msg: &[u8], output: &mut &mut [u8]) -> Result; + fn xcm_execute(msg: &[u8]) -> Result; /// Send an XCM program from the contract to the specified destination. /// This is equivalent to dispatching `pallet_xcm::send` through `call_runtime`, except that @@ -804,7 +794,6 @@ pub trait HostFn { /// traps otherwise. /// - `msg`: The message, should be decodable as a [VersionedXcm](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedXcm.html), /// traps otherwise. - /// - `output`: A reference to the output data buffer to write the [XcmHash](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v3/type.XcmHash.html) /// /// # Return /// diff --git a/substrate/frame/contracts/uapi/src/host/riscv32.rs b/substrate/frame/contracts/uapi/src/host/riscv32.rs index b1934cc469e4b5cf92d8bb861bbbe073415b1789..561ab28747df9e55d105d6db09f4776d5e453e28 100644 --- a/substrate/frame/contracts/uapi/src/host/riscv32.rs +++ b/substrate/frame/contracts/uapi/src/host/riscv32.rs @@ -130,7 +130,7 @@ impl HostFn for HostFnImpl { flags: CallFlags, callee: &[u8], ref_time_limit: u64, - proof_time_limit: u64, + proof_size_limit: u64, deposit: Option<&[u8]>, value: &[u8], input_data: &[u8], @@ -281,11 +281,11 @@ impl HostFn for HostFnImpl { todo!() } - fn add_delegate_dependency(code_hash: &[u8]) { + fn lock_delegate_dependency(code_hash: &[u8]) { todo!() } - fn remove_delegate_dependency(code_hash: &[u8]) { + fn unlock_delegate_dependency(code_hash: &[u8]) { todo!() } @@ -297,7 +297,7 @@ impl HostFn for HostFnImpl { todo!() } - fn xcm_execute(msg: &[u8], output: &mut &mut [u8]) -> Result { + fn xcm_execute(msg: &[u8]) -> Result { todo!() } diff --git a/substrate/frame/contracts/uapi/src/host/wasm32.rs b/substrate/frame/contracts/uapi/src/host/wasm32.rs index 77cf22891e2f5e325aeed102748603b6b3cb1143..bc697238061ab16e47d304bd9583f51f7eb99c0b 100644 --- a/substrate/frame/contracts/uapi/src/host/wasm32.rs +++ b/substrate/frame/contracts/uapi/src/host/wasm32.rs @@ -23,7 +23,7 @@ mod sys { extern "C" { pub fn account_reentrance_count(account_ptr: *const u8) -> u32; - pub fn add_delegate_dependency(code_hash_ptr: *const u8); + pub fn lock_delegate_dependency(code_hash_ptr: *const u8); pub fn address(output_ptr: *mut u8, output_len_ptr: *mut u32); @@ -125,7 +125,7 @@ mod sys { pub fn reentrance_count() -> u32; - pub fn remove_delegate_dependency(code_hash_ptr: *const u8); + pub fn unlock_delegate_dependency(code_hash_ptr: *const u8); pub fn seal_return(flags: u32, data_ptr: *const u8, data_len: u32) -> !; @@ -160,7 +160,7 @@ mod sys { pub fn weight_to_fee(gas: u64, output_ptr: *mut u8, output_len_ptr: *mut u32); - pub fn xcm_execute(msg_ptr: *const u8, msg_len: u32, output_ptr: *mut u8) -> ReturnCode; + pub fn xcm_execute(msg_ptr: *const u8, msg_len: u32) -> ReturnCode; pub fn xcm_send( dest_ptr: *const u8, @@ -223,7 +223,7 @@ mod sys { pub fn weight_to_fee( ref_time_limit: u64, - proof_time_limit: u64, + proof_size_limit: u64, output_ptr: *mut u8, output_len_ptr: *mut u32, ); @@ -239,7 +239,7 @@ mod sys { flags: u32, callee_ptr: *const u8, ref_time_limit: u64, - proof_time_limit: u64, + proof_size_limit: u64, deposit_ptr: *const u8, transferred_value_ptr: *const u8, input_data_ptr: *const u8, @@ -251,7 +251,7 @@ mod sys { pub fn instantiate( code_hash_ptr: *const u8, ref_time_limit: u64, - proof_time_limit: u64, + proof_size_limit: u64, deposit_ptr: *const u8, value_ptr: *const u8, input_ptr: *const u8, @@ -301,6 +301,7 @@ macro_rules! impl_wrapper_for { unsafe { $( $mod )::*::$name(output.as_mut_ptr(), &mut output_len); } + extract_from_slice(output, output_len as usize) } } }; @@ -487,7 +488,7 @@ impl HostFn for HostFnImpl { flags: CallFlags, callee: &[u8], ref_time_limit: u64, - proof_time_limit: u64, + proof_size_limit: u64, deposit: Option<&[u8]>, value: &[u8], input_data: &[u8], @@ -501,7 +502,7 @@ impl HostFn for HostFnImpl { flags.bits(), callee.as_ptr(), ref_time_limit, - proof_time_limit, + proof_size_limit, deposit_ptr, value.as_ptr(), input_data.as_ptr(), @@ -803,12 +804,12 @@ impl HostFn for HostFnImpl { unsafe { sys::account_reentrance_count(account.as_ptr()) } } - fn add_delegate_dependency(code_hash: &[u8]) { - unsafe { sys::add_delegate_dependency(code_hash.as_ptr()) } + fn lock_delegate_dependency(code_hash: &[u8]) { + unsafe { sys::lock_delegate_dependency(code_hash.as_ptr()) } } - fn remove_delegate_dependency(code_hash: &[u8]) { - unsafe { sys::remove_delegate_dependency(code_hash.as_ptr()) } + fn unlock_delegate_dependency(code_hash: &[u8]) { + unsafe { sys::unlock_delegate_dependency(code_hash.as_ptr()) } } fn instantiation_nonce() -> u64 { @@ -819,9 +820,8 @@ impl HostFn for HostFnImpl { unsafe { sys::reentrance_count() } } - fn xcm_execute(msg: &[u8], output: &mut &mut [u8]) -> Result { - let ret_code = - unsafe { sys::xcm_execute(msg.as_ptr(), msg.len() as _, output.as_mut_ptr()) }; + fn xcm_execute(msg: &[u8]) -> Result { + let ret_code = unsafe { sys::xcm_execute(msg.as_ptr(), msg.len() as _) }; ret_code.into() } diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index 28ef8cd32fb2b31147b23b32383991e583e8b642..ff5af995026f39527780d964aea16ec13be1ec2b 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "max-encoded-len", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", features = ["derive"], optional = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/conviction-voting/src/lib.rs b/substrate/frame/conviction-voting/src/lib.rs index 1d6fbaa38694233a6766410728bf8efec0671d0e..466fc70a619b649e4b1aade0002e506dde430a1e 100644 --- a/substrate/frame/conviction-voting/src/lib.rs +++ b/substrate/frame/conviction-voting/src/lib.rs @@ -185,7 +185,7 @@ pub mod pallet { /// The account is already delegating. AlreadyDelegating, /// The account currently has votes attached to it and the operation cannot succeed until - /// these are removed, either through `unvote` or `reap_vote`. + /// these are removed through `remove_vote`. AlreadyVoting, /// Too high a balance was provided that the account cannot afford. InsufficientFunds, @@ -231,8 +231,8 @@ pub mod pallet { /// /// The dispatch origin of this call must be _Signed_, and the signing account must either: /// - be delegating already; or - /// - have no voting activity (if there is, then it will need to be removed/consolidated - /// through `reap_vote` or `unvote`). + /// - have no voting activity (if there is, then it will need to be removed through + /// `remove_vote`). /// /// - `to`: The account whose voting the `target` account's voting power will follow. /// - `class`: The class of polls to delegate. To delegate multiple classes, multiple calls diff --git a/substrate/frame/conviction-voting/src/tests.rs b/substrate/frame/conviction-voting/src/tests.rs index b67290e7fec59d5fcac665a578fec10f7586b4f1..dbcd643b60ff7c5ac2ec0a0a351650c69c200e37 100644 --- a/substrate/frame/conviction-voting/src/tests.rs +++ b/substrate/frame/conviction-voting/src/tests.rs @@ -23,11 +23,7 @@ use frame_support::{ assert_noop, assert_ok, derive_impl, parameter_types, traits::{ConstU32, ConstU64, Contains, Polling, VoteTally}, }; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; use super::*; use crate as pallet_conviction_voting; @@ -53,29 +49,8 @@ impl Contains for BaseFilter { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = BaseFilter; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/conviction-voting/src/weights.rs b/substrate/frame/conviction-voting/src/weights.rs index 225f5c2cadd6fc3d4cb1dc735cf164d92150327f..75d9e8499ed8e0b3f71d1a15e23b9c26638e44f1 100644 --- a/substrate/frame/conviction-voting/src/weights.rs +++ b/substrate/frame/conviction-voting/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_conviction_voting +//! Autogenerated weights for `pallet_conviction_voting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/conviction-voting/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/conviction-voting/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_conviction_voting. +/// Weight functions needed for `pallet_conviction_voting`. pub trait WeightInfo { fn vote_new() -> Weight; fn vote_existing() -> Weight; @@ -61,280 +60,300 @@ pub trait WeightInfo { fn unlock() -> Weight; } -/// Weights for pallet_conviction_voting using the Substrate node and recommended hardware. +/// Weights for `pallet_conviction_voting` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, 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(59), added: 2534, 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, 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(59), added: 2534, 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13074` + // Measured: `13141` // Estimated: `219984` - // Minimum execution time: 112_936_000 picoseconds. - Weight::from_parts(116_972_000, 219984) + // Minimum execution time: 102_539_000 picoseconds. + Weight::from_parts(105_873_000, 219984) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, 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(59), added: 2534, 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, 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(59), added: 2534, 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `20216` + // Measured: `20283` // Estimated: `219984` - // Minimum execution time: 291_971_000 picoseconds. - Weight::from_parts(301_738_000, 219984) + // Minimum execution time: 275_424_000 picoseconds. + Weight::from_parts(283_690_000, 219984) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// 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(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `19968` + // Measured: `20035` // Estimated: `219984` - // Minimum execution time: 262_582_000 picoseconds. - Weight::from_parts(270_955_000, 219984) + // Minimum execution time: 275_109_000 picoseconds. + Weight::from_parts(281_315_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// 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(366), added: 2841, 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(366), added: 2841, mode: `MaxEncodedLen`) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `12675` + // Measured: `12742` // Estimated: `30706` - // Minimum execution time: 52_909_000 picoseconds. - Weight::from_parts(56_365_000, 30706) + // Minimum execution time: 49_629_000 picoseconds. + Weight::from_parts(51_300_000, 30706) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, 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:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, 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(67), added: 2542, 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 `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `240 + r * (1627 ±0)` + // Measured: `306 + r * (1628 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 54_640_000 picoseconds. - Weight::from_parts(57_185_281, 109992) - // Standard Error: 193_362 - .saturating_add(Weight::from_parts(44_897_418, 0).saturating_mul(r.into())) + // Minimum execution time: 45_776_000 picoseconds. + Weight::from_parts(47_917_822, 109992) + // Standard Error: 124_174 + .saturating_add(Weight::from_parts(43_171_077, 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)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).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:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, 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:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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 `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `406 + r * (1376 ±0)` + // Measured: `472 + r * (1377 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 26_514_000 picoseconds. - Weight::from_parts(28_083_732, 109992) - // Standard Error: 104_905 - .saturating_add(Weight::from_parts(40_722_467, 0).saturating_mul(r.into())) + // Minimum execution time: 23_600_000 picoseconds. + Weight::from_parts(25_001_426, 109992) + // Standard Error: 72_034 + .saturating_add(Weight::from_parts(37_851_873, 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)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).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(59), added: 2534, 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(59), added: 2534, 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(67), added: 2542, mode: `MaxEncodedLen`) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `11734` + // Measured: `11800` // Estimated: `30706` - // Minimum execution time: 71_140_000 picoseconds. - Weight::from_parts(77_388_000, 30706) + // Minimum execution time: 66_247_000 picoseconds. + Weight::from_parts(67_552_000, 30706) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, 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(59), added: 2534, 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, 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(59), added: 2534, 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13074` + // Measured: `13141` // Estimated: `219984` - // Minimum execution time: 112_936_000 picoseconds. - Weight::from_parts(116_972_000, 219984) + // Minimum execution time: 102_539_000 picoseconds. + Weight::from_parts(105_873_000, 219984) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, 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(59), added: 2534, 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, 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(59), added: 2534, 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(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `20216` + // Measured: `20283` // Estimated: `219984` - // Minimum execution time: 291_971_000 picoseconds. - Weight::from_parts(301_738_000, 219984) + // Minimum execution time: 275_424_000 picoseconds. + Weight::from_parts(283_690_000, 219984) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// 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(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `19968` + // Measured: `20035` // Estimated: `219984` - // Minimum execution time: 262_582_000 picoseconds. - Weight::from_parts(270_955_000, 219984) + // Minimum execution time: 275_109_000 picoseconds. + Weight::from_parts(281_315_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// 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(366), added: 2841, 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(366), added: 2841, mode: `MaxEncodedLen`) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `12675` + // Measured: `12742` // Estimated: `30706` - // Minimum execution time: 52_909_000 picoseconds. - Weight::from_parts(56_365_000, 30706) + // Minimum execution time: 49_629_000 picoseconds. + Weight::from_parts(51_300_000, 30706) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, 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:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, 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(67), added: 2542, 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 `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `240 + r * (1627 ±0)` + // Measured: `306 + r * (1628 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 54_640_000 picoseconds. - Weight::from_parts(57_185_281, 109992) - // Standard Error: 193_362 - .saturating_add(Weight::from_parts(44_897_418, 0).saturating_mul(r.into())) + // Minimum execution time: 45_776_000 picoseconds. + Weight::from_parts(47_917_822, 109992) + // Standard Error: 124_174 + .saturating_add(Weight::from_parts(43_171_077, 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)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).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:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, 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:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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 `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `406 + r * (1376 ±0)` + // Measured: `472 + r * (1377 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 26_514_000 picoseconds. - Weight::from_parts(28_083_732, 109992) - // Standard Error: 104_905 - .saturating_add(Weight::from_parts(40_722_467, 0).saturating_mul(r.into())) + // Minimum execution time: 23_600_000 picoseconds. + Weight::from_parts(25_001_426, 109992) + // Standard Error: 72_034 + .saturating_add(Weight::from_parts(37_851_873, 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)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).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(59), added: 2534, 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(59), added: 2534, 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(67), added: 2542, mode: `MaxEncodedLen`) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `11734` + // Measured: `11800` // Estimated: `30706` - // Minimum execution time: 71_140_000 picoseconds. - Weight::from_parts(77_388_000, 30706) + // Minimum execution time: 66_247_000 picoseconds. + Weight::from_parts(67_552_000, 30706) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index 8e59725d317443f14e6a2a0c78dbcb17d001f101..3e678d3274463f46619c19e71be97350fc1c5955 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/core-fellowship/src/lib.rs b/substrate/frame/core-fellowship/src/lib.rs index e3924594321aa60c69efbdb6df61ee9f0b488205..d1b81c3ca134fbe30a14034164e45710cea12317 100644 --- a/substrate/frame/core-fellowship/src/lib.rs +++ b/substrate/frame/core-fellowship/src/lib.rs @@ -56,7 +56,6 @@ //! cannot be approved - they must proceed only to promotion prior to the offboard timeout elapsing. #![cfg_attr(not(feature = "std"), no_std)] -#![recursion_limit = "128"] use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/substrate/frame/core-fellowship/src/weights.rs b/substrate/frame/core-fellowship/src/weights.rs index 8bbfd1a4dd81da2146994f668d722f1e8afa27b6..fce1d3747a8bb283c1ccaf5b8d7be1c113d39d92 100644 --- a/substrate/frame/core-fellowship/src/weights.rs +++ b/substrate/frame/core-fellowship/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_core_fellowship +//! Autogenerated weights for `pallet_core_fellowship` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/core-fellowship/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/core-fellowship/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_core_fellowship. +/// Weight functions needed for `pallet_core_fellowship`. pub trait WeightInfo { fn set_params() -> Weight; fn bump_offboard() -> Weight; @@ -64,336 +63,344 @@ pub trait WeightInfo { fn submit_evidence() -> Weight; } -/// Weights for pallet_core_fellowship using the Substrate node and recommended hardware. +/// Weights for `pallet_core_fellowship` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: CoreFellowship Params (r:0 w:1) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Params` (r:0 w:1) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) fn set_params() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_454_000 picoseconds. - Weight::from_parts(9_804_000, 0) + // Minimum execution time: 7_146_000 picoseconds. + Weight::from_parts(7_426_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Params (r:1 w:0) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:1 w:0) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Params` (r:1 w:0) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn bump_offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `16887` + // Measured: `17274` // Estimated: `19894` - // Minimum execution time: 58_489_000 picoseconds. - Weight::from_parts(60_202_000, 19894) + // Minimum execution time: 54_511_000 picoseconds. + Weight::from_parts(56_995_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Params (r:1 w:0) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:1 w:0) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Params` (r:1 w:0) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn bump_demote() -> Weight { // Proof Size summary in bytes: - // Measured: `16997` + // Measured: `17384` // Estimated: `19894` - // Minimum execution time: 60_605_000 picoseconds. - Weight::from_parts(63_957_000, 19894) + // Minimum execution time: 56_453_000 picoseconds. + Weight::from_parts(59_030_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn set_active() -> Weight { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3514` - // Minimum execution time: 17_816_000 picoseconds. - Weight::from_parts(18_524_000, 3514) + // Minimum execution time: 15_940_000 picoseconds. + Weight::from_parts(16_381_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3514` - // Minimum execution time: 27_249_000 picoseconds. - Weight::from_parts(28_049_000, 3514) + // Minimum execution time: 24_193_000 picoseconds. + Weight::from_parts(24_963_000, 3514) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship Params (r:1 w:0) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Params` (r:1 w:0) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn promote() -> Weight { // Proof Size summary in bytes: // Measured: `16865` // Estimated: `19894` - // Minimum execution time: 56_642_000 picoseconds. - Weight::from_parts(59_353_000, 19894) + // Minimum execution time: 48_138_000 picoseconds. + Weight::from_parts(50_007_000, 19894) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:0 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:0 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) fn offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `359` + // Measured: `293` // Estimated: `3514` - // Minimum execution time: 17_459_000 picoseconds. - Weight::from_parts(18_033_000, 3514) + // Minimum execution time: 15_225_000 picoseconds. + Weight::from_parts(15_730_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) fn import() -> Weight { // Proof Size summary in bytes: // Measured: `313` // Estimated: `3514` - // Minimum execution time: 16_728_000 picoseconds. - Weight::from_parts(17_263_000, 3514) + // Minimum execution time: 14_507_000 picoseconds. + Weight::from_parts(14_935_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) fn approve() -> Weight { // Proof Size summary in bytes: // Measured: `16843` // Estimated: `19894` - // Minimum execution time: 41_487_000 picoseconds. - Weight::from_parts(43_459_000, 19894) + // Minimum execution time: 34_050_000 picoseconds. + Weight::from_parts(36_323_000, 19894) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: CoreFellowship Member (r:1 w:0) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:0) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) fn submit_evidence() -> Weight { // Proof Size summary in bytes: // Measured: `79` // Estimated: `19894` - // Minimum execution time: 26_033_000 picoseconds. - Weight::from_parts(26_612_000, 19894) + // Minimum execution time: 24_016_000 picoseconds. + Weight::from_parts(24_607_000, 19894) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: CoreFellowship Params (r:0 w:1) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Params` (r:0 w:1) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) fn set_params() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_454_000 picoseconds. - Weight::from_parts(9_804_000, 0) + // Minimum execution time: 7_146_000 picoseconds. + Weight::from_parts(7_426_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Params (r:1 w:0) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:1 w:0) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Params` (r:1 w:0) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn bump_offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `16887` + // Measured: `17274` // Estimated: `19894` - // Minimum execution time: 58_489_000 picoseconds. - Weight::from_parts(60_202_000, 19894) + // Minimum execution time: 54_511_000 picoseconds. + Weight::from_parts(56_995_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Params (r:1 w:0) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:1 w:0) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Params` (r:1 w:0) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn bump_demote() -> Weight { // Proof Size summary in bytes: - // Measured: `16997` + // Measured: `17384` // Estimated: `19894` - // Minimum execution time: 60_605_000 picoseconds. - Weight::from_parts(63_957_000, 19894) + // Minimum execution time: 56_453_000 picoseconds. + Weight::from_parts(59_030_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn set_active() -> Weight { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3514` - // Minimum execution time: 17_816_000 picoseconds. - Weight::from_parts(18_524_000, 3514) + // Minimum execution time: 15_940_000 picoseconds. + Weight::from_parts(16_381_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3514` - // Minimum execution time: 27_249_000 picoseconds. - Weight::from_parts(28_049_000, 3514) + // Minimum execution time: 24_193_000 picoseconds. + Weight::from_parts(24_963_000, 3514) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship Params (r:1 w:0) - /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Params` (r:1 w:0) + /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn promote() -> Weight { // Proof Size summary in bytes: // Measured: `16865` // Estimated: `19894` - // Minimum execution time: 56_642_000 picoseconds. - Weight::from_parts(59_353_000, 19894) + // Minimum execution time: 48_138_000 picoseconds. + Weight::from_parts(50_007_000, 19894) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:0 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:0 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) fn offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `359` + // Measured: `293` // Estimated: `3514` - // Minimum execution time: 17_459_000 picoseconds. - Weight::from_parts(18_033_000, 3514) + // Minimum execution time: 15_225_000 picoseconds. + Weight::from_parts(15_730_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) fn import() -> Weight { // Proof Size summary in bytes: // Measured: `313` // Estimated: `3514` - // Minimum execution time: 16_728_000 picoseconds. - Weight::from_parts(17_263_000, 3514) + // Minimum execution time: 14_507_000 picoseconds. + Weight::from_parts(14_935_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: CoreFellowship Member (r:1 w:1) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:1 w:1) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) fn approve() -> Weight { // Proof Size summary in bytes: // Measured: `16843` // Estimated: `19894` - // Minimum execution time: 41_487_000 picoseconds. - Weight::from_parts(43_459_000, 19894) + // Minimum execution time: 34_050_000 picoseconds. + Weight::from_parts(36_323_000, 19894) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: CoreFellowship Member (r:1 w:0) - /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: CoreFellowship MemberEvidence (r:1 w:1) - /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: `CoreFellowship::Member` (r:1 w:0) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) fn submit_evidence() -> Weight { // Proof Size summary in bytes: // Measured: `79` // Estimated: `19894` - // Minimum execution time: 26_033_000 picoseconds. - Weight::from_parts(26_612_000, 19894) + // Minimum execution time: 24_016_000 picoseconds. + Weight::from_parts(24_607_000, 19894) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 0ade0d58a6d91b44965a85b45efd5532c329ba68..9a55cda5340c2fa795fd79b17ee4e2b5f568bed2 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", features = ["derive"], optional = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } @@ -28,7 +28,7 @@ sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] pallet-balances = { path = "../balances" } diff --git a/substrate/frame/democracy/src/lib.rs b/substrate/frame/democracy/src/lib.rs index 089556191cd14eee735d12976ba6b0ed471a4eac..08e2a7599f5542a8b87ce80df8d96b5cf4ee9af5 100644 --- a/substrate/frame/democracy/src/lib.rs +++ b/substrate/frame/democracy/src/lib.rs @@ -211,7 +211,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index 8136fa5c4c97fedd7915ad77fb92e44bd68bb58e..973e0c28eb2f7307d8e18ff3470c7df8d106a609 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -29,9 +29,8 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EnsureSigned, EnsureSignedBy}; use pallet_balances::{BalanceLock, Error as BalancesError}; -use sp_core::H256; use sp_runtime::{ - traits::{BadOrigin, BlakeTwo256, Hash, IdentityLookup}, + traits::{BadOrigin, BlakeTwo256, Hash}, BuildStorage, Perbill, }; mod cancellation; @@ -81,28 +80,8 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; diff --git a/substrate/frame/democracy/src/weights.rs b/substrate/frame/democracy/src/weights.rs index 241f6c3cb38de2c270411cd2d39913f857bbe807..d6097922a82f2cfed77f974dcbaaa64a69c8d82d 100644 --- a/substrate/frame/democracy/src/weights.rs +++ b/substrate/frame/democracy/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_democracy +//! Autogenerated weights for `pallet_democracy` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/democracy/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/democracy/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_democracy. +/// Weight functions needed for `pallet_democracy`. pub trait WeightInfo { fn propose() -> Weight; fn second() -> Weight; @@ -82,904 +81,916 @@ pub trait WeightInfo { fn clear_referendum_metadata() -> Weight; } -/// Weights for pallet_democracy using the Substrate node and recommended hardware. +/// Weights for `pallet_democracy` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Democracy PublicPropCount (r:1 w:1) - /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:0 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicPropCount` (r:1 w:1) + /// Proof: `Democracy::PublicPropCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::PublicProps` (r:1 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:1 w:0) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: `Democracy::DepositOf` (r:0 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) fn propose() -> Weight { // Proof Size summary in bytes: - // Measured: `4801` + // Measured: `4834` // Estimated: `18187` - // Minimum execution time: 49_339_000 picoseconds. - Weight::from_parts(50_942_000, 18187) + // Minimum execution time: 39_930_000 picoseconds. + Weight::from_parts(41_746_000, 18187) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: `Democracy::DepositOf` (r:1 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) fn second() -> Weight { // Proof Size summary in bytes: - // Measured: `3556` + // Measured: `3589` // Estimated: `6695` - // Minimum execution time: 43_291_000 picoseconds. - Weight::from_parts(44_856_000, 6695) + // Minimum execution time: 36_490_000 picoseconds. + Weight::from_parts(37_615_000, 6695) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(67), added: 2542, mode: `MaxEncodedLen`) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3470` + // Measured: `3503` // Estimated: `7260` - // Minimum execution time: 61_890_000 picoseconds. - Weight::from_parts(63_626_000, 7260) + // Minimum execution time: 54_257_000 picoseconds. + Weight::from_parts(55_912_000, 7260) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(67), added: 2542, mode: `MaxEncodedLen`) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3492` + // Measured: `3525` // Estimated: `7260` - // Minimum execution time: 67_802_000 picoseconds. - Weight::from_parts(69_132_000, 7260) + // Minimum execution time: 56_878_000 picoseconds. + Weight::from_parts(58_796_000, 7260) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Cancellations (r:1 w:1) - /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Cancellations` (r:1 w:1) + /// Proof: `Democracy::Cancellations` (`max_values`: None, `max_size`: Some(33), added: 2508, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `366` + // Measured: `399` // Estimated: `3666` - // Minimum execution time: 25_757_000 picoseconds. - Weight::from_parts(27_226_000, 3666) + // Minimum execution time: 22_700_000 picoseconds. + Weight::from_parts(23_539_000, 3666) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:3 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:0 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::DepositOf` (r:1 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:3 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:0 w:1) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5910` + // Measured: `5943` // Estimated: `18187` - // Minimum execution time: 113_060_000 picoseconds. - Weight::from_parts(114_813_000, 18187) + // Minimum execution time: 95_398_000 picoseconds. + Weight::from_parts(97_261_000, 18187) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:1 w:0) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) fn external_propose() -> Weight { // Proof Size summary in bytes: - // Measured: `3416` + // Measured: `3449` // Estimated: `6703` - // Minimum execution time: 13_413_000 picoseconds. - Weight::from_parts(13_794_000, 6703) + // Minimum execution time: 11_745_000 picoseconds. + Weight::from_parts(12_304_000, 6703) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:0 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) fn external_propose_majority() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_213_000 picoseconds. - Weight::from_parts(3_429_000, 0) + // Minimum execution time: 2_710_000 picoseconds. + Weight::from_parts(2_918_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:0 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) fn external_propose_default() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_280_000 picoseconds. - Weight::from_parts(3_389_000, 0) + // Minimum execution time: 2_664_000 picoseconds. + Weight::from_parts(2_776_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:1) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:2) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumCount` (r:1 w:1) + /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:2) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `286` + // Measured: `319` // Estimated: `3518` - // Minimum execution time: 28_142_000 picoseconds. - Weight::from_parts(28_862_000, 3518) + // Minimum execution time: 22_585_000 picoseconds. + Weight::from_parts(23_689_000, 3518) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:1 w:1) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3519` + // Measured: `3552` // Estimated: `6703` - // Minimum execution time: 32_395_000 picoseconds. - Weight::from_parts(33_617_000, 6703) + // Minimum execution time: 26_391_000 picoseconds. + Weight::from_parts(27_141_000, 6703) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::DepositOf` (r:1 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5821` + // Measured: `5854` // Estimated: `18187` - // Minimum execution time: 92_255_000 picoseconds. - Weight::from_parts(93_704_000, 18187) + // Minimum execution time: 77_905_000 picoseconds. + Weight::from_parts(79_628_000, 18187) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `304` // Estimated: `3518` - // Minimum execution time: 19_623_000 picoseconds. - Weight::from_parts(20_545_000, 3518) + // Minimum execution time: 15_735_000 picoseconds. + Weight::from_parts(16_525_000, 3518) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) + /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumCount` (r:1 w:0) + /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (86 ±0)` + // Measured: `277 + r * (86 ±0)` // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 7_032_000 picoseconds. - Weight::from_parts(7_931_421, 1489) - // Standard Error: 7_395 - .saturating_add(Weight::from_parts(3_236_964, 0).saturating_mul(r.into())) + // Minimum execution time: 5_274_000 picoseconds. + Weight::from_parts(6_162_399, 1489) + // Standard Error: 6_924 + .saturating_add(Weight::from_parts(3_186_702, 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)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy LastTabledWasExternal (r:1 w:0) - /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) + /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumCount` (r:1 w:0) + /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::LastTabledWasExternal` (r:1 w:0) + /// Proof: `Democracy::LastTabledWasExternal` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `Democracy::NextExternal` (r:1 w:0) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::PublicProps` (r:1 w:0) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (86 ±0)` + // Measured: `277 + r * (86 ±0)` // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 10_524_000 picoseconds. - Weight::from_parts(10_369_064, 18187) - // Standard Error: 8_385 - .saturating_add(Weight::from_parts(3_242_334, 0).saturating_mul(r.into())) + // Minimum execution time: 7_950_000 picoseconds. + Weight::from_parts(7_381_228, 18187) + // Standard Error: 6_650 + .saturating_add(Weight::from_parts(3_198_515, 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)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy VotingOf (r:3 w:3) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, 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: `Democracy::VotingOf` (r:3 w:3) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, 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(67), added: 2542, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (108 ±0)` + // Measured: `863 + r * (108 ±0)` // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 46_106_000 picoseconds. - Weight::from_parts(48_936_654, 19800) - // Standard Error: 8_879 - .saturating_add(Weight::from_parts(4_708_141, 0).saturating_mul(r.into())) + // Minimum execution time: 40_109_000 picoseconds. + Weight::from_parts(43_164_384, 19800) + // Standard Error: 7_267 + .saturating_add(Weight::from_parts(4_161_526, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy VotingOf (r:2 w:2) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::VotingOf` (r:2 w:2) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `493 + r * (108 ±0)` + // Measured: `526 + r * (108 ±0)` // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 21_078_000 picoseconds. - Weight::from_parts(22_732_737, 13530) - // Standard Error: 7_969 - .saturating_add(Weight::from_parts(4_626_458, 0).saturating_mul(r.into())) + // Minimum execution time: 17_466_000 picoseconds. + Weight::from_parts(18_004_456, 13530) + // Standard Error: 6_327 + .saturating_add(Weight::from_parts(4_194_583, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy PublicProps (r:0 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:0 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) fn clear_public_proposals() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_229_000 picoseconds. - Weight::from_parts(3_415_000, 0) + // Minimum execution time: 2_824_000 picoseconds. + Weight::from_parts(2_948_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(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 `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `596` // Estimated: `7260` - // Minimum execution time: 25_735_000 picoseconds. - Weight::from_parts(41_341_468, 7260) - // Standard Error: 3_727 - .saturating_add(Weight::from_parts(94_755, 0).saturating_mul(r.into())) + // Minimum execution time: 23_373_000 picoseconds. + Weight::from_parts(34_306_582, 7260) + // Standard Error: 2_849 + .saturating_add(Weight::from_parts(85_027, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(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 `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `564 + r * (22 ±0)` + // Measured: `597 + r * (22 ±0)` // Estimated: `7260` - // Minimum execution time: 36_233_000 picoseconds. - Weight::from_parts(39_836_017, 7260) - // Standard Error: 1_791 - .saturating_add(Weight::from_parts(132_158, 0).saturating_mul(r.into())) + // Minimum execution time: 31_574_000 picoseconds. + Weight::from_parts(33_906_658, 7260) + // Standard Error: 1_514 + .saturating_add(Weight::from_parts(124_471, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + r * (26 ±0)` + // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 16_081_000 picoseconds. - Weight::from_parts(19_624_101, 7260) - // Standard Error: 1_639 - .saturating_add(Weight::from_parts(133_630, 0).saturating_mul(r.into())) + // Minimum execution time: 15_204_000 picoseconds. + Weight::from_parts(18_405_879, 7260) + // Standard Error: 1_851 + .saturating_add(Weight::from_parts(119_018, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + r * (26 ±0)` + // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_634_000 picoseconds. - Weight::from_parts(19_573_407, 7260) - // Standard Error: 1_790 - .saturating_add(Weight::from_parts(139_707, 0).saturating_mul(r.into())) + // Minimum execution time: 15_120_000 picoseconds. + Weight::from_parts(18_282_222, 7260) + // Standard Error: 1_669 + .saturating_add(Weight::from_parts(127_649, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:0) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, 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: `Democracy::MetadataOf` (r:0 w:1) + /// 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: `356` + // Measured: `456` // Estimated: `3556` - // Minimum execution time: 18_344_000 picoseconds. - Weight::from_parts(18_727_000, 3556) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 17_351_000 picoseconds. + Weight::from_parts(17_964_000, 3556) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:0) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `286` + // Measured: `319` // Estimated: `3518` - // Minimum execution time: 16_497_000 picoseconds. - Weight::from_parts(16_892_000, 3518) + // Minimum execution time: 13_669_000 picoseconds. + Weight::from_parts(14_410_000, 3518) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:0) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, 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: `Democracy::MetadataOf` (r:0 w:1) + /// 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: `4888` + // Measured: `4988` // Estimated: `18187` - // Minimum execution time: 39_517_000 picoseconds. - Weight::from_parts(40_632_000, 18187) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 39_162_000 picoseconds. + Weight::from_parts(40_109_000, 18187) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:0) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4822` + // Measured: `4855` // Estimated: `18187` - // Minimum execution time: 37_108_000 picoseconds. - Weight::from_parts(37_599_000, 18187) + // Minimum execution time: 34_141_000 picoseconds. + Weight::from_parts(34_732_000, 18187) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, 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: `Democracy::MetadataOf` (r:0 w:1) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 13_997_000 picoseconds. - Weight::from_parts(14_298_000, 3556) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 13_413_000 picoseconds. + Weight::from_parts(14_039_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:0) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `302` + // Measured: `335` // Estimated: `3666` - // Minimum execution time: 18_122_000 picoseconds. - Weight::from_parts(18_655_000, 3666) + // Minimum execution time: 16_010_000 picoseconds. + Weight::from_parts(16_474_000, 3666) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Democracy PublicPropCount (r:1 w:1) - /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:0 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicPropCount` (r:1 w:1) + /// Proof: `Democracy::PublicPropCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::PublicProps` (r:1 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:1 w:0) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: `Democracy::DepositOf` (r:0 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) fn propose() -> Weight { // Proof Size summary in bytes: - // Measured: `4801` + // Measured: `4834` // Estimated: `18187` - // Minimum execution time: 49_339_000 picoseconds. - Weight::from_parts(50_942_000, 18187) + // Minimum execution time: 39_930_000 picoseconds. + Weight::from_parts(41_746_000, 18187) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: `Democracy::DepositOf` (r:1 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) fn second() -> Weight { // Proof Size summary in bytes: - // Measured: `3556` + // Measured: `3589` // Estimated: `6695` - // Minimum execution time: 43_291_000 picoseconds. - Weight::from_parts(44_856_000, 6695) + // Minimum execution time: 36_490_000 picoseconds. + Weight::from_parts(37_615_000, 6695) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(67), added: 2542, mode: `MaxEncodedLen`) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3470` + // Measured: `3503` // Estimated: `7260` - // Minimum execution time: 61_890_000 picoseconds. - Weight::from_parts(63_626_000, 7260) + // Minimum execution time: 54_257_000 picoseconds. + Weight::from_parts(55_912_000, 7260) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(67), added: 2542, mode: `MaxEncodedLen`) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3492` + // Measured: `3525` // Estimated: `7260` - // Minimum execution time: 67_802_000 picoseconds. - Weight::from_parts(69_132_000, 7260) + // Minimum execution time: 56_878_000 picoseconds. + Weight::from_parts(58_796_000, 7260) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Cancellations (r:1 w:1) - /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Cancellations` (r:1 w:1) + /// Proof: `Democracy::Cancellations` (`max_values`: None, `max_size`: Some(33), added: 2508, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `366` + // Measured: `399` // Estimated: `3666` - // Minimum execution time: 25_757_000 picoseconds. - Weight::from_parts(27_226_000, 3666) + // Minimum execution time: 22_700_000 picoseconds. + Weight::from_parts(23_539_000, 3666) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:3 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:0 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::DepositOf` (r:1 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:3 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:0 w:1) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5910` + // Measured: `5943` // Estimated: `18187` - // Minimum execution time: 113_060_000 picoseconds. - Weight::from_parts(114_813_000, 18187) + // Minimum execution time: 95_398_000 picoseconds. + Weight::from_parts(97_261_000, 18187) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:1 w:0) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) fn external_propose() -> Weight { // Proof Size summary in bytes: - // Measured: `3416` + // Measured: `3449` // Estimated: `6703` - // Minimum execution time: 13_413_000 picoseconds. - Weight::from_parts(13_794_000, 6703) + // Minimum execution time: 11_745_000 picoseconds. + Weight::from_parts(12_304_000, 6703) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:0 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) fn external_propose_majority() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_213_000 picoseconds. - Weight::from_parts(3_429_000, 0) + // Minimum execution time: 2_710_000 picoseconds. + Weight::from_parts(2_918_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:0 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) fn external_propose_default() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_280_000 picoseconds. - Weight::from_parts(3_389_000, 0) + // Minimum execution time: 2_664_000 picoseconds. + Weight::from_parts(2_776_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:1) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:2) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumCount` (r:1 w:1) + /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:2) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `286` + // Measured: `319` // Estimated: `3518` - // Minimum execution time: 28_142_000 picoseconds. - Weight::from_parts(28_862_000, 3518) + // Minimum execution time: 22_585_000 picoseconds. + Weight::from_parts(23_689_000, 3518) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:1) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::Blacklist` (r:1 w:1) + /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3519` + // Measured: `3552` // Estimated: `6703` - // Minimum execution time: 32_395_000 picoseconds. - Weight::from_parts(33_617_000, 6703) + // Minimum execution time: 26_391_000 picoseconds. + Weight::from_parts(27_141_000, 6703) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::DepositOf` (r:1 w:1) + /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5821` + // Measured: `5854` // Estimated: `18187` - // Minimum execution time: 92_255_000 picoseconds. - Weight::from_parts(93_704_000, 18187) + // Minimum execution time: 77_905_000 picoseconds. + Weight::from_parts(79_628_000, 18187) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `304` // Estimated: `3518` - // Minimum execution time: 19_623_000 picoseconds. - Weight::from_parts(20_545_000, 3518) + // Minimum execution time: 15_735_000 picoseconds. + Weight::from_parts(16_525_000, 3518) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) + /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumCount` (r:1 w:0) + /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (86 ±0)` + // Measured: `277 + r * (86 ±0)` // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 7_032_000 picoseconds. - Weight::from_parts(7_931_421, 1489) - // Standard Error: 7_395 - .saturating_add(Weight::from_parts(3_236_964, 0).saturating_mul(r.into())) + // Minimum execution time: 5_274_000 picoseconds. + Weight::from_parts(6_162_399, 1489) + // Standard Error: 6_924 + .saturating_add(Weight::from_parts(3_186_702, 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)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy LastTabledWasExternal (r:1 w:0) - /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) + /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumCount` (r:1 w:0) + /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Democracy::LastTabledWasExternal` (r:1 w:0) + /// Proof: `Democracy::LastTabledWasExternal` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `Democracy::NextExternal` (r:1 w:0) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::PublicProps` (r:1 w:0) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (86 ±0)` + // Measured: `277 + r * (86 ±0)` // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 10_524_000 picoseconds. - Weight::from_parts(10_369_064, 18187) - // Standard Error: 8_385 - .saturating_add(Weight::from_parts(3_242_334, 0).saturating_mul(r.into())) + // Minimum execution time: 7_950_000 picoseconds. + Weight::from_parts(7_381_228, 18187) + // Standard Error: 6_650 + .saturating_add(Weight::from_parts(3_198_515, 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)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy VotingOf (r:3 w:3) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, 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: `Democracy::VotingOf` (r:3 w:3) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, 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(67), added: 2542, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `830 + r * (108 ±0)` + // Measured: `863 + r * (108 ±0)` // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 46_106_000 picoseconds. - Weight::from_parts(48_936_654, 19800) - // Standard Error: 8_879 - .saturating_add(Weight::from_parts(4_708_141, 0).saturating_mul(r.into())) + // Minimum execution time: 40_109_000 picoseconds. + Weight::from_parts(43_164_384, 19800) + // Standard Error: 7_267 + .saturating_add(Weight::from_parts(4_161_526, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy VotingOf (r:2 w:2) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: `Democracy::VotingOf` (r:2 w:2) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `493 + r * (108 ±0)` + // Measured: `526 + r * (108 ±0)` // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 21_078_000 picoseconds. - Weight::from_parts(22_732_737, 13530) - // Standard Error: 7_969 - .saturating_add(Weight::from_parts(4_626_458, 0).saturating_mul(r.into())) + // Minimum execution time: 17_466_000 picoseconds. + Weight::from_parts(18_004_456, 13530) + // Standard Error: 6_327 + .saturating_add(Weight::from_parts(4_194_583, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: Democracy PublicProps (r:0 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:0 w:1) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) fn clear_public_proposals() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_229_000 picoseconds. - Weight::from_parts(3_415_000, 0) + // Minimum execution time: 2_824_000 picoseconds. + Weight::from_parts(2_948_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(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 `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `596` // Estimated: `7260` - // Minimum execution time: 25_735_000 picoseconds. - Weight::from_parts(41_341_468, 7260) - // Standard Error: 3_727 - .saturating_add(Weight::from_parts(94_755, 0).saturating_mul(r.into())) + // Minimum execution time: 23_373_000 picoseconds. + Weight::from_parts(34_306_582, 7260) + // Standard Error: 2_849 + .saturating_add(Weight::from_parts(85_027, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, 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(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 `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `564 + r * (22 ±0)` + // Measured: `597 + r * (22 ±0)` // Estimated: `7260` - // Minimum execution time: 36_233_000 picoseconds. - Weight::from_parts(39_836_017, 7260) - // Standard Error: 1_791 - .saturating_add(Weight::from_parts(132_158, 0).saturating_mul(r.into())) + // Minimum execution time: 31_574_000 picoseconds. + Weight::from_parts(33_906_658, 7260) + // Standard Error: 1_514 + .saturating_add(Weight::from_parts(124_471, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + r * (26 ±0)` + // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 16_081_000 picoseconds. - Weight::from_parts(19_624_101, 7260) - // Standard Error: 1_639 - .saturating_add(Weight::from_parts(133_630, 0).saturating_mul(r.into())) + // Minimum execution time: 15_204_000 picoseconds. + Weight::from_parts(18_405_879, 7260) + // Standard Error: 1_851 + .saturating_add(Weight::from_parts(119_018, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::VotingOf` (r:1 w:1) + /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + r * (26 ±0)` + // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_634_000 picoseconds. - Weight::from_parts(19_573_407, 7260) - // Standard Error: 1_790 - .saturating_add(Weight::from_parts(139_707, 0).saturating_mul(r.into())) + // Minimum execution time: 15_120_000 picoseconds. + Weight::from_parts(18_282_222, 7260) + // Standard Error: 1_669 + .saturating_add(Weight::from_parts(127_649, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:0) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, 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: `Democracy::MetadataOf` (r:0 w:1) + /// 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: `356` + // Measured: `456` // Estimated: `3556` - // Minimum execution time: 18_344_000 picoseconds. - Weight::from_parts(18_727_000, 3556) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 17_351_000 picoseconds. + Weight::from_parts(17_964_000, 3556) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::NextExternal` (r:1 w:0) + /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `286` + // Measured: `319` // Estimated: `3518` - // Minimum execution time: 16_497_000 picoseconds. - Weight::from_parts(16_892_000, 3518) + // Minimum execution time: 13_669_000 picoseconds. + Weight::from_parts(14_410_000, 3518) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:0) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, 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: `Democracy::MetadataOf` (r:0 w:1) + /// 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: `4888` + // Measured: `4988` // Estimated: `18187` - // Minimum execution time: 39_517_000 picoseconds. - Weight::from_parts(40_632_000, 18187) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 39_162_000 picoseconds. + Weight::from_parts(40_109_000, 18187) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::PublicProps` (r:1 w:0) + /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4822` + // Measured: `4855` // Estimated: `18187` - // Minimum execution time: 37_108_000 picoseconds. - Weight::from_parts(37_599_000, 18187) + // Minimum execution time: 34_141_000 picoseconds. + Weight::from_parts(34_732_000, 18187) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, 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: `Democracy::MetadataOf` (r:0 w:1) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 13_997_000 picoseconds. - Weight::from_parts(14_298_000, 3556) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 13_413_000 picoseconds. + Weight::from_parts(14_039_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Democracy ReferendumInfoOf (r:1 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:0) + /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: `Democracy::MetadataOf` (r:1 w:1) + /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `302` + // Measured: `335` // Estimated: `3666` - // Minimum execution time: 18_122_000 picoseconds. - Weight::from_parts(18_655_000, 3666) + // Minimum execution time: 16_010_000 picoseconds. + Weight::from_parts(16_474_000, 3666) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index 91bdb3c027ffb45a6ec5f4eca6b1f61ee454cdf6..eadce8c1ff847b2902d2d3ca9eb21d797060da4f 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = [ "derive", ] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 4f43f89abed222f963156c2f5afaebb8288bf45a..6bf4dfe4f1eb993e35a99a34bd21b2bde81d4355 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1343,7 +1343,7 @@ pub mod pallet { #[pallet::getter(fn minimum_untrusted_score)] pub type MinimumUntrustedScore = StorageValue<_, ElectionScore>; - /// The current storage version. + /// The in-code storage version. /// /// v1: https://github.com/paritytech/substrate/pull/12237/ const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); diff --git a/substrate/frame/election-provider-multi-phase/src/migrations.rs b/substrate/frame/election-provider-multi-phase/src/migrations.rs index 50b821e6db6ae8c7a2cc68192f9dd8cb39e9f460..156f1c02e27cd23e3e37014650fdff66115cd18f 100644 --- a/substrate/frame/election-provider-multi-phase/src/migrations.rs +++ b/substrate/frame/election-provider-multi-phase/src/migrations.rs @@ -27,12 +27,12 @@ pub mod v1 { pub struct MigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); log!( info, - "Running migration with current storage version {:?} / onchain {:?}", + "Running migration with in-code storage version {:?} / onchain {:?}", current, onchain ); diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 18dcd7061c1fc35c7cc64134c33363b746e9baf8..312dc5570900beb19812e5d7667804568997a7a2 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -441,7 +441,7 @@ where type Extrinsic = Extrinsic; } -pub type Extrinsic = sp_runtime::testing::TestXt; +pub type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; parameter_types! { pub MaxNominations: u32 = ::LIMIT as u32; diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 94348181334061a3c2de81b90742f53c4390ddc9..94cfd059b6c5b05a5add5c08cd946d011d7085ad 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -1813,7 +1813,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 { .. }))); }) } @@ -1830,7 +1830,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 be578fac8c435769de3b030a4c7fb20832786b83..ed3e942716e265837dd0021b917222b1d3eba4aa 100644 --- a/substrate/frame/election-provider-multi-phase/src/weights.rs +++ b/substrate/frame/election-provider-multi-phase/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_election_provider_multi_phase +//! Autogenerated weights for `pallet_election_provider_multi_phase` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/election-provider-multi-phase/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/election-provider-multi-phase/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_election_provider_multi_phase. +/// Weight functions needed for `pallet_election_provider_multi_phase`. pub trait WeightInfo { fn on_initialize_nothing() -> Weight; fn on_initialize_open_signed() -> Weight; @@ -64,169 +63,171 @@ pub trait WeightInfo { fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight; } -/// Weights for pallet_election_provider_multi_phase using the Substrate node and recommended hardware. +/// Weights for `pallet_election_provider_multi_phase` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentPlannedSession (r:1 w:0) - /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Babe EpochIndex (r:1 w:0) - /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe GenesisSlot (r:1 w:0) - /// Proof: Babe GenesisSlot (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: Staking ForceEra (r:1 w:0) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentPlannedSession` (r:1 w:0) + /// Proof: `Staking::CurrentPlannedSession` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStartSessionIndex` (r:1 w:0) + /// Proof: `Staking::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `Babe::EpochIndex` (r:1 w:0) + /// Proof: `Babe::EpochIndex` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Babe::GenesisSlot` (r:1 w:0) + /// Proof: `Babe::GenesisSlot` (`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: `Staking::ForceEra` (r:1 w:0) + /// Proof: `Staking::ForceEra` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: - // Measured: `1028` + // Measured: `1061` // Estimated: `3481` - // Minimum execution time: 22_089_000 picoseconds. - Weight::from_parts(22_677_000, 3481) + // Minimum execution time: 19_340_000 picoseconds. + Weight::from_parts(19_886_000, 3481) .saturating_add(T::DbWeight::get().reads(8_u64)) } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 11_986_000 picoseconds. - Weight::from_parts(12_445_000, 1633) + // Minimum execution time: 8_067_000 picoseconds. + Weight::from_parts(8_508_000, 1633) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 12_988_000 picoseconds. - Weight::from_parts(13_281_000, 1633) + // Minimum execution time: 8_810_000 picoseconds. + Weight::from_parts(9_061_000, 1633) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 32_659_000 picoseconds. - Weight::from_parts(33_281_000, 3593) + // Minimum execution time: 24_339_000 picoseconds. + Weight::from_parts(25_322_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn finalize_signed_phase_reject_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 22_471_000 picoseconds. - Weight::from_parts(23_046_000, 3593) + // Minimum execution time: 16_635_000 picoseconds. + Weight::from_parts(17_497_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 262_360_000 picoseconds. - Weight::from_parts(279_313_000, 0) - // Standard Error: 2_384 - .saturating_add(Weight::from_parts(176_415, 0).saturating_mul(v.into())) + // Minimum execution time: 170_730_000 picoseconds. + Weight::from_parts(175_009_000, 0) + // Standard Error: 2_010 + .saturating_add(Weight::from_parts(224_974, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) + /// 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: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + a * (768 ±0) + d * (48 ±0)` // Estimated: `3923 + a * (768 ±0) + d * (49 ±0)` - // Minimum execution time: 301_283_000 picoseconds. - Weight::from_parts(324_586_000, 3923) - // Standard Error: 4_763 - .saturating_add(Weight::from_parts(279_812, 0).saturating_mul(a.into())) + // Minimum execution time: 280_705_000 picoseconds. + Weight::from_parts(303_018_000, 3923) + // Standard Error: 4_633 + .saturating_add(Weight::from_parts(307_274, 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())) .saturating_add(Weight::from_parts(0, 49).saturating_mul(d.into())) } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (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 SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) + /// 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: 52_276_000 picoseconds. - Weight::from_parts(53_846_000, 2412) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 43_405_000 picoseconds. + Weight::from_parts(45_734_000, 2412) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -235,25 +236,25 @@ 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_448_459_000 picoseconds. - Weight::from_parts(5_525_622_000, 1738) - // Standard Error: 21_478 - .saturating_add(Weight::from_parts(256_345, 0).saturating_mul(v.into())) - // Standard Error: 63_648 - .saturating_add(Weight::from_parts(5_103_224, 0).saturating_mul(a.into())) + // Minimum execution time: 5_059_092_000 picoseconds. + Weight::from_parts(5_263_076_000, 1738) + // Standard Error: 17_317 + .saturating_add(Weight::from_parts(384_051, 0).saturating_mul(v.into())) + // Standard Error: 51_319 + .saturating_add(Weight::from_parts(4_095_128, 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())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -262,180 +263,182 @@ 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_724_399_000 picoseconds. - Weight::from_parts(4_886_472_000, 1713) - // Standard Error: 15_220 - .saturating_add(Weight::from_parts(365_569, 0).saturating_mul(v.into())) - // Standard Error: 45_104 - .saturating_add(Weight::from_parts(3_176_675, 0).saturating_mul(a.into())) + // Minimum execution time: 4_426_416_000 picoseconds. + Weight::from_parts(4_466_923_000, 1713) + // Standard Error: 15_415 + .saturating_add(Weight::from_parts(334_047, 0).saturating_mul(v.into())) + // Standard Error: 45_682 + .saturating_add(Weight::from_parts(3_097_318, 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())) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentPlannedSession (r:1 w:0) - /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Babe EpochIndex (r:1 w:0) - /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe GenesisSlot (r:1 w:0) - /// Proof: Babe GenesisSlot (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: Staking ForceEra (r:1 w:0) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentPlannedSession` (r:1 w:0) + /// Proof: `Staking::CurrentPlannedSession` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStartSessionIndex` (r:1 w:0) + /// Proof: `Staking::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `Babe::EpochIndex` (r:1 w:0) + /// Proof: `Babe::EpochIndex` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Babe::GenesisSlot` (r:1 w:0) + /// Proof: `Babe::GenesisSlot` (`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: `Staking::ForceEra` (r:1 w:0) + /// Proof: `Staking::ForceEra` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: - // Measured: `1028` + // Measured: `1061` // Estimated: `3481` - // Minimum execution time: 22_089_000 picoseconds. - Weight::from_parts(22_677_000, 3481) + // Minimum execution time: 19_340_000 picoseconds. + Weight::from_parts(19_886_000, 3481) .saturating_add(RocksDbWeight::get().reads(8_u64)) } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 11_986_000 picoseconds. - Weight::from_parts(12_445_000, 1633) + // Minimum execution time: 8_067_000 picoseconds. + Weight::from_parts(8_508_000, 1633) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 12_988_000 picoseconds. - Weight::from_parts(13_281_000, 1633) + // Minimum execution time: 8_810_000 picoseconds. + Weight::from_parts(9_061_000, 1633) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 32_659_000 picoseconds. - Weight::from_parts(33_281_000, 3593) + // Minimum execution time: 24_339_000 picoseconds. + Weight::from_parts(25_322_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn finalize_signed_phase_reject_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 22_471_000 picoseconds. - Weight::from_parts(23_046_000, 3593) + // Minimum execution time: 16_635_000 picoseconds. + Weight::from_parts(17_497_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 262_360_000 picoseconds. - Weight::from_parts(279_313_000, 0) - // Standard Error: 2_384 - .saturating_add(Weight::from_parts(176_415, 0).saturating_mul(v.into())) + // Minimum execution time: 170_730_000 picoseconds. + Weight::from_parts(175_009_000, 0) + // Standard Error: 2_010 + .saturating_add(Weight::from_parts(224_974, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) + /// 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: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + a * (768 ±0) + d * (48 ±0)` // Estimated: `3923 + a * (768 ±0) + d * (49 ±0)` - // Minimum execution time: 301_283_000 picoseconds. - Weight::from_parts(324_586_000, 3923) - // Standard Error: 4_763 - .saturating_add(Weight::from_parts(279_812, 0).saturating_mul(a.into())) + // Minimum execution time: 280_705_000 picoseconds. + Weight::from_parts(303_018_000, 3923) + // Standard Error: 4_633 + .saturating_add(Weight::from_parts(307_274, 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())) .saturating_add(Weight::from_parts(0, 49).saturating_mul(d.into())) } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (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 SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) + /// 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: 52_276_000 picoseconds. - Weight::from_parts(53_846_000, 2412) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 43_405_000 picoseconds. + Weight::from_parts(45_734_000, 2412) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) + /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -444,25 +447,25 @@ 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_448_459_000 picoseconds. - Weight::from_parts(5_525_622_000, 1738) - // Standard Error: 21_478 - .saturating_add(Weight::from_parts(256_345, 0).saturating_mul(v.into())) - // Standard Error: 63_648 - .saturating_add(Weight::from_parts(5_103_224, 0).saturating_mul(a.into())) + // Minimum execution time: 5_059_092_000 picoseconds. + Weight::from_parts(5_263_076_000, 1738) + // Standard Error: 17_317 + .saturating_add(Weight::from_parts(384_051, 0).saturating_mul(v.into())) + // Standard Error: 51_319 + .saturating_add(Weight::from_parts(4_095_128, 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())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -471,12 +474,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_724_399_000 picoseconds. - Weight::from_parts(4_886_472_000, 1713) - // Standard Error: 15_220 - .saturating_add(Weight::from_parts(365_569, 0).saturating_mul(v.into())) - // Standard Error: 45_104 - .saturating_add(Weight::from_parts(3_176_675, 0).saturating_mul(a.into())) + // Minimum execution time: 4_426_416_000 picoseconds. + Weight::from_parts(4_466_923_000, 1713) + // Standard Error: 15_415 + .saturating_add(Weight::from_parts(334_047, 0).saturating_mul(v.into())) + // Standard Error: 45_682 + .saturating_add(Weight::from_parts(3_097_318, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 05c6a6d404629f8bdc5a9cdb1d2ccdb785972693..e6384450a6fd632f206b7c9bf2bbc870604143e7 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] parking_lot = "0.12.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } scale-info = { version = "2.10.0", features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } sp-runtime = { path = "../../../primitives/runtime" } sp-io = { path = "../../../primitives/io" } @@ -35,7 +35,23 @@ frame-election-provider-support = { path = "../../election-provider-support" } pallet-election-provider-multi-phase = { path = ".." } pallet-staking = { path = "../../staking" } +pallet-nomination-pools = { path = "../../nomination-pools" } pallet-bags-list = { path = "../../bags-list" } pallet-balances = { path = "../../balances" } pallet-timestamp = { path = "../../timestamp" } pallet-session = { path = "../../session" } + +[features] +try-runtime = [ + "frame-election-provider-support/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-bags-list/try-runtime", + "pallet-balances/try-runtime", + "pallet-election-provider-multi-phase/try-runtime", + "pallet-nomination-pools/try-runtime", + "pallet-session/try-runtime", + "pallet-staking/try-runtime", + "pallet-timestamp/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 1d3f4712b1d604988047f5643ddd86296f453878..53bff50f7482fd61fb2c77594fa9c3a8957c0a8a 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 @@ -53,9 +53,9 @@ fn log_current_time() { #[test] fn block_progression_works() { - let (mut ext, pool_state, _) = ExtBuilder::default().build_offchainify(); + let (ext, pool_state, _) = ExtBuilder::default().build_offchainify(); - ext.execute_with(|| { + execute_with(ext, || { assert_eq!(active_era(), 0); assert_eq!(Session::current_index(), 0); assert!(ElectionProviderMultiPhase::current_phase().is_off()); @@ -70,9 +70,9 @@ fn block_progression_works() { assert!(ElectionProviderMultiPhase::current_phase().is_signed()); }); - let (mut ext, pool_state, _) = ExtBuilder::default().build_offchainify(); + let (ext, pool_state, _) = ExtBuilder::default().build_offchainify(); - ext.execute_with(|| { + execute_with(ext, || { assert_eq!(active_era(), 0); assert_eq!(Session::current_index(), 0); assert!(ElectionProviderMultiPhase::current_phase().is_off()); @@ -93,12 +93,12 @@ fn offchainify_works() { let staking_builder = StakingExtBuilder::default(); let epm_builder = EpmExtBuilder::default(); - let (mut ext, pool_state, _) = ExtBuilder::default() + let (ext, pool_state, _) = ExtBuilder::default() .epm(epm_builder) .staking(staking_builder) .build_offchainify(); - ext.execute_with(|| { + execute_with(ext, || { // test ocw progression and solution queue if submission when unsigned phase submission is // not delayed. for _ in 0..100 { @@ -142,9 +142,9 @@ fn offchainify_works() { /// restarts. Note that in this test case, the emergency throttling is disabled. fn enters_emergency_phase_after_forcing_before_elect() { let epm_builder = EpmExtBuilder::default().disable_emergency_throttling(); - let (mut ext, pool_state, _) = ExtBuilder::default().epm(epm_builder).build_offchainify(); + let (ext, pool_state, _) = ExtBuilder::default().epm(epm_builder).build_offchainify(); - ext.execute_with(|| { + execute_with(ext, || { log!( trace, "current validators (staking): {:?}", @@ -213,12 +213,12 @@ fn continous_slashes_below_offending_threshold() { let staking_builder = StakingExtBuilder::default().validator_count(10); let epm_builder = EpmExtBuilder::default().disable_emergency_throttling(); - let (mut ext, pool_state, _) = ExtBuilder::default() + let (ext, pool_state, _) = ExtBuilder::default() .epm(epm_builder) .staking(staking_builder) .build_offchainify(); - ext.execute_with(|| { + execute_with(ext, || { assert_eq!(Session::validators().len(), 10); let mut active_validator_set = Session::validators(); @@ -271,12 +271,12 @@ fn set_validation_intention_after_chilled() { use frame_election_provider_support::SortedListProvider; use pallet_staking::{Event, Forcing, Nominators}; - let (mut ext, pool_state, _) = ExtBuilder::default() + let (ext, pool_state, _) = ExtBuilder::default() .epm(EpmExtBuilder::default()) .staking(StakingExtBuilder::default()) .build_offchainify(); - ext.execute_with(|| { + execute_with(ext, || { assert_eq!(active_era(), 0); // validator is part of the validator set. assert!(Session::validators().contains(&41)); @@ -334,10 +334,10 @@ fn set_validation_intention_after_chilled() { fn ledger_consistency_active_balance_below_ed() { use pallet_staking::{Error, Event}; - let (mut ext, pool_state, _) = + let (ext, pool_state, _) = ExtBuilder::default().staking(StakingExtBuilder::default()).build_offchainify(); - ext.execute_with(|| { + execute_with(ext, || { assert_eq!(Staking::ledger(11.into()).unwrap().active, 1000); // unbonding total of active stake fails because the active ledger balance would fall @@ -387,3 +387,141 @@ fn ledger_consistency_active_balance_below_ed() { assert!(Staking::ledger(11.into()).is_err()); }); } + +#[test] +/// Automatic withdrawal of unlocking funds in staking propagates to the nomination pools and its +/// state correctly. +/// +/// The staking pallet may withdraw unlocking funds from a pool's bonded account without a pool +/// member or operator calling explicitly `Call::withdraw*`. This test verifies that the member's +/// are eventually paid and the `TotalValueLocked` is kept in sync in those cases. +fn automatic_unbonding_pools() { + use pallet_nomination_pools::TotalValueLocked; + + // closure to fetch the staking unlocking chunks of an account. + let unlocking_chunks_of = |account: AccountId| -> usize { + Staking::ledger(sp_staking::StakingAccount::Controller(account)) + .unwrap() + .unlocking + .len() + }; + + let (ext, pool_state, _) = ExtBuilder::default() + .pools(PoolsExtBuilder::default().max_unbonding(1)) + .staking(StakingExtBuilder::default().max_unlocking(1).bonding_duration(2)) + .build_offchainify(); + + execute_with(ext, || { + assert_eq!(::MaxUnlockingChunks::get(), 1); + assert_eq!(::BondingDuration::get(), 2); + 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 pool_bonded_account = Pools::create_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); + + 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); + + // 3 joins the pool. + assert_ok!(Pools::join(RuntimeOrigin::signed(3), 10, 1)); + assert_eq!(locked_amount_for(pool_bonded_account), 25); + + assert_eq!(TotalValueLocked::::get(), 25); + + // currently unlocking 0 chunks in the bonded pools ledger. + assert_eq!(unlocking_chunks_of(pool_bonded_account), 0); + + // unbond 2 from pool. + 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); + + // max chunks in the ledger are now filled up (`MaxUnlockingChunks == 1`). + assert_eq!(unlocking_chunks_of(pool_bonded_account), 1); + + // tries to unbond 3 from pool. it will fail since there are no unlocking chunks left + // available and the current in the queue haven't been there for more than bonding + // duration. + assert_err!( + Pools::unbond(RuntimeOrigin::signed(3), 3, 10), + pallet_staking::Error::::NoMoreChunks + ); + + assert_eq!(current_era(), 0); + + // progress over bonding duration. + for _ in 0..=::BondingDuration::get() { + start_next_active_era(pool_state.clone()).unwrap(); + } + 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); + + // now unbonding 3 will work, although the pool's ledger still has the unlocking chunks + // filled up. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(3), 3, 10)); + assert_eq!(unlocking_chunks_of(pool_bonded_account), 1); + + assert_eq!( + staking_events(), + [ + // auto-withdraw happened as expected to release 2's unbonding funds, but the funds + // were not transfered to 2 and stay in the pool's tranferrable balance instead. + pallet_staking::Event::Withdrawn { stash: 7939698191839293293, amount: 10 }, + pallet_staking::Event::Unbonded { stash: 7939698191839293293, amount: 10 } + ] + ); + + // 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); + // 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)); + + // 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); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10)); + assert_eq!(Balances::free_balance(pool_bonded_account), 16); + + assert_eq!(Balances::free_balance(2), 20); + assert_eq!(TotalValueLocked::::get(), 15); + + // 3 cannot withdraw yet. + assert_err!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(3), 3, 10), + pallet_nomination_pools::Error::::CannotWithdrawAny + ); + + // progress over bonding duration. + for _ in 0..=::BondingDuration::get() { + start_next_active_era(pool_state.clone()).unwrap(); + } + assert_eq!(current_era(), 6); + System::reset_events(); + + 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!(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 32633a0ed7d348f5ba0b83d047a33106e8b7cb93..7fade251e6d1c62b1b64a7ec1a86e29e0e18f40d 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 @@ -62,13 +62,14 @@ 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::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime { System: frame_system, ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, + Pools: pallet_nomination_pools, Balances: pallet_balances, BagsList: pallet_bags_list, Session: pallet_session, @@ -114,7 +115,7 @@ impl pallet_balances::Config for Runtime { type MaxFreezes = traits::ConstU32<1>; type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; type WeightInfo = (); } @@ -233,7 +234,7 @@ const THRESHOLDS: [VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_00 parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub const SessionsPerEra: sp_staking::SessionIndex = 2; - pub const BondingDuration: sp_staking::EraIndex = 28; + pub static BondingDuration: sp_staking::EraIndex = 28; pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(40); pub HistoryDepth: u32 = 84; @@ -247,6 +248,45 @@ impl pallet_bags_list::Config for Runtime { type Score = VoteWeight; } +pub struct BalanceToU256; +impl sp_runtime::traits::Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl sp_runtime::traits::Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub const PoolsPalletId: frame_support::PalletId = frame_support::PalletId(*b"py/nopls"); + pub static MaxUnbonding: u32 = 8; +} + +impl pallet_nomination_pools::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; + type RewardCounter = sp_runtime::FixedU128; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type Staking = Staking; + type PostUnbondingPoolsWindow = ConstU32<2>; + type PalletId = PoolsPalletId; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = MaxUnbonding; + type MaxPointsToBalance = frame_support::traits::ConstU8<10>; +} + +parameter_types! { + pub static MaxUnlockingChunks: u32 = 32; +} + /// Upper limit on the number of NPOS nominations. const MAX_QUOTA_NOMINATIONS: u32 = 16; @@ -273,10 +313,10 @@ impl pallet_staking::Config for Runtime { type VoterList = BagsList; type NominationsQuota = pallet_staking::FixedNominationsQuota; type TargetList = pallet_staking::UseValidatorsMap; - type MaxUnlockingChunks = ConstU32<32>; + type MaxUnlockingChunks = MaxUnlockingChunks; type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = HistoryDepth; - type EventListeners = (); + type EventListeners = Pools; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; } @@ -394,6 +434,14 @@ impl StakingExtBuilder { self.validator_count = n; self } + pub fn max_unlocking(self, max: u32) -> Self { + ::set(max); + self + } + pub fn bonding_duration(self, eras: EraIndex) -> Self { + ::set(eras); + self + } } pub struct EpmExtBuilder {} @@ -417,6 +465,21 @@ impl EpmExtBuilder { } } +pub struct PoolsExtBuilder {} + +impl Default for PoolsExtBuilder { + fn default() -> Self { + PoolsExtBuilder {} + } +} + +impl PoolsExtBuilder { + pub fn max_unbonding(self, max: u32) -> Self { + ::set(max); + self + } +} + pub struct BalancesExtBuilder { balances: Vec<(AccountId, Balance)>, } @@ -464,6 +527,7 @@ pub struct ExtBuilder { staking_builder: StakingExtBuilder, epm_builder: EpmExtBuilder, balances_builder: BalancesExtBuilder, + pools_builder: PoolsExtBuilder, } impl Default for ExtBuilder { @@ -472,6 +536,7 @@ impl Default for ExtBuilder { staking_builder: StakingExtBuilder::default(), epm_builder: EpmExtBuilder::default(), balances_builder: BalancesExtBuilder::default(), + pools_builder: PoolsExtBuilder::default(), } } } @@ -548,6 +613,11 @@ impl ExtBuilder { self } + pub fn pools(mut self, builder: PoolsExtBuilder) -> Self { + self.pools_builder = builder; + self + } + pub fn balances(mut self, builder: BalancesExtBuilder) -> Self { self.balances_builder = builder; self @@ -567,20 +637,20 @@ impl ExtBuilder { (ext, pool_state, offchain_state) } +} - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { - let mut ext = self.build(); - ext.execute_with(test); +pub(crate) fn execute_with(mut ext: sp_io::TestExternalities, test: impl FnOnce() -> ()) { + ext.execute_with(test); - #[cfg(feature = "try-runtime")] - ext.execute_with(|| { - let bn = System::block_number(); + #[cfg(feature = "try-runtime")] + ext.execute_with(|| { + let bn = System::block_number(); - assert_ok!(>::try_state(bn)); - assert_ok!(>::try_state(bn)); - assert_ok!(>::try_state(bn)); - }); - } + assert_ok!(>::try_state(bn)); + assert_ok!(>::try_state(bn)); + assert_ok!(>::try_state(bn)); + assert_ok!(>::try_state(bn)); + }); } // Progress to given block, triggering session and era changes as we progress and ensuring that @@ -606,6 +676,7 @@ pub fn roll_to(n: BlockNumber, delay_solution: bool) { if b != n { Staking::on_finalize(System::block_number()); } + Pools::on_initialize(b); log_current_time(); } @@ -628,7 +699,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 { .. }, ) => { @@ -860,6 +931,11 @@ 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 staking_events() -> Vec> { System::events() .into_iter() diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 0b410364690305ecd90ad90ce7cbda57875d1982..1bf1165229a7dd20700bb561d4dd776ca7c250bb 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -18,8 +18,8 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "2.0.48", features = ["full", "visit"] } -quote = "1.0.28" +syn = { features = ["full", "visit"], workspace = true } +quote = { workspace = true } proc-macro2 = "1.0.56" proc-macro-crate = "3.0.0" diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 7200d207aeccf9c3b83202bce7ad61bfc4c289d5..8a73dd38fa2df251fcd0ef5826f51b6cf56e0160 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index 4f8c5638d4bf4825295bbd1ffe6909aebf4f9d55..4dc4a3454aa031da708f536aadcbe9764b093726 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -log = { version = "0.4.14", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index 5d20a3cfcee2e72ace6b70adaee85e0ed1cdd7bf..e08412a6e87f49a9d66377ab07e57b5792a9ee6b 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -188,7 +188,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] @@ -1313,39 +1313,13 @@ mod tests { traits::{ConstU32, ConstU64, OnInitialize}, }; use frame_system::ensure_signed; - use sp_core::H256; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, - }; + use sp_runtime::{testing::Header, BuildStorage}; use substrate_test_utils::assert_eq_uvec; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { @@ -1448,7 +1422,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 b7ed13dae9f734e524072bcd6ac5e116fca632bc..cd67918e85b2f60cb30ac06a38d097b430c6812e 100644 --- a/substrate/frame/elections-phragmen/src/weights.rs +++ b/substrate/frame/elections-phragmen/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_elections_phragmen +//! Autogenerated weights for `pallet_elections_phragmen` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/elections-phragmen/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/elections-phragmen/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_elections_phragmen. +/// Weight functions needed for `pallet_elections_phragmen`. pub trait WeightInfo { fn vote_equal(v: u32, ) -> Weight; fn vote_more(v: u32, ) -> Weight; @@ -66,165 +65,165 @@ pub trait WeightInfo { fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight; } -/// Weights for pallet_elections_phragmen using the Substrate node and recommended hardware. +/// Weights for `pallet_elections_phragmen` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 33_028_000 picoseconds. - Weight::from_parts(34_073_914, 4764) - // Standard Error: 3_474 - .saturating_add(Weight::from_parts(205_252, 0).saturating_mul(v.into())) + // Minimum execution time: 29_390_000 picoseconds. + Weight::from_parts(30_525_476, 4764) + // Standard Error: 3_185 + .saturating_add(Weight::from_parts(143_073, 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())) } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 45_725_000 picoseconds. - Weight::from_parts(47_169_586, 4764) - // Standard Error: 5_148 - .saturating_add(Weight::from_parts(213_742, 0).saturating_mul(v.into())) + // Minimum execution time: 39_765_000 picoseconds. + Weight::from_parts(41_374_102, 4764) + // Standard Error: 4_310 + .saturating_add(Weight::from_parts(153_015, 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())) } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 45_519_000 picoseconds. - Weight::from_parts(47_339_108, 4764) - // Standard Error: 5_501 - .saturating_add(Weight::from_parts(195_247, 0).saturating_mul(v.into())) + // Minimum execution time: 39_647_000 picoseconds. + Weight::from_parts(41_474_523, 4764) + // Standard Error: 5_503 + .saturating_add(Weight::from_parts(149_029, 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())) } - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn remove_voter() -> Weight { // Proof Size summary in bytes: // Measured: `925` // Estimated: `4764` - // Minimum execution time: 50_386_000 picoseconds. - Weight::from_parts(51_378_000, 4764) + // Minimum execution time: 41_882_000 picoseconds. + Weight::from_parts(42_794_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Candidates` (r:1 w:1) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// 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: 38_987_000 picoseconds. - Weight::from_parts(41_302_276, 3055) - // Standard Error: 2_047 - .saturating_add(Weight::from_parts(125_200, 0).saturating_mul(c.into())) + // Minimum execution time: 33_719_000 picoseconds. + Weight::from_parts(35_017_073, 3055) + // Standard Error: 1_587 + .saturating_add(Weight::from_parts(121_130, 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())) } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Candidates` (r:1 w:1) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// 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: 33_510_000 picoseconds. - Weight::from_parts(34_947_760, 1770) - // Standard Error: 1_781 - .saturating_add(Weight::from_parts(78_851, 0).saturating_mul(c.into())) + // Minimum execution time: 27_263_000 picoseconds. + Weight::from_parts(28_215_666, 1770) + // Standard Error: 1_196 + .saturating_add(Weight::from_parts(86_804, 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())) } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:1) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:0 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `1900` - // Estimated: `3385` - // Minimum execution time: 50_603_000 picoseconds. - Weight::from_parts(51_715_000, 3385) + // Measured: `1933` + // Estimated: `3418` + // Minimum execution time: 41_531_000 picoseconds. + Weight::from_parts(42_937_000, 3418) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// 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: 33_441_000 picoseconds. - Weight::from_parts(34_812_000, 2365) + // Minimum execution time: 27_680_000 picoseconds. + Weight::from_parts(28_810_000, 2365) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn remove_member_without_replacement() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -232,87 +231,90 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 2_000_000_000_000 picoseconds. Weight::from_parts(2_000_000_000_000, 0) } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:1) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:0 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `1900` + // Measured: `1933` // Estimated: `3593` - // Minimum execution time: 57_289_000 picoseconds. - Weight::from_parts(58_328_000, 3593) + // Minimum execution time: 45_333_000 picoseconds. + Weight::from_parts(46_523_000, 3593) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Elections Voting (r:513 w:512) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:512 w:512) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:512 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:512 w:512) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Elections::Voting` (r:257 w:256) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:256 w:256) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:256 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:256 w:256) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `v` is `[256, 512]`. /// The range of component `d` is `[0, 256]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1149 + v * (811 ±0)` - // Estimated: `4621 + v * (3774 ±0)` - // Minimum execution time: 18_774_231_000 picoseconds. - Weight::from_parts(18_933_040_000, 4621) - // Standard Error: 301_534 - .saturating_add(Weight::from_parts(44_306_903, 0).saturating_mul(v.into())) + // Measured: `0 + d * (818 ±0) + v * (57 ±0)` + // Estimated: `24906 + d * (3774 ±1) + v * (24 ±0)` + // Minimum execution time: 5_620_000 picoseconds. + Weight::from_parts(5_817_000, 24906) + // Standard Error: 18_357 + .saturating_add(Weight::from_parts(106_164, 0).saturating_mul(v.into())) + // Standard Error: 39_980 + .saturating_add(Weight::from_parts(52_456_337, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(d.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(d.into()))) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 24).saturating_mul(v.into())) } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:513 w:0) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:44 w:44) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections ElectionRounds (r:1 w:1) - /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Candidates` (r:1 w:1) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:1) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:513 w:0) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:44 w:44) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Elections::ElectionRounds` (r:1 w:1) + /// Proof: `Elections::ElectionRounds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:0 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:0 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `c` is `[1, 64]`. /// The range of component `v` is `[1, 512]`. /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + e * (28 ±0) + v * (606 ±0)` - // Estimated: `178887 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` - // Minimum execution time: 1_281_877_000 picoseconds. - Weight::from_parts(1_288_147_000, 178887) - // Standard Error: 528_851 - .saturating_add(Weight::from_parts(17_761_407, 0).saturating_mul(v.into())) - // Standard Error: 33_932 - .saturating_add(Weight::from_parts(698_277, 0).saturating_mul(e.into())) + // Estimated: `178920 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_082_582_000 picoseconds. + Weight::from_parts(1_084_730_000, 178920) + // Standard Error: 594_096 + .saturating_add(Weight::from_parts(19_096_288, 0).saturating_mul(v.into())) + // Standard Error: 38_118 + .saturating_add(Weight::from_parts(792_945, 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()))) @@ -324,164 +326,164 @@ impl WeightInfo for SubstrateWeight { } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 33_028_000 picoseconds. - Weight::from_parts(34_073_914, 4764) - // Standard Error: 3_474 - .saturating_add(Weight::from_parts(205_252, 0).saturating_mul(v.into())) + // Minimum execution time: 29_390_000 picoseconds. + Weight::from_parts(30_525_476, 4764) + // Standard Error: 3_185 + .saturating_add(Weight::from_parts(143_073, 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())) } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 45_725_000 picoseconds. - Weight::from_parts(47_169_586, 4764) - // Standard Error: 5_148 - .saturating_add(Weight::from_parts(213_742, 0).saturating_mul(v.into())) + // Minimum execution time: 39_765_000 picoseconds. + Weight::from_parts(41_374_102, 4764) + // Standard Error: 4_310 + .saturating_add(Weight::from_parts(153_015, 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())) } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 45_519_000 picoseconds. - Weight::from_parts(47_339_108, 4764) - // Standard Error: 5_501 - .saturating_add(Weight::from_parts(195_247, 0).saturating_mul(v.into())) + // Minimum execution time: 39_647_000 picoseconds. + Weight::from_parts(41_474_523, 4764) + // Standard Error: 5_503 + .saturating_add(Weight::from_parts(149_029, 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())) } - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// 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: `Elections::Voting` (r:1 w:1) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// 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`) fn remove_voter() -> Weight { // Proof Size summary in bytes: // Measured: `925` // Estimated: `4764` - // Minimum execution time: 50_386_000 picoseconds. - Weight::from_parts(51_378_000, 4764) + // Minimum execution time: 41_882_000 picoseconds. + Weight::from_parts(42_794_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Candidates` (r:1 w:1) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// 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: 38_987_000 picoseconds. - Weight::from_parts(41_302_276, 3055) - // Standard Error: 2_047 - .saturating_add(Weight::from_parts(125_200, 0).saturating_mul(c.into())) + // Minimum execution time: 33_719_000 picoseconds. + Weight::from_parts(35_017_073, 3055) + // Standard Error: 1_587 + .saturating_add(Weight::from_parts(121_130, 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())) } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Candidates` (r:1 w:1) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// 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: 33_510_000 picoseconds. - Weight::from_parts(34_947_760, 1770) - // Standard Error: 1_781 - .saturating_add(Weight::from_parts(78_851, 0).saturating_mul(c.into())) + // Minimum execution time: 27_263_000 picoseconds. + Weight::from_parts(28_215_666, 1770) + // Standard Error: 1_196 + .saturating_add(Weight::from_parts(86_804, 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())) } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:1) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:0 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `1900` - // Estimated: `3385` - // Minimum execution time: 50_603_000 picoseconds. - Weight::from_parts(51_715_000, 3385) + // Measured: `1933` + // Estimated: `3418` + // Minimum execution time: 41_531_000 picoseconds. + Weight::from_parts(42_937_000, 3418) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// 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: 33_441_000 picoseconds. - Weight::from_parts(34_812_000, 2365) + // Minimum execution time: 27_680_000 picoseconds. + Weight::from_parts(28_810_000, 2365) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn remove_member_without_replacement() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -489,87 +491,90 @@ impl WeightInfo for () { // Minimum execution time: 2_000_000_000_000 picoseconds. Weight::from_parts(2_000_000_000_000, 0) } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:1) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:1 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:0 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `1900` + // Measured: `1933` // Estimated: `3593` - // Minimum execution time: 57_289_000 picoseconds. - Weight::from_parts(58_328_000, 3593) + // Minimum execution time: 45_333_000 picoseconds. + Weight::from_parts(46_523_000, 3593) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Elections Voting (r:513 w:512) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:512 w:512) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:512 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:512 w:512) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Elections::Voting` (r:257 w:256) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:0) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Candidates` (r:1 w:0) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:256 w:256) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:256 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:256 w:256) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `v` is `[256, 512]`. /// The range of component `d` is `[0, 256]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1149 + v * (811 ±0)` - // Estimated: `4621 + v * (3774 ±0)` - // Minimum execution time: 18_774_231_000 picoseconds. - Weight::from_parts(18_933_040_000, 4621) - // Standard Error: 301_534 - .saturating_add(Weight::from_parts(44_306_903, 0).saturating_mul(v.into())) + // Measured: `0 + d * (818 ±0) + v * (57 ±0)` + // Estimated: `24906 + d * (3774 ±1) + v * (24 ±0)` + // Minimum execution time: 5_620_000 picoseconds. + Weight::from_parts(5_817_000, 24906) + // Standard Error: 18_357 + .saturating_add(Weight::from_parts(106_164, 0).saturating_mul(v.into())) + // Standard Error: 39_980 + .saturating_add(Weight::from_parts(52_456_337, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(v.into()))) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(d.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(d.into()))) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 24).saturating_mul(v.into())) } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:513 w:0) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:44 w:44) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections ElectionRounds (r:1 w:1) - /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Elections::Candidates` (r:1 w:1) + /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:1) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::RunnersUp` (r:1 w:1) + /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Voting` (r:513 w:0) + /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Council::Proposals` (r:1 w:0) + /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:44 w:44) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Elections::ElectionRounds` (r:1 w:1) + /// Proof: `Elections::ElectionRounds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Members` (r:0 w:1) + /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Council::Prime` (r:0 w:1) + /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `c` is `[1, 64]`. /// The range of component `v` is `[1, 512]`. /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + e * (28 ±0) + v * (606 ±0)` - // Estimated: `178887 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` - // Minimum execution time: 1_281_877_000 picoseconds. - Weight::from_parts(1_288_147_000, 178887) - // Standard Error: 528_851 - .saturating_add(Weight::from_parts(17_761_407, 0).saturating_mul(v.into())) - // Standard Error: 33_932 - .saturating_add(Weight::from_parts(698_277, 0).saturating_mul(e.into())) + // Estimated: `178920 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_082_582_000 picoseconds. + Weight::from_parts(1_084_730_000, 178920) + // Standard Error: 594_096 + .saturating_add(Weight::from_parts(19_096_288, 0).saturating_mul(v.into())) + // Standard Error: 38_118 + .saturating_add(Weight::from_parts(792_945, 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 eb6355edd312a1ff5f865c235ffd034f085a3027..45c7440eb89135eca98cf00a4aaf5d6ad2c094ca 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -23,6 +23,7 @@ pallet-example-frame-crate = { path = "frame-crate", default-features = false } pallet-example-kitchensink = { path = "kitchensink", default-features = false } pallet-example-offchain-worker = { path = "offchain-worker", default-features = false } pallet-example-split = { path = "split", default-features = false } +pallet-example-single-block-migrations = { path = "single-block-migrations", default-features = false } pallet-example-tasks = { path = "tasks", default-features = false } [features] @@ -34,6 +35,7 @@ std = [ "pallet-example-frame-crate/std", "pallet-example-kitchensink/std", "pallet-example-offchain-worker/std", + "pallet-example-single-block-migrations/std", "pallet-example-split/std", "pallet-example-tasks/std", ] @@ -43,6 +45,7 @@ try-runtime = [ "pallet-example-basic/try-runtime", "pallet-example-kitchensink/try-runtime", "pallet-example-offchain-worker/try-runtime", + "pallet-example-single-block-migrations/try-runtime", "pallet-example-split/try-runtime", "pallet-example-tasks/try-runtime", ] diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index 2be5aecb9681d990366f8d79bf6b6020069ffb99..e4ab5112201d1661d1bbc991489bb6d847d6c32d 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/examples/basic/src/benchmarking.rs b/substrate/frame/examples/basic/src/benchmarking.rs index 4b2ebb41fbda1d6d8a0d12a65b32391510f1a488..65ca3089aba4247cae65932cd4bca9b68d520b75 100644 --- a/substrate/frame/examples/basic/src/benchmarking.rs +++ b/substrate/frame/examples/basic/src/benchmarking.rs @@ -48,7 +48,7 @@ mod benchmarks { set_dummy(RawOrigin::Root, value); // The execution phase is just running `set_dummy` extrinsic call // This is the optional benchmark verification phase, asserting certain states. - assert_eq!(Pallet::::dummy(), Some(value)) + assert_eq!(Dummy::::get(), Some(value)) } // An example method that returns a Result that can be called within a benchmark diff --git a/substrate/frame/examples/basic/src/lib.rs b/substrate/frame/examples/basic/src/lib.rs index dad4d01978f95391e88cd99dce82f86f9d942e87..94b2f276e00b7482febf9e69fe6af15b39e1b09a 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)] @@ -64,10 +65,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, OriginOf, SaturatedConversion, Saturating, TransactionExtension, + TransactionExtensionBase, ValidateResult, }, + transaction_validity::{InvalidTransaction, ValidTransaction}, }; use sp_std::vec::Vec; @@ -286,9 +289,7 @@ pub mod pallet { let _sender = ensure_signed(origin)?; // Read the value of dummy from storage. - // let dummy = Self::dummy(); - // Will also work using the `::get` on the storage item type itself: - // let dummy = >::get(); + // let dummy = Dummy::::get(); // Calculate the new value. // let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); @@ -381,20 +382,14 @@ pub mod pallet { // - `Foo::put(1); Foo::get()` returns `1`; // - `Foo::kill(); Foo::get()` returns `0` (u32::default()). #[pallet::storage] - // The getter attribute generate a function on `Pallet` placeholder: - // `fn getter_name() -> Type` for basic value items or - // `fn getter_name(key: KeyType) -> ValueType` for map items. - #[pallet::getter(fn dummy)] pub(super) type Dummy = StorageValue<_, T::Balance>; // A map that has enumerable entries. #[pallet::storage] - #[pallet::getter(fn bar)] pub(super) type Bar = StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance>; // this one uses the query kind: `ValueQuery`, we'll demonstrate the usage of 'mutate' API. #[pallet::storage] - #[pallet::getter(fn foo)] pub(super) type Foo = StorageValue<_, T::Balance, ValueQuery>; #[pallet::storage] @@ -433,10 +428,10 @@ impl Pallet { fn accumulate_foo(origin: T::RuntimeOrigin, increase_by: T::Balance) -> DispatchResult { let _sender = ensure_signed(origin)?; - let prev = >::get(); + let prev = Foo::::get(); // Because Foo has 'default', the type of 'foo' in closure is the raw type instead of an // Option<> type. - let result = >::mutate(|foo| { + let result = Foo::::mutate(|foo| { *foo = foo.saturating_add(increase_by); *foo }); @@ -448,8 +443,8 @@ 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: +// 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 @@ -463,18 +458,18 @@ impl Pallet { // // 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). +// [here](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.TransactionExtension.html). // // 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 +// 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 @@ -492,52 +487,45 @@ impl core::fmt::Debug for WatchDummy { } } -impl SignedExtension for WatchDummy +impl TransactionExtensionBase for WatchDummy { + const IDENTIFIER: &'static str = "WatchDummy"; + type Implicit = (); +} +impl + TransactionExtension<::RuntimeCall, Context> for WatchDummy where ::RuntimeCall: IsSubType>, { - const IDENTIFIER: &'static str = "WatchDummy"; - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); 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: OriginOf<::RuntimeCall>, + call: &::RuntimeCall, + _info: &DispatchInfoOf<::RuntimeCall>, len: usize, - ) -> TransactionValidity { + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> 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; Context; prepare); } diff --git a/substrate/frame/examples/basic/src/tests.rs b/substrate/frame/examples/basic/src/tests.rs index 9434ace35ffe35467a9c513d67f0450e5b6ade6e..e460ad0992f064c72aaca7a13ce33db6d96d5dcd 100644 --- a/substrate/frame/examples/basic/src/tests.rs +++ b/substrate/frame/examples/basic/src/tests.rs @@ -27,7 +27,7 @@ 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}, BuildStorage, }; // Reexport crate as its pallet name for construct_runtime. @@ -119,25 +119,25 @@ fn it_works_for_optional_value() { // Check that GenesisBuilder works properly. let val1 = 42; let val2 = 27; - assert_eq!(Example::dummy(), Some(val1)); + assert_eq!(Dummy::::get(), Some(val1)); // Check that accumulate works when we have Some value in Dummy already. assert_ok!(Example::accumulate_dummy(RuntimeOrigin::signed(1), val2)); - assert_eq!(Example::dummy(), Some(val1 + val2)); + assert_eq!(Dummy::::get(), Some(val1 + val2)); // Check that accumulate works when we Dummy has None in it. >::on_initialize(2); assert_ok!(Example::accumulate_dummy(RuntimeOrigin::signed(1), val1)); - assert_eq!(Example::dummy(), Some(val1 + val2 + val1)); + assert_eq!(Dummy::::get(), Some(val1 + val2 + val1)); }); } #[test] fn it_works_for_default_value() { new_test_ext().execute_with(|| { - assert_eq!(Example::foo(), 24); + assert_eq!(Foo::::get(), 24); assert_ok!(Example::accumulate_foo(RuntimeOrigin::signed(1), 1)); - assert_eq!(Example::foo(), 25); + assert_eq!(Foo::::get(), 25); }); } @@ -146,7 +146,7 @@ fn set_dummy_works() { new_test_ext().execute_with(|| { let test_val = 133; assert_ok!(Example::set_dummy(RuntimeOrigin::root(), test_val.into())); - assert_eq!(Example::dummy(), Some(test_val)); + assert_eq!(Dummy::::get(), Some(test_val)); }); } @@ -158,13 +158,16 @@ fn signed_ext_watch_dummy_works() { assert_eq!( WatchDummy::(PhantomData) - .validate(&1, &call, &info, 150) + .validate_only(Some(1).into(), &call, &info, 150) .unwrap() + .0 .priority, u64::MAX, ); assert_eq!( - WatchDummy::(PhantomData).validate(&1, &call, &info, 250), + WatchDummy::(PhantomData) + .validate_only(Some(1).into(), &call, &info, 250) + .unwrap_err(), InvalidTransaction::ExhaustsResources.into(), ); }) diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index 83d9ae79510da26280a2f150e70312d35eeb07fb..e40845a425a29d8d2868e823c1ba34dbabd136c0 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/default-config/src/lib.rs b/substrate/frame/examples/default-config/src/lib.rs index cd1653e6c764358165c8306d4810c1d4c9bea3b4..224faf9dfd431a0ce9281c406738b7aa2fddb0f6 100644 --- a/substrate/frame/examples/default-config/src/lib.rs +++ b/substrate/frame/examples/default-config/src/lib.rs @@ -108,7 +108,7 @@ pub mod pallet { } /// A type providing default configurations for this pallet in another environment. Examples - /// could be a parachain, or a solo-chain. + /// could be a parachain, or a solochain. /// /// Appropriate derive for `frame_system::DefaultConfig` needs to be provided. In this /// example, we simple derive `frame_system::config_preludes::TestDefaultConfig` again. @@ -149,7 +149,7 @@ pub mod tests { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { // these items are defined by frame-system as `no_default`, so we must specify them here. type Block = Block; diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index f150f446446cf99da82f4a5535a8e8f031d54b73..a9c4e3f3b1fccb9085f1bc9a6a2f018a055d683a 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index 4255ebb66b650efb77264b250396c0a05ba0763a..37384107530ee4dca645f12f1b50e4af5547dabc 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -17,10 +17,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-support = { path = "../../support", default-features = false } +frame-support = { path = "../../support", default-features = false, features = ["experimental"] } frame-system = { path = "../../system", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } diff --git a/substrate/frame/examples/kitchensink/src/benchmarking.rs b/substrate/frame/examples/kitchensink/src/benchmarking.rs index 24da581fc967b8e8c8586bf3b41a4452a89a4dcd..5f1d378e06fe67ee3978124ce7b557ad39b89e0a 100644 --- a/substrate/frame/examples/kitchensink/src/benchmarking.rs +++ b/substrate/frame/examples/kitchensink/src/benchmarking.rs @@ -51,7 +51,7 @@ mod benchmarks { set_foo(RawOrigin::Root, value, 10u128); // The execution phase is just running `set_foo` extrinsic call // This is the optional benchmark verification phase, asserting certain states. - assert_eq!(Pallet::::foo(), Some(value)) + assert_eq!(Foo::::get(), Some(value)) } // This line generates test cases for benchmarking, and could be run by: diff --git a/substrate/frame/examples/kitchensink/src/lib.rs b/substrate/frame/examples/kitchensink/src/lib.rs index 18429bc967d7c1e1f7b181e708ca3a86ef6f251c..b7425b0c0846afc3e9488a490144a89e7b647301 100644 --- a/substrate/frame/examples/kitchensink/src/lib.rs +++ b/substrate/frame/examples/kitchensink/src/lib.rs @@ -125,7 +125,6 @@ pub mod pallet { #[pallet::storage] #[pallet::unbounded] // optional #[pallet::storage_prefix = "OtherFoo"] // optional - #[pallet::getter(fn foo)] // optional pub type Foo = StorageValue; #[pallet::type_value] diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index cc337707a2962120eb035d355c328705381a152d..fc5151ff292b4571d9cb898d6246668d5f3b4dc8 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } lite-json = { version = "0.2.0", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/offchain-worker/src/lib.rs b/substrate/frame/examples/offchain-worker/src/lib.rs index 6c1fa6ea8ec42dbee21875a0610b3724aadff802..d21c8b4cfd24971f945b73c558463ee7a1f47f77 100644 --- a/substrate/frame/examples/offchain-worker/src/lib.rs +++ b/substrate/frame/examples/offchain-worker/src/lib.rs @@ -332,7 +332,6 @@ pub mod pallet { /// /// This is used to calculate average price, should have bounded size. #[pallet::storage] - #[pallet::getter(fn prices)] pub(super) type Prices = StorageValue<_, BoundedVec, ValueQuery>; /// Defines the block when next unsigned transaction will be accepted. @@ -341,7 +340,6 @@ pub mod pallet { /// we only allow one transaction every `T::UnsignedInterval` blocks. /// This storage entry defines when new transaction is going to be accepted. #[pallet::storage] - #[pallet::getter(fn next_unsigned_at)] pub(super) type NextUnsignedAt = StorageValue<_, BlockNumberFor, ValueQuery>; } @@ -479,7 +477,7 @@ impl Pallet { ) -> Result<(), &'static str> { // Make sure we don't fetch the price if unsigned transaction is going to be rejected // anyway. - let next_unsigned_at = >::get(); + let next_unsigned_at = NextUnsignedAt::::get(); if next_unsigned_at > block_number { return Err("Too early to send unsigned transaction") } @@ -513,7 +511,7 @@ impl Pallet { ) -> Result<(), &'static str> { // Make sure we don't fetch the price if unsigned transaction is going to be rejected // anyway. - let next_unsigned_at = >::get(); + let next_unsigned_at = NextUnsignedAt::::get(); if next_unsigned_at > block_number { return Err("Too early to send unsigned transaction") } @@ -543,7 +541,7 @@ impl Pallet { ) -> Result<(), &'static str> { // Make sure we don't fetch the price if unsigned transaction is going to be rejected // anyway. - let next_unsigned_at = >::get(); + let next_unsigned_at = NextUnsignedAt::::get(); if next_unsigned_at > block_number { return Err("Too early to send unsigned transaction") } @@ -664,7 +662,7 @@ impl Pallet { /// Calculate current average price. fn average_price() -> Option { - let prices = >::get(); + let prices = Prices::::get(); if prices.is_empty() { None } else { @@ -677,7 +675,7 @@ impl Pallet { new_price: &u32, ) -> TransactionValidity { // Now let's check if the transaction has any chance to succeed. - let next_unsigned_at = >::get(); + let next_unsigned_at = NextUnsignedAt::::get(); if &next_unsigned_at > block_number { return InvalidTransaction::Stale.into() } diff --git a/substrate/frame/examples/offchain-worker/src/tests.rs b/substrate/frame/examples/offchain-worker/src/tests.rs index ea37a2da493d69ae6550c8d999fe2eb9dcfefad1..81f2a40840badd286be14b381df1db904aeeb2b1 100644 --- a/substrate/frame/examples/offchain-worker/src/tests.rs +++ b/substrate/frame/examples/offchain-worker/src/tests.rs @@ -30,7 +30,7 @@ use sp_core::{ use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; use sp_runtime::{ - testing::TestXt, + generic::UncheckedExtrinsic, traits::{BlakeTwo256, Extrinsic as ExtrinsicT, IdentifyAccount, IdentityLookup, Verify}, RuntimeAppPublic, }; @@ -73,7 +73,7 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } -type Extrinsic = TestXt; +type Extrinsic = UncheckedExtrinsic; type AccountId = <::Signer as IdentifyAccount>::AccountId; impl frame_system::offchain::SigningTypes for Test { @@ -99,7 +99,7 @@ where _account: AccountId, nonce: u64, ) -> Option<(RuntimeCall, ::SignaturePayload)> { - Some((call, (nonce, ()))) + Some((call, (nonce, (), ()))) } } @@ -219,8 +219,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 })); }); } @@ -259,11 +259,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 +313,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); @@ -353,9 +353,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/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..5059b2433c77139568d99326473cded73a5af9e9 --- /dev/null +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -0,0 +1,61 @@ +[package] +name = "pallet-example-single-block-migrations" +version = "0.0.1" +authors.workspace = true +edition.workspace = true +license = "MIT-0" +homepage = "https://substrate.io" +repository.workspace = true +description = "FRAME example pallet demonstrating best-practices for writing storage migrations." +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +docify = { version = "0.2.3", default-features = false } +log = { version = "0.4.20", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +frame-support = { path = "../../support", default-features = false } +frame-executive = { path = "../../executive", default-features = false } +frame-system = { path = "../../system", default-features = false } +frame-try-runtime = { path = "../../try-runtime", default-features = false, optional = true } +pallet-balances = { path = "../../balances", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-version = { path = "../../../primitives/version", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-executive/std", + "frame-support/std", + "frame-system/std", + "frame-try-runtime/std", + "log/std", + "pallet-balances/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "sp-version/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-balances/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/examples/single-block-migrations/src/lib.rs b/substrate/frame/examples/single-block-migrations/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..86a9e5d6e95bbeaa0230b81153c3f4149f332436 --- /dev/null +++ b/substrate/frame/examples/single-block-migrations/src/lib.rs @@ -0,0 +1,213 @@ +// 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. + +//! # Single Block Migration Example Pallet +//! +//! An example pallet demonstrating best-practices for writing single-block migrations in the +//! context of upgrading pallet storage. +//! +//! ## Forwarning +//! +//! Single block migrations **MUST** execute in a single block, therefore when executed on a +//! parachain are only appropriate when guaranteed to not exceed block weight limits. If a +//! parachain submits a block that exceeds the block weight limit it will **brick the chain**! +//! +//! If weight is a concern or you are not sure which type of migration to use, you should probably +//! use a multi-block migration. +//! +//! TODO: Link above to multi-block migration example. +//! +//! ## Pallet Overview +//! +//! This example pallet contains a single storage item [`Value`](pallet::Value), which may be set by +//! any signed origin by calling the [`set_value`](crate::Call::set_value) extrinsic. +//! +//! For the purposes of this exercise, we imagine that in [`StorageVersion`] V0 of this pallet +//! [`Value`](pallet::Value) is a `u32`, and this what is currently stored on-chain. +//! +//! ```ignore +//! // (Old) Storage Version V0 representation of `Value` +//! #[pallet::storage] +//! pub type Value = StorageValue<_, u32>; +//! ``` +//! +//! In [`StorageVersion`] V1 of the pallet a new struct [`CurrentAndPreviousValue`] is introduced: +#![doc = docify::embed!("src/lib.rs", CurrentAndPreviousValue)] +//! and [`Value`](pallet::Value) is updated to store this new struct instead of a `u32`: +#![doc = docify::embed!("src/lib.rs", Value)] +//! +//! In StorageVersion V1 of the pallet when [`set_value`](crate::Call::set_value) is called, the +//! new value is stored in the `current` field of [`CurrentAndPreviousValue`], and the previous +//! value (if it exists) is stored in the `previous` field. +#![doc = docify::embed!("src/lib.rs", pallet_calls)] +//! +//! ## Why a migration is necessary +//! +//! Without a migration, there will be a discrepancy between the on-chain storage for [`Value`] (in +//! V0 it is a `u32`) and the current storage for [`Value`] (in V1 it was changed to a +//! [`CurrentAndPreviousValue`] struct). +//! +//! The on-chain storage for [`Value`] would be a `u32` but the runtime would try to read it as a +//! [`CurrentAndPreviousValue`]. This would result in unacceptable undefined behavior. +//! +//! ## Adding a migration module +//! +//! Writing a pallets migrations in a seperate module is strongly recommended. +//! +//! Here's how the migration module is defined for this pallet: +//! +//! ```text +//! substrate/frame/examples/single-block-migrations/src/ +//! ├── lib.rs <-- pallet definition +//! ├── Cargo.toml <-- pallet manifest +//! └── migrations/ +//! ├── mod.rs <-- migrations module definition +//! └── v1.rs <-- migration logic for the V0 to V1 transition +//! ``` +//! +//! This structure allows keeping migration logic separate from the pallet logic and +//! easily adding new migrations in the future. +//! +//! ## Writing the Migration +//! +//! All code related to the migration can be found under +//! [`v1.rs`](migrations::v1). +//! +//! See the migration source code for detailed comments. +//! +//! To keep the migration logic organised, it is split across additional modules: +//! +//! ### `mod v0` +//! +//! Here we define a [`storage_alias`](frame_support::storage_alias) for the old v0 [`Value`] +//! format. +//! +//! This allows reading the old v0 value from storage during the migration. +//! +//! ### `mod version_unchecked` +//! +//! Here we define our raw migration logic, +//! `version_unchecked::MigrateV0ToV1` which implements the [`OnRuntimeUpgrade`] trait. +//! +//! Importantly, it is kept in a private module so that it cannot be accidentally used in a runtime. +//! +//! Private modules cannot be referenced in docs, so please read the code directly. +//! +//! #### Standalone Struct or Pallet Hook? +//! +//! Note that the storage migration logic is attached to a standalone struct implementing +//! [`OnRuntimeUpgrade`], rather than implementing the +//! [`Hooks::on_runtime_upgrade`](frame_support::traits::Hooks::on_runtime_upgrade) hook directly on +//! the pallet. The pallet hook is better suited for special types of logic that need to execute on +//! every runtime upgrade, but not so much for one-off storage migrations. +//! +//! ### `pub mod versioned` +//! +//! Here, `version_unchecked::MigrateV0ToV1` is wrapped in a +//! [`VersionedMigration`] to define +//! [`versioned::MigrateV0ToV1`](crate::migrations::v1::versioned::MigrateV0ToV1), which may be used +//! in runtimes. +//! +//! Using [`VersionedMigration`] ensures that +//! - The migration only runs once when the on-chain storage version is `0` +//! - The on-chain storage version is updated to `1` after the migration executes +//! - Reads and writes from checking and setting the on-chain storage version are accounted for in +//! the final [`Weight`](frame_support::weights::Weight) +//! +//! This is the only public module exported from `v1`. +//! +//! ### `mod test` +//! +//! Here basic unit tests are defined for the migration. +//! +//! When writing migration tests, don't forget to check: +//! - `on_runtime_upgrade` returns the expected weight +//! - `post_upgrade` succeeds when given the bytes returned by `pre_upgrade` +//! - Pallet storage is in the expected state after the migration +//! +//! [`VersionedMigration`]: frame_support::migrations::VersionedMigration +//! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion +//! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade +//! [`MigrateV0ToV1`]: crate::migrations::v1::versioned::MigrationV0ToV1 + +// We make sure this pallet uses `no_std` for compiling to Wasm. +#![cfg_attr(not(feature = "std"), no_std)] +// allow non-camel-case names for storage version V0 value +#![allow(non_camel_case_types)] + +// Re-export pallet items so that they can be accessed from the crate namespace. +pub use pallet::*; + +// Export migrations so they may be used in the runtime. +pub mod migrations; +#[doc(hidden)] +mod mock; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::traits::StorageVersion; +use sp_runtime::RuntimeDebug; + +/// Example struct holding the most recently set [`u32`] and the +/// second most recently set [`u32`] (if one existed). +#[docify::export] +#[derive( + Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen, +)] +pub struct CurrentAndPreviousValue { + /// The most recently set value. + pub current: u32, + /// The previous value, if one existed. + pub previous: Option, +} + +// Pallet for demonstrating storage migrations. +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + /// Define the current [`StorageVersion`] of the pallet. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + /// [`StorageVersion`] V1 of [`Value`]. + /// + /// Currently used. + #[docify::export] + #[pallet::storage] + pub type Value = StorageValue<_, CurrentAndPreviousValue>; + + #[docify::export(pallet_calls)] + #[pallet::call] + impl Pallet { + pub fn set_value(origin: OriginFor, value: u32) -> DispatchResult { + ensure_signed(origin)?; + + let previous = Value::::get().map(|v| v.current); + let new_struct = CurrentAndPreviousValue { current: value, previous }; + >::put(new_struct); + + Ok(()) + } + } +} diff --git a/substrate/frame/examples/single-block-migrations/src/migrations/mod.rs b/substrate/frame/examples/single-block-migrations/src/migrations/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..80a33f69941aa1a49563971ab0c9e13a88ecda19 --- /dev/null +++ b/substrate/frame/examples/single-block-migrations/src/migrations/mod.rs @@ -0,0 +1,20 @@ +// 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. + +/// Module containing all logic associated with the example migration from +/// [`StorageVersion`](frame_support::traits::StorageVersion) V0 to V1. +pub mod v1; diff --git a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs new file mode 100644 index 0000000000000000000000000000000000000000..b46640a320207551ab55b1dc793574ce68c4c26c --- /dev/null +++ b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs @@ -0,0 +1,222 @@ +// 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::{ + storage_alias, + traits::{Get, OnRuntimeUpgrade}, +}; + +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; + +/// Collection of storage item formats from the previous storage version. +/// +/// Required so we can read values in the v0 storage format during the migration. +mod v0 { + use super::*; + + /// V0 type for [`crate::Value`]. + #[storage_alias] + pub type Value = StorageValue, u32>; +} + +/// Private module containing *version unchecked* migration logic. +/// +/// Should only be used by the [`VersionedMigration`](frame_support::migrations::VersionedMigration) +/// type in this module to create something to export. +/// +/// The unversioned migration should be kept private so the unversioned migration cannot +/// accidentally be used in any runtimes. +/// +/// For more about this pattern of keeping items private, see +/// - +/// - +mod version_unchecked { + use super::*; + + /// Implements [`OnRuntimeUpgrade`], migrating the state of this pallet from V0 to V1. + /// + /// In V0 of the template [`crate::Value`] is just a `u32`. In V1, it has been upgraded to + /// contain the struct [`crate::CurrentAndPreviousValue`]. + /// + /// In this migration, update the on-chain storage for the pallet to reflect the new storage + /// layout. + pub struct MigrateV0ToV1(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for MigrateV0ToV1 { + /// Return the existing [`crate::Value`] so we can check that it was correctly set in + /// `version_unchecked::MigrateV0ToV1::post_upgrade`. + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + use codec::Encode; + + // Access the old value using the `storage_alias` type + let old_value = v0::Value::::get(); + // Return it as an encoded `Vec` + Ok(old_value.encode()) + } + + /// Migrate the storage from V0 to V1. + /// + /// - If the value doesn't exist, there is nothing to do. + /// - If the value exists, it is read and then written back to storage inside a + /// [`crate::CurrentAndPreviousValue`]. + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Read the old value from storage + if let Some(old_value) = v0::Value::::take() { + // Write the new value to storage + let new = crate::CurrentAndPreviousValue { current: old_value, previous: None }; + crate::Value::::put(new); + // One read for the old value, one write for the new value + T::DbWeight::get().reads_writes(1, 1) + } else { + // One read for trying to access the old value + T::DbWeight::get().reads(1) + } + } + + /// Verifies the storage was migrated correctly. + /// + /// - If there was no old value, the new value should not be set. + /// - If there was an old value, the new value should be a + /// [`crate::CurrentAndPreviousValue`]. + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + use codec::Decode; + use frame_support::ensure; + + let maybe_old_value = Option::::decode(&mut &state[..]).map_err(|_| { + sp_runtime::TryRuntimeError::Other("Failed to decode old value from storage") + })?; + + match maybe_old_value { + Some(old_value) => { + let expected_new_value = + crate::CurrentAndPreviousValue { current: old_value, previous: None }; + let actual_new_value = crate::Value::::get(); + + ensure!(actual_new_value.is_some(), "New value not set"); + ensure!( + actual_new_value == Some(expected_new_value), + "New value not set correctly" + ); + }, + None => { + ensure!(crate::Value::::get().is_none(), "New value unexpectedly set"); + }, + }; + Ok(()) + } + } +} + +/// Public module containing *version checked* migration logic. +/// +/// This is the only module that should be exported from this module. +/// +/// See [`VersionedMigration`](frame_support::migrations::VersionedMigration) docs for more about +/// how it works. +pub mod versioned { + use super::*; + + /// `version_unchecked::MigrateV0ToV1` wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), which ensures that: + /// - The migration only runs once when the on-chain storage version is 0 + /// - The on-chain storage version is updated to `1` after the migration executes + /// - Reads/Writes from checking/settings the on-chain storage version are accounted for + pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< + 0, // The migration will only execute when the on-chain storage version is 0 + 1, // The on-chain storage version will be set to 1 after the migration is complete + version_unchecked::MigrateV0ToV1, + crate::pallet::Pallet, + ::DbWeight, + >; +} + +/// Tests for our migration. +/// +/// When writing migration tests, it is important to check: +/// 1. `on_runtime_upgrade` returns the expected weight +/// 2. `post_upgrade` succeeds when given the bytes returned by `pre_upgrade` +/// 3. The storage is in the expected state after the migration +#[cfg(any(all(feature = "try-runtime", test), doc))] +mod test { + use super::*; + use crate::mock::{new_test_ext, MockRuntime}; + use frame_support::assert_ok; + use version_unchecked::MigrateV0ToV1; + + #[test] + fn handles_no_existing_value() { + new_test_ext().execute_with(|| { + // By default, no value should be set. Verify this assumption. + assert!(crate::Value::::get().is_none()); + assert!(v0::Value::::get().is_none()); + + // Get the pre_upgrade bytes + let bytes = match MigrateV0ToV1::::pre_upgrade() { + Ok(bytes) => bytes, + Err(e) => panic!("pre_upgrade failed: {:?}", e), + }; + + // Execute the migration + let weight = MigrateV0ToV1::::on_runtime_upgrade(); + + // Verify post_upgrade succeeds + assert_ok!(MigrateV0ToV1::::post_upgrade(bytes)); + + // The weight should be just 1 read for trying to access the old value. + assert_eq!(weight, ::DbWeight::get().reads(1)); + + // After the migration, no value should have been set. + assert!(crate::Value::::get().is_none()); + }) + } + + #[test] + fn handles_existing_value() { + new_test_ext().execute_with(|| { + // Set up an initial value + let initial_value = 42; + v0::Value::::put(initial_value); + + // Get the pre_upgrade bytes + let bytes = match MigrateV0ToV1::::pre_upgrade() { + Ok(bytes) => bytes, + Err(e) => panic!("pre_upgrade failed: {:?}", e), + }; + + // Execute the migration + let weight = MigrateV0ToV1::::on_runtime_upgrade(); + + // Verify post_upgrade succeeds + assert_ok!(MigrateV0ToV1::::post_upgrade(bytes)); + + // The weight used should be 1 read for the old value, and 1 write for the new + // value. + assert_eq!( + weight, + ::DbWeight::get().reads_writes(1, 1) + ); + + // After the migration, the new value should be set as the `current` value. + let expected_new_value = + crate::CurrentAndPreviousValue { current: initial_value, previous: None }; + assert_eq!(crate::Value::::get(), Some(expected_new_value)); + }) + } +} diff --git a/substrate/frame/examples/single-block-migrations/src/mock.rs b/substrate/frame/examples/single-block-migrations/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..02f72e01836f2462de2043cae737ea46ec2072ed --- /dev/null +++ b/substrate/frame/examples/single-block-migrations/src/mock.rs @@ -0,0 +1,69 @@ +// 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(any(all(feature = "try-runtime", test), doc))] + +use crate::*; +use frame_support::{derive_impl, traits::ConstU64, weights::constants::ParityDbWeight}; + +// Re-export crate as its pallet name for construct_runtime. +use crate as pallet_example_storage_migration; + +type Block = frame_system::mocking::MockBlock; + +// For testing the pallet, we construct a mock runtime. +frame_support::construct_runtime!( + pub struct MockRuntime { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Example: pallet_example_storage_migration::{Pallet, Call, Storage}, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for MockRuntime { + type Block = Block; + type AccountData = pallet_balances::AccountData; + type DbWeight = ParityDbWeight; +} + +impl pallet_balances::Config for MockRuntime { + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u64; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); +} + +impl Config for MockRuntime {} + +pub fn new_test_ext() -> sp_io::TestExternalities { + use sp_runtime::BuildStorage; + + let t = RuntimeGenesisConfig { system: Default::default(), balances: Default::default() } + .build_storage() + .unwrap(); + t.into() +} diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index 733ca92b820d6b8a4230f7c8868494ec0410656e..d140fc3eef43b04ca7b9175efbdae2830e2d6282 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/examples/split/src/lib.rs b/substrate/frame/examples/split/src/lib.rs index 74d2e0cc24b7bf5789da19f2657c5e7d2514bbfe..5245d90e390cff1ccab79ecc279fe57188cde030 100644 --- a/substrate/frame/examples/split/src/lib.rs +++ b/substrate/frame/examples/split/src/lib.rs @@ -107,7 +107,7 @@ pub mod pallet { let _who = ensure_signed(origin)?; // Read a value from storage. - match >::get() { + match Something::::get() { // Return an error if the value has not been set. None => return Err(Error::::NoneValue.into()), Some(old) => { diff --git a/substrate/frame/examples/src/lib.rs b/substrate/frame/examples/src/lib.rs index f38bbe52dc114900e4b497cb17da6deb4406512c..dee23a41379fc8b732252b9fe4db39bf809699fd 100644 --- a/substrate/frame/examples/src/lib.rs +++ b/substrate/frame/examples/src/lib.rs @@ -43,6 +43,9 @@ //! - [`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. //! //! **Tip**: Use `cargo doc --package --open` to view each pallet's documentation. diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml index f6850b53c030262d49b59205c1dec22923f1a38d..41521114366a298861c883b4d6f14b0eaf6c4276 100644 --- a/substrate/frame/examples/tasks/Cargo.toml +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/examples/tasks/src/weights.rs b/substrate/frame/examples/tasks/src/weights.rs index 793af6e962201fd9f92e0260ea0e24f5bc39753d..c9ddea6f9a8ab4ed19d12f8db89fa3dff59cca3f 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/Cargo.toml b/substrate/frame/executive/Cargo.toml index 7c72fc77be90a12c055329b3e71c07bfb0167bc1..63285e4cb4939c10db3342b5d59eeffc63103d48 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -16,10 +16,11 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +aquamarine = "0.3.2" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } @@ -44,6 +45,7 @@ default = ["std"] with-tracing = ["sp-tracing/with-tracing"] std = [ "codec/std", + "frame-support/experimental", "frame-support/std", "frame-system/std", "frame-try-runtime/std", diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 48ff675f8082ddd0e7779c946b32dde66b171078..3028eaf318e0881c1b6f4d4ea6ac17adfe99a75f 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![cfg_attr(not(feature = "std"), no_std)] + //! # Executive Module //! //! The Executive module acts as the orchestration layer for the runtime. It dispatches incoming @@ -35,6 +37,8 @@ //! - Finalize a block. //! - Start an off-chain worker. //! +//! The flow of their application in a block is explained in the [block flowchart](block_flowchart). +//! //! ### Implementations //! //! The Executive module provides the following implementations: @@ -114,17 +118,51 @@ //! pub type Executive = executive::Executive; //! ``` -#![cfg_attr(not(feature = "std"), no_std)] +#[cfg(doc)] +#[cfg_attr(doc, aquamarine::aquamarine)] +/// # Block Execution +/// +/// These are the steps of block execution as done by [`Executive::execute_block`]. A block is +/// invalid if any of them fail. +/// +/// ```mermaid +/// flowchart TD +/// Executive::execute_block --> on_runtime_upgrade +/// on_runtime_upgrade --> System::initialize +/// Executive::initialize_block --> System::initialize +/// System::initialize --> on_initialize +/// on_initialize --> PreInherents[System::PreInherents] +/// PreInherents --> Inherents[Apply Inherents] +/// Inherents --> PostInherents[System::PostInherents] +/// PostInherents --> Check{MBM ongoing?} +/// Check -->|No| poll +/// Check -->|Yes| post_transactions_2[System::PostTransaction] +/// post_transactions_2 --> Step[MBMs::step] +/// Step --> on_finalize +/// poll --> transactions[Apply Transactions] +/// transactions --> post_transactions_1[System::PostTransaction] +/// post_transactions_1 --> CheckIdle{Weight remaining?} +/// CheckIdle -->|Yes| on_idle +/// CheckIdle -->|No| on_finalize +/// on_idle --> on_finalize +/// ``` +pub mod block_flowchart {} + +#[cfg(test)] +mod tests; use codec::{Codec, Encode}; use frame_support::{ + defensive_assert, dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, + migrations::MultiStepMigrator, pallet_prelude::InvalidTransaction, traits::{ BeforeAllRuntimeMigrations, EnsureInherentsAreFirst, ExecuteBlock, OffchainWorker, - OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, + OnFinalize, OnIdle, OnInitialize, OnPoll, OnRuntimeUpgrade, PostInherents, + PostTransactions, PreInherents, }, - weights::Weight, + weights::{Weight, WeightMeter}, }; use frame_system::pallet_prelude::BlockNumberFor; use sp_runtime::{ @@ -134,7 +172,7 @@ use sp_runtime::{ ValidateUnsigned, Zero, }, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, + ApplyExtrinsicResult, ExtrinsicInclusionMode, }; use sp_std::{marker::PhantomData, prelude::*}; @@ -198,7 +236,8 @@ impl< + OnInitialize> + OnIdle> + OnFinalize> - + OffchainWorker>, + + OffchainWorker> + + OnPoll>, COnRuntimeUpgrade: OnRuntimeUpgrade, > ExecuteBlock for Executive @@ -237,6 +276,7 @@ impl< + OnIdle> + OnFinalize> + OffchainWorker> + + OnPoll> + TryState> + TryDecodeEntireStorage, COnRuntimeUpgrade: OnRuntimeUpgrade, @@ -272,36 +312,50 @@ where select, ); - Self::initialize_block(block.header()); - Self::initial_checks(&block); - + let mode = Self::initialize_block(block.header()); + let num_inherents = Self::initial_checks(&block) as usize; let (header, extrinsics) = block.deconstruct(); + // Check if there are any forbidden non-inherents in the block. + if mode == ExtrinsicInclusionMode::OnlyInherents && extrinsics.len() > num_inherents { + return Err("Only inherents allowed".into()) + } + let try_apply_extrinsic = |uxt: Block::Extrinsic| -> ApplyExtrinsicResult { sp_io::init_tracing(); let encoded = uxt.encode(); let encoded_len = encoded.len(); + let is_inherent = System::is_inherent(&uxt); // skip signature verification. let xt = if signature_check { uxt.check(&Default::default()) } else { uxt.unchecked_into_checked_i_know_what_i_am_doing(&Default::default()) }?; - >::note_extrinsic(encoded); let dispatch_info = xt.get_dispatch_info(); + if !is_inherent && !>::inherents_applied() { + Self::inherents_applied(); + } + + >::note_extrinsic(encoded); let r = Applyable::apply::(xt, &dispatch_info, encoded_len)?; + if r.is_err() && dispatch_info.class == DispatchClass::Mandatory { + return Err(InvalidTransaction::BadMandatory.into()) + } + >::note_applied_extrinsic(&r, dispatch_info); Ok(r.map(|_| ()).map_err(|e| e.error)) }; - for e in extrinsics { + // Apply extrinsics: + for e in extrinsics.iter() { if let Err(err) = try_apply_extrinsic(e.clone()) { log::error!( - target: LOG_TARGET, "executing transaction {:?} failed due to {:?}. Aborting the rest of the block execution.", + target: LOG_TARGET, "transaction {:?} failed due to {:?}. Aborting the rest of the block execution.", e, err, ); @@ -309,9 +363,17 @@ where } } + // In this case there were no transactions to trigger this state transition: + if !>::inherents_applied() { + Self::inherents_applied(); + } + // post-extrinsics book-keeping >::note_finished_extrinsics(); - Self::idle_and_finalize_hook(*header.number()); + ::PostTransactions::post_transactions(); + + Self::on_idle_hook(*header.number()); + Self::on_finalize_hook(*header.number()); // run the try-state checks of all pallets, ensuring they don't alter any state. let _guard = frame_support::StorageNoopGuard::default(); @@ -449,7 +511,8 @@ impl< + OnInitialize> + OnIdle> + OnFinalize> - + OffchainWorker>, + + OffchainWorker> + + OnPoll>, COnRuntimeUpgrade: OnRuntimeUpgrade, > Executive where @@ -464,16 +527,36 @@ where pub fn execute_on_runtime_upgrade() -> Weight { let before_all_weight = ::before_all_runtime_migrations(); - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::on_runtime_upgrade() - .saturating_add(before_all_weight) + + let runtime_upgrade_weight = <( + COnRuntimeUpgrade, + ::SingleBlockMigrations, + // We want to run the migrations before we call into the pallets as they may + // access any state that would then not be migrated. + AllPalletsWithSystem, + ) as OnRuntimeUpgrade>::on_runtime_upgrade(); + + before_all_weight.saturating_add(runtime_upgrade_weight) } /// Start the execution of a particular block. - pub fn initialize_block(header: &frame_system::pallet_prelude::HeaderFor) { + pub fn initialize_block( + header: &frame_system::pallet_prelude::HeaderFor, + ) -> ExtrinsicInclusionMode { sp_io::init_tracing(); sp_tracing::enter_span!(sp_tracing::Level::TRACE, "init_block"); let digests = Self::extract_pre_digest(header); Self::initialize_block_impl(header.number(), header.parent_hash(), &digests); + + Self::extrinsic_mode() + } + + fn extrinsic_mode() -> ExtrinsicInclusionMode { + if ::MultiBlockMigrator::ongoing() { + ExtrinsicInclusionMode::OnlyInherents + } else { + ExtrinsicInclusionMode::AllExtrinsics + } } fn extract_pre_digest(header: &frame_system::pallet_prelude::HeaderFor) -> Digest { @@ -519,6 +602,7 @@ where ); frame_system::Pallet::::note_finished_initialize(); + ::PreInherents::pre_inherents(); } /// Returns if the runtime has been upgraded, based on [`frame_system::LastRuntimeUpgrade`]. @@ -529,7 +613,8 @@ where last.map(|v| v.was_upgraded(¤t)).unwrap_or(true) } - fn initial_checks(block: &Block) { + /// Returns the number of inherents in the block. + fn initial_checks(block: &Block) -> u32 { sp_tracing::enter_span!(sp_tracing::Level::TRACE, "initial_checks"); let header = block.header(); @@ -542,8 +627,9 @@ where "Parent hash should be valid.", ); - if let Err(i) = System::ensure_inherents_are_first(block) { - panic!("Invalid inherent position for extrinsic at index {}", i); + match System::ensure_inherents_are_first(block) { + Ok(num) => num, + Err(i) => panic!("Invalid inherent position for extrinsic at index {}", i), } } @@ -552,53 +638,90 @@ where sp_io::init_tracing(); sp_tracing::within_span! { sp_tracing::info_span!("execute_block", ?block); + // Execute `on_runtime_upgrade` and `on_initialize`. + let mode = Self::initialize_block(block.header()); + let num_inherents = Self::initial_checks(&block) as usize; + let (header, extrinsics) = block.deconstruct(); + let num_extrinsics = extrinsics.len(); - Self::initialize_block(block.header()); + if mode == ExtrinsicInclusionMode::OnlyInherents && num_extrinsics > num_inherents { + // Invalid block + panic!("Only inherents are allowed in this block") + } - // any initial checks - Self::initial_checks(&block); + Self::apply_extrinsics(extrinsics.into_iter()); - // execute extrinsics - let (header, extrinsics) = block.deconstruct(); - Self::execute_extrinsics_with_book_keeping(extrinsics, *header.number()); + // In this case there were no transactions to trigger this state transition: + if !>::inherents_applied() { + defensive_assert!(num_inherents == num_extrinsics); + Self::inherents_applied(); + } - // any final checks + >::note_finished_extrinsics(); + ::PostTransactions::post_transactions(); + + Self::on_idle_hook(*header.number()); + Self::on_finalize_hook(*header.number()); Self::final_checks(&header); } } - /// Execute given extrinsics and take care of post-extrinsics book-keeping. - fn execute_extrinsics_with_book_keeping( - extrinsics: Vec, - block_number: NumberFor, - ) { + /// Logic that runs directly after inherent application. + /// + /// It advances the Multi-Block-Migrations or runs the `on_poll` hook. + pub fn inherents_applied() { + >::note_inherents_applied(); + ::PostInherents::post_inherents(); + + if ::MultiBlockMigrator::ongoing() { + let used_weight = ::MultiBlockMigrator::step(); + >::register_extra_weight_unchecked( + used_weight, + DispatchClass::Mandatory, + ); + } else { + let block_number = >::block_number(); + Self::on_poll_hook(block_number); + } + } + + /// Execute given extrinsics. + fn apply_extrinsics(extrinsics: impl Iterator) { extrinsics.into_iter().for_each(|e| { if let Err(e) = Self::apply_extrinsic(e) { let err: &'static str = e.into(); panic!("{}", err) } }); - - // post-extrinsics book-keeping - >::note_finished_extrinsics(); - - Self::idle_and_finalize_hook(block_number); } /// Finalize the block - it is up the caller to ensure that all header fields are valid /// except state-root. + // Note: Only used by the block builder - not Executive itself. pub fn finalize_block() -> frame_system::pallet_prelude::HeaderFor { sp_io::init_tracing(); sp_tracing::enter_span!(sp_tracing::Level::TRACE, "finalize_block"); - >::note_finished_extrinsics(); - let block_number = >::block_number(); - Self::idle_and_finalize_hook(block_number); + // In this case there were no transactions to trigger this state transition: + if !>::inherents_applied() { + Self::inherents_applied(); + } + >::note_finished_extrinsics(); + ::PostTransactions::post_transactions(); + let block_number = >::block_number(); + Self::on_idle_hook(block_number); + Self::on_finalize_hook(block_number); >::finalize() } - fn idle_and_finalize_hook(block_number: NumberFor) { + /// Run the `on_idle` hook of all pallet, but only if there is weight remaining and there are no + /// ongoing MBMs. + fn on_idle_hook(block_number: NumberFor) { + if ::MultiBlockMigrator::ongoing() { + return + } + let weight = >::block_weight(); let max_weight = >::get().max_block; let remaining_weight = max_weight.saturating_sub(weight.total()); @@ -613,7 +736,33 @@ where DispatchClass::Mandatory, ); } + } + + fn on_poll_hook(block_number: NumberFor) { + defensive_assert!( + !::MultiBlockMigrator::ongoing(), + "on_poll should not be called during migrations" + ); + let weight = >::block_weight(); + let max_weight = >::get().max_block; + let remaining = max_weight.saturating_sub(weight.total()); + + if remaining.all_gt(Weight::zero()) { + let mut meter = WeightMeter::with_limit(remaining); + >>::on_poll( + block_number, + &mut meter, + ); + >::register_extra_weight_unchecked( + meter.consumed(), + DispatchClass::Mandatory, + ); + } + } + + /// Run the `on_finalize` hook of all pallet. + fn on_finalize_hook(block_number: NumberFor) { >>::on_finalize(block_number); } @@ -627,8 +776,18 @@ where let encoded_len = encoded.len(); sp_tracing::enter_span!(sp_tracing::info_span!("apply_extrinsic", ext=?sp_core::hexdisplay::HexDisplay::from(&encoded))); + + // We use the dedicated `is_inherent` check here, since just relying on `Mandatory` dispatch + // class does not capture optional inherents. + let is_inherent = System::is_inherent(&uxt); + // Verify that the signature is good. let xt = uxt.check(&Default::default())?; + let dispatch_info = xt.get_dispatch_info(); + + if !is_inherent && !>::inherents_applied() { + Self::inherents_applied(); + } // We don't need to make sure to `note_extrinsic` only after we know it's going to be // executed to prevent it from leaking in storage since at this point, it will either @@ -637,8 +796,6 @@ where // AUDIT: Under no circumstances may this function panic from here onwards. - // Decode parameters and dispatch - let dispatch_info = xt.get_dispatch_info(); let r = Applyable::apply::(xt, &dispatch_info, encoded_len)?; // Mandatory(inherents) are not allowed to fail. @@ -745,956 +902,3 @@ where ) } } - -#[cfg(test)] -mod tests { - use super::*; - - use sp_core::H256; - use sp_runtime::{ - generic::{DigestItem, Era}, - testing::{Block, Digest, Header}, - traits::{BlakeTwo256, Block as BlockT, Header as HeaderT, IdentityLookup}, - transaction_validity::{ - InvalidTransaction, TransactionValidityError, UnknownTransaction, ValidTransaction, - }, - BuildStorage, DispatchError, - }; - - use frame_support::{ - assert_err, derive_impl, parameter_types, - traits::{fungible, ConstU32, ConstU64, ConstU8, Currency}, - weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, - }; - use frame_system::{ChainContext, LastRuntimeUpgrade, LastRuntimeUpgradeInfo}; - use pallet_balances::Call as BalancesCall; - use pallet_transaction_payment::CurrencyAdapter; - - const TEST_KEY: &[u8] = b":test:key:"; - - #[frame_support::pallet(dev_mode)] - mod custom { - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::pallet] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::hooks] - impl Hooks> for Pallet { - // module hooks. - // one with block number arg and one without - fn on_initialize(n: BlockNumberFor) -> Weight { - println!("on_initialize({})", n); - Weight::from_parts(175, 0) - } - - fn on_idle(n: BlockNumberFor, remaining_weight: Weight) -> Weight { - println!("on_idle{}, {})", n, remaining_weight); - Weight::from_parts(175, 0) - } - - fn on_finalize(n: BlockNumberFor) { - println!("on_finalize({})", n); - } - - fn on_runtime_upgrade() -> Weight { - sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); - Weight::from_parts(200, 0) - } - - fn offchain_worker(n: BlockNumberFor) { - assert_eq!(BlockNumberFor::::from(1u32), n); - } - } - - #[pallet::call] - impl Pallet { - pub fn some_function(origin: OriginFor) -> DispatchResult { - // NOTE: does not make any different. - frame_system::ensure_signed(origin)?; - Ok(()) - } - - #[pallet::weight((200, DispatchClass::Operational))] - pub fn some_root_operation(origin: OriginFor) -> DispatchResult { - frame_system::ensure_root(origin)?; - Ok(()) - } - - pub fn some_unsigned_message(origin: OriginFor) -> DispatchResult { - frame_system::ensure_none(origin)?; - Ok(()) - } - - pub fn allowed_unsigned(origin: OriginFor) -> DispatchResult { - frame_system::ensure_root(origin)?; - Ok(()) - } - - pub fn unallowed_unsigned(origin: OriginFor) -> DispatchResult { - frame_system::ensure_root(origin)?; - Ok(()) - } - - #[pallet::weight((0, DispatchClass::Mandatory))] - pub fn inherent_call(origin: OriginFor) -> DispatchResult { - frame_system::ensure_none(origin)?; - Ok(()) - } - - pub fn calculate_storage_root(_origin: OriginFor) -> DispatchResult { - let root = sp_io::storage::root(sp_runtime::StateVersion::V1); - sp_io::storage::set("storage_root".as_bytes(), &root); - Ok(()) - } - } - - #[pallet::inherent] - impl ProvideInherent for Pallet { - type Call = Call; - - type Error = sp_inherents::MakeFatalError<()>; - - const INHERENT_IDENTIFIER: [u8; 8] = *b"test1234"; - - fn create_inherent(_data: &InherentData) -> Option { - None - } - - fn is_inherent(call: &Self::Call) -> bool { - *call == Call::::inherent_call {} - } - } - - #[pallet::validate_unsigned] - impl ValidateUnsigned for Pallet { - type Call = Call; - - // Inherent call is accepted for being dispatched - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - match call { - Call::allowed_unsigned { .. } => Ok(()), - Call::inherent_call { .. } => Ok(()), - _ => Err(UnknownTransaction::NoUnsignedValidator.into()), - } - } - - // Inherent call is not validated as unsigned - fn validate_unsigned( - _source: TransactionSource, - call: &Self::Call, - ) -> TransactionValidity { - match call { - Call::allowed_unsigned { .. } => Ok(Default::default()), - _ => UnknownTransaction::NoUnsignedValidator.into(), - } - } - } - } - - frame_support::construct_runtime!( - pub enum Runtime { - System: frame_system, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - Custom: custom, - } - ); - - parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::builder() - .base_block(Weight::from_parts(10, 0)) - .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_parts(5, 0)) - .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_parts(1024, u64::MAX).into()) - .build_or_panic(); - pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 10, - write: 100, - }; - } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] - impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = sp_core::H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Block = TestBlock; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = RuntimeVersion; - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; - } - - type Balance = u64; - impl pallet_balances::Config for Runtime { - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ConstU64<1>; - type AccountStore = System; - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = ConstU32<1>; - type RuntimeHoldReason = (); - type RuntimeFreezeReason = (); - } - - parameter_types! { - pub const TransactionByteFee: Balance = 0; - } - impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter; - type OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = IdentityFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = (); - } - impl custom::Config for Runtime {} - - pub struct RuntimeVersion; - impl frame_support::traits::Get for RuntimeVersion { - fn get() -> sp_version::RuntimeVersion { - RuntimeVersionTestValues::get().clone() - } - } - - parameter_types! { - pub static RuntimeVersionTestValues: sp_version::RuntimeVersion = - Default::default(); - } - - type SignedExtra = ( - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, - ); - type TestXt = sp_runtime::testing::TestXt; - type TestBlock = Block; - - // Will contain `true` when the custom runtime logic was called. - const CUSTOM_ON_RUNTIME_KEY: &[u8] = b":custom:on_runtime"; - - struct CustomOnRuntimeUpgrade; - impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { - fn on_runtime_upgrade() -> Weight { - sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes()); - sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode()); - System::deposit_event(frame_system::Event::CodeUpdated); - - assert_eq!(0, System::last_runtime_upgrade_spec_version()); - - Weight::from_parts(100, 0) - } - } - - type Executive = super::Executive< - Runtime, - Block, - ChainContext, - Runtime, - AllPalletsWithSystem, - CustomOnRuntimeUpgrade, - >; - - fn extra(nonce: u64, fee: Balance) -> SignedExtra { - ( - 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))) - } - - fn call_transfer(dest: u64, value: u64) -> RuntimeCall { - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) - } - - #[test] - fn balance_transfer_dispatch_works() { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - 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 + - ::BlockWeights::get() - .get(DispatchClass::Normal) - .base_extrinsic; - let fee: Balance = - ::WeightToFee::weight_to_fee(&weight); - let mut t = sp_io::TestExternalities::new(t); - t.execute_with(|| { - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - let r = Executive::apply_extrinsic(xt); - assert!(r.is_ok()); - assert_eq!(>::total_balance(&1), 142 - fee); - assert_eq!(>::total_balance(&2), 69); - }); - } - - fn new_test_ext(balance_factor: Balance) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } - .assimilate_storage(&mut t) - .unwrap(); - t.into() - } - - fn new_test_ext_v0(balance_factor: Balance) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } - .assimilate_storage(&mut t) - .unwrap(); - (t, sp_runtime::StateVersion::V0).into() - } - - #[test] - fn block_import_works() { - block_import_works_inner( - new_test_ext_v0(1), - array_bytes::hex_n_into_unchecked( - "65e953676859e7a33245908af7ad3637d6861eb90416d433d485e95e2dd174a1", - ), - ); - block_import_works_inner( - new_test_ext(1), - array_bytes::hex_n_into_unchecked( - "5a19b3d6fdb7241836349fdcbe2d9df4d4f945b949d979e31ad50bff1cbcd1c2", - ), - ); - } - fn block_import_works_inner(mut ext: sp_io::TestExternalities, state_root: H256) { - ext.execute_with(|| { - Executive::execute_block(Block { - header: Header { - parent_hash: [69u8; 32].into(), - number: 1, - state_root, - extrinsics_root: array_bytes::hex_n_into_unchecked( - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", - ), - digest: Digest { logs: vec![] }, - }, - extrinsics: vec![], - }); - }); - } - - #[test] - #[should_panic] - fn block_import_of_bad_state_root_fails() { - new_test_ext(1).execute_with(|| { - Executive::execute_block(Block { - header: Header { - parent_hash: [69u8; 32].into(), - number: 1, - state_root: [0u8; 32].into(), - extrinsics_root: array_bytes::hex_n_into_unchecked( - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", - ), - digest: Digest { logs: vec![] }, - }, - extrinsics: vec![], - }); - }); - } - - #[test] - #[should_panic] - fn block_import_of_bad_extrinsic_root_fails() { - new_test_ext(1).execute_with(|| { - Executive::execute_block(Block { - header: Header { - parent_hash: [69u8; 32].into(), - number: 1, - state_root: array_bytes::hex_n_into_unchecked( - "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", - ), - extrinsics_root: [0u8; 32].into(), - digest: Digest { logs: vec![] }, - }, - extrinsics: vec![], - }); - }); - } - - #[test] - 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)); - t.execute_with(|| { - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - assert_err!( - Executive::apply_extrinsic(xt), - TransactionValidityError::Invalid(InvalidTransaction::Future) - ); - assert_eq!(>::extrinsic_index(), Some(0)); - }); - } - - #[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; - // 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); - t.execute_with(|| { - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - // 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( - RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: 33, - value: 0, - }), - sign_extra(1, nonce.into(), 0), - ); - 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 - Weight::from_parts((encoded_len + 5) * (nonce + 1), 0) + base_block_weight, - ); - assert_eq!( - >::extrinsic_index(), - Some(nonce as u32 + 1) - ); - } else { - assert_eq!(res, Err(InvalidTransaction::ExhaustsResources.into())); - } - } - }); - } - - #[test] - fn block_weight_and_size_is_stored_per_tx() { - let xt = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 0, 0), - ); - let x1 = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 1, 0), - ); - let x2 = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 2, 0), - ); - let len = xt.clone().encode().len() as u32; - let mut t = new_test_ext(1); - t.execute_with(|| { - // Block execution weight + on_initialize weight from custom module - let base_block_weight = Weight::from_parts(175, 0) + - ::BlockWeights::get().base_block; - - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - assert_eq!(>::block_weight().total(), base_block_weight); - assert_eq!(>::all_extrinsics_len(), 0); - - assert!(Executive::apply_extrinsic(xt.clone()).unwrap().is_ok()); - 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) + - ::BlockWeights::get() - .get(DispatchClass::Normal) - .base_extrinsic; - assert_eq!( - >::block_weight().total(), - base_block_weight + 3u64 * extrinsic_weight, - ); - assert_eq!(>::all_extrinsics_len(), 3 * len); - - let _ = >::finalize(); - // All extrinsics length cleaned on `System::finalize` - assert_eq!(>::all_extrinsics_len(), 0); - - // New Block - Executive::initialize_block(&Header::new( - 2, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - // Block weight cleaned up on `System::initialize` - assert_eq!(>::block_weight().total(), base_block_weight); - }); - } - - #[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 mut t = new_test_ext(1); - - t.execute_with(|| { - assert_eq!( - Executive::validate_transaction( - TransactionSource::InBlock, - valid.clone(), - Default::default(), - ), - Ok(ValidTransaction::default()), - ); - assert_eq!( - Executive::validate_transaction( - TransactionSource::InBlock, - invalid.clone(), - Default::default(), - ), - Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)), - ); - assert_eq!(Executive::apply_extrinsic(valid), Ok(Err(DispatchError::BadOrigin))); - assert_eq!( - Executive::apply_extrinsic(invalid), - Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)) - ); - }); - } - - #[test] - fn can_not_pay_for_tx_fee_on_full_lock() { - let mut t = new_test_ext(1); - t.execute_with(|| { - as fungible::MutateFreeze>::set_freeze( - &(), - &1, - 110, - ) - .unwrap(); - let xt = TestXt::new( - RuntimeCall::System(frame_system::Call::remark { remark: vec![1u8] }), - sign_extra(1, 0, 0), - ); - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - assert_eq!(Executive::apply_extrinsic(xt), Err(InvalidTransaction::Payment.into()),); - assert_eq!(>::total_balance(&1), 111); - }); - } - - #[test] - fn block_hooks_weight_is_stored() { - new_test_ext(1).execute_with(|| { - Executive::initialize_block(&Header::new_from_number(1)); - Executive::finalize_block(); - // NOTE: might need updates over time if new weights are introduced. - // For now it only accounts for the base block execution weight and - // the `on_initialize` weight defined in the custom test module. - assert_eq!( - >::block_weight().total(), - Weight::from_parts(175 + 175 + 10, 0) - ); - }) - } - - #[test] - fn runtime_upgraded_should_work() { - new_test_ext(1).execute_with(|| { - RuntimeVersionTestValues::mutate(|v| *v = Default::default()); - // It should be added at genesis - assert!(LastRuntimeUpgrade::::exists()); - assert!(!Executive::runtime_upgraded()); - - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } - }); - assert!(Executive::runtime_upgraded()); - - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { - spec_version: 1, - spec_name: "test".into(), - ..Default::default() - } - }); - assert!(Executive::runtime_upgraded()); - - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { - spec_version: 0, - impl_version: 2, - ..Default::default() - } - }); - assert!(!Executive::runtime_upgraded()); - - LastRuntimeUpgrade::::take(); - assert!(Executive::runtime_upgraded()); - }) - } - - #[test] - fn last_runtime_upgrade_was_upgraded_works() { - let test_data = vec![ - (0, "", 1, "", true), - (1, "", 1, "", false), - (1, "", 1, "test", true), - (1, "", 0, "", false), - (1, "", 0, "test", true), - ]; - - for (spec_version, spec_name, c_spec_version, c_spec_name, result) in test_data { - let current = sp_version::RuntimeVersion { - spec_version: c_spec_version, - spec_name: c_spec_name.into(), - ..Default::default() - }; - - let last = LastRuntimeUpgradeInfo { - spec_version: spec_version.into(), - spec_name: spec_name.into(), - }; - - assert_eq!(result, last.was_upgraded(¤t)); - } - } - - #[test] - fn custom_runtime_upgrade_is_called_before_modules() { - new_test_ext(1).execute_with(|| { - // Make sure `on_runtime_upgrade` is called. - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } - }); - - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); - assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); - assert_eq!( - Some(RuntimeVersionTestValues::get().into()), - LastRuntimeUpgrade::::get(), - ) - }); - } - - #[test] - fn event_from_runtime_upgrade_is_included() { - new_test_ext(1).execute_with(|| { - // Make sure `on_runtime_upgrade` is called. - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } - }); - - // set block number to non zero so events are not excluded - System::set_block_number(1); - - Executive::initialize_block(&Header::new( - 2, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - System::assert_last_event(frame_system::Event::::CodeUpdated.into()); - }); - } - - /// Regression test that ensures that the custom on runtime upgrade is called when executive is - /// used through the `ExecuteBlock` trait. - #[test] - fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { - let xt = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 0, 0), - ); - - let header = new_test_ext(1).execute_with(|| { - // Make sure `on_runtime_upgrade` is called. - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } - }); - - // Let's build some fake block. - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); - - Executive::finalize_block() - }); - - // Reset to get the correct new genesis below. - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } - }); - - new_test_ext(1).execute_with(|| { - // Make sure `on_runtime_upgrade` is called. - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } - }); - - >>::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()); - }); - } - - #[test] - fn all_weights_are_recorded_correctly() { - // Reset to get the correct new genesis below. - RuntimeVersionTestValues::take(); - - new_test_ext(1).execute_with(|| { - // Make sure `on_runtime_upgrade` is called for maximum complexity - RuntimeVersionTestValues::mutate(|v| { - *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } - }); - - let block_number = 1; - - Executive::initialize_block(&Header::new( - block_number, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - // Reset the last runtime upgrade info, to make the second call to `on_runtime_upgrade` - // succeed. - LastRuntimeUpgrade::::take(); - - // All weights that show up in the `initialize_block_impl` - let custom_runtime_upgrade_weight = CustomOnRuntimeUpgrade::on_runtime_upgrade(); - let runtime_upgrade_weight = - ::on_runtime_upgrade(); - let on_initialize_weight = - >::on_initialize(block_number); - let base_block_weight = - ::BlockWeights::get().base_block; - - // Weights are recorded correctly - assert_eq!( - frame_system::Pallet::::block_weight().total(), - custom_runtime_upgrade_weight + - runtime_upgrade_weight + - on_initialize_weight + base_block_weight, - ); - }); - } - - #[test] - fn offchain_worker_works_as_expected() { - new_test_ext(1).execute_with(|| { - let parent_hash = sp_core::H256::from([69u8; 32]); - let mut digest = Digest::default(); - digest.push(DigestItem::Seal([1, 2, 3, 4], vec![5, 6, 7, 8])); - - let header = - Header::new(1, H256::default(), H256::default(), parent_hash, digest.clone()); - - Executive::offchain_worker(&header); - - assert_eq!(digest, System::digest()); - assert_eq!(parent_hash, System::block_hash(0)); - assert_eq!(header.hash(), System::block_hash(1)); - }); - } - - #[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 header = new_test_ext(1).execute_with(|| { - // Let's build some fake block. - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); - - Executive::finalize_block() - }); - - new_test_ext(1).execute_with(|| { - Executive::execute_block(Block::new(header, vec![xt])); - }); - } - - #[test] - #[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] - fn invalid_inherent_position_fail() { - let xt1 = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 0, 0), - ); - let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); - - let header = new_test_ext(1).execute_with(|| { - // Let's build some fake block. - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); - Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); - - Executive::finalize_block() - }); - - new_test_ext(1).execute_with(|| { - Executive::execute_block(Block::new(header, vec![xt1, xt2])); - }); - } - - #[test] - fn valid_inherents_position_works() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); - let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); - - let header = new_test_ext(1).execute_with(|| { - // Let's build some fake block. - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); - Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); - - Executive::finalize_block() - }); - - new_test_ext(1).execute_with(|| { - Executive::execute_block(Block::new(header, vec![xt1, xt2])); - }); - } - - #[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_call {}), sign_extra(1, 0, 0)); - - new_test_ext(1).execute_with(|| { - Executive::execute_block(Block::new( - Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - ), - vec![xt1], - )); - }); - } - - // 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_call {}), None); - - new_test_ext(1).execute_with(|| { - assert_eq!( - Executive::validate_transaction(TransactionSource::External, xt1, H256::random()) - .unwrap_err(), - InvalidTransaction::MandatoryValidation.into() - ); - }) - } -} diff --git a/substrate/frame/executive/src/tests.rs b/substrate/frame/executive/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..a3f70a9fc3c2a081b52a08f3e9a8a617ab75c7a9 --- /dev/null +++ b/substrate/frame/executive/src/tests.rs @@ -0,0 +1,1476 @@ +// 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 `frame-executive` crate. + +use super::*; + +use sp_core::H256; +use sp_runtime::{ + generic::{DigestItem, Era}, + testing::{Block, Digest, Header}, + traits::{Block as BlockT, Header as HeaderT}, + transaction_validity::{ + InvalidTransaction, TransactionValidityError, UnknownTransaction, ValidTransaction, + }, + BuildStorage, DispatchError, +}; + +use frame_support::{ + assert_err, assert_ok, derive_impl, + migrations::MultiStepMigrator, + pallet_prelude::*, + parameter_types, + traits::{fungible, ConstU8, Currency, IsInherent}, + weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightMeter, WeightToFee}, +}; +use frame_system::{pallet_prelude::*, ChainContext, LastRuntimeUpgrade, LastRuntimeUpgradeInfo}; +use pallet_balances::Call as BalancesCall; +use pallet_transaction_payment::CurrencyAdapter; + +const TEST_KEY: &[u8] = b":test:key:"; + +#[frame_support::pallet(dev_mode)] +mod custom { + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::hooks] + impl Hooks> for Pallet { + // module hooks. + // one with block number arg and one without + fn on_initialize(_: BlockNumberFor) -> Weight { + Weight::from_parts(175, 0) + } + + fn on_idle(_: BlockNumberFor, _: Weight) -> Weight { + Weight::from_parts(175, 0) + } + + fn on_poll(_: BlockNumberFor, _: &mut WeightMeter) {} + + fn on_finalize(_: BlockNumberFor) {} + + fn on_runtime_upgrade() -> Weight { + sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); + Weight::from_parts(200, 0) + } + + fn offchain_worker(n: BlockNumberFor) { + assert_eq!(BlockNumberFor::::from(1u32), n); + } + } + + #[pallet::call] + impl Pallet { + pub fn some_function(origin: OriginFor) -> DispatchResult { + // NOTE: does not make any difference. + frame_system::ensure_signed(origin)?; + Ok(()) + } + + #[pallet::weight((200, DispatchClass::Operational))] + pub fn some_root_operation(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + pub fn some_unsigned_message(origin: OriginFor) -> DispatchResult { + frame_system::ensure_none(origin)?; + Ok(()) + } + + pub fn allowed_unsigned(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + pub fn unallowed_unsigned(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + #[pallet::weight((0, DispatchClass::Mandatory))] + pub fn inherent(origin: OriginFor) -> DispatchResult { + frame_system::ensure_none(origin)?; + Ok(()) + } + + pub fn calculate_storage_root(_origin: OriginFor) -> DispatchResult { + let root = sp_io::storage::root(sp_runtime::StateVersion::V1); + sp_io::storage::set("storage_root".as_bytes(), &root); + Ok(()) + } + } + + #[pallet::inherent] + impl ProvideInherent for Pallet { + type Call = Call; + + type Error = sp_inherents::MakeFatalError<()>; + + const INHERENT_IDENTIFIER: [u8; 8] = *b"test1234"; + + fn create_inherent(_data: &InherentData) -> Option { + None + } + + fn is_inherent(call: &Self::Call) -> bool { + *call == Call::::inherent {} + } + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + // Inherent call is accepted for being dispatched + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + match call { + Call::allowed_unsigned { .. } => Ok(()), + Call::inherent { .. } => Ok(()), + _ => Err(UnknownTransaction::NoUnsignedValidator.into()), + } + } + + // Inherent call is not validated as unsigned + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + match call { + Call::allowed_unsigned { .. } => Ok(Default::default()), + _ => UnknownTransaction::NoUnsignedValidator.into(), + } + } + } +} + +#[frame_support::pallet(dev_mode)] +mod custom2 { + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::hooks] + impl Hooks> for Pallet { + // module hooks. + // one with block number arg and one without + fn on_initialize(_: BlockNumberFor) -> Weight { + assert!( + !MockedSystemCallbacks::pre_inherent_called(), + "Pre inherent hook goes after on_initialize" + ); + + Weight::from_parts(0, 0) + } + + fn on_idle(_: BlockNumberFor, _: Weight) -> Weight { + assert!( + MockedSystemCallbacks::post_transactions_called(), + "Post transactions hook goes before after on_idle" + ); + Weight::from_parts(0, 0) + } + + fn on_finalize(_: BlockNumberFor) { + assert!( + MockedSystemCallbacks::post_transactions_called(), + "Post transactions hook goes before after on_finalize" + ); + } + + fn on_runtime_upgrade() -> Weight { + sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); + Weight::from_parts(0, 0) + } + } + + #[pallet::call] + impl Pallet { + pub fn allowed_unsigned(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + pub fn some_call(_: OriginFor) -> DispatchResult { + assert!(MockedSystemCallbacks::post_inherent_called()); + assert!(!MockedSystemCallbacks::post_transactions_called()); + assert!(System::inherents_applied()); + + Ok(()) + } + + #[pallet::weight({0})] + pub fn optional_inherent(origin: OriginFor) -> DispatchResult { + frame_system::ensure_none(origin)?; + + assert!(MockedSystemCallbacks::pre_inherent_called()); + assert!(!MockedSystemCallbacks::post_inherent_called(), "Should not already be called"); + assert!(!System::inherents_applied()); + + Ok(()) + } + + #[pallet::weight((0, DispatchClass::Mandatory))] + pub fn inherent(origin: OriginFor) -> DispatchResult { + frame_system::ensure_none(origin)?; + + assert!(MockedSystemCallbacks::pre_inherent_called()); + assert!(!MockedSystemCallbacks::post_inherent_called(), "Should not already be called"); + assert!(!System::inherents_applied()); + + Ok(()) + } + } + + #[pallet::inherent] + impl ProvideInherent for Pallet { + type Call = Call; + + type Error = sp_inherents::MakeFatalError<()>; + + const INHERENT_IDENTIFIER: [u8; 8] = *b"test1235"; + + fn create_inherent(_data: &InherentData) -> Option { + None + } + + fn is_inherent(call: &Self::Call) -> bool { + matches!(call, Call::::inherent {} | Call::::optional_inherent {}) + } + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + // Inherent call is accepted for being dispatched + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + match call { + Call::allowed_unsigned { .. } | + Call::optional_inherent { .. } | + Call::inherent { .. } => Ok(()), + _ => Err(UnknownTransaction::NoUnsignedValidator.into()), + } + } + + // Inherent call is not validated as unsigned + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + match call { + Call::allowed_unsigned { .. } => Ok(Default::default()), + _ => UnknownTransaction::NoUnsignedValidator.into(), + } + } + } +} + +frame_support::construct_runtime!( + pub struct Runtime + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + Custom: custom::{Pallet, Call, ValidateUnsigned, Inherent}, + Custom2: custom2::{Pallet, Call, ValidateUnsigned, Inherent}, + } +); + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::builder() + .base_block(Weight::from_parts(10, 0)) + .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_parts(5, 0)) + .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_parts(1024, u64::MAX).into()) + .build_or_panic(); + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 10, + write: 100, + }; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type BlockWeights = BlockWeights; + type RuntimeOrigin = RuntimeOrigin; + type Nonce = u64; + type RuntimeCall = RuntimeCall; + type Block = TestBlock; + type RuntimeEvent = RuntimeEvent; + type Version = RuntimeVersion; + type AccountData = pallet_balances::AccountData; + type PreInherents = MockedSystemCallbacks; + type PostInherents = MockedSystemCallbacks; + type PostTransactions = MockedSystemCallbacks; + type MultiBlockMigrator = MockedModeGetter; +} + +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() + } +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type AccountStore = System; + type WeightInfo = BalancesWeights; +} + +parameter_types! { + pub const TransactionByteFee: Balance = 0; +} +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = CurrencyAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = (); + type WeightInfo = (); +} + +impl custom::Config for Runtime {} +impl custom2::Config for Runtime {} + +pub struct RuntimeVersion; +impl frame_support::traits::Get for RuntimeVersion { + fn get() -> sp_version::RuntimeVersion { + RuntimeVersionTestValues::get().clone() + } +} + +#[derive(Clone, Debug, Encode, codec::Decode, PartialEq, Eq, scale_info::TypeInfo)] +pub struct AccountU64(u64); +impl sp_runtime::traits::IdentifyAccount for AccountU64 { + type AccountId = u64; + fn into_account(self) -> u64 { + self.0 + } +} + +impl sp_runtime::traits::Verify for AccountU64 { + type Signer = AccountU64; + fn verify>( + &self, + _msg: L, + _signer: &::AccountId, + ) -> bool { + true + } +} + +impl From for AccountU64 { + fn from(value: u64) -> Self { + Self(value) + } +} + +parameter_types! { + pub static RuntimeVersionTestValues: sp_version::RuntimeVersion = + Default::default(); +} + +type TxExtension = ( + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +type UncheckedXt = + sp_runtime::generic::UncheckedExtrinsic; +type TestBlock = Block; + +// Will contain `true` when the custom runtime logic was called. +const CUSTOM_ON_RUNTIME_KEY: &[u8] = b":custom:on_runtime"; + +struct CustomOnRuntimeUpgrade; +impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { + fn on_runtime_upgrade() -> Weight { + sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes()); + sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode()); + System::deposit_event(frame_system::Event::CodeUpdated); + + assert_eq!(0, System::last_runtime_upgrade_spec_version()); + + Weight::from_parts(100, 0) + } +} + +type Executive = super::Executive< + Runtime, + Block, + ChainContext, + Runtime, + AllPalletsWithSystem, + CustomOnRuntimeUpgrade, +>; + +parameter_types! { + pub static SystemCallbacksCalled: u32 = 0; +} + +pub struct MockedSystemCallbacks; +impl PreInherents for MockedSystemCallbacks { + fn pre_inherents() { + assert_eq!(SystemCallbacksCalled::get(), 0); + SystemCallbacksCalled::set(1); + // Change the storage to modify the root hash: + frame_support::storage::unhashed::put(b":pre_inherent", b"0"); + } +} + +impl PostInherents for MockedSystemCallbacks { + fn post_inherents() { + assert_eq!(SystemCallbacksCalled::get(), 1); + SystemCallbacksCalled::set(2); + // Change the storage to modify the root hash: + frame_support::storage::unhashed::put(b":post_inherent", b"0"); + } +} + +impl PostTransactions for MockedSystemCallbacks { + fn post_transactions() { + assert_eq!(SystemCallbacksCalled::get(), 2); + SystemCallbacksCalled::set(3); + // Change the storage to modify the root hash: + frame_support::storage::unhashed::put(b":post_transaction", b"0"); + } +} + +impl MockedSystemCallbacks { + fn pre_inherent_called() -> bool { + SystemCallbacksCalled::get() >= 1 + } + + fn post_inherent_called() -> bool { + SystemCallbacksCalled::get() >= 2 + } + + fn post_transactions_called() -> bool { + SystemCallbacksCalled::get() >= 3 + } + + fn reset() { + SystemCallbacksCalled::set(0); + frame_support::storage::unhashed::kill(b":pre_inherent"); + frame_support::storage::unhashed::kill(b":post_inherent"); + frame_support::storage::unhashed::kill(b":post_transaction"); + } +} + +parameter_types! { + pub static MbmActive: bool = false; +} + +pub struct MockedModeGetter; +impl MultiStepMigrator for MockedModeGetter { + fn ongoing() -> bool { + MbmActive::get() + } + + fn step() -> Weight { + Weight::zero() + } +} + +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), + ) + .into() +} + +fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) +} + +#[test] +fn balance_transfer_dispatch_works() { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 211)] } + .assimilate_storage(&mut t) + .unwrap(); + let xt = UncheckedXt::new_signed(call_transfer(2, 69), 1, 1.into(), tx_ext(0, 0)); + let weight = xt.get_dispatch_info().weight + + ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let fee: Balance = + ::WeightToFee::weight_to_fee(&weight); + let mut t = sp_io::TestExternalities::new(t); + t.execute_with(|| { + Executive::initialize_block(&Header::new_from_number(1)); + let r = Executive::apply_extrinsic(xt); + assert!(r.is_ok()); + assert_eq!(>::total_balance(&1), 142 - fee); + assert_eq!(>::total_balance(&2), 69); + }); +} + +fn new_test_ext(balance_factor: Balance) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext: sp_io::TestExternalities = t.into(); + ext.execute_with(|| { + SystemCallbacksCalled::set(0); + }); + ext +} + +fn new_test_ext_v0(balance_factor: Balance) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } + .assimilate_storage(&mut t) + .unwrap(); + (t, sp_runtime::StateVersion::V0).into() +} + +#[test] +fn block_import_works() { + block_import_works_inner( + new_test_ext_v0(1), + array_bytes::hex_n_into_unchecked( + "4826d3bdf87dbbc883d2ab274cbe272f58ed94a904619b59953e48294d1142d2", + ), + ); + block_import_works_inner( + new_test_ext(1), + array_bytes::hex_n_into_unchecked( + "d6b465f5a50c9f8d5a6edc0f01d285a6b19030f097d3aaf1649b7be81649f118", + ), + ); +} +fn block_import_works_inner(mut ext: sp_io::TestExternalities, state_root: H256) { + ext.execute_with(|| { + Executive::execute_block(Block { + header: Header { + parent_hash: [69u8; 32].into(), + number: 1, + state_root, + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), + digest: Digest { logs: vec![] }, + }, + extrinsics: vec![], + }); + }); +} + +#[test] +#[should_panic] +fn block_import_of_bad_state_root_fails() { + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block { + header: Header { + parent_hash: [69u8; 32].into(), + number: 1, + state_root: [0u8; 32].into(), + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), + digest: Digest { logs: vec![] }, + }, + extrinsics: vec![], + }); + }); +} + +#[test] +#[should_panic] +fn block_import_of_bad_extrinsic_root_fails() { + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block { + header: Header { + parent_hash: [69u8; 32].into(), + number: 1, + state_root: array_bytes::hex_n_into_unchecked( + "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", + ), + extrinsics_root: [0u8; 32].into(), + digest: Digest { logs: vec![] }, + }, + extrinsics: vec![], + }); + }); +} + +#[test] +fn bad_extrinsic_not_inserted() { + let mut t = new_test_ext(1); + // bad nonce check! + 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!( + Executive::apply_extrinsic(xt), + TransactionValidityError::Invalid(InvalidTransaction::Future) + ); + assert_eq!(>::extrinsic_index(), Some(0)); + }); +} + +#[test] +fn block_weight_limit_enforced() { + let mut t = new_test_ext(10000); + let transfer_weight = + <::WeightInfo as pallet_balances::WeightInfo>::transfer_allow_death(); + // 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() / (transfer_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 = UncheckedXt::new_signed( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + 1, + 1.into(), + tx_ext(nonce.into(), 0), + ); + 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 + Weight::from_parts((transfer_weight.ref_time() + 5) * (nonce + 1), 0) + + base_block_weight, + ); + assert_eq!( + >::extrinsic_index(), + Some(nonce as u32 + 1) + ); + } else { + assert_eq!(res, Err(InvalidTransaction::ExhaustsResources.into())); + } + } + }); +} + +#[test] +fn block_weight_and_size_is_stored_per_tx() { + let xt = UncheckedXt::new_signed( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + 1, + 1.into(), + tx_ext(0, 0), + ); + let x1 = UncheckedXt::new_signed( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + 1, + 1.into(), + tx_ext(1, 0), + ); + let x2 = UncheckedXt::new_signed( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + 1, + 1.into(), + tx_ext(2, 0), + ); + let len = xt.clone().encode().len() as u32; + let transfer_weight = <::WeightInfo as pallet_balances::WeightInfo>::transfer_allow_death(); + let mut t = new_test_ext(1); + t.execute_with(|| { + // Block execution weight + on_initialize weight from custom module + let base_block_weight = Weight::from_parts(175, 0) + + ::BlockWeights::get().base_block; + + Executive::initialize_block(&Header::new_from_number(1)); + + assert_eq!(>::block_weight().total(), base_block_weight); + assert_eq!(>::all_extrinsics_len(), 0); + + assert!(Executive::apply_extrinsic(xt.clone()).unwrap().is_ok()); + assert!(Executive::apply_extrinsic(x1.clone()).unwrap().is_ok()); + assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); + + let extrinsic_weight = transfer_weight + + ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + assert_eq!( + >::block_weight().total(), + base_block_weight + 3u64 * extrinsic_weight, + ); + assert_eq!(>::all_extrinsics_len(), 3 * len); + + let _ = >::finalize(); + // All extrinsics length cleaned on `System::finalize` + assert_eq!(>::all_extrinsics_len(), 0); + + // Reset to a new block. + SystemCallbacksCalled::take(); + Executive::initialize_block(&Header::new_from_number(2)); + + // Block weight cleaned up on `System::initialize` + assert_eq!(>::block_weight().total(), base_block_weight); + }); +} + +#[test] +fn validate_unsigned() { + 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(|| { + assert_eq!( + Executive::validate_transaction( + TransactionSource::InBlock, + valid.clone(), + Default::default(), + ), + Ok(ValidTransaction::default()), + ); + assert_eq!( + Executive::validate_transaction( + TransactionSource::InBlock, + invalid.clone(), + Default::default(), + ), + Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)), + ); + // Need to initialize the block before applying extrinsics for the `MockedSystemCallbacks` + // check. + Executive::initialize_block(&Header::new_from_number(1)); + assert_eq!(Executive::apply_extrinsic(valid), Ok(Err(DispatchError::BadOrigin))); + assert_eq!( + Executive::apply_extrinsic(invalid), + Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)) + ); + }); +} + +#[test] +fn can_not_pay_for_tx_fee_on_full_lock() { + let mut t = new_test_ext(1); + t.execute_with(|| { + as fungible::MutateFreeze>::set_freeze(&(), &1, 110) + .unwrap(); + let xt = UncheckedXt::new_signed( + RuntimeCall::System(frame_system::Call::remark { remark: vec![1u8] }), + 1, + 1.into(), + tx_ext(0, 0), + ); + Executive::initialize_block(&Header::new_from_number(1)); + + assert_eq!(Executive::apply_extrinsic(xt), Err(InvalidTransaction::Payment.into()),); + assert_eq!(>::total_balance(&1), 111); + }); +} + +#[test] +fn block_hooks_weight_is_stored() { + new_test_ext(1).execute_with(|| { + Executive::initialize_block(&Header::new_from_number(1)); + Executive::finalize_block(); + // NOTE: might need updates over time if new weights are introduced. + // For now it only accounts for the base block execution weight and + // the `on_initialize` weight defined in the custom test module. + assert_eq!( + >::block_weight().total(), + Weight::from_parts(175 + 175 + 10, 0) + ); + }) +} + +#[test] +fn runtime_upgraded_should_work() { + new_test_ext(1).execute_with(|| { + RuntimeVersionTestValues::mutate(|v| *v = Default::default()); + // It should be added at genesis + assert!(LastRuntimeUpgrade::::exists()); + assert!(!Executive::runtime_upgraded()); + + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + assert!(Executive::runtime_upgraded()); + + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { + spec_version: 1, + spec_name: "test".into(), + ..Default::default() + } + }); + assert!(Executive::runtime_upgraded()); + + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { + spec_version: 0, + impl_version: 2, + ..Default::default() + } + }); + assert!(!Executive::runtime_upgraded()); + + LastRuntimeUpgrade::::take(); + assert!(Executive::runtime_upgraded()); + }) +} + +#[test] +fn last_runtime_upgrade_was_upgraded_works() { + let test_data = vec![ + (0, "", 1, "", true), + (1, "", 1, "", false), + (1, "", 1, "test", true), + (1, "", 0, "", false), + (1, "", 0, "test", true), + ]; + + for (spec_version, spec_name, c_spec_version, c_spec_name, result) in test_data { + let current = sp_version::RuntimeVersion { + spec_version: c_spec_version, + spec_name: c_spec_name.into(), + ..Default::default() + }; + + let last = LastRuntimeUpgradeInfo { + spec_version: spec_version.into(), + spec_name: spec_name.into(), + }; + + assert_eq!(result, last.was_upgraded(¤t)); + } +} + +#[test] +fn custom_runtime_upgrade_is_called_before_modules() { + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + Executive::initialize_block(&Header::new_from_number(1)); + + assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); + assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); + assert_eq!( + Some(RuntimeVersionTestValues::get().into()), + LastRuntimeUpgrade::::get(), + ) + }); +} + +#[test] +fn event_from_runtime_upgrade_is_included() { + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + // set block number to non zero so events are not excluded + System::set_block_number(1); + + Executive::initialize_block(&Header::new_from_number(2)); + System::assert_last_event(frame_system::Event::::CodeUpdated.into()); + }); +} + +/// Regression test that ensures that the custom on runtime upgrade is called when executive is +/// used through the `ExecuteBlock` trait. +#[test] +fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { + let xt = UncheckedXt::new_signed( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + 1, + 1.into(), + tx_ext(0, 0), + ); + + let header = new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + // Let's build some fake block. + Executive::initialize_block(&Header::new_from_number(1)); + + Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + // Reset to get the correct new genesis below. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } + }); + + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + >>::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()); + }); +} + +#[test] +fn all_weights_are_recorded_correctly() { + // Reset to get the correct new genesis below. + RuntimeVersionTestValues::take(); + + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called for maximum complexity + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + let block_number = 1; + + Executive::initialize_block(&Header::new_from_number(block_number)); + + // Reset the last runtime upgrade info, to make the second call to `on_runtime_upgrade` + // succeed. + LastRuntimeUpgrade::::take(); + MockedSystemCallbacks::reset(); + + // All weights that show up in the `initialize_block_impl` + let custom_runtime_upgrade_weight = CustomOnRuntimeUpgrade::on_runtime_upgrade(); + let runtime_upgrade_weight = + ::on_runtime_upgrade(); + let on_initialize_weight = + >::on_initialize(block_number); + let base_block_weight = ::BlockWeights::get().base_block; + + // Weights are recorded correctly + assert_eq!( + frame_system::Pallet::::block_weight().total(), + custom_runtime_upgrade_weight + + runtime_upgrade_weight + + on_initialize_weight + + base_block_weight, + ); + }); +} + +#[test] +fn offchain_worker_works_as_expected() { + new_test_ext(1).execute_with(|| { + let parent_hash = sp_core::H256::from([69u8; 32]); + let mut digest = Digest::default(); + digest.push(DigestItem::Seal([1, 2, 3, 4], vec![5, 6, 7, 8])); + + let header = Header::new(1, H256::default(), H256::default(), parent_hash, digest.clone()); + + Executive::offchain_worker(&header); + + assert_eq!(digest, System::digest()); + assert_eq!(parent_hash, System::block_hash(0)); + assert_eq!(header.hash(), System::block_hash(1)); + }); +} + +#[test] +fn calculating_storage_root_twice_works() { + let call = RuntimeCall::Custom(custom::Call::calculate_storage_root {}); + 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. + Executive::initialize_block(&Header::new_from_number(1)); + + Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new(header, vec![xt])); + }); +} + +#[test] +#[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] +fn invalid_inherent_position_fail() { + let xt1 = UncheckedXt::new_signed( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + 1, + 1.into(), + tx_ext(0, 0), + ); + let xt2 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + + let header = new_test_ext(1).execute_with(|| { + // Let's build some fake block. + Executive::initialize_block(&Header::new_from_number(1)); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new(header, vec![xt1, xt2])); + }); +} + +#[test] +fn valid_inherents_position_works() { + 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. + Executive::initialize_block(&Header::new_from_number(1)); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new(header, vec![xt1, xt2])); + }); +} + +#[test] +#[should_panic(expected = "A call was labelled as mandatory, but resulted in an Error.")] +fn invalid_inherents_fail_block_execution() { + 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( + Header::new(1, H256::default(), H256::default(), [69u8; 32].into(), Digest::default()), + vec![xt1], + )); + }); +} + +// Inherents are created by the runtime and don't need to be validated. +#[test] +fn inherents_fail_validate_block() { + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + + new_test_ext(1).execute_with(|| { + assert_eq!( + Executive::validate_transaction(TransactionSource::External, xt1, H256::random()) + .unwrap_err(), + InvalidTransaction::MandatoryValidation.into() + ); + }) +} + +/// Inherents still work while `initialize_block` forbids transactions. +#[test] +fn inherents_ok_while_exts_forbidden_works() { + 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)); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + // This is not applied: + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + // Tell `initialize_block` to forbid extrinsics: + Executive::execute_block(Block::new(header, vec![xt1])); + }); +} + +/// Refuses to import blocks with transactions during `OnlyInherents` mode. +#[test] +#[should_panic = "Only inherents are allowed in this block"] +fn transactions_in_only_inherents_block_errors() { + 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)); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + MbmActive::set(true); + Executive::execute_block(Block::new(header, vec![xt1, xt2])); + }); +} + +/// Same as above but no error. +#[test] +fn transactions_in_normal_block_works() { + 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)); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + // Tell `initialize_block` to forbid extrinsics: + Executive::execute_block(Block::new(header, vec![xt1, xt2])); + }); +} + +#[test] +#[cfg(feature = "try-runtime")] +fn try_execute_block_works() { + 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)); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + Executive::try_execute_block( + Block::new(header, vec![xt1, xt2]), + true, + true, + frame_try_runtime::TryStateSelect::All, + ) + .unwrap(); + }); +} + +/// Same as `extrinsic_while_exts_forbidden_errors` but using the try-runtime function. +#[test] +#[cfg(feature = "try-runtime")] +#[should_panic = "Only inherents allowed"] +fn try_execute_tx_forbidden_errors() { + 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. + Executive::initialize_block(&Header::new_from_number(1)); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + MbmActive::set(true); + Executive::try_execute_block( + Block::new(header, vec![xt1, xt2]), + true, + true, + frame_try_runtime::TryStateSelect::All, + ) + .unwrap(); + }); +} + +/// Check that `ensure_inherents_are_first` reports the correct indices. +#[test] +fn ensure_inherents_are_first_works() { + 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(|| { + Executive::initialize_block(&Header::new_from_number(1)); + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + assert_ok!(Runtime::ensure_inherents_are_first(&Block::new(header.clone(), vec![]),), 0); + assert_ok!( + Runtime::ensure_inherents_are_first(&Block::new(header.clone(), vec![xt2.clone()]),), + 0 + ); + assert_ok!( + Runtime::ensure_inherents_are_first(&Block::new(header.clone(), vec![in1.clone()])), + 1 + ); + assert_ok!( + Runtime::ensure_inherents_are_first(&Block::new( + header.clone(), + vec![in1.clone(), xt2.clone()] + ),), + 1 + ); + assert_ok!( + Runtime::ensure_inherents_are_first(&Block::new( + header.clone(), + vec![in2.clone(), in1.clone(), xt2.clone()] + ),), + 2 + ); + + assert_eq!( + Runtime::ensure_inherents_are_first(&Block::new( + header.clone(), + vec![xt2.clone(), in1.clone()] + ),), + Err(1) + ); + assert_eq!( + Runtime::ensure_inherents_are_first(&Block::new( + header.clone(), + vec![xt2.clone(), xt2.clone(), in1.clone()] + ),), + Err(2) + ); + assert_eq!( + Runtime::ensure_inherents_are_first(&Block::new( + header.clone(), + vec![xt2.clone(), xt2.clone(), xt2.clone(), in2.clone()] + ),), + Err(3) + ); + }); +} + +/// Check that block execution rejects blocks with transactions in them while MBMs are active and +/// also that all the system callbacks are called correctly. +#[test] +fn callbacks_in_block_execution_works() { + callbacks_in_block_execution_works_inner(false); + callbacks_in_block_execution_works_inner(true); +} + +fn callbacks_in_block_execution_works_inner(mbms_active: bool) { + MbmActive::set(mbms_active); + + for (n_in, n_tx) in (0..10usize).zip(0..10usize) { + let mut extrinsics = Vec::new(); + + let header = new_test_ext(10).execute_with(|| { + MockedSystemCallbacks::reset(); + Executive::initialize_block(&Header::new_from_number(1)); + assert_eq!(SystemCallbacksCalled::get(), 1); + + for i in 0..n_in { + let xt = if i % 2 == 0 { + UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})) + } else { + 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 = UncheckedXt::new_signed( + RuntimeCall::Custom2(custom2::Call::some_call {}), + 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. + Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); + extrinsics.push(xt); + } + + Executive::finalize_block() + }); + assert_eq!(SystemCallbacksCalled::get(), 3); + + new_test_ext(10).execute_with(|| { + let header = std::panic::catch_unwind(|| { + Executive::execute_block(Block::new(header, extrinsics)); + }); + + match header { + Err(e) => { + let err = e.downcast::<&str>().unwrap(); + assert_eq!(*err, "Only inherents are allowed in this block"); + assert!( + MbmActive::get() && n_tx > 0, + "Transactions should be rejected when MBMs are active" + ); + }, + Ok(_) => { + assert_eq!(SystemCallbacksCalled::get(), 3); + assert!( + !MbmActive::get() || n_tx == 0, + "MBMs should be deactivated after finalization" + ); + }, + } + }); + } +} + +#[test] +fn post_inherent_called_after_all_inherents() { + 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. + Executive::initialize_block(&Header::new_from_number(1)); + + Executive::apply_extrinsic(in1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + #[cfg(feature = "try-runtime")] + new_test_ext(1).execute_with(|| { + Executive::try_execute_block( + Block::new(header.clone(), vec![in1.clone(), xt1.clone()]), + true, + true, + frame_try_runtime::TryStateSelect::All, + ) + .unwrap(); + assert!(MockedSystemCallbacks::post_transactions_called()); + }); + + new_test_ext(1).execute_with(|| { + MockedSystemCallbacks::reset(); + Executive::execute_block(Block::new(header, vec![in1, xt1])); + assert!(MockedSystemCallbacks::post_transactions_called()); + }); +} + +/// Regression test for AppSec finding #40. +#[test] +fn post_inherent_called_after_all_optional_inherents() { + 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. + Executive::initialize_block(&Header::new_from_number(1)); + + Executive::apply_extrinsic(in1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + #[cfg(feature = "try-runtime")] + new_test_ext(1).execute_with(|| { + Executive::try_execute_block( + Block::new(header.clone(), vec![in1.clone(), xt1.clone()]), + true, + true, + frame_try_runtime::TryStateSelect::All, + ) + .unwrap(); + assert!(MockedSystemCallbacks::post_transactions_called()); + }); + + new_test_ext(1).execute_with(|| { + MockedSystemCallbacks::reset(); + Executive::execute_block(Block::new(header, vec![in1, xt1])); + assert!(MockedSystemCallbacks::post_transactions_called()); + }); +} + +#[test] +fn is_inherent_works() { + let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::inherent {})); + assert!(Runtime::is_inherent(&ext)); + let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::optional_inherent {})); + assert!(Runtime::is_inherent(&ext)); + + let ext = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + assert!(!Runtime::is_inherent(&ext)); + + 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/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index 5d0a5410f8db0e32daf44b9523cd8b85614325ab..eca8247845e2a5990ee98426866fdf5ac929034d 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/fast-unstake/src/migrations.rs b/substrate/frame/fast-unstake/src/migrations.rs index 564388407045e0ae86b87c7823f3f07c5613e012..97ad86bfff42bf6ee1e258f5663d9bb53144373c 100644 --- a/substrate/frame/fast-unstake/src/migrations.rs +++ b/substrate/frame/fast-unstake/src/migrations.rs @@ -33,12 +33,12 @@ pub mod v1 { pub struct MigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); log!( info, - "Running migration with current storage version {:?} / onchain {:?}", + "Running migration with in-code storage version {:?} / onchain {:?}", current, onchain ); diff --git a/substrate/frame/fast-unstake/src/weights.rs b/substrate/frame/fast-unstake/src/weights.rs index 9c25a409f74099fc4d13158f99fae9036b34eff8..d783ba921bf9c11fcf1475d25ad87c6ca600ebf1 100644 --- a/substrate/frame/fast-unstake/src/weights.rs +++ b/substrate/frame/fast-unstake/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_fast_unstake +//! Autogenerated weights for `pallet_fast_unstake` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/fast-unstake/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/fast-unstake/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_fast_unstake. +/// Weight functions needed for `pallet_fast_unstake`. pub trait WeightInfo { fn on_idle_unstake(b: u32, ) -> Weight; fn on_idle_check(v: u32, b: u32, ) -> Weight; @@ -59,301 +58,305 @@ pub trait WeightInfo { fn control() -> Weight; } -/// Weights for pallet_fast_unstake using the Substrate node and recommended hardware. +/// Weights for `pallet_fast_unstake` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:64 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Bonded (r:64 w:64) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:64 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:64 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: System Account (r:64 w:64) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:64) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:64) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:1) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) + /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::SlashingSpans` (r:64 w:0) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Bonded` (r:64 w:64) + /// 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: `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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:64 w:64) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:64 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:64 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:64) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1378 + b * (343 ±0)` + // Measured: `1475 + b * (452 ±0)` // Estimated: `7253 + b * (3774 ±0)` - // Minimum execution time: 92_847_000 picoseconds. - Weight::from_parts(42_300_813, 7253) - // Standard Error: 40_514 - .saturating_add(Weight::from_parts(58_412_402, 0).saturating_mul(b.into())) + // Minimum execution time: 89_005_000 picoseconds. + Weight::from_parts(50_257_055, 7253) + // Standard Error: 68_836 + .saturating_add(Weight::from_parts(57_329_950, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().reads((8_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(Weight::from_parts(0, 3774).saturating_mul(b.into())) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:257 w:0) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:1) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) + /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakers` (r:1 w:0) + /// Proof: `Staking::ErasStakers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersPaged` (r:257 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1, 256]`. /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1546 + b * (48 ±0) + v * (10037 ±0)` - // Estimated: `7253 + b * (49 ±0) + v * (12513 ±0)` - // Minimum execution time: 1_685_784_000 picoseconds. - Weight::from_parts(1_693_370_000, 7253) - // Standard Error: 13_295_842 - .saturating_add(Weight::from_parts(425_349_148, 0).saturating_mul(v.into())) - // Standard Error: 53_198_180 - .saturating_add(Weight::from_parts(1_673_328_444, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(7_u64)) + // Measured: `1879 + b * (55 ±0) + v * (10055 ±0)` + // Estimated: `7253 + b * (56 ±0) + v * (12531 ±0)` + // Minimum execution time: 1_737_131_000 picoseconds. + Weight::from_parts(1_746_770_000, 7253) + // Standard Error: 13_401_143 + .saturating_add(Weight::from_parts(426_946_450, 0).saturating_mul(v.into())) + // Standard Error: 53_619_501 + .saturating_add(Weight::from_parts(1_664_681_508, 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)) - .saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 12513).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 56).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 12531).saturating_mul(v.into())) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// 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: 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: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Queue` (r:1 w:1) + /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:0) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// 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: `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`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) + /// 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: `1964` + // Measured: `1955` // Estimated: `7253` - // Minimum execution time: 125_512_000 picoseconds. - Weight::from_parts(129_562_000, 7253) + // Minimum execution time: 112_632_000 picoseconds. + Weight::from_parts(117_267_000, 7253) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Queue` (r:1 w:1) + /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:0) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) + /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `1223` + // Measured: `1251` // Estimated: `7253` - // Minimum execution time: 43_943_000 picoseconds. - Weight::from_parts(45_842_000, 7253) + // Minimum execution time: 39_253_000 picoseconds. + Weight::from_parts(40_053_000, 7253) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:0 w:1) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn control() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_677_000 picoseconds. - Weight::from_parts(2_849_000, 0) + // Minimum execution time: 2_386_000 picoseconds. + Weight::from_parts(2_508_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:64 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Bonded (r:64 w:64) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:64 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:64 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: System Account (r:64 w:64) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:64) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:64) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:1) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) + /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::SlashingSpans` (r:64 w:0) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Bonded` (r:64 w:64) + /// 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: `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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:64 w:64) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:64 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:64 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:64) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1378 + b * (343 ±0)` + // Measured: `1475 + b * (452 ±0)` // Estimated: `7253 + b * (3774 ±0)` - // Minimum execution time: 92_847_000 picoseconds. - Weight::from_parts(42_300_813, 7253) - // Standard Error: 40_514 - .saturating_add(Weight::from_parts(58_412_402, 0).saturating_mul(b.into())) + // Minimum execution time: 89_005_000 picoseconds. + Weight::from_parts(50_257_055, 7253) + // Standard Error: 68_836 + .saturating_add(Weight::from_parts(57_329_950, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().reads((8_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(Weight::from_parts(0, 3774).saturating_mul(b.into())) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:257 w:0) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:1) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) + /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakers` (r:1 w:0) + /// Proof: `Staking::ErasStakers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ErasStakersPaged` (r:257 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1, 256]`. /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1546 + b * (48 ±0) + v * (10037 ±0)` - // Estimated: `7253 + b * (49 ±0) + v * (12513 ±0)` - // Minimum execution time: 1_685_784_000 picoseconds. - Weight::from_parts(1_693_370_000, 7253) - // Standard Error: 13_295_842 - .saturating_add(Weight::from_parts(425_349_148, 0).saturating_mul(v.into())) - // Standard Error: 53_198_180 - .saturating_add(Weight::from_parts(1_673_328_444, 0).saturating_mul(b.into())) - .saturating_add(RocksDbWeight::get().reads(7_u64)) + // Measured: `1879 + b * (55 ±0) + v * (10055 ±0)` + // Estimated: `7253 + b * (56 ±0) + v * (12531 ±0)` + // Minimum execution time: 1_737_131_000 picoseconds. + Weight::from_parts(1_746_770_000, 7253) + // Standard Error: 13_401_143 + .saturating_add(Weight::from_parts(426_946_450, 0).saturating_mul(v.into())) + // Standard Error: 53_619_501 + .saturating_add(Weight::from_parts(1_664_681_508, 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)) - .saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 12513).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 56).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 12531).saturating_mul(v.into())) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// 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: 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: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Queue` (r:1 w:1) + /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:0) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// 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: `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`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) + /// 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: `1964` + // Measured: `1955` // Estimated: `7253` - // Minimum execution time: 125_512_000 picoseconds. - Weight::from_parts(129_562_000, 7253) + // Minimum execution time: 112_632_000 picoseconds. + Weight::from_parts(117_267_000, 7253) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Queue` (r:1 w:1) + /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::Head` (r:1 w:0) + /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) + /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) + /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `1223` + // Measured: `1251` // Estimated: `7253` - // Minimum execution time: 43_943_000 picoseconds. - Weight::from_parts(45_842_000, 7253) + // Minimum execution time: 39_253_000 picoseconds. + Weight::from_parts(40_053_000, 7253) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:0 w:1) + /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn control() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_677_000 picoseconds. - Weight::from_parts(2_849_000, 0) + // Minimum execution time: 2_386_000 picoseconds. + Weight::from_parts(2_508_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index b9543e7f47c041202767ae35be932721417f52ce..7de18080b879edb369811a321501c8fe0630e3b7 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] blake2 = { version = "0.10.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -log = { version = "0.4.14", default-features = false } +log = { workspace = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/glutton/src/mock.rs b/substrate/frame/glutton/src/mock.rs index 26863811e29a76b1f8b3249050287e90c39a713b..0049800d95298386a9ed63e23c608d4a2938c758 100644 --- a/substrate/frame/glutton/src/mock.rs +++ b/substrate/frame/glutton/src/mock.rs @@ -18,15 +18,8 @@ use super::*; use crate as pallet_glutton; -use frame_support::{ - assert_ok, derive_impl, - traits::{ConstU32, ConstU64}, -}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use frame_support::{assert_ok, derive_impl}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -40,29 +33,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl Config for Test { diff --git a/substrate/frame/glutton/src/weights.rs b/substrate/frame/glutton/src/weights.rs index cbc0fb022f510889e66a403f1624c025faa5a7f8..b2e28dc488a6f24dc6da4690ff4939129ea9d2f3 100644 --- a/substrate/frame/glutton/src/weights.rs +++ b/substrate/frame/glutton/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_glutton +//! Autogenerated weights for `pallet_glutton` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/glutton/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/glutton/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_glutton. +/// Weight functions needed for `pallet_glutton`. pub trait WeightInfo { fn initialize_pallet_grow(n: u32, ) -> Weight; fn initialize_pallet_shrink(n: u32, ) -> Weight; @@ -63,39 +62,39 @@ pub trait WeightInfo { fn set_storage() -> Weight; } -/// Weights for pallet_glutton using the Substrate node and recommended hardware. +/// Weights for `pallet_glutton` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Glutton TrashDataCount (r:1 w:1) - /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:0 w:1000) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::TrashDataCount` (r:1 w:1) + /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:0 w:1000) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1489` - // Minimum execution time: 11_488_000 picoseconds. - Weight::from_parts(93_073_710, 1489) - // Standard Error: 22_390 - .saturating_add(Weight::from_parts(9_572_012, 0).saturating_mul(n.into())) + // Minimum execution time: 8_443_000 picoseconds. + Weight::from_parts(103_698_651, 1489) + // Standard Error: 21_777 + .saturating_add(Weight::from_parts(9_529_476, 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()))) } - /// Storage: Glutton TrashDataCount (r:1 w:1) - /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:0 w:1000) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::TrashDataCount` (r:1 w:1) + /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:0 w:1000) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119` // Estimated: `1489` - // Minimum execution time: 11_378_000 picoseconds. - Weight::from_parts(5_591_508, 1489) - // Standard Error: 1_592 - .saturating_add(Weight::from_parts(1_163_758, 0).saturating_mul(n.into())) + // Minimum execution time: 8_343_000 picoseconds. + Weight::from_parts(304_498, 1489) + // Standard Error: 1_568 + .saturating_add(Weight::from_parts(1_146_553, 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()))) @@ -105,119 +104,119 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 669_000 picoseconds. - Weight::from_parts(990_745, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(105_224, 0).saturating_mul(i.into())) + // Minimum execution time: 656_000 picoseconds. + Weight::from_parts(1_875_128, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(103_381, 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) + /// 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)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 435_000 picoseconds. - Weight::from_parts(66_547_542, 990) - // Standard Error: 4_557 - .saturating_add(Weight::from_parts(5_851_324, 0).saturating_mul(i.into())) + // Minimum execution time: 454_000 picoseconds. + Weight::from_parts(521_000, 990) + // Standard Error: 1_940 + .saturating_add(Weight::from_parts(5_729_831, 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())) } - /// Storage: Glutton Storage (r:1 w:0) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton Compute (r:1 w:0) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:1737 w:0) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:1737 w:0) + /// 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` // Estimated: `5239782` - // Minimum execution time: 67_699_845_000 picoseconds. - Weight::from_parts(67_893_204_000, 5239782) + // Minimum execution time: 55_403_909_000 picoseconds. + Weight::from_parts(55_472_412_000, 5239782) .saturating_add(T::DbWeight::get().reads(1739_u64)) } - /// Storage: Glutton Storage (r:1 w:0) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton Compute (r:1 w:0) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:5 w:0) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:5 w:0) + /// 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` // Estimated: `16070` - // Minimum execution time: 122_297_527_000 picoseconds. - Weight::from_parts(122_394_818_000, 16070) + // Minimum execution time: 97_959_007_000 picoseconds. + Weight::from_parts(98_030_476_000, 16070) .saturating_add(T::DbWeight::get().reads(7_u64)) } - /// Storage: Glutton Storage (r:1 w:0) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton Compute (r:1 w:0) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// 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` // Estimated: `1493` - // Minimum execution time: 5_882_000 picoseconds. - Weight::from_parts(6_138_000, 1493) + // Minimum execution time: 5_011_000 picoseconds. + Weight::from_parts(5_183_000, 1493) .saturating_add(T::DbWeight::get().reads(2_u64)) } - /// Storage: Glutton Compute (r:0 w:1) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Glutton::Compute` (r:0 w:1) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set_compute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_830_000 picoseconds. - Weight::from_parts(8_366_000, 0) + // Minimum execution time: 5_591_000 picoseconds. + Weight::from_parts(5_970_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Glutton Storage (r:0 w:1) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:0 w:1) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_933_000 picoseconds. - Weight::from_parts(8_213_000, 0) + // Minimum execution time: 5_689_000 picoseconds. + Weight::from_parts(6_038_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Glutton TrashDataCount (r:1 w:1) - /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:0 w:1000) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::TrashDataCount` (r:1 w:1) + /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:0 w:1000) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1489` - // Minimum execution time: 11_488_000 picoseconds. - Weight::from_parts(93_073_710, 1489) - // Standard Error: 22_390 - .saturating_add(Weight::from_parts(9_572_012, 0).saturating_mul(n.into())) + // Minimum execution time: 8_443_000 picoseconds. + Weight::from_parts(103_698_651, 1489) + // Standard Error: 21_777 + .saturating_add(Weight::from_parts(9_529_476, 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()))) } - /// Storage: Glutton TrashDataCount (r:1 w:1) - /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:0 w:1000) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::TrashDataCount` (r:1 w:1) + /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:0 w:1000) + /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119` // Estimated: `1489` - // Minimum execution time: 11_378_000 picoseconds. - Weight::from_parts(5_591_508, 1489) - // Standard Error: 1_592 - .saturating_add(Weight::from_parts(1_163_758, 0).saturating_mul(n.into())) + // Minimum execution time: 8_343_000 picoseconds. + Weight::from_parts(304_498, 1489) + // Standard Error: 1_568 + .saturating_add(Weight::from_parts(1_146_553, 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()))) @@ -227,83 +226,83 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 669_000 picoseconds. - Weight::from_parts(990_745, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(105_224, 0).saturating_mul(i.into())) + // Minimum execution time: 656_000 picoseconds. + Weight::from_parts(1_875_128, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(103_381, 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) + /// 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)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 435_000 picoseconds. - Weight::from_parts(66_547_542, 990) - // Standard Error: 4_557 - .saturating_add(Weight::from_parts(5_851_324, 0).saturating_mul(i.into())) + // Minimum execution time: 454_000 picoseconds. + Weight::from_parts(521_000, 990) + // Standard Error: 1_940 + .saturating_add(Weight::from_parts(5_729_831, 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())) } - /// Storage: Glutton Storage (r:1 w:0) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton Compute (r:1 w:0) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:1737 w:0) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:1737 w:0) + /// 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` // Estimated: `5239782` - // Minimum execution time: 67_699_845_000 picoseconds. - Weight::from_parts(67_893_204_000, 5239782) + // Minimum execution time: 55_403_909_000 picoseconds. + Weight::from_parts(55_472_412_000, 5239782) .saturating_add(RocksDbWeight::get().reads(1739_u64)) } - /// Storage: Glutton Storage (r:1 w:0) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton Compute (r:1 w:0) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:5 w:0) - /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::TrashData` (r:5 w:0) + /// 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` // Estimated: `16070` - // Minimum execution time: 122_297_527_000 picoseconds. - Weight::from_parts(122_394_818_000, 16070) + // Minimum execution time: 97_959_007_000 picoseconds. + Weight::from_parts(98_030_476_000, 16070) .saturating_add(RocksDbWeight::get().reads(7_u64)) } - /// Storage: Glutton Storage (r:1 w:0) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Glutton Compute (r:1 w:0) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:1 w:0) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Glutton::Compute` (r:1 w:0) + /// 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` // Estimated: `1493` - // Minimum execution time: 5_882_000 picoseconds. - Weight::from_parts(6_138_000, 1493) + // Minimum execution time: 5_011_000 picoseconds. + Weight::from_parts(5_183_000, 1493) .saturating_add(RocksDbWeight::get().reads(2_u64)) } - /// Storage: Glutton Compute (r:0 w:1) - /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Glutton::Compute` (r:0 w:1) + /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set_compute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_830_000 picoseconds. - Weight::from_parts(8_366_000, 0) + // Minimum execution time: 5_591_000 picoseconds. + Weight::from_parts(5_970_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Glutton Storage (r:0 w:1) - /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Glutton::Storage` (r:0 w:1) + /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_933_000 picoseconds. - Weight::from_parts(8_213_000, 0) + // Minimum execution time: 5_689_000 picoseconds. + Weight::from_parts(6_038_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index 3775ccdac1dc2cddaa59f995d51eae76b4495028..db540564fbe7bda05b006b5fb7d2b6da2e33d7c5 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/grandpa/src/lib.rs b/substrate/frame/grandpa/src/lib.rs index 0b9f2b3582792e9d93695d34656912a8d70a131f..90bcd8721dfa1f6d091edc34da883c2172d9f6ca 100644 --- a/substrate/frame/grandpa/src/lib.rs +++ b/substrate/frame/grandpa/src/lib.rs @@ -73,7 +73,7 @@ pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); #[pallet::pallet] diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 990a820d3a94addac60a0d47699064df6470d812..e1be487dbb75cf2c7523e808ec8dc8ec015eadb1 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -35,11 +35,8 @@ use sp_consensus_grandpa::{RoundNumber, SetId, GRANDPA_ENGINE_ID}; use sp_core::{crypto::KeyTypeId, H256}; use sp_keyring::Ed25519Keyring; use sp_runtime::{ - curve::PiecewiseLinear, - impl_opaque_keys, - testing::{TestXt, UintAuthorityId}, - traits::{IdentityLookup, OpaqueKeys}, - BuildStorage, DigestItem, Perbill, + curve::PiecewiseLinear, generic::UncheckedExtrinsic, impl_opaque_keys, + testing::UintAuthorityId, traits::OpaqueKeys, BuildStorage, DigestItem, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; @@ -68,29 +65,8 @@ impl_opaque_keys! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = sp_runtime::traits::BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl frame_system::offchain::SendTransactionTypes for Test @@ -98,7 +74,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = TestXt; + type Extrinsic = UncheckedExtrinsic; } parameter_types! { diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index ba1fd500f707566743ea4aa3c3b80ddd4a9d167b..912444bf603606e885d7b0c38c8f8bccbbe93d34 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.7" } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index fe2fb0b048933c13425c0127b752bf773e00bea2..e0b45eeecd1cf5494f52f83ec835037075155ea7 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -23,9 +23,7 @@ use super::*; use crate::Pallet as Identity; use codec::Encode; -use frame_benchmarking::{ - account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, -}; +use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ assert_ok, ensure, traits::{EnsureOrigin, Get, OnFinalize, OnInitialize}, diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 5c9304ca8c13d9eac1ed1f6e8a90d8ba0b5493f1..60866f12baa61783aa27333f66a07193059ce727 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -55,29 +55,10 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 1feb8252c845383ff8a31f2f992e6cf6b3c0001d..81de520d7f2bca8f298e136b7fb58d35ba3f28d8 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_identity +//! Autogenerated weights for `pallet_identity` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/identity/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/identity/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_identity. +/// Weight functions needed for `pallet_identity`. pub trait WeightInfo { fn add_registrar(r: u32, ) -> Weight; fn set_identity(r: u32, ) -> Weight; @@ -77,278 +76,274 @@ pub trait WeightInfo { fn remove_dangling_username() -> Weight; } -/// Weights for pallet_identity using the Substrate node and recommended hardware. +/// Weights for `pallet_identity` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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: 11_683_000 picoseconds. - Weight::from_parts(12_515_830, 2626) - // Standard Error: 2_154 - .saturating_add(Weight::from_parts(147_919, 0).saturating_mul(r.into())) + // Minimum execution time: 8_857_000 picoseconds. + Weight::from_parts(9_331_464, 2626) + // Standard Error: 1_745 + .saturating_add(Weight::from_parts(94_096, 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(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: 32_949_000 picoseconds. - Weight::from_parts(31_329_634, 11003) - // Standard Error: 4_496 - .saturating_add(Weight::from_parts(203_570, 0).saturating_mul(r.into())) + fn set_identity(_r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6978 + r * (5 ±0)` + // Estimated: `11037` + // Minimum execution time: 96_522_000 picoseconds. + Weight::from_parts(102_738_605, 11037) .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(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_157_000 picoseconds. - Weight::from_parts(24_917_444, 11003) - // Standard Error: 4_554 - .saturating_add(Weight::from_parts(3_279_868, 0).saturating_mul(s.into())) + // Estimated: `11037 + s * (2589 ±0)` + // Minimum execution time: 9_112_000 picoseconds. + Weight::from_parts(22_676_873, 11037) + // Standard Error: 6_494 + .saturating_add(Weight::from_parts(3_279_196, 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)) .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_240_000 picoseconds. - Weight::from_parts(23_326_035, 11003) - // Standard Error: 3_664 - .saturating_add(Weight::from_parts(1_439_873, 0).saturating_mul(p.into())) + // Estimated: `11037` + // Minimum execution time: 8_902_000 picoseconds. + Weight::from_parts(21_168_031, 11037) + // Standard Error: 3_576 + .saturating_add(Weight::from_parts(1_431_542, 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()))) } - /// 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 { - // Proof Size summary in bytes: - // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 55_687_000 picoseconds. - Weight::from_parts(30_695_182, 11003) - // Standard Error: 9_921 - .saturating_add(Weight::from_parts(162_357, 0).saturating_mul(r.into())) - // Standard Error: 1_937 - .saturating_add(Weight::from_parts(1_427_998, 0).saturating_mul(s.into())) + 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: 52_468_000 picoseconds. + Weight::from_parts(56_065_452, 11037) + // Standard Error: 2_274 + .saturating_add(Weight::from_parts(1_399_051, 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()))) } - /// 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: 34_876_000 picoseconds. - Weight::from_parts(32_207_018, 11003) - // Standard Error: 5_247 - .saturating_add(Weight::from_parts(249_156, 0).saturating_mul(r.into())) + // Measured: `6968 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 67_951_000 picoseconds. + Weight::from_parts(69_591_058, 11037) + // Standard Error: 4_420 + .saturating_add(Weight::from_parts(209_239, 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(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: 30_689_000 picoseconds. - Weight::from_parts(31_967_170, 11003) - // Standard Error: 5_387 - .saturating_add(Weight::from_parts(42_676, 0).saturating_mul(r.into())) + // Measured: `6999` + // Estimated: `11037` + // Minimum execution time: 67_818_000 picoseconds. + Weight::from_parts(70_356_319, 11037) + // Standard Error: 5_116 + .saturating_add(Weight::from_parts(4_264, 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: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_357_000 picoseconds. - Weight::from_parts(7_932_950, 2626) - // Standard Error: 1_804 - .saturating_add(Weight::from_parts(132_653, 0).saturating_mul(r.into())) + // Minimum execution time: 6_096_000 picoseconds. + Weight::from_parts(6_470_752, 2626) + // Standard Error: 1_328 + .saturating_add(Weight::from_parts(94_764, 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: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_437_000 picoseconds. - Weight::from_parts(8_051_889, 2626) - // Standard Error: 1_997 - .saturating_add(Weight::from_parts(129_592, 0).saturating_mul(r.into())) + // Minimum execution time: 6_278_000 picoseconds. + Weight::from_parts(6_678_997, 2626) + // Standard Error: 1_396 + .saturating_add(Weight::from_parts(87_207, 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: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_385_000 picoseconds. - Weight::from_parts(7_911_589, 2626) - // Standard Error: 1_791 - .saturating_add(Weight::from_parts(125_788, 0).saturating_mul(r.into())) + // Minimum execution time: 6_130_000 picoseconds. + Weight::from_parts(6_516_146, 2626) + // Standard Error: 1_356 + .saturating_add(Weight::from_parts(88_455, 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(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: 24_073_000 picoseconds. - Weight::from_parts(17_817_684, 11003) - // Standard Error: 8_612 - .saturating_add(Weight::from_parts(406_251, 0).saturating_mul(r.into())) + // Measured: `7046 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 87_100_000 picoseconds. + Weight::from_parts(87_601_945, 11037) + // Standard Error: 22_724 + .saturating_add(Weight::from_parts(458_296, 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(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: 73_981_000 picoseconds. - Weight::from_parts(51_684_057, 11003) - // Standard Error: 12_662 - .saturating_add(Weight::from_parts(145_285, 0).saturating_mul(r.into())) - // Standard Error: 2_472 - .saturating_add(Weight::from_parts(1_421_039, 0).saturating_mul(s.into())) + // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037` + // Minimum execution time: 65_925_000 picoseconds. + Weight::from_parts(70_786_250, 11037) + // Standard Error: 19_680 + .saturating_add(Weight::from_parts(29_782, 0).saturating_mul(r.into())) + // Standard Error: 3_839 + .saturating_add(Weight::from_parts(1_377_604, 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(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: 29_367_000 picoseconds. - Weight::from_parts(34_214_998, 11003) - // Standard Error: 1_522 - .saturating_add(Weight::from_parts(114_551, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 25_916_000 picoseconds. + Weight::from_parts(29_781_270, 11037) + // Standard Error: 1_326 + .saturating_add(Weight::from_parts(101_515, 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(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_384_000 picoseconds. - Weight::from_parts(14_417_903, 11003) - // Standard Error: 539 - .saturating_add(Weight::from_parts(38_371, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 12_142_000 picoseconds. + Weight::from_parts(14_179_741, 11037) + // Standard Error: 538 + .saturating_add(Weight::from_parts(38_847, 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(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: 33_327_000 picoseconds. - Weight::from_parts(36_208_941, 11003) - // Standard Error: 1_240 - .saturating_add(Weight::from_parts(105_805, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 29_327_000 picoseconds. + Weight::from_parts(32_163_402, 11037) + // Standard Error: 1_047 + .saturating_add(Weight::from_parts(87_159, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: 23_764_000 picoseconds. - Weight::from_parts(26_407_731, 6723) - // Standard Error: 1_025 - .saturating_add(Weight::from_parts(101_112, 0).saturating_mul(s.into())) + // Minimum execution time: 22_380_000 picoseconds. + Weight::from_parts(24_557_574, 6723) + // Standard Error: 1_131 + .saturating_add(Weight::from_parts(86_358, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -358,367 +353,359 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_873_000 picoseconds. - Weight::from_parts(13_873_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) + // Minimum execution time: 6_791_000 picoseconds. + Weight::from_parts(7_126_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 9_657_000 picoseconds. + Weight::from_parts(9_922_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(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 { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` - // Minimum execution time: 75_928_000 picoseconds. - Weight::from_parts(75_928_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Minimum execution time: 67_928_000 picoseconds. + Weight::from_parts(69_993_000, 11037) + .saturating_add(T::DbWeight::get().reads(4_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(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) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) + // Minimum execution time: 20_496_000 picoseconds. + Weight::from_parts(20_971_000, 11037) + .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(77), added: 2552, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn remove_expired_approval() -> 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)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `115` + // Estimated: `3550` + // Minimum execution time: 13_845_000 picoseconds. + Weight::from_parts(16_201_000, 3550) + .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(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) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + // Minimum execution time: 15_900_000 picoseconds. + Weight::from_parts(16_716_000, 11037) + .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(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: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` + // Measured: `98` // 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)) + // Minimum execution time: 11_538_000 picoseconds. + Weight::from_parts(11_898_000, 11037) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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: 11_683_000 picoseconds. - Weight::from_parts(12_515_830, 2626) - // Standard Error: 2_154 - .saturating_add(Weight::from_parts(147_919, 0).saturating_mul(r.into())) + // Minimum execution time: 8_857_000 picoseconds. + Weight::from_parts(9_331_464, 2626) + // Standard Error: 1_745 + .saturating_add(Weight::from_parts(94_096, 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(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: 32_949_000 picoseconds. - Weight::from_parts(31_329_634, 11003) - // Standard Error: 4_496 - .saturating_add(Weight::from_parts(203_570, 0).saturating_mul(r.into())) + fn set_identity(_r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6978 + r * (5 ±0)` + // Estimated: `11037` + // Minimum execution time: 96_522_000 picoseconds. + Weight::from_parts(102_738_605, 11037) .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(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_157_000 picoseconds. - Weight::from_parts(24_917_444, 11003) - // Standard Error: 4_554 - .saturating_add(Weight::from_parts(3_279_868, 0).saturating_mul(s.into())) + // Estimated: `11037 + s * (2589 ±0)` + // Minimum execution time: 9_112_000 picoseconds. + Weight::from_parts(22_676_873, 11037) + // Standard Error: 6_494 + .saturating_add(Weight::from_parts(3_279_196, 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)) .saturating_add(RocksDbWeight::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_240_000 picoseconds. - Weight::from_parts(23_326_035, 11003) - // Standard Error: 3_664 - .saturating_add(Weight::from_parts(1_439_873, 0).saturating_mul(p.into())) + // Estimated: `11037` + // Minimum execution time: 8_902_000 picoseconds. + Weight::from_parts(21_168_031, 11037) + // Standard Error: 3_576 + .saturating_add(Weight::from_parts(1_431_542, 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()))) } - /// 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 { - // Proof Size summary in bytes: - // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 55_687_000 picoseconds. - Weight::from_parts(30_695_182, 11003) - // Standard Error: 9_921 - .saturating_add(Weight::from_parts(162_357, 0).saturating_mul(r.into())) - // Standard Error: 1_937 - .saturating_add(Weight::from_parts(1_427_998, 0).saturating_mul(s.into())) + 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: 52_468_000 picoseconds. + Weight::from_parts(56_065_452, 11037) + // Standard Error: 2_274 + .saturating_add(Weight::from_parts(1_399_051, 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()))) } - /// 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: 34_876_000 picoseconds. - Weight::from_parts(32_207_018, 11003) - // Standard Error: 5_247 - .saturating_add(Weight::from_parts(249_156, 0).saturating_mul(r.into())) + // Measured: `6968 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 67_951_000 picoseconds. + Weight::from_parts(69_591_058, 11037) + // Standard Error: 4_420 + .saturating_add(Weight::from_parts(209_239, 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(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: 30_689_000 picoseconds. - Weight::from_parts(31_967_170, 11003) - // Standard Error: 5_387 - .saturating_add(Weight::from_parts(42_676, 0).saturating_mul(r.into())) + // Measured: `6999` + // Estimated: `11037` + // Minimum execution time: 67_818_000 picoseconds. + Weight::from_parts(70_356_319, 11037) + // Standard Error: 5_116 + .saturating_add(Weight::from_parts(4_264, 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: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_357_000 picoseconds. - Weight::from_parts(7_932_950, 2626) - // Standard Error: 1_804 - .saturating_add(Weight::from_parts(132_653, 0).saturating_mul(r.into())) + // Minimum execution time: 6_096_000 picoseconds. + Weight::from_parts(6_470_752, 2626) + // Standard Error: 1_328 + .saturating_add(Weight::from_parts(94_764, 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: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_437_000 picoseconds. - Weight::from_parts(8_051_889, 2626) - // Standard Error: 1_997 - .saturating_add(Weight::from_parts(129_592, 0).saturating_mul(r.into())) + // Minimum execution time: 6_278_000 picoseconds. + Weight::from_parts(6_678_997, 2626) + // Standard Error: 1_396 + .saturating_add(Weight::from_parts(87_207, 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: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_385_000 picoseconds. - Weight::from_parts(7_911_589, 2626) - // Standard Error: 1_791 - .saturating_add(Weight::from_parts(125_788, 0).saturating_mul(r.into())) + // Minimum execution time: 6_130_000 picoseconds. + Weight::from_parts(6_516_146, 2626) + // Standard Error: 1_356 + .saturating_add(Weight::from_parts(88_455, 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(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: 24_073_000 picoseconds. - Weight::from_parts(17_817_684, 11003) - // Standard Error: 8_612 - .saturating_add(Weight::from_parts(406_251, 0).saturating_mul(r.into())) + // Measured: `7046 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 87_100_000 picoseconds. + Weight::from_parts(87_601_945, 11037) + // Standard Error: 22_724 + .saturating_add(Weight::from_parts(458_296, 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(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: 73_981_000 picoseconds. - Weight::from_parts(51_684_057, 11003) - // Standard Error: 12_662 - .saturating_add(Weight::from_parts(145_285, 0).saturating_mul(r.into())) - // Standard Error: 2_472 - .saturating_add(Weight::from_parts(1_421_039, 0).saturating_mul(s.into())) + // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037` + // Minimum execution time: 65_925_000 picoseconds. + Weight::from_parts(70_786_250, 11037) + // Standard Error: 19_680 + .saturating_add(Weight::from_parts(29_782, 0).saturating_mul(r.into())) + // Standard Error: 3_839 + .saturating_add(Weight::from_parts(1_377_604, 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(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: 29_367_000 picoseconds. - Weight::from_parts(34_214_998, 11003) - // Standard Error: 1_522 - .saturating_add(Weight::from_parts(114_551, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 25_916_000 picoseconds. + Weight::from_parts(29_781_270, 11037) + // Standard Error: 1_326 + .saturating_add(Weight::from_parts(101_515, 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(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_384_000 picoseconds. - Weight::from_parts(14_417_903, 11003) - // Standard Error: 539 - .saturating_add(Weight::from_parts(38_371, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 12_142_000 picoseconds. + Weight::from_parts(14_179_741, 11037) + // Standard Error: 538 + .saturating_add(Weight::from_parts(38_847, 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(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: 33_327_000 picoseconds. - Weight::from_parts(36_208_941, 11003) - // Standard Error: 1_240 - .saturating_add(Weight::from_parts(105_805, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 29_327_000 picoseconds. + Weight::from_parts(32_163_402, 11037) + // Standard Error: 1_047 + .saturating_add(Weight::from_parts(87_159, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: 23_764_000 picoseconds. - Weight::from_parts(26_407_731, 6723) - // Standard Error: 1_025 - .saturating_add(Weight::from_parts(101_112, 0).saturating_mul(s.into())) + // Minimum execution time: 22_380_000 picoseconds. + Weight::from_parts(24_557_574, 6723) + // Standard Error: 1_131 + .saturating_add(Weight::from_parts(86_358, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -728,92 +715,88 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_873_000 picoseconds. - Weight::from_parts(13_873_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Minimum execution time: 6_791_000 picoseconds. + Weight::from_parts(7_126_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 9_657_000 picoseconds. + Weight::from_parts(9_922_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(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 { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` - // Minimum execution time: 75_928_000 picoseconds. - Weight::from_parts(75_928_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Minimum execution time: 67_928_000 picoseconds. + Weight::from_parts(69_993_000, 11037) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// 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) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Minimum execution time: 20_496_000 picoseconds. + Weight::from_parts(20_971_000, 11037) + .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(77), added: 2552, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn remove_expired_approval() -> 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)) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Measured: `115` + // Estimated: `3550` + // Minimum execution time: 13_845_000 picoseconds. + Weight::from_parts(16_201_000, 3550) + .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(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) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Minimum execution time: 15_900_000 picoseconds. + Weight::from_parts(16_716_000, 11037) + .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(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: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` + // Measured: `98` // 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(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Minimum execution time: 11_538_000 picoseconds. + Weight::from_parts(11_898_000, 11037) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 04c35908c535513f1c0aa0b5741f36281a01646b..038cbbcd678cca4d947eb4750e11314f643f2ad9 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/im-online/src/lib.rs b/substrate/frame/im-online/src/lib.rs index 1de89dd00c8121c64a19f8b45f24fc6500126dce..239b47834d1f8b1625a186e4a8f90e9861bfa303 100644 --- a/substrate/frame/im-online/src/lib.rs +++ b/substrate/frame/im-online/src/lib.rs @@ -251,7 +251,7 @@ type OffchainResult = Result>>; pub mod pallet { use super::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] @@ -338,26 +338,22 @@ pub mod pallet { /// progress estimate from `NextSessionRotation`, as those estimates should be /// more accurate then the value we calculate for `HeartbeatAfter`. #[pallet::storage] - #[pallet::getter(fn heartbeat_after)] - pub(super) type HeartbeatAfter = StorageValue<_, BlockNumberFor, ValueQuery>; + pub type HeartbeatAfter = StorageValue<_, BlockNumberFor, ValueQuery>; /// The current set of keys that may issue a heartbeat. #[pallet::storage] - #[pallet::getter(fn keys)] - pub(super) type Keys = + pub type Keys = StorageValue<_, WeakBoundedVec, ValueQuery>; /// For each session index, we keep a mapping of `SessionIndex` and `AuthIndex`. #[pallet::storage] - #[pallet::getter(fn received_heartbeats)] - pub(super) type ReceivedHeartbeats = + pub type ReceivedHeartbeats = StorageDoubleMap<_, Twox64Concat, SessionIndex, Twox64Concat, AuthIndex, bool>; /// For each session index, we keep a mapping of `ValidatorId` to the /// number of blocks authored by the given authority. #[pallet::storage] - #[pallet::getter(fn authored_blocks)] - pub(super) type AuthoredBlocks = StorageDoubleMap< + pub type AuthoredBlocks = StorageDoubleMap< _, Twox64Concat, SessionIndex, diff --git a/substrate/frame/im-online/src/migration.rs b/substrate/frame/im-online/src/migration.rs index 3860a7ca53295d971dd2122e721d4b03b2af1285..754a2e672e6cfaec32ed0e44c9af54469fddbb04 100644 --- a/substrate/frame/im-online/src/migration.rs +++ b/substrate/frame/im-online/src/migration.rs @@ -72,7 +72,7 @@ pub mod v1 { if StorageVersion::get::>() != 0 { log::warn!( target: TARGET, - "Skipping migration because current storage version is not 0" + "Skipping migration because in-code storage version is not 0" ); return weight } @@ -116,6 +116,21 @@ pub mod v1 { } } +/// Clears the pallet's offchain storage. +/// +/// Must be put in `OffchainWorkerApi::offchain_worker` after +/// the pallet was removed. +pub fn clear_offchain_storage(validator_set_size: u32) { + (0..validator_set_size).for_each(|idx| { + let key = { + let mut key = DB_PREFIX.to_vec(); + key.extend(idx.encode()); + key + }; + sp_runtime::offchain::storage::StorageValueRef::persistent(&key).clear(); + }); +} + #[cfg(all(feature = "try-runtime", test))] mod test { use super::*; diff --git a/substrate/frame/im-online/src/mock.rs b/substrate/frame/im-online/src/mock.rs index 9dad148b10fa1b0942e93f1c5d183264ab282f05..c0ba9143e1385ebc0b57445c864a270d28936b8d 100644 --- a/substrate/frame/im-online/src/mock.rs +++ b/substrate/frame/im-online/src/mock.rs @@ -27,7 +27,7 @@ use frame_support::{ use pallet_session::historical as pallet_session_historical; use sp_core::H256; use sp_runtime::{ - testing::{TestXt, UintAuthorityId}, + testing::UintAuthorityId, traits::{BlakeTwo256, ConvertInto, IdentityLookup}, BuildStorage, Permill, }; @@ -78,7 +78,7 @@ impl pallet_session::historical::SessionManager for TestSessionManager } /// An extrinsic type used for tests. -pub type Extrinsic = TestXt; +pub type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; type IdentificationTuple = (u64, u64); type Offence = crate::UnresponsivenessOffence; diff --git a/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs index 79036760c2d427c2895163b150f3806bf17222f2..6f5a14d7e7fb5dc3e73e1660a8f55d9916f32be9 100644 --- a/substrate/frame/im-online/src/tests.rs +++ b/substrate/frame/im-online/src/tests.rs @@ -26,10 +26,7 @@ use sp_core::offchain::{ testing::{TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }; -use sp_runtime::{ - testing::UintAuthorityId, - transaction_validity::{InvalidTransaction, TransactionValidityError}, -}; +use sp_runtime::testing::UintAuthorityId; #[test] fn test_unresponsiveness_slash_fraction() { @@ -231,7 +228,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), @@ -267,14 +264,14 @@ fn should_cleanup_received_heartbeats_on_session_end() { let _ = heartbeat(1, 2, 0, 1.into(), Session::validators()).unwrap(); // the heartbeat is stored - assert!(!ImOnline::received_heartbeats(&2, &0).is_none()); + assert!(!super::pallet::ReceivedHeartbeats::::get(2, 0).is_none()); advance_session(); // after the session has ended we have already processed the heartbeat // message, so any messages received on the previous session should have // been pruned. - assert!(ImOnline::received_heartbeats(&2, &0).is_none()); + assert!(super::pallet::ReceivedHeartbeats::::get(2, 0).is_none()); }); } @@ -345,7 +342,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 c3db02af2578209d9ab97a777ef4a7447d45b738..11357b1e7b7d38983966ff6d03e91ddec0bd10cf 100644 --- a/substrate/frame/im-online/src/weights.rs +++ b/substrate/frame/im-online/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_im_online +//! Autogenerated weights for `pallet_im_online` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/im-online/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/im-online/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,60 +49,60 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_im_online. +/// Weight functions needed for `pallet_im_online`. pub trait WeightInfo { fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight; } -/// Weights for pallet_im_online using the Substrate node and recommended hardware. +/// Weights for `pallet_im_online` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ImOnline Keys (r:1 w:0) - /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) - /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) - /// Storage: ImOnline AuthoredBlocks (r:1 w:0) - /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::CurrentIndex` (r:1 w:0) + /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ImOnline::Keys` (r:1 w:0) + /// Proof: `ImOnline::Keys` (`max_values`: Some(1), `max_size`: Some(320002), added: 320497, mode: `MaxEncodedLen`) + /// Storage: `ImOnline::ReceivedHeartbeats` (r:1 w:1) + /// Proof: `ImOnline::ReceivedHeartbeats` (`max_values`: None, `max_size`: Some(25), added: 2500, mode: `MaxEncodedLen`) + /// Storage: `ImOnline::AuthoredBlocks` (r:1 w:0) + /// Proof: `ImOnline::AuthoredBlocks` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 1000]`. fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `295 + k * (32 ±0)` + // Measured: `327 + k * (32 ±0)` // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 80_568_000 picoseconds. - Weight::from_parts(95_175_595, 321487) - // Standard Error: 627 - .saturating_add(Weight::from_parts(39_094, 0).saturating_mul(k.into())) + // Minimum execution time: 65_515_000 picoseconds. + Weight::from_parts(74_765_329, 321487) + // Standard Error: 500 + .saturating_add(Weight::from_parts(39_171, 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())) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ImOnline Keys (r:1 w:0) - /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) - /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) - /// Storage: ImOnline AuthoredBlocks (r:1 w:0) - /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::CurrentIndex` (r:1 w:0) + /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ImOnline::Keys` (r:1 w:0) + /// Proof: `ImOnline::Keys` (`max_values`: Some(1), `max_size`: Some(320002), added: 320497, mode: `MaxEncodedLen`) + /// Storage: `ImOnline::ReceivedHeartbeats` (r:1 w:1) + /// Proof: `ImOnline::ReceivedHeartbeats` (`max_values`: None, `max_size`: Some(25), added: 2500, mode: `MaxEncodedLen`) + /// Storage: `ImOnline::AuthoredBlocks` (r:1 w:0) + /// Proof: `ImOnline::AuthoredBlocks` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 1000]`. fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `295 + k * (32 ±0)` + // Measured: `327 + k * (32 ±0)` // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 80_568_000 picoseconds. - Weight::from_parts(95_175_595, 321487) - // Standard Error: 627 - .saturating_add(Weight::from_parts(39_094, 0).saturating_mul(k.into())) + // Minimum execution time: 65_515_000 picoseconds. + Weight::from_parts(74_765_329, 321487) + // Standard Error: 500 + .saturating_add(Weight::from_parts(39_171, 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/weights.rs b/substrate/frame/indices/src/weights.rs index d081cc738b1dbe6c1991b30ccb454307e4ca19ab..6b571164eb69e3ac25732a19067ee445ead52514 100644 --- a/substrate/frame/indices/src/weights.rs +++ b/substrate/frame/indices/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_indices +//! Autogenerated weights for `pallet_indices` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/indices/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/indices/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_indices. +/// Weight functions needed for `pallet_indices`. pub trait WeightInfo { fn claim() -> Weight; fn transfer() -> Weight; @@ -59,128 +58,128 @@ pub trait WeightInfo { fn freeze() -> Weight; } -/// Weights for pallet_indices using the Substrate node and recommended hardware. +/// Weights for `pallet_indices` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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: `76` // Estimated: `3534` - // Minimum execution time: 25_491_000 picoseconds. - Weight::from_parts(26_456_000, 3534) + // Minimum execution time: 20_825_000 picoseconds. + Weight::from_parts(21_507_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `275` // Estimated: `3593` - // Minimum execution time: 38_027_000 picoseconds. - Weight::from_parts(38_749_000, 3593) + // Minimum execution time: 31_091_000 picoseconds. + Weight::from_parts(31_923_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `172` // Estimated: `3534` - // Minimum execution time: 26_652_000 picoseconds. - Weight::from_parts(27_273_000, 3534) + // Minimum execution time: 21_832_000 picoseconds. + Weight::from_parts(22_436_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `275` // Estimated: `3593` - // Minimum execution time: 29_464_000 picoseconds. - Weight::from_parts(30_959_000, 3593) + // Minimum execution time: 23_876_000 picoseconds. + Weight::from_parts(24_954_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `172` // Estimated: `3534` - // Minimum execution time: 29_015_000 picoseconds. - Weight::from_parts(29_714_000, 3534) + // Minimum execution time: 22_954_000 picoseconds. + Weight::from_parts(23_792_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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: `76` // Estimated: `3534` - // Minimum execution time: 25_491_000 picoseconds. - Weight::from_parts(26_456_000, 3534) + // Minimum execution time: 20_825_000 picoseconds. + Weight::from_parts(21_507_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `275` // Estimated: `3593` - // Minimum execution time: 38_027_000 picoseconds. - Weight::from_parts(38_749_000, 3593) + // Minimum execution time: 31_091_000 picoseconds. + Weight::from_parts(31_923_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `172` // Estimated: `3534` - // Minimum execution time: 26_652_000 picoseconds. - Weight::from_parts(27_273_000, 3534) + // Minimum execution time: 21_832_000 picoseconds. + Weight::from_parts(22_436_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `275` // Estimated: `3593` - // Minimum execution time: 29_464_000 picoseconds. - Weight::from_parts(30_959_000, 3593) + // Minimum execution time: 23_876_000 picoseconds. + Weight::from_parts(24_954_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `172` // Estimated: `3534` - // Minimum execution time: 29_015_000 picoseconds. - Weight::from_parts(29_714_000, 3534) + // Minimum execution time: 22_954_000 picoseconds. + Weight::from_parts(23_792_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/insecure-randomness-collective-flip/src/lib.rs b/substrate/frame/insecure-randomness-collective-flip/src/lib.rs index 00f1055f6f271c9ef21b914a499c652161f551f1..04f8cda6541dd37685b86b7a25f7b84d5880de45 100644 --- a/substrate/frame/insecure-randomness-collective-flip/src/lib.rs +++ b/substrate/frame/insecure-randomness-collective-flip/src/lib.rs @@ -163,14 +163,11 @@ mod tests { use crate as pallet_insecure_randomness_collective_flip; use sp_core::H256; - use sp_runtime::{ - traits::{BlakeTwo256, Header as _, IdentityLookup}, - BuildStorage, - }; + use sp_runtime::{traits::Header as _, BuildStorage}; use frame_support::{ derive_impl, parameter_types, - traits::{ConstU32, ConstU64, OnInitialize, Randomness}, + traits::{OnInitialize, Randomness}, }; use frame_system::limits; @@ -191,29 +188,7 @@ mod tests { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = BlockLength; - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_insecure_randomness_collective_flip::Config for Test {} diff --git a/substrate/frame/lottery/src/benchmarking.rs b/substrate/frame/lottery/src/benchmarking.rs index 1510d250dbeaf6814a35f1262f08ba727b340ee2..123b425b976f3b5b2842e748498513611dca5bc2 100644 --- a/substrate/frame/lottery/src/benchmarking.rs +++ b/substrate/frame/lottery/src/benchmarking.rs @@ -23,7 +23,6 @@ use super::*; use crate::Pallet as Lottery; use frame_benchmarking::{ - impl_benchmark_test_suite, v1::{account, whitelisted_caller, BenchmarkError}, v2::*, }; diff --git a/substrate/frame/lottery/src/mock.rs b/substrate/frame/lottery/src/mock.rs index 0b73bba61355a283785ec95ecfa744174f279af0..563ce7202ec39c5b16af1efc58c0cde077400db7 100644 --- a/substrate/frame/lottery/src/mock.rs +++ b/substrate/frame/lottery/src/mock.rs @@ -26,11 +26,7 @@ use frame_support::{ }; use frame_support_test::TestRandomness; use frame_system::EnsureRoot; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, Perbill, -}; +use sp_runtime::{BuildStorage, Perbill}; type Block = frame_system::mocking::MockBlock; @@ -49,29 +45,8 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/lottery/src/weights.rs b/substrate/frame/lottery/src/weights.rs index 3b4e562375345befa93f431145a2aff776ec7517..7e56cdf90db5c7844dc8183b0a14381a910fdd24 100644 --- a/substrate/frame/lottery/src/weights.rs +++ b/substrate/frame/lottery/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_lottery +//! Autogenerated weights for `pallet_lottery` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/lottery/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/lottery/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_lottery. +/// Weight functions needed for `pallet_lottery`. pub trait WeightInfo { fn buy_ticket() -> Weight; fn set_calls(n: u32, ) -> Weight; @@ -60,214 +59,222 @@ pub trait WeightInfo { fn on_initialize_repeat() -> Weight; } -/// Weights for pallet_lottery using the Substrate node and recommended hardware. +/// Weights for `pallet_lottery` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Lottery Lottery (r:1 w:0) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: Lottery CallIndices (r:1 w:0) - /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) - /// Storage: Lottery TicketsCount (r:1 w:1) - /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Lottery Participants (r:1 w:1) - /// Proof: Lottery Participants (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: Lottery LotteryIndex (r:1 w:0) - /// Proof: Lottery LotteryIndex (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: Lottery Tickets (r:0 w:1) - /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Lottery` (r:1 w:0) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `Lottery::CallIndices` (r:1 w:0) + /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + /// Storage: `Lottery::TicketsCount` (r:1 w:1) + /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Participants` (r:1 w:1) + /// Proof: `Lottery::Participants` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Lottery::LotteryIndex` (r:1 w:0) + /// Proof: `Lottery::LotteryIndex` (`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: `Lottery::Tickets` (r:0 w:1) + /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `452` - // Estimated: `3593` - // Minimum execution time: 60_298_000 picoseconds. - Weight::from_parts(62_058_000, 3593) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Measured: `492` + // Estimated: `3997` + // Minimum execution time: 57_891_000 picoseconds. + Weight::from_parts(59_508_000, 3997) + .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Lottery CallIndices (r:0 w:1) - /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) + /// Storage: `Lottery::CallIndices` (r:0 w:1) + /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_291_000 picoseconds. - Weight::from_parts(8_178_186, 0) - // Standard Error: 3_048 - .saturating_add(Weight::from_parts(330_871, 0).saturating_mul(n.into())) + // Minimum execution time: 5_026_000 picoseconds. + Weight::from_parts(5_854_666, 0) + // Standard Error: 3_233 + .saturating_add(Weight::from_parts(334_818, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: Lottery LotteryIndex (r:1 w:1) - /// Proof: Lottery LotteryIndex (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: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `Lottery::LotteryIndex` (r:1 w:1) + /// Proof: `Lottery::LotteryIndex` (`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 start_lottery() -> Weight { // Proof Size summary in bytes: - // Measured: `161` + // Measured: `194` // Estimated: `3593` - // Minimum execution time: 36_741_000 picoseconds. - Weight::from_parts(38_288_000, 3593) + // Minimum execution time: 26_216_000 picoseconds. + Weight::from_parts(27_216_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) fn stop_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `219` + // Measured: `252` // Estimated: `1514` - // Minimum execution time: 7_270_000 picoseconds. - Weight::from_parts(7_578_000, 1514) + // Minimum execution time: 6_208_000 picoseconds. + Weight::from_parts(6_427_000, 1514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Lottery TicketsCount (r:1 w:1) - /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Lottery Tickets (r:1 w:0) - /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) + /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Lottery::TicketsCount` (r:1 w:1) + /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Tickets` (r:1 w:0) + /// 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: `558` + // Measured: `591` // Estimated: `6196` - // Minimum execution time: 76_611_000 picoseconds. - Weight::from_parts(78_107_000, 6196) + // Minimum execution time: 58_660_000 picoseconds. + Weight::from_parts(59_358_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Lottery TicketsCount (r:1 w:1) - /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Lottery Tickets (r:1 w:0) - /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: Lottery LotteryIndex (r:1 w:1) - /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) + /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Lottery::TicketsCount` (r:1 w:1) + /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Tickets` (r:1 w:0) + /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `Lottery::LotteryIndex` (r:1 w:1) + /// 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: `558` + // Measured: `591` // Estimated: `6196` - // Minimum execution time: 78_731_000 picoseconds. - Weight::from_parts(80_248_000, 6196) + // Minimum execution time: 59_376_000 picoseconds. + Weight::from_parts(60_598_000, 6196) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Lottery Lottery (r:1 w:0) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: Lottery CallIndices (r:1 w:0) - /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) - /// Storage: Lottery TicketsCount (r:1 w:1) - /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Lottery Participants (r:1 w:1) - /// Proof: Lottery Participants (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: Lottery LotteryIndex (r:1 w:0) - /// Proof: Lottery LotteryIndex (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: Lottery Tickets (r:0 w:1) - /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Lottery` (r:1 w:0) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `Lottery::CallIndices` (r:1 w:0) + /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + /// Storage: `Lottery::TicketsCount` (r:1 w:1) + /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Participants` (r:1 w:1) + /// Proof: `Lottery::Participants` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Lottery::LotteryIndex` (r:1 w:0) + /// Proof: `Lottery::LotteryIndex` (`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: `Lottery::Tickets` (r:0 w:1) + /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `452` - // Estimated: `3593` - // Minimum execution time: 60_298_000 picoseconds. - Weight::from_parts(62_058_000, 3593) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Measured: `492` + // Estimated: `3997` + // Minimum execution time: 57_891_000 picoseconds. + Weight::from_parts(59_508_000, 3997) + .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Lottery CallIndices (r:0 w:1) - /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) + /// Storage: `Lottery::CallIndices` (r:0 w:1) + /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_291_000 picoseconds. - Weight::from_parts(8_178_186, 0) - // Standard Error: 3_048 - .saturating_add(Weight::from_parts(330_871, 0).saturating_mul(n.into())) + // Minimum execution time: 5_026_000 picoseconds. + Weight::from_parts(5_854_666, 0) + // Standard Error: 3_233 + .saturating_add(Weight::from_parts(334_818, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: Lottery LotteryIndex (r:1 w:1) - /// Proof: Lottery LotteryIndex (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: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `Lottery::LotteryIndex` (r:1 w:1) + /// Proof: `Lottery::LotteryIndex` (`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 start_lottery() -> Weight { // Proof Size summary in bytes: - // Measured: `161` + // Measured: `194` // Estimated: `3593` - // Minimum execution time: 36_741_000 picoseconds. - Weight::from_parts(38_288_000, 3593) + // Minimum execution time: 26_216_000 picoseconds. + Weight::from_parts(27_216_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) fn stop_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `219` + // Measured: `252` // Estimated: `1514` - // Minimum execution time: 7_270_000 picoseconds. - Weight::from_parts(7_578_000, 1514) + // Minimum execution time: 6_208_000 picoseconds. + Weight::from_parts(6_427_000, 1514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Lottery TicketsCount (r:1 w:1) - /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Lottery Tickets (r:1 w:0) - /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) + /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Lottery::TicketsCount` (r:1 w:1) + /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Tickets` (r:1 w:0) + /// 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: `558` + // Measured: `591` // Estimated: `6196` - // Minimum execution time: 76_611_000 picoseconds. - Weight::from_parts(78_107_000, 6196) + // Minimum execution time: 58_660_000 picoseconds. + Weight::from_parts(59_358_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) - /// Storage: Lottery Lottery (r:1 w:1) - /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Lottery TicketsCount (r:1 w:1) - /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Lottery Tickets (r:1 w:0) - /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: Lottery LotteryIndex (r:1 w:1) - /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) + /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Lottery` (r:1 w:1) + /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Lottery::TicketsCount` (r:1 w:1) + /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Lottery::Tickets` (r:1 w:0) + /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `Lottery::LotteryIndex` (r:1 w:1) + /// 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: `558` + // Measured: `591` // Estimated: `6196` - // Minimum execution time: 78_731_000 picoseconds. - Weight::from_parts(80_248_000, 6196) + // Minimum execution time: 59_376_000 picoseconds. + Weight::from_parts(60_598_000, 6196) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 658bf67f12f2c67d9abe84984437ce98c4373958..64214670292739395dc38a024085dec52868d275 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/membership/src/lib.rs b/substrate/frame/membership/src/lib.rs index 0e03c097d1233e5b253fbf3be86faf44b065f145..f4ac697130de87ea48fdb6be522289c6368d10c8 100644 --- a/substrate/frame/membership/src/lib.rs +++ b/substrate/frame/membership/src/lib.rs @@ -27,7 +27,7 @@ use frame_support::{ traits::{ChangeMembers, Contains, Get, InitializeMembers, SortedMembers}, BoundedVec, }; -use sp_runtime::traits::StaticLookup; +use sp_runtime::traits::{StaticLookup, UniqueSaturatedInto}; use sp_std::prelude::*; pub mod migrations; @@ -46,7 +46,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] @@ -163,12 +163,16 @@ pub mod pallet { /// /// May only be called from `T::AddOrigin`. #[pallet::call_index(0)] - #[pallet::weight({50_000_000})] - pub fn add_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { + #[pallet::weight(T::WeightInfo::add_member(T::MaxMembers::get()))] + pub fn add_member( + origin: OriginFor, + who: AccountIdLookupOf, + ) -> DispatchResultWithPostInfo { T::AddOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(who)?; let mut members = >::get(); + let init_length = members.len(); let location = members.binary_search(&who).err().ok_or(Error::::AlreadyMember)?; members .try_insert(location, who.clone()) @@ -179,19 +183,24 @@ pub mod pallet { T::MembershipChanged::change_members_sorted(&[who], &[], &members[..]); Self::deposit_event(Event::MemberAdded); - Ok(()) + + Ok(Some(T::WeightInfo::add_member(init_length as u32)).into()) } /// Remove a member `who` from the set. /// /// May only be called from `T::RemoveOrigin`. #[pallet::call_index(1)] - #[pallet::weight({50_000_000})] - pub fn remove_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { + #[pallet::weight(T::WeightInfo::remove_member(T::MaxMembers::get()))] + pub fn remove_member( + origin: OriginFor, + who: AccountIdLookupOf, + ) -> DispatchResultWithPostInfo { T::RemoveOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(who)?; let mut members = >::get(); + let init_length = members.len(); let location = members.binary_search(&who).ok().ok_or(Error::::NotMember)?; members.remove(location); @@ -201,7 +210,7 @@ pub mod pallet { Self::rejig_prime(&members); Self::deposit_event(Event::MemberRemoved); - Ok(()) + Ok(Some(T::WeightInfo::remove_member(init_length as u32)).into()) } /// Swap out one member `remove` for another `add`. @@ -210,18 +219,18 @@ pub mod pallet { /// /// Prime membership is *not* passed from `remove` to `add`, if extant. #[pallet::call_index(2)] - #[pallet::weight({50_000_000})] + #[pallet::weight(T::WeightInfo::swap_member(T::MaxMembers::get()))] pub fn swap_member( origin: OriginFor, remove: AccountIdLookupOf, add: AccountIdLookupOf, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { T::SwapOrigin::ensure_origin(origin)?; let remove = T::Lookup::lookup(remove)?; let add = T::Lookup::lookup(add)?; if remove == add { - return Ok(()) + return Ok(().into()); } let mut members = >::get(); @@ -236,7 +245,7 @@ pub mod pallet { Self::rejig_prime(&members); Self::deposit_event(Event::MembersSwapped); - Ok(()) + Ok(Some(T::WeightInfo::swap_member(members.len() as u32)).into()) } /// Change the membership to a new set, disregarding the existing membership. Be nice and @@ -244,7 +253,7 @@ pub mod pallet { /// /// May only be called from `T::ResetOrigin`. #[pallet::call_index(3)] - #[pallet::weight({50_000_000})] + #[pallet::weight(T::WeightInfo::reset_members(members.len().unique_saturated_into()))] pub fn reset_members(origin: OriginFor, members: Vec) -> DispatchResult { T::ResetOrigin::ensure_origin(origin)?; @@ -267,56 +276,65 @@ pub mod pallet { /// /// Prime membership is passed from the origin account to `new`, if extant. #[pallet::call_index(4)] - #[pallet::weight({50_000_000})] - pub fn change_key(origin: OriginFor, new: AccountIdLookupOf) -> DispatchResult { + #[pallet::weight(T::WeightInfo::change_key(T::MaxMembers::get()))] + pub fn change_key( + origin: OriginFor, + new: AccountIdLookupOf, + ) -> DispatchResultWithPostInfo { let remove = ensure_signed(origin)?; let new = T::Lookup::lookup(new)?; - if remove != new { - let mut members = >::get(); - let location = - members.binary_search(&remove).ok().ok_or(Error::::NotMember)?; - let _ = members.binary_search(&new).err().ok_or(Error::::AlreadyMember)?; - members[location] = new.clone(); - members.sort(); - - >::put(&members); - - T::MembershipChanged::change_members_sorted( - &[new.clone()], - &[remove.clone()], - &members[..], - ); - - if Prime::::get() == Some(remove) { - Prime::::put(&new); - T::MembershipChanged::set_prime(Some(new)); - } + if remove == new { + return Ok(().into()); + } + + let mut members = >::get(); + let members_length = members.len() as u32; + let location = members.binary_search(&remove).ok().ok_or(Error::::NotMember)?; + let _ = members.binary_search(&new).err().ok_or(Error::::AlreadyMember)?; + members[location] = new.clone(); + members.sort(); + + >::put(&members); + + T::MembershipChanged::change_members_sorted( + &[new.clone()], + &[remove.clone()], + &members[..], + ); + + if Prime::::get() == Some(remove) { + Prime::::put(&new); + T::MembershipChanged::set_prime(Some(new)); } Self::deposit_event(Event::KeyChanged); - Ok(()) + Ok(Some(T::WeightInfo::change_key(members_length)).into()) } /// Set the prime member. Must be a current member. /// /// May only be called from `T::PrimeOrigin`. #[pallet::call_index(5)] - #[pallet::weight({50_000_000})] - pub fn set_prime(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { + #[pallet::weight(T::WeightInfo::set_prime(T::MaxMembers::get()))] + pub fn set_prime( + origin: OriginFor, + who: AccountIdLookupOf, + ) -> DispatchResultWithPostInfo { T::PrimeOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(who)?; - Self::members().binary_search(&who).ok().ok_or(Error::::NotMember)?; + let members = Self::members(); + members.binary_search(&who).ok().ok_or(Error::::NotMember)?; Prime::::put(&who); T::MembershipChanged::set_prime(Some(who)); - Ok(()) + Ok(Some(T::WeightInfo::set_prime(members.len() as u32)).into()) } /// Remove the prime member if it exists. /// /// May only be called from `T::PrimeOrigin`. #[pallet::call_index(6)] - #[pallet::weight({50_000_000})] + #[pallet::weight(T::WeightInfo::clear_prime())] pub fn clear_prime(origin: OriginFor) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; Prime::::kill(); @@ -442,7 +460,7 @@ mod benchmark { } // er keep the prime common between incoming and outgoing to make sure it is rejigged. - reset_member { + reset_members { let m in 1 .. T::MaxMembers::get(); let members = (1..m+1).map(|i| account("member", i, SEED)).collect::>(); @@ -500,8 +518,7 @@ mod benchmark { } clear_prime { - let m in 1 .. T::MaxMembers::get(); - let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); + let members = (0..T::MaxMembers::get()).map(|i| account("member", i, SEED)).collect::>(); let prime = members.last().cloned().unwrap(); set_members::(members, None); }: { @@ -523,16 +540,12 @@ mod tests { use super::*; use crate as pallet_membership; - use sp_core::H256; - use sp_runtime::{ - bounded_vec, - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, - BuildStorage, - }; + use sp_runtime::{bounded_vec, traits::BadOrigin, BuildStorage}; use frame_support::{ - assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, - traits::{ConstU32, ConstU64, StorageVersion}, + assert_noop, assert_ok, assert_storage_noop, derive_impl, ord_parameter_types, + parameter_types, + traits::{ConstU32, StorageVersion}, }; use frame_system::EnsureSignedBy; @@ -553,29 +566,7 @@ mod tests { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } ord_parameter_types! { pub const One: u64 = 1; @@ -743,6 +734,17 @@ mod tests { }); } + #[test] + fn swap_member_with_identical_arguments_changes_nothing() { + new_test_ext().execute_with(|| { + assert_storage_noop!(assert_ok!(Membership::swap_member( + RuntimeOrigin::signed(3), + 10, + 10 + ))); + }); + } + #[test] fn change_key_works() { new_test_ext().execute_with(|| { @@ -772,6 +774,13 @@ mod tests { }); } + #[test] + fn change_key_with_same_caller_as_argument_changes_nothing() { + new_test_ext().execute_with(|| { + assert_storage_noop!(assert_ok!(Membership::change_key(RuntimeOrigin::signed(10), 10))); + }); + } + #[test] fn reset_members_works() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/membership/src/weights.rs b/substrate/frame/membership/src/weights.rs index 18ea7fcb315a3134747743f1a913856d084e5ad6..f21867d687079a7dd5396320e621d26ee2af8996 100644 --- a/substrate/frame/membership/src/weights.rs +++ b/substrate/frame/membership/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_membership +//! Autogenerated weights for `pallet_membership` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/membership/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/membership/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,316 +49,310 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_membership. +/// Weight functions needed for `pallet_membership`. pub trait WeightInfo { fn add_member(m: u32, ) -> Weight; fn remove_member(m: u32, ) -> Weight; fn swap_member(m: u32, ) -> Weight; - fn reset_member(m: u32, ) -> Weight; + fn reset_members(m: u32, ) -> Weight; fn change_key(m: u32, ) -> Weight; fn set_prime(m: u32, ) -> Weight; - fn clear_prime(m: u32, ) -> Weight; + fn clear_prime() -> Weight; } -/// Weights for pallet_membership using the Substrate node and recommended hardware. +/// Weights for `pallet_membership` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `208 + m * (64 ±0)` + // Measured: `207 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 17_040_000 picoseconds. - Weight::from_parts(18_344_571, 4687) - // Standard Error: 847 - .saturating_add(Weight::from_parts(50_842, 0).saturating_mul(m.into())) + // Minimum execution time: 12_126_000 picoseconds. + Weight::from_parts(13_085_583, 4687) + // Standard Error: 659 + .saturating_add(Weight::from_parts(36_103, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:0) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_088_000 picoseconds. - Weight::from_parts(21_271_384, 4687) - // Standard Error: 786 - .saturating_add(Weight::from_parts(44_806, 0).saturating_mul(m.into())) + // Minimum execution time: 14_571_000 picoseconds. + Weight::from_parts(15_532_232, 4687) + // Standard Error: 531 + .saturating_add(Weight::from_parts(35_757, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:0) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_308_000 picoseconds. - Weight::from_parts(21_469_843, 4687) - // Standard Error: 782 - .saturating_add(Weight::from_parts(56_893, 0).saturating_mul(m.into())) + // Minimum execution time: 14_833_000 picoseconds. + Weight::from_parts(15_657_084, 4687) + // Standard Error: 650 + .saturating_add(Weight::from_parts(44_467, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:0) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. - fn reset_member(m: u32, ) -> Weight { + fn reset_members(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 19_464_000 picoseconds. - Weight::from_parts(21_223_702, 4687) - // Standard Error: 1_068 - .saturating_add(Weight::from_parts(165_438, 0).saturating_mul(m.into())) + // Minimum execution time: 14_629_000 picoseconds. + Weight::from_parts(15_578_203, 4687) + // Standard Error: 910 + .saturating_add(Weight::from_parts(145_101, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:1) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_965_000 picoseconds. - Weight::from_parts(22_551_007, 4687) - // Standard Error: 860 - .saturating_add(Weight::from_parts(52_397, 0).saturating_mul(m.into())) + // Minimum execution time: 15_218_000 picoseconds. + Weight::from_parts(16_388_690, 4687) + // Standard Error: 626 + .saturating_add(Weight::from_parts(46_204, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:0) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:0) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalMembership::Prime` (r:0 w:1) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` + // Measured: `31 + m * (32 ±0)` // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 7_481_000 picoseconds. - Weight::from_parts(7_959_053, 4687) - // Standard Error: 364 - .saturating_add(Weight::from_parts(18_653, 0).saturating_mul(m.into())) + // Minimum execution time: 5_954_000 picoseconds. + Weight::from_parts(6_544_638, 4687) + // Standard Error: 346 + .saturating_add(Weight::from_parts(17_638, 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())) } - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn clear_prime(m: u32, ) -> Weight { + /// Storage: `TechnicalMembership::Prime` (r:0 w:1) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn clear_prime() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_373_000 picoseconds. - Weight::from_parts(3_750_452, 0) - // Standard Error: 142 - .saturating_add(Weight::from_parts(505, 0).saturating_mul(m.into())) + // Minimum execution time: 2_569_000 picoseconds. + Weight::from_parts(2_776_000, 0) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `208 + m * (64 ±0)` + // Measured: `207 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 17_040_000 picoseconds. - Weight::from_parts(18_344_571, 4687) - // Standard Error: 847 - .saturating_add(Weight::from_parts(50_842, 0).saturating_mul(m.into())) + // Minimum execution time: 12_126_000 picoseconds. + Weight::from_parts(13_085_583, 4687) + // Standard Error: 659 + .saturating_add(Weight::from_parts(36_103, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:0) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_088_000 picoseconds. - Weight::from_parts(21_271_384, 4687) - // Standard Error: 786 - .saturating_add(Weight::from_parts(44_806, 0).saturating_mul(m.into())) + // Minimum execution time: 14_571_000 picoseconds. + Weight::from_parts(15_532_232, 4687) + // Standard Error: 531 + .saturating_add(Weight::from_parts(35_757, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:0) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_308_000 picoseconds. - Weight::from_parts(21_469_843, 4687) - // Standard Error: 782 - .saturating_add(Weight::from_parts(56_893, 0).saturating_mul(m.into())) + // Minimum execution time: 14_833_000 picoseconds. + Weight::from_parts(15_657_084, 4687) + // Standard Error: 650 + .saturating_add(Weight::from_parts(44_467, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:0) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. - fn reset_member(m: u32, ) -> Weight { + fn reset_members(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 19_464_000 picoseconds. - Weight::from_parts(21_223_702, 4687) - // Standard Error: 1_068 - .saturating_add(Weight::from_parts(165_438, 0).saturating_mul(m.into())) + // Minimum execution time: 14_629_000 picoseconds. + Weight::from_parts(15_578_203, 4687) + // Standard Error: 910 + .saturating_add(Weight::from_parts(145_101, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:1) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) + /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalMembership::Prime` (r:1 w:1) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Members` (r:0 w:1) + /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` + // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_965_000 picoseconds. - Weight::from_parts(22_551_007, 4687) - // Standard Error: 860 - .saturating_add(Weight::from_parts(52_397, 0).saturating_mul(m.into())) + // Minimum execution time: 15_218_000 picoseconds. + Weight::from_parts(16_388_690, 4687) + // Standard Error: 626 + .saturating_add(Weight::from_parts(46_204, 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())) } - /// Storage: TechnicalMembership Members (r:1 w:0) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TechnicalMembership::Members` (r:1 w:0) + /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: `TechnicalMembership::Prime` (r:0 w:1) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` + // Measured: `31 + m * (32 ±0)` // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 7_481_000 picoseconds. - Weight::from_parts(7_959_053, 4687) - // Standard Error: 364 - .saturating_add(Weight::from_parts(18_653, 0).saturating_mul(m.into())) + // Minimum execution time: 5_954_000 picoseconds. + Weight::from_parts(6_544_638, 4687) + // Standard Error: 346 + .saturating_add(Weight::from_parts(17_638, 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())) } - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn clear_prime(m: u32, ) -> Weight { + /// Storage: `TechnicalMembership::Prime` (r:0 w:1) + /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) + /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn clear_prime() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_373_000 picoseconds. - Weight::from_parts(3_750_452, 0) - // Standard Error: 142 - .saturating_add(Weight::from_parts(505, 0).saturating_mul(m.into())) + // Minimum execution time: 2_569_000 picoseconds. + Weight::from_parts(2_776_000, 0) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 607fa340e9695ea1f66145e27e7ba0ac3183908d..d623e25cec2613d590562e5b17d077a10a833357 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index c2ecf4452627d36a4fdac3cf05d9758bb6a47701..8d9da7df39ea58ad1f91d45e5db1bc026031ed89 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -14,8 +14,8 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +log = { workspace = true } environmental = { version = "1.1.4", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs index aa6f019d650df0f2d97be7b3584dba706eb686f7..ce8eb80805ab0401bf7f4ff4e2448983333c7b36 100644 --- a/substrate/frame/message-queue/src/integration_test.rs +++ b/substrate/frame/message-queue/src/integration_test.rs @@ -37,14 +37,9 @@ use crate::{ }; use crate as pallet_message_queue; -use frame_support::{ - derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, -}; +use frame_support::{derive_impl, parameter_types}; use rand::{rngs::StdRng, Rng, SeedableRng}; use rand_distr::Pareto; -use sp_core::H256; -use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; use std::collections::{BTreeMap, BTreeSet}; type Block = frame_system::mocking::MockBlock; @@ -59,29 +54,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } parameter_types! { @@ -357,6 +330,11 @@ fn process_some_messages(num_msgs: u32) { ServiceWeight::set(Some(weight)); let consumed = next_block(); + for origin in BookStateFor::::iter_keys() { + let fp = MessageQueue::footprint(origin); + assert_eq!(fp.pages, fp.ready_pages); + } + assert_eq!(consumed, weight, "\n{}", MessageQueue::debug_info()); assert_eq!(NumMessagesProcessed::take(), num_msgs as usize); } diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 07eb0041985342522a113339769b98f834ef4a17..61028057394f6f3bedda173288fa1c9aea3e9e9a 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -208,8 +208,9 @@ use frame_support::{ defensive, pallet_prelude::*, traits::{ - Defensive, DefensiveTruncateFrom, EnqueueMessage, ExecuteOverweightError, Footprint, - ProcessMessage, ProcessMessageError, QueueFootprint, QueuePausedQuery, ServiceQueues, + Defensive, DefensiveSaturating, DefensiveTruncateFrom, EnqueueMessage, + ExecuteOverweightError, Footprint, ProcessMessage, ProcessMessageError, QueueFootprint, + QueuePausedQuery, ServiceQueues, }, BoundedSlice, CloneNoBound, DefaultNoBound, }; @@ -442,6 +443,7 @@ impl From> for QueueFootprint { fn from(book: BookState) -> Self { QueueFootprint { pages: book.count, + ready_pages: book.end.defensive_saturating_sub(book.begin), storage: Footprint { count: book.message_count, size: book.size }, } } @@ -1281,6 +1283,9 @@ impl Pallet { ensure!(book.message_count < 1 << 30, "Likely overflow or corruption"); ensure!(book.size < 1 << 30, "Likely overflow or corruption"); ensure!(book.count < 1 << 30, "Likely overflow or corruption"); + + let fp: QueueFootprint = book.into(); + ensure!(fp.ready_pages <= fp.pages, "There cannot be more ready than total pages"); } //loop around this origin diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index f1067ed961e8adfd0b206a480a6d76bda32428a2..d176a981ca8ee2f6911176b1a25907c7bc197566 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -23,15 +23,8 @@ pub use super::mock_helpers::*; use super::*; use crate as pallet_message_queue; -use frame_support::{ - derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, -}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use frame_support::{derive_impl, parameter_types}; +use sp_runtime::BuildStorage; use sp_std::collections::btree_map::BTreeMap; type Block = frame_system::mocking::MockBlock; @@ -46,29 +39,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } parameter_types! { pub const HeapSize: u32 = 24; @@ -384,8 +355,8 @@ pub fn num_overweight_enqueued_events() -> u32 { .count() as u32 } -pub fn fp(pages: u32, count: u64, size: u64) -> QueueFootprint { - QueueFootprint { storage: Footprint { count, size }, pages } +pub fn fp(pages: u32, ready_pages: u32, count: u64, size: u64) -> QueueFootprint { + QueueFootprint { storage: Footprint { count, size }, pages, ready_pages } } /// A random seed that can be overwritten with `MQ_SEED`. diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index 86a8b79fe8bd01fc5f906ef42e22339c669e57b5..dbef94b3b10354a8b503b795bd46bf90010bb80f 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -1064,13 +1064,13 @@ fn footprint_num_pages_works() { MessageQueue::enqueue_message(msg("weight=2"), Here); MessageQueue::enqueue_message(msg("weight=3"), Here); - assert_eq!(MessageQueue::footprint(Here), fp(2, 2, 16)); + assert_eq!(MessageQueue::footprint(Here), fp(2, 2, 2, 16)); // Mark the messages as overweight. assert_eq!(MessageQueue::service_queues(1.into_weight()), 0.into_weight()); assert_eq!(System::events().len(), 2); - // Overweight does not change the footprint. - assert_eq!(MessageQueue::footprint(Here), fp(2, 2, 16)); + // `ready_pages` decreases but `page` count does not. + assert_eq!(MessageQueue::footprint(Here), fp(2, 0, 2, 16)); // Now execute the second message. assert_eq!( @@ -1078,7 +1078,7 @@ fn footprint_num_pages_works() { .unwrap(), 3.into_weight() ); - assert_eq!(MessageQueue::footprint(Here), fp(1, 1, 8)); + assert_eq!(MessageQueue::footprint(Here), fp(1, 0, 1, 8)); // And the first one: assert_eq!( ::execute_overweight(2.into_weight(), (Here, 0, 0)) @@ -1086,6 +1086,11 @@ fn footprint_num_pages_works() { 2.into_weight() ); assert_eq!(MessageQueue::footprint(Here), Default::default()); + assert_eq!(MessageQueue::footprint(Here), fp(0, 0, 0, 0)); + + // `ready_pages` and normal `pages` increases again: + MessageQueue::enqueue_message(msg("weight=3"), Here); + assert_eq!(MessageQueue::footprint(Here), fp(1, 1, 1, 8)); }) } diff --git a/substrate/frame/message-queue/src/weights.rs b/substrate/frame/message-queue/src/weights.rs index e86f23e274ff246aa9f557626e06a42a4930154c..001e2834e1cc619b48500035c4505d453707dc03 100644 --- a/substrate/frame/message-queue/src/weights.rs +++ b/substrate/frame/message-queue/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_message_queue +//! Autogenerated weights for `pallet_message_queue` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/message-queue/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/message-queue/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_message_queue. +/// Weight functions needed for `pallet_message_queue`. pub trait WeightInfo { fn ready_ring_knit() -> Weight; fn ready_ring_unknit() -> Weight; @@ -64,246 +63,256 @@ pub trait WeightInfo { fn execute_overweight_page_updated() -> Weight; } -/// Weights for pallet_message_queue using the Substrate node and recommended hardware. +/// Weights for `pallet_message_queue` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `267` + // Measured: `301` // Estimated: `6038` - // Minimum execution time: 12_025_000 picoseconds. - Weight::from_parts(12_597_000, 6038) + // Minimum execution time: 11_563_000 picoseconds. + Weight::from_parts(11_956_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `267` + // Measured: `301` // Estimated: `6038` - // Minimum execution time: 11_563_000 picoseconds. - Weight::from_parts(11_785_000, 6038) + // Minimum execution time: 10_263_000 picoseconds. + Weight::from_parts(10_638_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3514` - // Minimum execution time: 4_467_000 picoseconds. - Weight::from_parts(4_655_000, 3514) + // Minimum execution time: 4_335_000 picoseconds. + Weight::from_parts(4_552_000, 3514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_103_000 picoseconds. - Weight::from_parts(6_254_000, 69049) + // Minimum execution time: 6_016_000 picoseconds. + Weight::from_parts(6_224_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_320_000 picoseconds. - Weight::from_parts(6_565_000, 69049) + // Minimum execution time: 6_183_000 picoseconds. + Weight::from_parts(6_348_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 66_062_000 picoseconds. - Weight::from_parts(66_371_000, 0) + // Minimum execution time: 112_864_000 picoseconds. + Weight::from_parts(114_269_000, 0) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `174` + // Measured: `246` // Estimated: `3514` - // Minimum execution time: 6_788_000 picoseconds. - Weight::from_parts(7_176_000, 3514) + // Minimum execution time: 6_665_000 picoseconds. + Weight::from_parts(7_108_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn reap_page() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 52_865_000 picoseconds. - Weight::from_parts(54_398_000, 69049) + // Minimum execution time: 51_420_000 picoseconds. + Weight::from_parts(52_252_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 69_168_000 picoseconds. - Weight::from_parts(70_560_000, 69049) + // Minimum execution time: 71_195_000 picoseconds. + Weight::from_parts(72_981_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 80_947_000 picoseconds. - Weight::from_parts(82_715_000, 69049) + // Minimum execution time: 83_238_000 picoseconds. + Weight::from_parts(84_422_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `267` + // Measured: `301` // Estimated: `6038` - // Minimum execution time: 12_025_000 picoseconds. - Weight::from_parts(12_597_000, 6038) + // Minimum execution time: 11_563_000 picoseconds. + Weight::from_parts(11_956_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `267` + // Measured: `301` // Estimated: `6038` - // Minimum execution time: 11_563_000 picoseconds. - Weight::from_parts(11_785_000, 6038) + // Minimum execution time: 10_263_000 picoseconds. + Weight::from_parts(10_638_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3514` - // Minimum execution time: 4_467_000 picoseconds. - Weight::from_parts(4_655_000, 3514) + // Minimum execution time: 4_335_000 picoseconds. + Weight::from_parts(4_552_000, 3514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_103_000 picoseconds. - Weight::from_parts(6_254_000, 69049) + // Minimum execution time: 6_016_000 picoseconds. + Weight::from_parts(6_224_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_320_000 picoseconds. - Weight::from_parts(6_565_000, 69049) + // Minimum execution time: 6_183_000 picoseconds. + Weight::from_parts(6_348_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 66_062_000 picoseconds. - Weight::from_parts(66_371_000, 0) + // Minimum execution time: 112_864_000 picoseconds. + Weight::from_parts(114_269_000, 0) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `174` + // Measured: `246` // Estimated: `3514` - // Minimum execution time: 6_788_000 picoseconds. - Weight::from_parts(7_176_000, 3514) + // Minimum execution time: 6_665_000 picoseconds. + Weight::from_parts(7_108_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn reap_page() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 52_865_000 picoseconds. - Weight::from_parts(54_398_000, 69049) + // Minimum execution time: 51_420_000 picoseconds. + Weight::from_parts(52_252_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 69_168_000 picoseconds. - Weight::from_parts(70_560_000, 69049) + // Minimum execution time: 71_195_000 picoseconds. + Weight::from_parts(72_981_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 80_947_000 picoseconds. - Weight::from_parts(82_715_000, 69049) + // Minimum execution time: 83_238_000 picoseconds. + Weight::from_parts(84_422_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..2914aa9ea973eafc3eee5419b3b8d8562b23c4f4 --- /dev/null +++ b/substrate/frame/migrations/Cargo.toml @@ -0,0 +1,64 @@ +[package] +name = "pallet-migrations" +version = "1.0.0" +description = "FRAME pallet to execute multi-block migrations." +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +docify = "0.1.14" +impl-trait-for-tuples = "0.2.2" +log = "0.4.18" +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } + +frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } +frame-support = { default-features = false, path = "../support" } +frame-system = { default-features = false, path = "../system" } +sp-core = { path = "../../primitives/core", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } + +[dev-dependencies] +frame-executive = { path = "../executive" } +sp-api = { path = "../../primitives/api", features = ["std"] } +sp-block-builder = { path = "../../primitives/block-builder", features = ["std"] } +sp-io = { path = "../../primitives/io", features = ["std"] } +sp-tracing = { path = "../../primitives/tracing", features = ["std"] } +sp-version = { path = "../../primitives/version", features = ["std"] } + +pretty_assertions = "1.3.0" + +[features] +default = ["std"] + +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] + +try-runtime = [ + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/migrations/src/benchmarking.rs b/substrate/frame/migrations/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..8ad1fa50d14985842051c9ac6fb3f95e30bdb030 --- /dev/null +++ b/substrate/frame/migrations/src/benchmarking.rs @@ -0,0 +1,222 @@ +// 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 = "runtime-benchmarks")] + +use super::*; + +use frame_benchmarking::{v2::*, BenchmarkError}; +use frame_system::{Pallet as System, RawOrigin}; +use sp_runtime::traits::One; + +fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +#[benchmarks] +mod benches { + use super::*; + use frame_support::traits::Hooks; + + #[benchmark] + fn onboard_new_mbms() { + T::Migrations::set_fail_after(0); // Should not be called anyway. + assert!(!Cursor::::exists()); + + #[block] + { + Pallet::::onboard_new_mbms(); + } + + assert_last_event::(Event::UpgradeStarted { migrations: 1 }.into()); + } + + #[benchmark] + fn progress_mbms_none() { + T::Migrations::set_fail_after(0); // Should not be called anyway. + assert!(!Cursor::::exists()); + + #[block] + { + Pallet::::progress_mbms(One::one()); + } + } + + /// All migrations completed. + #[benchmark] + fn exec_migration_completed() -> Result<(), BenchmarkError> { + T::Migrations::set_fail_after(0); // Should not be called anyway. + assert_eq!(T::Migrations::len(), 1, "Setup failed"); + let c = ActiveCursor { index: 1, inner_cursor: None, started_at: 0u32.into() }; + let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get()); + System::::set_block_number(1u32.into()); + + #[block] + { + Pallet::::exec_migration(c, false, &mut meter); + } + + assert_last_event::(Event::UpgradeCompleted {}.into()); + + Ok(()) + } + + /// No migration runs since it is skipped as historic. + #[benchmark] + fn exec_migration_skipped_historic() -> Result<(), BenchmarkError> { + T::Migrations::set_fail_after(0); // Should not be called anyway. + assert_eq!(T::Migrations::len(), 1, "Setup failed"); + let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() }; + + let id: IdentifierOf = T::Migrations::nth_id(0).unwrap().try_into().unwrap(); + Historic::::insert(id, ()); + + let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get()); + System::::set_block_number(1u32.into()); + + #[block] + { + Pallet::::exec_migration(c, false, &mut meter); + } + + assert_last_event::(Event::MigrationSkipped { index: 0 }.into()); + + Ok(()) + } + + /// Advance a migration by one step. + #[benchmark] + fn exec_migration_advance() -> Result<(), BenchmarkError> { + T::Migrations::set_success_after(1); + assert_eq!(T::Migrations::len(), 1, "Setup failed"); + let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() }; + let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get()); + System::::set_block_number(1u32.into()); + + #[block] + { + Pallet::::exec_migration(c, false, &mut meter); + } + + assert_last_event::(Event::MigrationAdvanced { index: 0, took: One::one() }.into()); + + Ok(()) + } + + /// Successfully complete a migration. + #[benchmark] + fn exec_migration_complete() -> Result<(), BenchmarkError> { + T::Migrations::set_success_after(0); + assert_eq!(T::Migrations::len(), 1, "Setup failed"); + let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() }; + let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get()); + System::::set_block_number(1u32.into()); + + #[block] + { + Pallet::::exec_migration(c, false, &mut meter); + } + + assert_last_event::(Event::MigrationCompleted { index: 0, took: One::one() }.into()); + + Ok(()) + } + + #[benchmark] + fn exec_migration_fail() -> Result<(), BenchmarkError> { + T::Migrations::set_fail_after(0); + assert_eq!(T::Migrations::len(), 1, "Setup failed"); + let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() }; + let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get()); + System::::set_block_number(1u32.into()); + + #[block] + { + Pallet::::exec_migration(c, false, &mut meter); + } + + assert_last_event::(Event::UpgradeFailed {}.into()); + + Ok(()) + } + + #[benchmark] + 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(); + + #[block] + { + Pallet::::on_initialize(1u32.into()); + } + } + + #[benchmark] + fn force_set_cursor() { + #[extrinsic_call] + _(RawOrigin::Root, Some(cursor::())); + } + + #[benchmark] + fn force_set_active_cursor() { + #[extrinsic_call] + _(RawOrigin::Root, 0, None, None); + } + + #[benchmark] + fn force_onboard_mbms() { + #[extrinsic_call] + _(RawOrigin::Root); + } + + #[benchmark] + fn clear_historic(n: Linear<0, { DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 }>) { + let id_max_len = ::IdentifierMaxLen::get(); + assert!(id_max_len >= 4, "Precondition violated"); + + for i in 0..DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 { + let id = IdentifierOf::::truncate_from( + i.encode().into_iter().cycle().take(id_max_len as usize).collect::>(), + ); + + Historic::::insert(&id, ()); + } + + #[extrinsic_call] + _( + RawOrigin::Root, + HistoricCleanupSelector::Wildcard { limit: n.into(), previous_cursor: None }, + ); + } + + fn cursor() -> CursorOf { + // Note: The weight of a function can depend on the weight of reading the `inner_cursor`. + // `Cursor` is a user provided type. Now instead of requiring something like `Cursor: + // From`, we instead rely on the fact that it is MEL and the PoV benchmarking will + // therefore already take the MEL bound, even when the cursor in storage is `None`. + MigrationCursor::Active(ActiveCursor { + index: u32::MAX, + inner_cursor: None, + started_at: 0u32.into(), + }) + } + + // Implements a test for each benchmark. Execute with: + // `cargo test -p pallet-migrations --features runtime-benchmarks`. + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..cd57d89f440f79d39f98a3da81ed57b6cb5bfcf5 --- /dev/null +++ b/substrate/frame/migrations/src/lib.rs @@ -0,0 +1,746 @@ +// 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. + +#![deny(missing_docs)] +#![deny(rustdoc::broken_intra_doc_links)] + +//! # `pallet-migrations` +//! +//! Provides multi block migrations for FRAME runtimes. +//! +//! ## Overview +//! +//! The pallet takes care of executing a batch of multi-step migrations over multiple blocks. The +//! process starts on each runtime upgrade. Normal and operational transactions are paused while +//! migrations are on-going. +//! +//! ### Example +//! +//! This example demonstrates a simple mocked walk through of a basic success scenario. The pallet +//! is configured with two migrations: one succeeding after just one step, and the second one +//! succeeding after two steps. A runtime upgrade is then enacted and the block number is advanced +//! until all migrations finish executing. Afterwards, the recorded historic migrations are +//! checked and events are asserted. +#![doc = docify::embed!("substrate/frame/migrations/src/tests.rs", simple_works)] +//! +//! ## Pallet API +//! +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events and errors. +//! +//! Otherwise noteworthy API of this pallet include its implementation of the +//! [`MultiStepMigrator`] trait. This must be plugged into +//! [`frame_system::Config::MultiBlockMigrator`] for proper function. +//! +//! The API contains some calls for emergency management. They are all prefixed with `force_` and +//! should normally not be needed. Pay special attention prior to using them. +//! +//! ### Design Goals +//! +//! 1. Must automatically execute migrations over multiple blocks. +//! 2. Must expose information about whether migrations are ongoing. +//! 3. Must respect pessimistic weight bounds of migrations. +//! 4. Must execute migrations in order. Skipping is not allowed; migrations are run on a +//! all-or-nothing basis. +//! 5. Must prevent re-execution of past migrations. +//! 6. Must provide transactional storage semantics for migrations. +//! 7. Must guarantee progress. +//! +//! ### Design +//! +//! Migrations are provided to the pallet through the associated type [`Config::Migrations`] of type +//! [`SteppedMigrations`]. This allows multiple migrations to be aggregated through a tuple. It +//! simplifies the trait bounds since all associated types of the trait must be provided by the +//! pallet. The actual progress of the pallet is stored in the [`Cursor`] storage item. This can +//! either be [`MigrationCursor::Active`] or [`MigrationCursor::Stuck`]. In the active case it +//! points to the currently active migration and stores its inner cursor. The inner cursor can then +//! be used by the migration to store its inner state and advance. Each time when the migration +//! returns `Some(cursor)`, it signals the pallet that it is not done yet. +//! The cursor is reset on each runtime upgrade. This ensures that it starts to execute at the +//! first migration in the vector. The pallets cursor is only ever incremented or set to `Stuck` +//! once it encounters an error (Goal 4). Once in the stuck state, the pallet will stay stuck until +//! it is fixed through manual governance intervention. +//! As soon as the cursor of the pallet becomes `Some(_)`; [`MultiStepMigrator::ongoing`] returns +//! `true` (Goal 2). This can be used by upstream code to possibly pause transactions. +//! In `on_initialize` the pallet will load the current migration and check whether it was already +//! executed in the past by checking for membership of its ID in the [`Historic`] set. Historic +//! migrations are skipped without causing an error. Each successfully executed migration is added +//! to this set (Goal 5). +//! This proceeds until no more migrations remain. At that point, the event `UpgradeCompleted` is +//! emitted (Goal 1). +//! The execution of each migration happens by calling [`SteppedMigration::transactional_step`]. +//! This function wraps the inner `step` function into a transactional layer to allow rollback in +//! the error case (Goal 6). +//! Weight limits must be checked by the migration itself. The pallet provides a [`WeightMeter`] for +//! that purpose. The pallet may return [`SteppedMigrationError::InsufficientWeight`] at any point. +//! In that scenario, one of two things will happen: if that migration was exclusively executed +//! in this block, and therefore required more than the maximum amount of weight possible, the +//! process becomes `Stuck`. Otherwise, one re-attempt is executed with the same logic in the next +//! block (Goal 3). Progress through the migrations is guaranteed by providing a timeout for each +//! migration via [`SteppedMigration::max_steps`]. The pallet **ONLY** guarantees progress if this +//! is set to sensible limits (Goal 7). +//! +//! ### Scenario: Governance cleanup +//! +//! Every now and then, governance can make use of the [`clear_historic`][Pallet::clear_historic] +//! call. This ensures that no old migrations pile up in the [`Historic`] set. This can be done very +//! rarely, since the storage should not grow quickly and the lookup weight does not suffer much. +//! Another possibility would be to have a synchronous single-block migration perpetually deployed +//! that cleans them up before the MBMs start. +//! +//! ### Scenario: Successful upgrade +//! +//! The standard procedure for a successful runtime upgrade can look like this: +//! 1. Migrations are configured in the `Migrations` config item. All migrations expose +//! [`max_steps`][SteppedMigration::max_steps], are error tolerant, check their weight bounds and +//! have a unique identifier. +//! 2. The runtime upgrade is enacted. An `UpgradeStarted` event is +//! followed by lots of `MigrationAdvanced` and `MigrationCompleted` events. Finally +//! `UpgradeCompleted` is emitted. +//! 3. Cleanup as described in the governance scenario be executed at any time after the migrations +//! completed. +//! +//! ### Advice: Failed upgrades +//! +//! Failed upgrades cannot be recovered from automatically and require governance intervention. Set +//! up monitoring for `UpgradeFailed` events to be made aware of any failures. The hook +//! [`FailedMigrationHandler::failed`] should be setup in a way that it allows governance to act, +//! but still prevent other transactions from interacting with the inconsistent storage state. Note +//! that this is paramount, since the inconsistent state might contain a faulty balance amount or +//! similar that could cause great harm if user transactions don't remain suspended. One way to +//! implement this would be to use the `SafeMode` or `TxPause` pallets that can prevent most user +//! interactions but still allow a whitelisted set of governance calls. +//! +//! ### Remark: Failed migrations +//! +//! Failed migrations are not added to the `Historic` set. This means that an erroneous +//! migration must be removed and fixed manually. This already applies, even before considering the +//! historic set. +//! +//! ### Remark: Transactional processing +//! +//! You can see the transactional semantics for migration steps as mostly useless, since in the +//! stuck case the state is already messed up. This just prevents it from becoming even more messed +//! up, but doesn't prevent it in the first place. + +#![cfg_attr(not(feature = "std"), no_std)] + +mod benchmarking; +mod mock; +pub mod mock_helpers; +mod tests; +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +use codec::{Decode, Encode, MaxEncodedLen}; +use core::ops::ControlFlow; +use frame_support::{ + defensive, defensive_assert, + migrations::*, + traits::Get, + weights::{Weight, WeightMeter}, + BoundedVec, +}; +use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System}; +use sp_runtime::Saturating; +use sp_std::vec::Vec; + +/// Points to the next migration to execute. +#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)] +pub enum MigrationCursor { + /// Points to the currently active migration and its inner cursor. + Active(ActiveCursor), + + /// Migration got stuck and cannot proceed. This is bad. + Stuck, +} + +impl MigrationCursor { + /// Try to return self as an [`ActiveCursor`]. + pub fn as_active(&self) -> Option<&ActiveCursor> { + match self { + MigrationCursor::Active(active) => Some(active), + MigrationCursor::Stuck => None, + } + } +} + +impl From> + for MigrationCursor +{ + fn from(active: ActiveCursor) -> Self { + MigrationCursor::Active(active) + } +} + +/// Points to the currently active migration and its inner cursor. +#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)] +pub struct ActiveCursor { + /// The index of the migration in the MBM tuple. + pub index: u32, + /// The cursor of the migration that is referenced by `index`. + pub inner_cursor: Option, + /// The block number that the migration started at. + /// + /// This is used to calculate how many blocks it took. + pub started_at: BlockNumber, +} + +impl ActiveCursor { + /// Advance the overarching cursor to the next migration. + pub(crate) fn goto_next_migration(&mut self, current_block: BlockNumber) { + self.index.saturating_inc(); + self.inner_cursor = None; + self.started_at = current_block; + } +} + +/// How to clear the records of historic migrations. +#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, scale_info::TypeInfo)] +pub enum HistoricCleanupSelector { + /// Clear exactly these entries. + /// + /// This is the advised way of doing it. + Specific(Vec), + + /// Clear up to this many entries + Wildcard { + /// How many should be cleared in this call at most. + limit: Option, + /// The cursor that was emitted from any previous `HistoricCleared`. + /// + /// Does not need to be passed when clearing the first batch. + previous_cursor: Option>, + }, +} + +/// The default number of entries that should be cleared by a `HistoricCleanupSelector::Wildcard`. +/// +/// The caller can explicitly specify a higher amount. Benchmarks are run with twice this value. +const DEFAULT_HISTORIC_BATCH_CLEAR_SIZE: u32 = 128; + +impl HistoricCleanupSelector { + /// The maximal number of entries that this will remove. + /// + /// Needed for weight calculation. + pub fn limit(&self) -> u32 { + match self { + Self::Specific(ids) => ids.len() as u32, + Self::Wildcard { limit, .. } => limit.unwrap_or(DEFAULT_HISTORIC_BATCH_CLEAR_SIZE), + } + } +} + +/// Convenience alias for [`MigrationCursor`]. +pub type CursorOf = MigrationCursor, BlockNumberFor>; + +/// Convenience alias for the raw inner cursor of a migration. +pub type RawCursorOf = BoundedVec::CursorMaxLen>; + +/// Convenience alias for the identifier of a migration. +pub type IdentifierOf = BoundedVec::IdentifierMaxLen>; + +/// Convenience alias for [`ActiveCursor`]. +pub type ActiveCursorOf = ActiveCursor, BlockNumberFor>; + +/// Trait for a tuple of No-OP migrations with one element. +pub trait MockedMigrations: SteppedMigrations { + /// The migration should fail after `n` steps. + fn set_fail_after(n: u32); + /// The migration should succeed after `n` steps. + fn set_success_after(n: u32); +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type of the runtime. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// All the multi-block migrations to run. + /// + /// Should only be updated in a runtime-upgrade once all the old migrations have completed. + /// (Check that [`Cursor`] is `None`). + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations: SteppedMigrations; + + /// Mocked migrations for benchmarking only. + /// + /// Should be configured to [`crate::mock_helpers::MockedMigrations`] in benchmarks. + #[cfg(feature = "runtime-benchmarks")] + type Migrations: MockedMigrations; + + /// The maximal length of an encoded cursor. + /// + /// A good default needs to selected such that no migration will ever have a cursor with MEL + /// above this limit. This is statically checked in `integrity_test`. + #[pallet::constant] + type CursorMaxLen: Get; + + /// The maximal length of an encoded identifier. + /// + /// A good default needs to selected such that no migration will ever have an identifier + /// with MEL above this limit. This is statically checked in `integrity_test`. + #[pallet::constant] + type IdentifierMaxLen: Get; + + /// Notifications for status updates of a runtime upgrade. + /// + /// Could be used to pause XCM etc. + type MigrationStatusHandler: MigrationStatusHandler; + + /// Handler for failed migrations. + type FailedMigrationHandler: FailedMigrationHandler; + + /// The maximum weight to spend each block to execute migrations. + type MaxServiceWeight: Get; + + /// Weight information for the calls and functions of this pallet. + type WeightInfo: WeightInfo; + } + + /// The currently active migration to run and its cursor. + /// + /// `None` indicates that no migration is running. + #[pallet::storage] + pub type Cursor = StorageValue<_, CursorOf, OptionQuery>; + + /// Set of all successfully executed migrations. + /// + /// This is used as blacklist, to not re-execute migrations that have not been removed from the + /// codebase yet. Governance can regularly clear this out via `clear_historic`. + #[pallet::storage] + pub type Historic = StorageMap<_, Twox64Concat, IdentifierOf, (), OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A Runtime upgrade started. + /// + /// Its end is indicated by `UpgradeCompleted` or `UpgradeFailed`. + UpgradeStarted { + /// The number of migrations that this upgrade contains. + /// + /// This can be used to design a progress indicator in combination with counting the + /// `MigrationCompleted` and `MigrationSkipped` events. + migrations: u32, + }, + /// The current runtime upgrade completed. + /// + /// This implies that all of its migrations completed successfully as well. + UpgradeCompleted, + /// Runtime upgrade failed. + /// + /// This is very bad and will require governance intervention. + UpgradeFailed, + /// A migration was skipped since it was already executed in the past. + MigrationSkipped { + /// The index of the skipped migration within the [`Config::Migrations`] list. + index: u32, + }, + /// A migration progressed. + MigrationAdvanced { + /// The index of the migration within the [`Config::Migrations`] list. + index: u32, + /// The number of blocks that this migration took so far. + took: BlockNumberFor, + }, + /// A Migration completed. + MigrationCompleted { + /// The index of the migration within the [`Config::Migrations`] list. + index: u32, + /// The number of blocks that this migration took so far. + took: BlockNumberFor, + }, + /// A Migration failed. + /// + /// This implies that the whole upgrade failed and governance intervention is required. + MigrationFailed { + /// The index of the migration within the [`Config::Migrations`] list. + index: u32, + /// The number of blocks that this migration took so far. + took: BlockNumberFor, + }, + /// The set of historical migrations has been cleared. + HistoricCleared { + /// Should be passed to `clear_historic` in a successive call. + next_cursor: Option>, + }, + } + + #[pallet::error] + pub enum Error { + /// The operation cannot complete since some MBMs are ongoing. + Ongoing, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_runtime_upgrade() -> Weight { + Self::onboard_new_mbms() + } + + #[cfg(feature = "std")] + fn integrity_test() { + // Check that the migrations tuple is legit. + frame_support::assert_ok!(T::Migrations::integrity_test()); + + // Very important! Ensure that the pallet is configured in `System::Config`. + { + assert!(!Cursor::::exists(), "Externalities storage should be clean"); + assert!(!::MultiBlockMigrator::ongoing()); + + Cursor::::put(MigrationCursor::Stuck); + assert!(::MultiBlockMigrator::ongoing()); + + Cursor::::kill(); + } + + // The per-block service weight is sane. + #[cfg(not(test))] + { + let want = T::MaxServiceWeight::get(); + let max = ::BlockWeights::get().max_block; + + assert!(want.all_lte(max), "Service weight is larger than a block: {want} > {max}",); + } + + // Cursor MEL + { + let mel = T::Migrations::cursor_max_encoded_len(); + let max_mel = T::CursorMaxLen::get() as usize; + assert!( + mel <= max_mel, + "A Cursor is not guaranteed to fit into the storage: {mel} > {max_mel}", + ); + } + + // Identifier MEL + { + let mel = T::Migrations::identifier_max_encoded_len(); + let max_mel = T::IdentifierMaxLen::get() as usize; + assert!( + mel <= max_mel, + "An Identifier is not guaranteed to fit into the storage: {mel} > {max_mel}", + ); + } + } + } + + #[pallet::call(weight = T::WeightInfo)] + impl Pallet { + /// Allows root to set a cursor to forcefully start, stop or forward the migration process. + /// + /// Should normally not be needed and is only in place as emergency measure. Note that + /// restarting the migration process in this manner will not call the + /// [`MigrationStatusHandler::started`] hook or emit an `UpgradeStarted` event. + #[pallet::call_index(0)] + pub fn force_set_cursor( + origin: OriginFor, + cursor: Option>, + ) -> DispatchResult { + ensure_root(origin)?; + + Cursor::::set(cursor); + + Ok(()) + } + + /// Allows root to set an active cursor to forcefully start/forward the migration process. + /// + /// This is an edge-case version of [`Self::force_set_cursor`] that allows to set the + /// `started_at` value to the next block number. Otherwise this would not be possible, since + /// `force_set_cursor` takes an absolute block number. Setting `started_at` to `None` + /// indicates that the current block number plus one should be used. + #[pallet::call_index(1)] + pub fn force_set_active_cursor( + origin: OriginFor, + index: u32, + inner_cursor: Option>, + started_at: Option>, + ) -> DispatchResult { + ensure_root(origin)?; + + let started_at = started_at.unwrap_or( + System::::block_number().saturating_add(sp_runtime::traits::One::one()), + ); + Cursor::::put(MigrationCursor::Active(ActiveCursor { + index, + inner_cursor, + started_at, + })); + + Ok(()) + } + + /// Forces the onboarding of the migrations. + /// + /// This process happens automatically on a runtime upgrade. It is in place as an emergency + /// measurement. The cursor needs to be `None` for this to succeed. + #[pallet::call_index(2)] + pub fn force_onboard_mbms(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + + ensure!(!Cursor::::exists(), Error::::Ongoing); + Self::onboard_new_mbms(); + + Ok(()) + } + + /// Clears the `Historic` set. + /// + /// `map_cursor` must be set to the last value that was returned by the + /// `HistoricCleared` event. The first time `None` can be used. `limit` must be chosen in a + /// way that will result in a sensible weight. + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::clear_historic(selector.limit()))] + pub fn clear_historic( + origin: OriginFor, + selector: HistoricCleanupSelector>, + ) -> DispatchResult { + ensure_root(origin)?; + + match &selector { + HistoricCleanupSelector::Specific(ids) => { + for id in ids { + Historic::::remove(id); + } + Self::deposit_event(Event::HistoricCleared { next_cursor: None }); + }, + HistoricCleanupSelector::Wildcard { previous_cursor, .. } => { + let next = Historic::::clear(selector.limit(), previous_cursor.as_deref()); + Self::deposit_event(Event::HistoricCleared { next_cursor: next.maybe_cursor }); + }, + } + + Ok(()) + } + } +} + +impl Pallet { + /// Onboard all new Multi-Block-Migrations and start the process of executing them. + /// + /// Should only be called once all previous migrations completed. + fn onboard_new_mbms() -> Weight { + if let Some(cursor) = Cursor::::get() { + log::error!("Ongoing migrations interrupted - chain stuck"); + + let maybe_index = cursor.as_active().map(|c| c.index); + Self::upgrade_failed(maybe_index); + return T::WeightInfo::onboard_new_mbms() + } + + let migrations = T::Migrations::len(); + log::debug!("Onboarding {migrations} new MBM migrations"); + + if migrations > 0 { + // Set the cursor to the first migration: + Cursor::::set(Some( + ActiveCursor { + index: 0, + inner_cursor: None, + started_at: System::::block_number(), + } + .into(), + )); + Self::deposit_event(Event::UpgradeStarted { migrations }); + T::MigrationStatusHandler::started(); + } + + T::WeightInfo::onboard_new_mbms() + } + + /// Tries to make progress on the Multi-Block-Migrations process. + fn progress_mbms(n: BlockNumberFor) -> Weight { + let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get()); + meter.consume(T::WeightInfo::progress_mbms_none()); + + let mut cursor = match Cursor::::get() { + None => { + log::trace!("[Block {n:?}] Waiting for cursor to become `Some`."); + return meter.consumed() + }, + Some(MigrationCursor::Active(cursor)) => { + log::debug!("Progressing MBM #{}", cursor.index); + cursor + }, + Some(MigrationCursor::Stuck) => { + log::error!("Migration stuck. Governance intervention required."); + return meter.consumed() + }, + }; + debug_assert!(Self::ongoing()); + + // The limit here is a defensive measure to prevent an infinite loop. It expresses that we + // allow no more than 8 MBMs to finish in a single block. This should be harmless, since we + // generally expect *Multi*-Block-Migrations to take *multiple* blocks. + for i in 0..8 { + match Self::exec_migration(cursor, i == 0, &mut meter) { + None => return meter.consumed(), + Some(ControlFlow::Continue(next_cursor)) => { + cursor = next_cursor; + }, + Some(ControlFlow::Break(last_cursor)) => { + cursor = last_cursor; + break + }, + } + } + + Cursor::::set(Some(cursor.into())); + + meter.consumed() + } + + /// Try to make progress on the current migration. + /// + /// Returns whether processing should continue or break for this block. The return value means: + /// - `None`: The migration process is completely finished. + /// - `ControlFlow::Break`: Continue in the *next* block with the given cursor. + /// - `ControlFlow::Continue`: Continue in the *current* block with the given cursor. + fn exec_migration( + mut cursor: ActiveCursorOf, + is_first: bool, + meter: &mut WeightMeter, + ) -> Option, ActiveCursorOf>> { + // The differences between the single branches' weights is not that big. And since we do + // only one step per block, we can just use the maximum instead of more precise accounting. + if meter.try_consume(Self::exec_migration_max_weight()).is_err() { + defensive_assert!(!is_first, "There should be enough weight to do this at least once"); + return Some(ControlFlow::Break(cursor)) + } + + let Some(id) = T::Migrations::nth_id(cursor.index) else { + // No more migrations in the tuple - we are done. + defensive_assert!(cursor.index == T::Migrations::len(), "Inconsistent MBMs tuple"); + Self::deposit_event(Event::UpgradeCompleted); + Cursor::::kill(); + T::MigrationStatusHandler::completed(); + return None; + }; + + let Ok(bounded_id): Result, _> = id.try_into() else { + defensive!("integrity_test ensures that all identifiers' MEL bounds fit into CursorMaxLen; qed."); + Self::upgrade_failed(Some(cursor.index)); + return None + }; + + if Historic::::contains_key(&bounded_id) { + Self::deposit_event(Event::MigrationSkipped { index: cursor.index }); + cursor.goto_next_migration(System::::block_number()); + return Some(ControlFlow::Continue(cursor)) + } + + let max_steps = T::Migrations::nth_max_steps(cursor.index); + let next_cursor = T::Migrations::nth_transactional_step( + cursor.index, + cursor.inner_cursor.clone().map(|c| c.into_inner()), + meter, + ); + let Some((max_steps, next_cursor)) = max_steps.zip(next_cursor) else { + defensive!("integrity_test ensures that the tuple is valid; qed"); + Self::upgrade_failed(Some(cursor.index)); + return None + }; + + let took = System::::block_number().saturating_sub(cursor.started_at); + match next_cursor { + Ok(Some(next_cursor)) => { + let Ok(bound_next_cursor) = next_cursor.try_into() else { + defensive!("The integrity check ensures that all cursors' MEL bound fits into CursorMaxLen; qed"); + Self::upgrade_failed(Some(cursor.index)); + return None + }; + + Self::deposit_event(Event::MigrationAdvanced { index: cursor.index, took }); + cursor.inner_cursor = Some(bound_next_cursor); + + if max_steps.map_or(false, |max| took > max.into()) { + Self::deposit_event(Event::MigrationFailed { index: cursor.index, took }); + Self::upgrade_failed(Some(cursor.index)); + None + } else { + // A migration cannot progress more than one step per block, we therefore break. + Some(ControlFlow::Break(cursor)) + } + }, + Ok(None) => { + // A migration is done when it returns cursor `None`. + Self::deposit_event(Event::MigrationCompleted { index: cursor.index, took }); + Historic::::insert(&bounded_id, ()); + cursor.goto_next_migration(System::::block_number()); + Some(ControlFlow::Continue(cursor)) + }, + Err(SteppedMigrationError::InsufficientWeight { required }) => { + if is_first || required.any_gt(meter.limit()) { + Self::deposit_event(Event::MigrationFailed { index: cursor.index, took }); + Self::upgrade_failed(Some(cursor.index)); + None + } else { + // Retry and hope that there is more weight in the next block. + Some(ControlFlow::Break(cursor)) + } + }, + Err(SteppedMigrationError::InvalidCursor | SteppedMigrationError::Failed) => { + Self::deposit_event(Event::MigrationFailed { index: cursor.index, took }); + Self::upgrade_failed(Some(cursor.index)); + None + }, + } + } + + /// Fail the current runtime upgrade, caused by `migration`. + fn upgrade_failed(migration: Option) { + use FailedMigrationHandling::*; + Self::deposit_event(Event::UpgradeFailed); + + match T::FailedMigrationHandler::failed(migration) { + KeepStuck => Cursor::::set(Some(MigrationCursor::Stuck)), + ForceUnstuck => Cursor::::kill(), + Ignore => {}, + } + } + + fn exec_migration_max_weight() -> Weight { + T::WeightInfo::exec_migration_complete() + .max(T::WeightInfo::exec_migration_completed()) + .max(T::WeightInfo::exec_migration_skipped_historic()) + .max(T::WeightInfo::exec_migration_advance()) + .max(T::WeightInfo::exec_migration_fail()) + } +} + +impl MultiStepMigrator for Pallet { + fn ongoing() -> bool { + Cursor::::exists() + } + + fn step() -> Weight { + Self::progress_mbms(System::::block_number()) + } +} diff --git a/substrate/frame/migrations/src/mock.rs b/substrate/frame/migrations/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..3729264755442a008641668b0a14214764d255b9 --- /dev/null +++ b/substrate/frame/migrations/src/mock.rs @@ -0,0 +1,163 @@ +// 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. + +//! Mocked runtime for testing the migrations pallet. + +#![cfg(test)] + +use crate::{mock_helpers::*, Event, Historic}; + +use frame_support::{ + derive_impl, + migrations::*, + traits::{OnFinalize, OnInitialize}, + weights::Weight, +}; +use frame_system::EventRecord; +use sp_core::{ConstU32, H256}; + +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test { + System: frame_system, + Migrations: crate, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; + type PalletInfo = PalletInfo; + type MultiBlockMigrator = Migrations; +} + +frame_support::parameter_types! { + pub const MaxServiceWeight: Weight = Weight::MAX.div(10); +} + +impl crate::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Migrations = MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = MockedMigrationStatusHandler; + type FailedMigrationHandler = MockedFailedMigrationHandler; + type MaxServiceWeight = MaxServiceWeight; + type WeightInfo = (); +} + +frame_support::parameter_types! { + /// The number of started upgrades. + pub static UpgradesStarted: u32 = 0; + /// The number of completed upgrades. + pub static UpgradesCompleted: u32 = 0; + /// The migrations that failed. + pub static UpgradesFailed: Vec> = vec![]; + /// Return value of [`MockedFailedMigrationHandler::failed`]. + pub static FailedUpgradeResponse: FailedMigrationHandling = FailedMigrationHandling::KeepStuck; +} + +/// Records all started and completed upgrades in `UpgradesStarted` and `UpgradesCompleted`. +pub struct MockedMigrationStatusHandler; +impl MigrationStatusHandler for MockedMigrationStatusHandler { + fn started() { + log::info!("MigrationStatusHandler started"); + UpgradesStarted::mutate(|v| *v += 1); + } + + fn completed() { + log::info!("MigrationStatusHandler completed"); + UpgradesCompleted::mutate(|v| *v += 1); + } +} + +/// Records all failed upgrades in `UpgradesFailed`. +pub struct MockedFailedMigrationHandler; +impl FailedMigrationHandler for MockedFailedMigrationHandler { + fn failed(migration: Option) -> FailedMigrationHandling { + UpgradesFailed::mutate(|v| v.push(migration)); + let res = FailedUpgradeResponse::get(); + log::error!("FailedMigrationHandler failed at: {migration:?}, handling as {res:?}"); + res + } +} + +/// Returns the number of `(started, completed, failed)` upgrades and resets their numbers. +pub fn upgrades_started_completed_failed() -> (u32, u32, u32) { + (UpgradesStarted::take(), UpgradesCompleted::take(), UpgradesFailed::take().len() as u32) +} + +/// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new(Default::default()) +} + +/// Run this closure in test externalities. +pub fn test_closure(f: impl FnOnce() -> R) -> R { + let mut ext = new_test_ext(); + ext.execute_with(f) +} + +pub fn run_to_block(n: u32) { + while System::block_number() < n as u64 { + log::debug!("Block {}", System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Migrations::on_initialize(System::block_number()); + // Executive calls this: + ::step(); + + Migrations::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + } +} + +/// Returns the historic migrations, sorted by their identifier. +pub fn historic() -> Vec { + let mut historic = Historic::::iter_keys().collect::>(); + historic.sort(); + historic +} + +// Traits to make using events less insufferable: +pub trait IntoRecord { + fn into_record(self) -> EventRecord<::RuntimeEvent, H256>; +} + +impl IntoRecord for Event { + fn into_record(self) -> EventRecord<::RuntimeEvent, H256> { + let re: ::RuntimeEvent = self.into(); + EventRecord { phase: frame_system::Phase::Initialization, event: re, topics: vec![] } + } +} + +pub trait IntoRecords { + fn into_records(self) -> Vec::RuntimeEvent, H256>>; +} + +impl IntoRecords for Vec { + fn into_records(self) -> Vec::RuntimeEvent, H256>> { + self.into_iter().map(|e| e.into_record()).collect() + } +} + +pub fn assert_events(events: Vec) { + pretty_assertions::assert_eq!(events.into_records(), System::events()); + System::reset_events(); +} diff --git a/substrate/frame/migrations/src/mock_helpers.rs b/substrate/frame/migrations/src/mock_helpers.rs new file mode 100644 index 0000000000000000000000000000000000000000..c5e23efb4e314e6f5562c50521a533c82f94669e --- /dev/null +++ b/substrate/frame/migrations/src/mock_helpers.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. + +//! Test helpers for internal and external usage. + +#![allow(missing_docs)] + +use codec::{Decode, Encode}; +use frame_support::{ + migrations::*, + weights::{Weight, WeightMeter}, +}; +use sp_core::ConstU32; +use sp_runtime::BoundedVec; +use sp_std::{vec, vec::Vec}; + +/// Opaque identifier of a migration. +pub type MockedIdentifier = BoundedVec>; + +/// How a mocked migration should behave. +#[derive(Debug, Clone, Copy, Encode, Decode)] +pub enum MockedMigrationKind { + /// Succeed after its number of steps elapsed. + SucceedAfter, + /// Fail after its number of steps elapsed. + FailAfter, + /// Never terminate. + TimeoutAfter, + /// Cause an [`SteppedMigrationError::InsufficientWeight`] error after its number of steps + /// elapsed. + HighWeightAfter(Weight), +} +use MockedMigrationKind::*; // C style + +/// Creates a migration identifier with a specific `kind` and `steps`. +pub fn mocked_id(kind: MockedMigrationKind, steps: u32) -> MockedIdentifier { + (b"MockedMigration", kind, steps).encode().try_into().unwrap() +} + +frame_support::parameter_types! { + /// The configs for the migrations to run. + storage MIGRATIONS: Vec<(MockedMigrationKind, u32)> = vec![]; +} + +/// Allows to set the migrations to run at runtime instead of compile-time. +/// +/// It achieves this by using the storage to store the migrations to run. +pub struct MockedMigrations; +impl SteppedMigrations for MockedMigrations { + fn len() -> u32 { + MIGRATIONS::get().len() as u32 + } + + fn nth_id(n: u32) -> Option> { + let k = MIGRATIONS::get().get(n as usize).copied(); + k.map(|(kind, steps)| mocked_id(kind, steps).into_inner()) + } + + fn nth_step( + n: u32, + cursor: Option>, + _meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + let (kind, steps) = MIGRATIONS::get()[n as usize]; + + let mut count: u32 = + cursor.as_ref().and_then(|c| Decode::decode(&mut &c[..]).ok()).unwrap_or(0); + log::debug!("MockedMigration: Step {}", count); + if count != steps || matches!(kind, TimeoutAfter) { + count += 1; + return Some(Ok(Some(count.encode()))) + } + + Some(match kind { + SucceedAfter => { + log::debug!("MockedMigration: Succeeded after {} steps", count); + Ok(None) + }, + HighWeightAfter(required) => { + log::debug!("MockedMigration: Not enough weight after {} steps", count); + Err(SteppedMigrationError::InsufficientWeight { required }) + }, + FailAfter => { + log::debug!("MockedMigration: Failed after {} steps", count); + Err(SteppedMigrationError::Failed) + }, + TimeoutAfter => unreachable!(), + }) + } + + fn nth_transactional_step( + n: u32, + cursor: Option>, + meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + // This is a hack but should be fine. We dont need it in testing. + Self::nth_step(n, cursor, meter) + } + + fn nth_max_steps(n: u32) -> Option> { + MIGRATIONS::get().get(n as usize).map(|(_, s)| Some(*s)) + } + + fn cursor_max_encoded_len() -> usize { + 65_536 + } + + fn identifier_max_encoded_len() -> usize { + 256 + } +} + +impl MockedMigrations { + /// Set the migrations to run. + pub fn set(migrations: Vec<(MockedMigrationKind, u32)>) { + MIGRATIONS::set(&migrations); + } +} + +impl crate::MockedMigrations for MockedMigrations { + fn set_fail_after(steps: u32) { + MIGRATIONS::set(&vec![(FailAfter, steps)]); + } + + fn set_success_after(steps: u32) { + MIGRATIONS::set(&vec![(SucceedAfter, steps)]); + } +} diff --git a/substrate/frame/migrations/src/tests.rs b/substrate/frame/migrations/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..9c9043d37a62e5f1df3d12da979b68251621c9d0 --- /dev/null +++ b/substrate/frame/migrations/src/tests.rs @@ -0,0 +1,335 @@ +// 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(test)] + +use crate::{ + mock::{Test as T, *}, + mock_helpers::{MockedMigrationKind::*, *}, + Cursor, Event, FailedMigrationHandling, MigrationCursor, +}; +use frame_support::{pallet_prelude::Weight, traits::OnRuntimeUpgrade}; + +#[docify::export] +#[test] +fn simple_works() { + use Event::*; + test_closure(|| { + // Add three migrations, each taking one block longer than the previous. + MockedMigrations::set(vec![(SucceedAfter, 0), (SucceedAfter, 1), (SucceedAfter, 2)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + // Check that the executed migrations are recorded in `Historical`. + assert_eq!( + historic(), + vec![ + mocked_id(SucceedAfter, 0), + mocked_id(SucceedAfter, 1), + mocked_id(SucceedAfter, 2), + ] + ); + + // Check that we got all events. + assert_events(vec![ + UpgradeStarted { migrations: 3 }, + MigrationCompleted { index: 0, took: 1 }, + MigrationAdvanced { index: 1, took: 0 }, + MigrationCompleted { index: 1, took: 1 }, + MigrationAdvanced { index: 2, took: 0 }, + MigrationAdvanced { index: 2, took: 1 }, + MigrationCompleted { index: 2, took: 2 }, + UpgradeCompleted, + ]); + }); +} + +#[test] +fn failing_migration_sets_cursor_to_stuck() { + test_closure(|| { + FailedUpgradeResponse::set(FailedMigrationHandling::KeepStuck); + MockedMigrations::set(vec![(FailAfter, 2)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + // Failed migrations are not recorded in `Historical`. + assert!(historic().is_empty()); + // Check that we got all events. + assert_events(vec![ + Event::UpgradeStarted { migrations: 1 }, + Event::MigrationAdvanced { index: 0, took: 1 }, + Event::MigrationAdvanced { index: 0, took: 2 }, + Event::MigrationFailed { index: 0, took: 3 }, + Event::UpgradeFailed, + ]); + + // Check that the handler was called correctly. + assert_eq!(UpgradesStarted::take(), 1); + assert_eq!(UpgradesCompleted::take(), 0); + assert_eq!(UpgradesFailed::take(), vec![Some(0)]); + + assert_eq!(Cursor::::get(), Some(MigrationCursor::Stuck), "Must stuck the chain"); + }); +} + +#[test] +fn failing_migration_force_unstuck_works() { + test_closure(|| { + FailedUpgradeResponse::set(FailedMigrationHandling::ForceUnstuck); + MockedMigrations::set(vec![(FailAfter, 2)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + // Failed migrations are not recorded in `Historical`. + assert!(historic().is_empty()); + // Check that we got all events. + assert_events(vec![ + Event::UpgradeStarted { migrations: 1 }, + Event::MigrationAdvanced { index: 0, took: 1 }, + Event::MigrationAdvanced { index: 0, took: 2 }, + Event::MigrationFailed { index: 0, took: 3 }, + Event::UpgradeFailed, + ]); + + // Check that the handler was called correctly. + assert_eq!(UpgradesStarted::take(), 1); + assert_eq!(UpgradesCompleted::take(), 0); + assert_eq!(UpgradesFailed::take(), vec![Some(0)]); + + assert!(Cursor::::get().is_none(), "Must unstuck the chain"); + }); +} + +/// A migration that reports not getting enough weight errors if it is the first one to run in that +/// block. +#[test] +fn high_weight_migration_singular_fails() { + test_closure(|| { + MockedMigrations::set(vec![(HighWeightAfter(Weight::zero()), 2)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + // Failed migrations are not recorded in `Historical`. + assert!(historic().is_empty()); + // Check that we got all events. + assert_events(vec![ + Event::UpgradeStarted { migrations: 1 }, + Event::MigrationAdvanced { index: 0, took: 1 }, + Event::MigrationAdvanced { index: 0, took: 2 }, + Event::MigrationFailed { index: 0, took: 3 }, + Event::UpgradeFailed, + ]); + + // Check that the handler was called correctly. + assert_eq!(upgrades_started_completed_failed(), (1, 0, 1)); + assert_eq!(Cursor::::get(), Some(MigrationCursor::Stuck)); + }); +} + +/// A migration that reports of not getting enough weight is retried once, if it is not the first +/// one to run in a block. +#[test] +fn high_weight_migration_retries_once() { + test_closure(|| { + MockedMigrations::set(vec![(SucceedAfter, 0), (HighWeightAfter(Weight::zero()), 0)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + assert_eq!(historic(), vec![mocked_id(SucceedAfter, 0)]); + // Check that we got all events. + assert_events::>(vec![ + Event::UpgradeStarted { migrations: 2 }, + Event::MigrationCompleted { index: 0, took: 1 }, + // `took=1` means that it was retried once. + Event::MigrationFailed { index: 1, took: 1 }, + Event::UpgradeFailed, + ]); + + // Check that the handler was called correctly. + assert_eq!(upgrades_started_completed_failed(), (1, 0, 1)); + assert_eq!(Cursor::::get(), Some(MigrationCursor::Stuck)); + }); +} + +/// If a migration uses more weight than the limit, then it will not retry but fail even when it is +/// not the first one in the block. +// Note: Same as `high_weight_migration_retries_once` but with different required weight for the +// migration. +#[test] +fn high_weight_migration_permanently_overweight_fails() { + test_closure(|| { + MockedMigrations::set(vec![(SucceedAfter, 0), (HighWeightAfter(Weight::MAX), 0)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + assert_eq!(historic(), vec![mocked_id(SucceedAfter, 0)]); + // Check that we got all events. + assert_events::>(vec![ + Event::UpgradeStarted { migrations: 2 }, + Event::MigrationCompleted { index: 0, took: 1 }, + // `blocks=0` means that it was not retried. + Event::MigrationFailed { index: 1, took: 0 }, + Event::UpgradeFailed, + ]); + + // Check that the handler was called correctly. + assert_eq!(upgrades_started_completed_failed(), (1, 0, 1)); + assert_eq!(Cursor::::get(), Some(MigrationCursor::Stuck)); + }); +} + +#[test] +fn historic_skipping_works() { + test_closure(|| { + MockedMigrations::set(vec![ + (SucceedAfter, 0), + (SucceedAfter, 0), // duplicate + (SucceedAfter, 1), + (SucceedAfter, 2), + (SucceedAfter, 1), // duplicate + ]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + // Just three historical ones, since two were added twice. + assert_eq!( + historic(), + vec![ + mocked_id(SucceedAfter, 0), + mocked_id(SucceedAfter, 1), + mocked_id(SucceedAfter, 2), + ] + ); + // Events received. + assert_events(vec![ + Event::UpgradeStarted { migrations: 5 }, + Event::MigrationCompleted { index: 0, took: 1 }, + Event::MigrationSkipped { index: 1 }, + Event::MigrationAdvanced { index: 2, took: 0 }, + Event::MigrationCompleted { index: 2, took: 1 }, + Event::MigrationAdvanced { index: 3, took: 0 }, + Event::MigrationAdvanced { index: 3, took: 1 }, + Event::MigrationCompleted { index: 3, took: 2 }, + Event::MigrationSkipped { index: 4 }, + Event::UpgradeCompleted, + ]); + assert_eq!(upgrades_started_completed_failed(), (1, 1, 0)); + + // Now go for another upgrade; just to make sure that it wont execute again. + System::reset_events(); + Migrations::on_runtime_upgrade(); + run_to_block(20); + + // Same historical ones as before. + assert_eq!( + historic(), + vec![ + mocked_id(SucceedAfter, 0), + mocked_id(SucceedAfter, 1), + mocked_id(SucceedAfter, 2), + ] + ); + + // Everything got skipped. + assert_events(vec![ + Event::UpgradeStarted { migrations: 5 }, + Event::MigrationSkipped { index: 0 }, + Event::MigrationSkipped { index: 1 }, + Event::MigrationSkipped { index: 2 }, + Event::MigrationSkipped { index: 3 }, + Event::MigrationSkipped { index: 4 }, + Event::UpgradeCompleted, + ]); + assert_eq!(upgrades_started_completed_failed(), (1, 1, 0)); + }); +} + +/// When another upgrade happens while a migration is still running, it should set the cursor to +/// stuck. +#[test] +fn upgrade_fails_when_migration_active() { + test_closure(|| { + MockedMigrations::set(vec![(SucceedAfter, 10)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(3); + + // Events received. + assert_events(vec![ + Event::UpgradeStarted { migrations: 1 }, + Event::MigrationAdvanced { index: 0, took: 1 }, + Event::MigrationAdvanced { index: 0, took: 2 }, + ]); + assert_eq!(upgrades_started_completed_failed(), (1, 0, 0)); + + // Upgrade again. + Migrations::on_runtime_upgrade(); + // -- Defensive path -- + assert_eq!(Cursor::::get(), Some(MigrationCursor::Stuck)); + assert_events(vec![Event::UpgradeFailed]); + assert_eq!(upgrades_started_completed_failed(), (0, 0, 1)); + }); +} + +#[test] +fn migration_timeout_errors() { + test_closure(|| { + MockedMigrations::set(vec![(TimeoutAfter, 3)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(5); + + // Times out after taking more than 3 steps. + assert_events(vec![ + Event::UpgradeStarted { migrations: 1 }, + Event::MigrationAdvanced { index: 0, took: 1 }, + Event::MigrationAdvanced { index: 0, took: 2 }, + Event::MigrationAdvanced { index: 0, took: 3 }, + Event::MigrationAdvanced { index: 0, took: 4 }, + Event::MigrationFailed { index: 0, took: 4 }, + Event::UpgradeFailed, + ]); + assert_eq!(upgrades_started_completed_failed(), (1, 0, 1)); + + // Failed migrations are not black-listed. + assert!(historic().is_empty()); + assert_eq!(Cursor::::get(), Some(MigrationCursor::Stuck)); + + Migrations::on_runtime_upgrade(); + run_to_block(6); + + assert_events(vec![Event::UpgradeFailed]); + assert_eq!(Cursor::::get(), Some(MigrationCursor::Stuck)); + assert_eq!(upgrades_started_completed_failed(), (0, 0, 1)); + }); +} diff --git a/substrate/frame/migrations/src/weights.rs b/substrate/frame/migrations/src/weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..9eca48ac3fd9ca8663a0b54a0258591e9b4023aa --- /dev/null +++ b/substrate/frame/migrations/src/weights.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. + +//! Autogenerated weights for `pallet_migrations` +//! +//! 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_migrations +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/migrations/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_migrations`. +pub trait WeightInfo { + fn onboard_new_mbms() -> Weight; + fn progress_mbms_none() -> Weight; + fn exec_migration_completed() -> Weight; + fn exec_migration_skipped_historic() -> Weight; + fn exec_migration_advance() -> Weight; + fn exec_migration_complete() -> Weight; + fn exec_migration_fail() -> Weight; + fn on_init_loop() -> Weight; + fn force_set_cursor() -> Weight; + fn force_set_active_cursor() -> Weight; + fn force_onboard_mbms() -> Weight; + fn clear_historic(n: u32, ) -> Weight; +} + +/// Weights for `pallet_migrations` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// 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_932_000 picoseconds. + Weight::from_parts(8_428_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_229_000 picoseconds. + Weight::from_parts(2_329_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: 6_051_000 picoseconds. + Weight::from_parts(6_483_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_066_000 picoseconds. + Weight::from_parts(10_713_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: 10_026_000 picoseconds. + Weight::from_parts(10_379_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_680_000 picoseconds. + Weight::from_parts(12_184_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_334_000 picoseconds. + Weight::from_parts(12_899_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: 187_000 picoseconds. + Weight::from_parts(209_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_688_000 picoseconds. + Weight::from_parts(2_874_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_108_000 picoseconds. + Weight::from_parts(3_263_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_993_000 picoseconds. + Weight::from_parts(6_359_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: 16_003_000 picoseconds. + Weight::from_parts(14_453_014, 3834) + // Standard Error: 3_305 + .saturating_add(Weight::from_parts(1_325_026, 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())) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// 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_932_000 picoseconds. + Weight::from_parts(8_428_000, 67035) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .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`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_229_000 picoseconds. + Weight::from_parts(2_329_000, 67035) + .saturating_add(RocksDbWeight::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: 6_051_000 picoseconds. + Weight::from_parts(6_483_000, 3599) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::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_066_000 picoseconds. + Weight::from_parts(10_713_000, 3795) + .saturating_add(RocksDbWeight::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: 10_026_000 picoseconds. + Weight::from_parts(10_379_000, 3741) + .saturating_add(RocksDbWeight::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_680_000 picoseconds. + Weight::from_parts(12_184_000, 3741) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::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_334_000 picoseconds. + Weight::from_parts(12_899_000, 3741) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 187_000 picoseconds. + Weight::from_parts(209_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_688_000 picoseconds. + Weight::from_parts(2_874_000, 0) + .saturating_add(RocksDbWeight::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_108_000 picoseconds. + Weight::from_parts(3_263_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: 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_993_000 picoseconds. + Weight::from_parts(6_359_000, 67035) + .saturating_add(RocksDbWeight::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: 16_003_000 picoseconds. + Weight::from_parts(14_453_014, 3834) + // Standard Error: 3_305 + .saturating_add(Weight::from_parts(1_325_026, 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()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index cb00b38890ea48498eab31da2ff29cbc970ccddf..d1bb01dde1a47e70587dc37ad27123a0632cdcf7 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -20,9 +20,9 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } frame-support = { default-features = false, path = "../support" } frame-system = { default-features = false, path = "../system" } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["derive"] } +serde = { features = ["derive"], workspace = true } sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto" } sp-arithmetic = { default-features = false, path = "../../primitives/arithmetic" } sp-io = { default-features = false, path = "../../primitives/io" } diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index aefdbe855a3c4b6cee4330b14c4e3d958ddccd2b..1d2a79bdc52f2fadd6fe2aa782029936c76a28e0 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -26,7 +26,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } # third party -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] pallet-balances = { path = "../balances" } diff --git a/substrate/frame/multisig/src/lib.rs b/substrate/frame/multisig/src/lib.rs index e4426c64b4125fe267a1e30a42a7196274b05e4e..a83b78e316f500ddc9c615420c2ac627b90ee7e9 100644 --- a/substrate/frame/multisig/src/lib.rs +++ b/substrate/frame/multisig/src/lib.rs @@ -168,7 +168,7 @@ pub mod pallet { type WeightInfo: WeightInfo; } - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] diff --git a/substrate/frame/multisig/src/migrations.rs b/substrate/frame/multisig/src/migrations.rs index d03e42a66a5b5af07248ee7b11061d5f26b66c98..e6402600d0d368783e30f43e0afc3adad4d0a1ba 100644 --- a/substrate/frame/multisig/src/migrations.rs +++ b/substrate/frame/multisig/src/migrations.rs @@ -51,7 +51,7 @@ pub mod v1 { fn on_runtime_upgrade() -> Weight { use sp_runtime::Saturating; - let current = Pallet::::current_storage_version(); + let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); if onchain > 0 { diff --git a/substrate/frame/multisig/src/weights.rs b/substrate/frame/multisig/src/weights.rs index 7b87d258d383d43aaf8ef8aaddc0546c60b5813e..4cbe7bb03b7d5fecc8b9b03edab6613c1d42f34e 100644 --- a/substrate/frame/multisig/src/weights.rs +++ b/substrate/frame/multisig/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_multisig +//! Autogenerated weights for `pallet_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/multisig/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/multisig/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_multisig. +/// Weight functions needed for `pallet_multisig`. pub trait WeightInfo { fn as_multi_threshold_1(z: u32, ) -> Weight; fn as_multi_create(s: u32, z: u32, ) -> Weight; @@ -61,220 +60,238 @@ pub trait WeightInfo { fn cancel_as_multi(s: u32, ) -> Weight; } -/// Weights for pallet_multisig using the Substrate node and recommended hardware. +/// Weights for `pallet_multisig` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); 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: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 13_452_000 picoseconds. - Weight::from_parts(14_425_869, 0) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(20_278_307, 3997) // Standard Error: 4 - .saturating_add(Weight::from_parts(493, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(488, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) } - /// 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: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 46_012_000 picoseconds. - Weight::from_parts(34_797_344, 6811) - // Standard Error: 833 - .saturating_add(Weight::from_parts(127_671, 0).saturating_mul(s.into())) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(z.into())) + // Minimum execution time: 39_478_000 picoseconds. + Weight::from_parts(29_195_487, 6811) + // Standard Error: 739 + .saturating_add(Weight::from_parts(118_766, 0).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_511, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `320` // Estimated: `6811` - // Minimum execution time: 29_834_000 picoseconds. - Weight::from_parts(20_189_154, 6811) - // Standard Error: 637 - .saturating_add(Weight::from_parts(110_080, 0).saturating_mul(s.into())) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_483, 0).saturating_mul(z.into())) + // Minimum execution time: 26_401_000 picoseconds. + Weight::from_parts(17_277_296, 6811) + // Standard Error: 492 + .saturating_add(Weight::from_parts(101_763, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_486, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, 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: `426 + s * (33 ±0)` + // Measured: `571 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 51_464_000 picoseconds. - Weight::from_parts(39_246_644, 6811) - // Standard Error: 1_251 - .saturating_add(Weight::from_parts(143_313, 0).saturating_mul(s.into())) + // Minimum execution time: 52_430_000 picoseconds. + Weight::from_parts(40_585_478, 6811) + // Standard Error: 1_240 + .saturating_add(Weight::from_parts(161_405, 0).saturating_mul(s.into())) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(1_547, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 33_275_000 picoseconds. - Weight::from_parts(34_073_221, 6811) - // Standard Error: 1_163 - .saturating_add(Weight::from_parts(124_815, 0).saturating_mul(s.into())) + // Minimum execution time: 27_797_000 picoseconds. + Weight::from_parts(29_064_584, 6811) + // Standard Error: 817 + .saturating_add(Weight::from_parts(108_179, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `320` // Estimated: `6811` - // Minimum execution time: 18_411_000 picoseconds. - Weight::from_parts(19_431_787, 6811) - // Standard Error: 694 - .saturating_add(Weight::from_parts(107_220, 0).saturating_mul(s.into())) + // Minimum execution time: 15_236_000 picoseconds. + Weight::from_parts(16_360_247, 6811) + // Standard Error: 584 + .saturating_add(Weight::from_parts(94_917, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `492 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 33_985_000 picoseconds. - Weight::from_parts(35_547_970, 6811) - // Standard Error: 1_135 - .saturating_add(Weight::from_parts(116_537, 0).saturating_mul(s.into())) + // Minimum execution time: 28_730_000 picoseconds. + Weight::from_parts(30_056_661, 6811) + // Standard Error: 792 + .saturating_add(Weight::from_parts(108_212, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. 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: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 13_452_000 picoseconds. - Weight::from_parts(14_425_869, 0) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(20_278_307, 3997) // Standard Error: 4 - .saturating_add(Weight::from_parts(493, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(488, 0).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) } - /// 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: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 46_012_000 picoseconds. - Weight::from_parts(34_797_344, 6811) - // Standard Error: 833 - .saturating_add(Weight::from_parts(127_671, 0).saturating_mul(s.into())) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(z.into())) + // Minimum execution time: 39_478_000 picoseconds. + Weight::from_parts(29_195_487, 6811) + // Standard Error: 739 + .saturating_add(Weight::from_parts(118_766, 0).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_511, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `320` // Estimated: `6811` - // Minimum execution time: 29_834_000 picoseconds. - Weight::from_parts(20_189_154, 6811) - // Standard Error: 637 - .saturating_add(Weight::from_parts(110_080, 0).saturating_mul(s.into())) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_483, 0).saturating_mul(z.into())) + // Minimum execution time: 26_401_000 picoseconds. + Weight::from_parts(17_277_296, 6811) + // Standard Error: 492 + .saturating_add(Weight::from_parts(101_763, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_486, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, 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: `426 + s * (33 ±0)` + // Measured: `571 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 51_464_000 picoseconds. - Weight::from_parts(39_246_644, 6811) - // Standard Error: 1_251 - .saturating_add(Weight::from_parts(143_313, 0).saturating_mul(s.into())) + // Minimum execution time: 52_430_000 picoseconds. + Weight::from_parts(40_585_478, 6811) + // Standard Error: 1_240 + .saturating_add(Weight::from_parts(161_405, 0).saturating_mul(s.into())) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(1_547, 0).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 33_275_000 picoseconds. - Weight::from_parts(34_073_221, 6811) - // Standard Error: 1_163 - .saturating_add(Weight::from_parts(124_815, 0).saturating_mul(s.into())) + // Minimum execution time: 27_797_000 picoseconds. + Weight::from_parts(29_064_584, 6811) + // Standard Error: 817 + .saturating_add(Weight::from_parts(108_179, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `320` // Estimated: `6811` - // Minimum execution time: 18_411_000 picoseconds. - Weight::from_parts(19_431_787, 6811) - // Standard Error: 694 - .saturating_add(Weight::from_parts(107_220, 0).saturating_mul(s.into())) + // Minimum execution time: 15_236_000 picoseconds. + Weight::from_parts(16_360_247, 6811) + // Standard Error: 584 + .saturating_add(Weight::from_parts(94_917, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `492 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 33_985_000 picoseconds. - Weight::from_parts(35_547_970, 6811) - // Standard Error: 1_135 - .saturating_add(Weight::from_parts(116_537, 0).saturating_mul(s.into())) + // Minimum execution time: 28_730_000 picoseconds. + Weight::from_parts(30_056_661, 6811) + // Standard Error: 792 + .saturating_add(Weight::from_parts(108_212, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index a55bcab533d8ee05476ac6fdc0520129e6525771..8002b7e1165f1648d5edd39486c996f4eabe2bc6 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/nft-fractionalization/src/mock.rs b/substrate/frame/nft-fractionalization/src/mock.rs index 40cce96d55073cd70f5368e575e12f3635bcdb24..a41386150091de0d77153593dfe6ce68a07cfe18 100644 --- a/substrate/frame/nft-fractionalization/src/mock.rs +++ b/substrate/frame/nft-fractionalization/src/mock.rs @@ -27,9 +27,8 @@ use frame_support::{ }; use frame_system::EnsureSigned; use pallet_nfts::PalletFeatures; -use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + traits::{IdentifyAccount, IdentityLookup, Verify}, BuildStorage, MultiSignature, }; @@ -52,29 +51,10 @@ construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/nft-fractionalization/src/weights.rs b/substrate/frame/nft-fractionalization/src/weights.rs index ebb4aa0fbcfba2df71b6b7ecb9368540ef8b9ffa..07872ebaea9083d9e9cf5326b5b93c1da7bcf9e3 100644 --- a/substrate/frame/nft-fractionalization/src/weights.rs +++ b/substrate/frame/nft-fractionalization/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_nft_fractionalization +//! Autogenerated weights for `pallet_nft_fractionalization` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/nft-fractionalization/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/nft-fractionalization/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,136 +49,136 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_nft_fractionalization. +/// Weight functions needed for `pallet_nft_fractionalization`. pub trait WeightInfo { fn fractionalize() -> Weight; fn unify() -> Weight; } -/// Weights for pallet_nft_fractionalization using the Substrate node and recommended hardware. +/// Weights for `pallet_nft_fractionalization` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); 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(85), added: 2560, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) - /// Storage: NftFractionalization NftToAsset (r:0 w:1) - /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// 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`) + /// 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::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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: `NftFractionalization::NftToAsset` (r:0 w:1) + /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn fractionalize() -> Weight { // Proof Size summary in bytes: // Measured: `609` // Estimated: `4326` - // Minimum execution time: 187_416_000 picoseconds. - Weight::from_parts(191_131_000, 4326) + // Minimum execution time: 164_764_000 picoseconds. + Weight::from_parts(168_243_000, 4326) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: NftFractionalization NftToAsset (r:1 w:1) - /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, 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: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// 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(85), added: 2560, 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) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `NftFractionalization::NftToAsset` (r:1 w:1) + /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, 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: `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: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// 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`) + /// 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) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn unify() -> Weight { // Proof Size summary in bytes: // Measured: `1422` // Estimated: `4326` - // Minimum execution time: 134_159_000 picoseconds. - Weight::from_parts(136_621_000, 4326) + // Minimum execution time: 120_036_000 picoseconds. + Weight::from_parts(123_550_000, 4326) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. 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(85), added: 2560, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Assets Metadata (r:1 w:1) - /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) - /// Storage: NftFractionalization NftToAsset (r:0 w:1) - /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// 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`) + /// 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::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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: `NftFractionalization::NftToAsset` (r:0 w:1) + /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn fractionalize() -> Weight { // Proof Size summary in bytes: // Measured: `609` // Estimated: `4326` - // Minimum execution time: 187_416_000 picoseconds. - Weight::from_parts(191_131_000, 4326) + // Minimum execution time: 164_764_000 picoseconds. + Weight::from_parts(168_243_000, 4326) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: NftFractionalization NftToAsset (r:1 w:1) - /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, 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: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// 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(85), added: 2560, 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) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `NftFractionalization::NftToAsset` (r:1 w:1) + /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, 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: `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: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// 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`) + /// 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) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn unify() -> Weight { // Proof Size summary in bytes: // Measured: `1422` // Estimated: `4326` - // Minimum execution time: 134_159_000 picoseconds. - Weight::from_parts(136_621_000, 4326) + // Minimum execution time: 120_036_000 picoseconds. + Weight::from_parts(123_550_000, 4326) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index d92a9c0b44ed00ed127808a011586e162b1e473e..69e9ea170b14c97ef81a9a5a4fa8ae855cce94d2 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } enumflags2 = { version = "0.7.7" } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/nfts/src/lib.rs b/substrate/frame/nfts/src/lib.rs index a7d505e2e397dbca5f547ed9ed1a7c3cc4235aa5..615720268fed611bbf7effa1f4b71eca0df4a7e7 100644 --- a/substrate/frame/nfts/src/lib.rs +++ b/substrate/frame/nfts/src/lib.rs @@ -76,7 +76,7 @@ pub mod pallet { use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] @@ -874,8 +874,8 @@ pub mod pallet { ), ); Self::deposit_event(Event::PalletAttributeSet { - collection, - item: Some(item), + collection: collection_id, + item: Some(owned_item), attribute: pallet_attribute, value: attribute_value, }); diff --git a/substrate/frame/nfts/src/migration.rs b/substrate/frame/nfts/src/migration.rs index d4cdf7e820d15b7df1d8f36807baf34b81c34bd3..8f82e092262fb2d63cf1dda563afb0dd11c6f6ac 100644 --- a/substrate/frame/nfts/src/migration.rs +++ b/substrate/frame/nfts/src/migration.rs @@ -54,17 +54,17 @@ pub mod v1 { pub struct MigrateToV1(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { - let current_version = Pallet::::current_storage_version(); - let onchain_version = Pallet::::on_chain_storage_version(); + let in_code_version = Pallet::::in_code_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); log::info!( target: LOG_TARGET, - "Running migration with current storage version {:?} / onchain {:?}", - current_version, - onchain_version + "Running migration with in-code storage version {:?} / onchain {:?}", + in_code_version, + on_chain_version ); - if onchain_version == 0 && current_version == 1 { + if on_chain_version == 0 && in_code_version == 1 { let mut translated = 0u64; let mut configs_iterated = 0u64; Collection::::translate::< @@ -77,13 +77,13 @@ pub mod v1 { Some(old_value.migrate_to_v1(item_configs)) }); - current_version.put::>(); + in_code_version.put::>(); log::info!( target: LOG_TARGET, "Upgraded {} records, storage to version {:?}", translated, - current_version + in_code_version ); T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1) } else { diff --git a/substrate/frame/nfts/src/mock.rs b/substrate/frame/nfts/src/mock.rs index ac6d0d757325d25981910354b58374a24838f3f5..e86fafd07e965ab995a04e512bd9794833735d4e 100644 --- a/substrate/frame/nfts/src/mock.rs +++ b/substrate/frame/nfts/src/mock.rs @@ -24,10 +24,9 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; -use sp_core::H256; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ - traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + traits::{IdentifyAccount, IdentityLookup, Verify}, BuildStorage, MultiSignature, }; @@ -48,29 +47,10 @@ pub type AccountId = ::AccountId; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/nfts/src/tests.rs b/substrate/frame/nfts/src/tests.rs index 9e521537534fab31c4626c21ecf06e3df366c01b..6bf9427f4e6cda9ef2eecaf9abed2721e7127ecf 100644 --- a/substrate/frame/nfts/src/tests.rs +++ b/substrate/frame/nfts/src/tests.rs @@ -440,6 +440,12 @@ fn mint_should_work() { account(2), Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); + assert!(events().contains(&Event::::PalletAttributeSet { + collection: 0, + item: Some(43), + attribute: PalletAttributes::<::CollectionId>::UsedToClaim(1), + value: Nfts::construct_attribute_value(vec![]).unwrap(), + })); // can't mint twice assert_noop!( diff --git a/substrate/frame/nfts/src/weights.rs b/substrate/frame/nfts/src/weights.rs index 6b8c577bb12e5d19bf5751d2a5019d60aea743b0..4fcc1e601f4116b75c4f86d7a19e41043f891876 100644 --- a/substrate/frame/nfts/src/weights.rs +++ b/substrate/frame/nfts/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_nfts +//! Autogenerated weights for `pallet_nfts` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -37,9 +37,9 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/nfts/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/nfts/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_nfts. +/// Weight functions needed for `pallet_nfts`. pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; @@ -92,564 +92,568 @@ pub trait WeightInfo { fn set_attributes_pre_signed(n: u32, ) -> Weight; } -/// Weights for pallet_nfts using the Substrate node and recommended hardware. +/// Weights for `pallet_nfts` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Nfts NextCollectionId (r:1 w:1) - /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:1) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::NextCollectionId` (r:1 w:1) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3549` - // Minimum execution time: 40_489_000 picoseconds. - Weight::from_parts(41_320_000, 3549) + // Minimum execution time: 34_035_000 picoseconds. + Weight::from_parts(35_228_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Nfts NextCollectionId (r:1 w:1) - /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:1) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::NextCollectionId` (r:1 w:1) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3549` - // Minimum execution time: 23_257_000 picoseconds. - Weight::from_parts(23_770_000, 3549) + // Minimum execution time: 19_430_000 picoseconds. + Weight::from_parts(20_054_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:0) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1001 w:1000) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1000 w:1000) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts CollectionMetadataOf (r:0 w:1) - /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:1) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1001 w:1000) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// 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 { // Proof Size summary in bytes: - // Measured: `32220 + a * (332 ±0)` - // Estimated: `2523990 + a * (2921 ±0)` - // Minimum execution time: 1_310_198_000 picoseconds. - Weight::from_parts(1_479_261_043, 2523990) - // Standard Error: 4_415 - .saturating_add(Weight::from_parts(6_016_212, 0).saturating_mul(a.into())) + // Measured: `32204 + a * (366 ±0)` + // Estimated: `2523990 + a * (2954 ±0)` + // Minimum execution time: 1_249_733_000 picoseconds. + Weight::from_parts(1_293_703_849, 2523990) + // Standard Error: 4_764 + .saturating_add(Weight::from_parts(6_433_523, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) - } - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:1) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(a.into())) + } + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 51_910_000 picoseconds. - Weight::from_parts(53_441_000, 4326) + // Minimum execution time: 48_645_000 picoseconds. + Weight::from_parts(50_287_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, 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::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 50_168_000 picoseconds. - Weight::from_parts(51_380_000, 4326) + // Minimum execution time: 46_688_000 picoseconds. + Weight::from_parts(47_680_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:0) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, 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) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, 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) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `564` // Estimated: `4326` - // Minimum execution time: 50_738_000 picoseconds. - Weight::from_parts(51_850_000, 4326) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Minimum execution time: 51_771_000 picoseconds. + Weight::from_parts(53_492_000, 4326) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:0) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:2) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:0 w:1) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:2) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `593` // Estimated: `4326` - // Minimum execution time: 41_055_000 picoseconds. - Weight::from_parts(42_336_000, 4326) + // Minimum execution time: 39_166_000 picoseconds. + Weight::from_parts(40_128_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:5000 w:5000) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:5000 w:5000) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `763 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 15_688_000 picoseconds. - Weight::from_parts(15_921_000, 3549) - // Standard Error: 14_827 - .saturating_add(Weight::from_parts(17_105_395, 0).saturating_mul(i.into())) + // Minimum execution time: 13_804_000 picoseconds. + Weight::from_parts(14_159_000, 3549) + // Standard Error: 13_812 + .saturating_add(Weight::from_parts(14_661_284, 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()))) .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 19_981_000 picoseconds. - Weight::from_parts(20_676_000, 3534) + // Minimum execution time: 17_485_000 picoseconds. + Weight::from_parts(18_412_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 19_911_000 picoseconds. - Weight::from_parts(20_612_000, 3534) + // Minimum execution time: 17_335_000 picoseconds. + Weight::from_parts(18_543_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 16_441_000 picoseconds. - Weight::from_parts(16_890_000, 3549) + // Minimum execution time: 14_608_000 picoseconds. + Weight::from_parts(15_696_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts OwnershipAcceptance (r:1 w:1) - /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:2) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:2) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `3549` - // Minimum execution time: 22_610_000 picoseconds. - Weight::from_parts(23_422_000, 3549) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Measured: `562` + // Estimated: `3593` + // Minimum execution time: 25_686_000 picoseconds. + Weight::from_parts(26_433_000, 3593) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:2 w:4) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `369` // Estimated: `6078` - // Minimum execution time: 39_739_000 picoseconds. - Weight::from_parts(41_306_000, 6078) + // Minimum execution time: 37_192_000 picoseconds. + Weight::from_parts(38_561_000, 6078) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:2) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:2) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: // Measured: `311` // Estimated: `3549` - // Minimum execution time: 17_685_000 picoseconds. - Weight::from_parts(18_258_000, 3549) + // Minimum execution time: 15_401_000 picoseconds. + Weight::from_parts(15_826_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `276` // Estimated: `3549` - // Minimum execution time: 13_734_000 picoseconds. - Weight::from_parts(14_337_000, 3549) + // Minimum execution time: 11_683_000 picoseconds. + Weight::from_parts(12_255_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 19_269_000 picoseconds. - Weight::from_parts(19_859_000, 3534) + // Minimum execution time: 16_899_000 picoseconds. + Weight::from_parts(17_404_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3911` - // Minimum execution time: 51_540_000 picoseconds. - Weight::from_parts(52_663_000, 3911) + // Estimated: `3944` + // Minimum execution time: 46_768_000 picoseconds. + Weight::from_parts(47_834_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `344` - // Estimated: `3911` - // Minimum execution time: 26_529_000 picoseconds. - Weight::from_parts(27_305_000, 3911) + // Estimated: `3944` + // Minimum execution time: 23_356_000 picoseconds. + Weight::from_parts(24_528_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, 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::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `950` - // Estimated: `3911` - // Minimum execution time: 46_951_000 picoseconds. - Weight::from_parts(48_481_000, 3911) + // Measured: `983` + // Estimated: `3944` + // Minimum execution time: 43_061_000 picoseconds. + Weight::from_parts(44_024_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `381` // Estimated: `4326` - // Minimum execution time: 17_222_000 picoseconds. - Weight::from_parts(17_819_000, 4326) + // Minimum execution time: 14_929_000 picoseconds. + Weight::from_parts(15_344_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1001 w:1000) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1001 w:1000) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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 `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837 + n * (364 ±0)` - // Estimated: `4326 + n * (2921 ±0)` - // Minimum execution time: 26_185_000 picoseconds. - Weight::from_parts(27_038_000, 4326) - // Standard Error: 2_378 - .saturating_add(Weight::from_parts(6_067_888, 0).saturating_mul(n.into())) + // Measured: `831 + n * (398 ±0)` + // Estimated: `4326 + n * (2954 ±0)` + // Minimum execution time: 23_707_000 picoseconds. + Weight::from_parts(24_688_000, 4326) + // Standard Error: 3_813 + .saturating_add(Weight::from_parts(6_422_256, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) - } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:1) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3605` - // Minimum execution time: 42_120_000 picoseconds. - Weight::from_parts(43_627_000, 3605) + // Estimated: `3812` + // Minimum execution time: 37_882_000 picoseconds. + Weight::from_parts(39_222_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:1) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `642` - // Estimated: `3605` - // Minimum execution time: 40_732_000 picoseconds. - Weight::from_parts(42_760_000, 3605) + // Measured: `849` + // Estimated: `3812` + // Minimum execution time: 36_629_000 picoseconds. + Weight::from_parts(37_351_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionMetadataOf (r:1 w:1) - /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `398` - // Estimated: `3552` - // Minimum execution time: 39_443_000 picoseconds. - Weight::from_parts(40_482_000, 3552) + // Estimated: `3759` + // Minimum execution time: 34_853_000 picoseconds. + Weight::from_parts(35_914_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionMetadataOf (r:1 w:1) - /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `509` - // Estimated: `3552` - // Minimum execution time: 37_676_000 picoseconds. - Weight::from_parts(39_527_000, 3552) + // Measured: `716` + // Estimated: `3759` + // Minimum execution time: 33_759_000 picoseconds. + Weight::from_parts(34_729_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `410` // Estimated: `4326` - // Minimum execution time: 20_787_000 picoseconds. - Weight::from_parts(21_315_000, 4326) + // Minimum execution time: 17_583_000 picoseconds. + Weight::from_parts(18_675_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 18_200_000 picoseconds. - Weight::from_parts(19_064_000, 4326) + // Minimum execution time: 15_036_000 picoseconds. + Weight::from_parts(15_995_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 17_128_000 picoseconds. - Weight::from_parts(17_952_000, 4326) + // Minimum execution time: 14_666_000 picoseconds. + Weight::from_parts(15_152_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts OwnershipAcceptance (r:1 w:1) - /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3517` - // Minimum execution time: 14_667_000 picoseconds. - Weight::from_parts(15_262_000, 3517) + // Minimum execution time: 12_393_000 picoseconds. + Weight::from_parts(12_895_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionConfigOf (r:1 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 18_435_000 picoseconds. - Weight::from_parts(18_775_000, 3549) + // Minimum execution time: 16_034_000 picoseconds. + Weight::from_parts(16_617_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: // Measured: `323` // Estimated: `3538` - // Minimum execution time: 18_125_000 picoseconds. - Weight::from_parts(18_415_000, 3538) + // Minimum execution time: 15_812_000 picoseconds. + Weight::from_parts(16_644_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:0 w:1) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `518` // Estimated: `4326` - // Minimum execution time: 23_237_000 picoseconds. - Weight::from_parts(24_128_000, 4326) + // Minimum execution time: 21_650_000 picoseconds. + Weight::from_parts(22_443_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:1 w:1) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:0) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:2) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:2) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `705` // Estimated: `4326` - // Minimum execution time: 53_291_000 picoseconds. - Weight::from_parts(54_614_000, 4326) + // Minimum execution time: 49_463_000 picoseconds. + Weight::from_parts(50_937_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -658,681 +662,685 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_192_000 picoseconds. - Weight::from_parts(4_039_901, 0) - // Standard Error: 10_309 - .saturating_add(Weight::from_parts(3_934_017, 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) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + // Minimum execution time: 2_029_000 picoseconds. + Weight::from_parts(3_749_829, 0) + // Standard Error: 8_497 + .saturating_add(Weight::from_parts(1_913_514, 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`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn create_swap() -> Weight { // Proof Size summary in bytes: // Measured: `494` // Estimated: `7662` - // Minimum execution time: 21_011_000 picoseconds. - Weight::from_parts(22_065_000, 7662) + // Minimum execution time: 18_181_000 picoseconds. + Weight::from_parts(18_698_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts PendingSwapOf (r:1 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::PendingSwapOf` (r:1 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `513` // Estimated: `4326` - // Minimum execution time: 21_423_000 picoseconds. - Weight::from_parts(21_743_000, 4326) + // Minimum execution time: 18_228_000 picoseconds. + Weight::from_parts(18_940_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:2 w:2) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:1 w:2) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:2 w:0) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:2 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:4) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:0 w:2) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:2 w:2) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:2 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:4) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: // Measured: `834` // Estimated: `7662` - // Minimum execution time: 86_059_000 picoseconds. - Weight::from_parts(88_401_000, 7662) + // Minimum execution time: 77_983_000 picoseconds. + Weight::from_parts(79_887_000, 7662) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } - /// Storage: Nfts CollectionRoleOf (r:2 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:10 w:10) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:1) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, 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::CollectionRoleOf` (r:2 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `629` - // Estimated: `6078 + n * (2921 ±0)` - // Minimum execution time: 146_746_000 picoseconds. - Weight::from_parts(152_885_862, 6078) - // Standard Error: 40_442 - .saturating_add(Weight::from_parts(32_887_800, 0).saturating_mul(n.into())) + // Estimated: `6078 + n * (2954 ±0)` + // Minimum execution time: 126_998_000 picoseconds. + Weight::from_parts(134_149_389, 6078) + // Standard Error: 33_180 + .saturating_add(Weight::from_parts(30_711_206, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) - } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:10 w:10) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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 `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `659` - // Estimated: `4326 + n * (2921 ±0)` - // Minimum execution time: 83_960_000 picoseconds. - Weight::from_parts(98_609_885, 4326) - // Standard Error: 85_991 - .saturating_add(Weight::from_parts(32_633_495, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2954 ±0)` + // Minimum execution time: 66_213_000 picoseconds. + Weight::from_parts(81_661_819, 4326) + // Standard Error: 87_003 + .saturating_add(Weight::from_parts(29_550_476, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Nfts NextCollectionId (r:1 w:1) - /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:1) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::NextCollectionId` (r:1 w:1) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3549` - // Minimum execution time: 40_489_000 picoseconds. - Weight::from_parts(41_320_000, 3549) + // Minimum execution time: 34_035_000 picoseconds. + Weight::from_parts(35_228_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Nfts NextCollectionId (r:1 w:1) - /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:1) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::NextCollectionId` (r:1 w:1) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3549` - // Minimum execution time: 23_257_000 picoseconds. - Weight::from_parts(23_770_000, 3549) + // Minimum execution time: 19_430_000 picoseconds. + Weight::from_parts(20_054_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:0) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1001 w:1000) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1000 w:1000) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts CollectionMetadataOf (r:0 w:1) - /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:1) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1001 w:1000) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// 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 { // Proof Size summary in bytes: - // Measured: `32220 + a * (332 ±0)` - // Estimated: `2523990 + a * (2921 ±0)` - // Minimum execution time: 1_310_198_000 picoseconds. - Weight::from_parts(1_479_261_043, 2523990) - // Standard Error: 4_415 - .saturating_add(Weight::from_parts(6_016_212, 0).saturating_mul(a.into())) + // Measured: `32204 + a * (366 ±0)` + // Estimated: `2523990 + a * (2954 ±0)` + // Minimum execution time: 1_249_733_000 picoseconds. + Weight::from_parts(1_293_703_849, 2523990) + // Standard Error: 4_764 + .saturating_add(Weight::from_parts(6_433_523, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) - } - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:1) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(a.into())) + } + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 51_910_000 picoseconds. - Weight::from_parts(53_441_000, 4326) + // Minimum execution time: 48_645_000 picoseconds. + Weight::from_parts(50_287_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, 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::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 50_168_000 picoseconds. - Weight::from_parts(51_380_000, 4326) + // Minimum execution time: 46_688_000 picoseconds. + Weight::from_parts(47_680_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:0) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, 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) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, 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) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `564` // Estimated: `4326` - // Minimum execution time: 50_738_000 picoseconds. - Weight::from_parts(51_850_000, 4326) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Minimum execution time: 51_771_000 picoseconds. + Weight::from_parts(53_492_000, 4326) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:0) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:2) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:0 w:1) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:2) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `593` // Estimated: `4326` - // Minimum execution time: 41_055_000 picoseconds. - Weight::from_parts(42_336_000, 4326) + // Minimum execution time: 39_166_000 picoseconds. + Weight::from_parts(40_128_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:5000 w:5000) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:5000 w:5000) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `763 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 15_688_000 picoseconds. - Weight::from_parts(15_921_000, 3549) - // Standard Error: 14_827 - .saturating_add(Weight::from_parts(17_105_395, 0).saturating_mul(i.into())) + // Minimum execution time: 13_804_000 picoseconds. + Weight::from_parts(14_159_000, 3549) + // Standard Error: 13_812 + .saturating_add(Weight::from_parts(14_661_284, 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()))) .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 19_981_000 picoseconds. - Weight::from_parts(20_676_000, 3534) + // Minimum execution time: 17_485_000 picoseconds. + Weight::from_parts(18_412_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 19_911_000 picoseconds. - Weight::from_parts(20_612_000, 3534) + // Minimum execution time: 17_335_000 picoseconds. + Weight::from_parts(18_543_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 16_441_000 picoseconds. - Weight::from_parts(16_890_000, 3549) + // Minimum execution time: 14_608_000 picoseconds. + Weight::from_parts(15_696_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts OwnershipAcceptance (r:1 w:1) - /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:2) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:2) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `3549` - // Minimum execution time: 22_610_000 picoseconds. - Weight::from_parts(23_422_000, 3549) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Measured: `562` + // Estimated: `3593` + // Minimum execution time: 25_686_000 picoseconds. + Weight::from_parts(26_433_000, 3593) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:2 w:4) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `369` // Estimated: `6078` - // Minimum execution time: 39_739_000 picoseconds. - Weight::from_parts(41_306_000, 6078) + // Minimum execution time: 37_192_000 picoseconds. + Weight::from_parts(38_561_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionAccount (r:0 w:2) - /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:2) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: // Measured: `311` // Estimated: `3549` - // Minimum execution time: 17_685_000 picoseconds. - Weight::from_parts(18_258_000, 3549) + // Minimum execution time: 15_401_000 picoseconds. + Weight::from_parts(15_826_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:0 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `276` // Estimated: `3549` - // Minimum execution time: 13_734_000 picoseconds. - Weight::from_parts(14_337_000, 3549) + // Minimum execution time: 11_683_000 picoseconds. + Weight::from_parts(12_255_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 19_269_000 picoseconds. - Weight::from_parts(19_859_000, 3534) + // Minimum execution time: 16_899_000 picoseconds. + Weight::from_parts(17_404_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3911` - // Minimum execution time: 51_540_000 picoseconds. - Weight::from_parts(52_663_000, 3911) + // Estimated: `3944` + // Minimum execution time: 46_768_000 picoseconds. + Weight::from_parts(47_834_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `344` - // Estimated: `3911` - // Minimum execution time: 26_529_000 picoseconds. - Weight::from_parts(27_305_000, 3911) + // Estimated: `3944` + // Minimum execution time: 23_356_000 picoseconds. + Weight::from_parts(24_528_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Nfts Attribute (r:1 w:1) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, 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::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `950` - // Estimated: `3911` - // Minimum execution time: 46_951_000 picoseconds. - Weight::from_parts(48_481_000, 3911) + // Measured: `983` + // Estimated: `3944` + // Minimum execution time: 43_061_000 picoseconds. + Weight::from_parts(44_024_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `381` // Estimated: `4326` - // Minimum execution time: 17_222_000 picoseconds. - Weight::from_parts(17_819_000, 4326) + // Minimum execution time: 14_929_000 picoseconds. + Weight::from_parts(15_344_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1001 w:1000) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1001 w:1000) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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 `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837 + n * (364 ±0)` - // Estimated: `4326 + n * (2921 ±0)` - // Minimum execution time: 26_185_000 picoseconds. - Weight::from_parts(27_038_000, 4326) - // Standard Error: 2_378 - .saturating_add(Weight::from_parts(6_067_888, 0).saturating_mul(n.into())) + // Measured: `831 + n * (398 ±0)` + // Estimated: `4326 + n * (2954 ±0)` + // Minimum execution time: 23_707_000 picoseconds. + Weight::from_parts(24_688_000, 4326) + // Standard Error: 3_813 + .saturating_add(Weight::from_parts(6_422_256, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) - } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:1) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3605` - // Minimum execution time: 42_120_000 picoseconds. - Weight::from_parts(43_627_000, 3605) + // Estimated: `3812` + // Minimum execution time: 37_882_000 picoseconds. + Weight::from_parts(39_222_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:1) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `642` - // Estimated: `3605` - // Minimum execution time: 40_732_000 picoseconds. - Weight::from_parts(42_760_000, 3605) + // Measured: `849` + // Estimated: `3812` + // Minimum execution time: 36_629_000 picoseconds. + Weight::from_parts(37_351_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionMetadataOf (r:1 w:1) - /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `398` - // Estimated: `3552` - // Minimum execution time: 39_443_000 picoseconds. - Weight::from_parts(40_482_000, 3552) + // Estimated: `3759` + // Minimum execution time: 34_853_000 picoseconds. + Weight::from_parts(35_914_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionMetadataOf (r:1 w:1) - /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `509` - // Estimated: `3552` - // Minimum execution time: 37_676_000 picoseconds. - Weight::from_parts(39_527_000, 3552) + // Measured: `716` + // Estimated: `3759` + // Minimum execution time: 33_759_000 picoseconds. + Weight::from_parts(34_729_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `410` // Estimated: `4326` - // Minimum execution time: 20_787_000 picoseconds. - Weight::from_parts(21_315_000, 4326) + // Minimum execution time: 17_583_000 picoseconds. + Weight::from_parts(18_675_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 18_200_000 picoseconds. - Weight::from_parts(19_064_000, 4326) + // Minimum execution time: 15_036_000 picoseconds. + Weight::from_parts(15_995_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 17_128_000 picoseconds. - Weight::from_parts(17_952_000, 4326) + // Minimum execution time: 14_666_000 picoseconds. + Weight::from_parts(15_152_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts OwnershipAcceptance (r:1 w:1) - /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3517` - // Minimum execution time: 14_667_000 picoseconds. - Weight::from_parts(15_262_000, 3517) + // Minimum execution time: 12_393_000 picoseconds. + Weight::from_parts(12_895_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionConfigOf (r:1 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 18_435_000 picoseconds. - Weight::from_parts(18_775_000, 3549) + // Minimum execution time: 16_034_000 picoseconds. + Weight::from_parts(16_617_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:1) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: // Measured: `323` // Estimated: `3538` - // Minimum execution time: 18_125_000 picoseconds. - Weight::from_parts(18_415_000, 3538) + // Minimum execution time: 15_812_000 picoseconds. + Weight::from_parts(16_644_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:0 w:1) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `518` // Estimated: `4326` - // Minimum execution time: 23_237_000 picoseconds. - Weight::from_parts(24_128_000, 4326) + // Minimum execution time: 21_650_000 picoseconds. + Weight::from_parts(22_443_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:1 w:1) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1 w:0) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:2) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:2) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `705` // Estimated: `4326` - // Minimum execution time: 53_291_000 picoseconds. - Weight::from_parts(54_614_000, 4326) + // Minimum execution time: 49_463_000 picoseconds. + Weight::from_parts(50_937_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1341,120 +1349,120 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_192_000 picoseconds. - Weight::from_parts(4_039_901, 0) - // Standard Error: 10_309 - .saturating_add(Weight::from_parts(3_934_017, 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) - /// Storage: Nfts PendingSwapOf (r:0 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + // Minimum execution time: 2_029_000 picoseconds. + Weight::from_parts(3_749_829, 0) + // Standard Error: 8_497 + .saturating_add(Weight::from_parts(1_913_514, 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`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn create_swap() -> Weight { // Proof Size summary in bytes: // Measured: `494` // Estimated: `7662` - // Minimum execution time: 21_011_000 picoseconds. - Weight::from_parts(22_065_000, 7662) + // Minimum execution time: 18_181_000 picoseconds. + Weight::from_parts(18_698_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts PendingSwapOf (r:1 w:1) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: `Nfts::PendingSwapOf` (r:1 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `513` // Estimated: `4326` - // Minimum execution time: 21_423_000 picoseconds. - Weight::from_parts(21_743_000, 4326) + // Minimum execution time: 18_228_000 picoseconds. + Weight::from_parts(18_940_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Item (r:2 w:2) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts PendingSwapOf (r:1 w:2) - /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:2 w:0) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:2 w:0) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:4) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Nfts ItemPriceOf (r:0 w:2) - /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: `Nfts::Item` (r:2 w:2) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:2 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:4) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: // Measured: `834` // Estimated: `7662` - // Minimum execution time: 86_059_000 picoseconds. - Weight::from_parts(88_401_000, 7662) + // Minimum execution time: 77_983_000 picoseconds. + Weight::from_parts(79_887_000, 7662) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } - /// Storage: Nfts CollectionRoleOf (r:2 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1 w:1) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:1 w:1) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:10 w:10) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1 w:1) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, 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::CollectionRoleOf` (r:2 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `629` - // Estimated: `6078 + n * (2921 ±0)` - // Minimum execution time: 146_746_000 picoseconds. - Weight::from_parts(152_885_862, 6078) - // Standard Error: 40_442 - .saturating_add(Weight::from_parts(32_887_800, 0).saturating_mul(n.into())) + // Estimated: `6078 + n * (2954 ±0)` + // Minimum execution time: 126_998_000 picoseconds. + Weight::from_parts(134_149_389, 6078) + // Standard Error: 33_180 + .saturating_add(Weight::from_parts(30_711_206, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) - } - /// Storage: Nfts Item (r:1 w:0) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts CollectionConfigOf (r:1 w:0) - /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:10 w:10) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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 `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `659` - // Estimated: `4326 + n * (2921 ±0)` - // Minimum execution time: 83_960_000 picoseconds. - Weight::from_parts(98_609_885, 4326) - // Standard Error: 85_991 - .saturating_add(Weight::from_parts(32_633_495, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2954 ±0)` + // Minimum execution time: 66_213_000 picoseconds. + Weight::from_parts(81_661_819, 4326) + // Standard Error: 87_003 + .saturating_add(Weight::from_parts(29_550_476, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } } diff --git a/substrate/frame/nis/src/mock.rs b/substrate/frame/nis/src/mock.rs index 98b653635caf23b0225df697b8c7629f49447623..03976bc66c4df6844c81232fef7f912cb02b5292 100644 --- a/substrate/frame/nis/src/mock.rs +++ b/substrate/frame/nis/src/mock.rs @@ -21,19 +21,13 @@ use crate::{self as pallet_nis, Perquintill, WithMaximumOf}; use frame_support::{ derive_impl, ord_parameter_types, parameter_types, - traits::{ - fungible::Inspect, ConstU16, ConstU32, ConstU64, Everything, OnFinalize, OnInitialize, - StorageMapShim, - }, + traits::{fungible::Inspect, ConstU32, ConstU64, OnFinalize, OnInitialize, StorageMapShim}, weights::Weight, PalletId, }; use pallet_balances::{Instance1, Instance2}; -use sp_core::{ConstU128, H256}; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_core::ConstU128; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -52,29 +46,8 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/nis/src/weights.rs b/substrate/frame/nis/src/weights.rs index cba2f0049055b8f3e69aeba7d7d572ba19030801..6390827139119eaa2e98192313b7702766d0ccd1 100644 --- a/substrate/frame/nis/src/weights.rs +++ b/substrate/frame/nis/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_nis +//! Autogenerated weights for `pallet_nis` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/nis/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/nis/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_nis. +/// Weight functions needed for `pallet_nis`. pub trait WeightInfo { fn place_bid(l: u32, ) -> Weight; fn place_bid_max() -> Weight; @@ -65,367 +64,367 @@ pub trait WeightInfo { fn process_bid() -> Weight; } -/// Weights for pallet_nis using the Substrate node and recommended hardware. +/// Weights for `pallet_nis` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); 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(85), added: 2560, 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(193), added: 2668, 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: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 49_410_000 picoseconds. - Weight::from_parts(57_832_282, 51487) - // Standard Error: 288 - .saturating_add(Weight::from_parts(51_621, 0).saturating_mul(l.into())) + // Minimum execution time: 47_908_000 picoseconds. + Weight::from_parts(50_096_676, 51487) + // Standard Error: 208 + .saturating_add(Weight::from_parts(41_318, 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(85), added: 2560, 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(193), added: 2668, 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: `54178` // Estimated: `51487` - // Minimum execution time: 119_696_000 picoseconds. - Weight::from_parts(121_838_000, 51487) + // Minimum execution time: 100_836_000 picoseconds. + Weight::from_parts(102_497_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(85), added: 2560, 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(193), added: 2668, 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: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 50_843_000 picoseconds. - Weight::from_parts(54_237_365, 51487) - // Standard Error: 243 - .saturating_add(Weight::from_parts(67_732, 0).saturating_mul(l.into())) + // Minimum execution time: 45_830_000 picoseconds. + Weight::from_parts(46_667_676, 51487) + // Standard Error: 130 + .saturating_add(Weight::from_parts(33_007, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// 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) + /// 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: `191` // Estimated: `3593` - // Minimum execution time: 40_752_000 picoseconds. - Weight::from_parts(41_899_000, 3593) + // Minimum execution time: 30_440_000 picoseconds. + Weight::from_parts(31_240_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(85), added: 2560, 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: 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: `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`) + /// 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: `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`) fn communify() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `3675` - // Minimum execution time: 79_779_000 picoseconds. - Weight::from_parts(82_478_000, 3675) + // Minimum execution time: 71_017_000 picoseconds. + Weight::from_parts(72_504_000, 3675) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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: 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: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, 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: `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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn privatize() -> Weight { // Proof Size summary in bytes: // Measured: `829` // Estimated: `3675` - // Minimum execution time: 99_588_000 picoseconds. - Weight::from_parts(102_340_000, 3675) + // Minimum execution time: 89_138_000 picoseconds. + Weight::from_parts(91_290_000, 3675) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// 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(85), added: 2560, 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(193), added: 2668, mode: `MaxEncodedLen`) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `354` - // Estimated: `3593` - // Minimum execution time: 53_094_000 picoseconds. - Weight::from_parts(54_543_000, 3593) + // Estimated: `3658` + // Minimum execution time: 47_917_000 picoseconds. + Weight::from_parts(49_121_000, 3658) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// 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: 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: 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: `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: `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: `773` // Estimated: `3675` - // Minimum execution time: 107_248_000 picoseconds. - Weight::from_parts(109_923_000, 3675) + // Minimum execution time: 91_320_000 picoseconds. + Weight::from_parts(93_080_000, 3675) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// 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) + /// 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: `6624` // Estimated: `7487` - // Minimum execution time: 27_169_000 picoseconds. - Weight::from_parts(29_201_000, 7487) + // Minimum execution time: 20_117_000 picoseconds. + Weight::from_parts(20_829_000, 7487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `42` // Estimated: `51487` - // Minimum execution time: 4_540_000 picoseconds. - Weight::from_parts(4_699_000, 51487) + // Minimum execution time: 4_460_000 picoseconds. + Weight::from_parts(4_797_000, 51487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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_085_000 picoseconds. - Weight::from_parts(7_336_000, 0) + // Minimum execution time: 4_609_000 picoseconds. + Weight::from_parts(4_834_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. 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(85), added: 2560, 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(193), added: 2668, 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: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 49_410_000 picoseconds. - Weight::from_parts(57_832_282, 51487) - // Standard Error: 288 - .saturating_add(Weight::from_parts(51_621, 0).saturating_mul(l.into())) + // Minimum execution time: 47_908_000 picoseconds. + Weight::from_parts(50_096_676, 51487) + // Standard Error: 208 + .saturating_add(Weight::from_parts(41_318, 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(85), added: 2560, 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(193), added: 2668, 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: `54178` // Estimated: `51487` - // Minimum execution time: 119_696_000 picoseconds. - Weight::from_parts(121_838_000, 51487) + // Minimum execution time: 100_836_000 picoseconds. + Weight::from_parts(102_497_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(85), added: 2560, 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(193), added: 2668, 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: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 50_843_000 picoseconds. - Weight::from_parts(54_237_365, 51487) - // Standard Error: 243 - .saturating_add(Weight::from_parts(67_732, 0).saturating_mul(l.into())) + // Minimum execution time: 45_830_000 picoseconds. + Weight::from_parts(46_667_676, 51487) + // Standard Error: 130 + .saturating_add(Weight::from_parts(33_007, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// 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) + /// 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: `191` // Estimated: `3593` - // Minimum execution time: 40_752_000 picoseconds. - Weight::from_parts(41_899_000, 3593) + // Minimum execution time: 30_440_000 picoseconds. + Weight::from_parts(31_240_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(85), added: 2560, 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: 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: `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`) + /// 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: `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`) fn communify() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `3675` - // Minimum execution time: 79_779_000 picoseconds. - Weight::from_parts(82_478_000, 3675) + // Minimum execution time: 71_017_000 picoseconds. + Weight::from_parts(72_504_000, 3675) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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: 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: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, 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: `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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn privatize() -> Weight { // Proof Size summary in bytes: // Measured: `829` // Estimated: `3675` - // Minimum execution time: 99_588_000 picoseconds. - Weight::from_parts(102_340_000, 3675) + // Minimum execution time: 89_138_000 picoseconds. + Weight::from_parts(91_290_000, 3675) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// 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(85), added: 2560, 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(193), added: 2668, mode: `MaxEncodedLen`) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `354` - // Estimated: `3593` - // Minimum execution time: 53_094_000 picoseconds. - Weight::from_parts(54_543_000, 3593) + // Estimated: `3658` + // Minimum execution time: 47_917_000 picoseconds. + Weight::from_parts(49_121_000, 3658) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// 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: 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: 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: `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: `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: `773` // Estimated: `3675` - // Minimum execution time: 107_248_000 picoseconds. - Weight::from_parts(109_923_000, 3675) + // Minimum execution time: 91_320_000 picoseconds. + Weight::from_parts(93_080_000, 3675) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// 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) + /// 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: `6624` // Estimated: `7487` - // Minimum execution time: 27_169_000 picoseconds. - Weight::from_parts(29_201_000, 7487) + // Minimum execution time: 20_117_000 picoseconds. + Weight::from_parts(20_829_000, 7487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `42` // Estimated: `51487` - // Minimum execution time: 4_540_000 picoseconds. - Weight::from_parts(4_699_000, 51487) + // Minimum execution time: 4_460_000 picoseconds. + Weight::from_parts(4_797_000, 51487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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_085_000 picoseconds. - Weight::from_parts(7_336_000, 0) + // Minimum execution time: 4_609_000 picoseconds. + Weight::from_parts(4_834_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index ac139853cdbd322c7aaba6743077186ebaf4ebc0..a39b0ec4eff8b7fce397866acc7be3a8b812c827 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/node-authorization/src/mock.rs b/substrate/frame/node-authorization/src/mock.rs index bd648de2b243c781c6db8c7e9375add8ee07dcf4..84ca4d7eff701118e8ec4d140d164e709cc1c8f6 100644 --- a/substrate/frame/node-authorization/src/mock.rs +++ b/substrate/frame/node-authorization/src/mock.rs @@ -20,16 +20,9 @@ use super::*; use crate as pallet_node_authorization; -use frame_support::{ - derive_impl, ord_parameter_types, - traits::{ConstU32, ConstU64}, -}; +use frame_support::{derive_impl, ord_parameter_types, traits::ConstU32}; use frame_system::EnsureSignedBy; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -43,29 +36,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type DbWeight = (); - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } ord_parameter_types! { diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index cac092c98dc400815ef3a8b221b43e6a948be888..9830f31d5fa9accedeb5edbde0c526df4ecefee2 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -31,7 +31,7 @@ sp-std = { path = "../../primitives/std", default-features = false } sp-staking = { path = "../../primitives/staking", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } -log = { version = "0.4.0", default-features = false } +log = { workspace = true } # Optional: use for testing and/or fuzzing pallet-balances = { path = "../balances", optional = true } diff --git a/substrate/frame/nomination-pools/fuzzer/Cargo.toml b/substrate/frame/nomination-pools/fuzzer/Cargo.toml index 52f49b28457c26c3c247dd4c137565cd9564dcc8..c0d63a2685937a10e6a53288403099bc78ed1fa9 100644 --- a/substrate/frame/nomination-pools/fuzzer/Cargo.toml +++ b/substrate/frame/nomination-pools/fuzzer/Cargo.toml @@ -29,7 +29,7 @@ sp-io = { path = "../../../primitives/io" } sp-tracing = { path = "../../../primitives/tracing" } rand = { version = "0.8.5", features = ["small_rng"] } -log = "0.4.17" +log = { workspace = true, default-features = true } [[bin]] name = "call" diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index c2653d8bdabcc5a0bcc9378bd300252faf829ff6..a0dbdb3aaa47f6108d6b1f0fec92dc4d6826d624 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -1293,27 +1293,6 @@ impl BondedPool { }); }; } - - /// Withdraw all the funds that are already unlocked from staking for the - /// [`BondedPool::bonded_account`]. - /// - /// Also reduces the [`TotalValueLocked`] by the difference of the - /// [`T::Staking::total_stake`] of the [`BondedPool::bonded_account`] that might occur by - /// [`T::Staking::withdraw_unbonded`]. - /// - /// Returns the result of [`T::Staking::withdraw_unbonded`] - fn withdraw_from_staking(&self, num_slashing_spans: u32) -> Result { - let bonded_account = self.bonded_account(); - - let prev_total = T::Staking::total_stake(&bonded_account.clone()).unwrap_or_default(); - let outcome = T::Staking::withdraw_unbonded(bonded_account.clone(), num_slashing_spans); - let diff = prev_total - .defensive_saturating_sub(T::Staking::total_stake(&bonded_account).unwrap_or_default()); - TotalValueLocked::::mutate(|tvl| { - tvl.saturating_reduce(diff); - }); - outcome - } } /// A reward pool. @@ -1597,7 +1576,7 @@ pub mod pallet { use frame_system::{ensure_signed, pallet_prelude::*}; use sp_runtime::Perbill; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); #[pallet::pallet] @@ -1733,7 +1712,7 @@ pub mod pallet { CountedStorageMap<_, Twox64Concat, PoolId, BondedPoolInner>; /// Reward pools. This is where there rewards for each pool accumulate. When a members payout is - /// claimed, the balance comes out fo the reward pool. Keyed by the bonded pools account. + /// claimed, the balance comes out of the reward pool. Keyed by the bonded pools account. #[pallet::storage] pub type RewardPools = CountedStorageMap<_, Twox64Concat, PoolId, RewardPool>; @@ -1753,8 +1732,8 @@ pub mod pallet { /// A reverse lookup from the pool's account id to its id. /// - /// This is only used for slashing. In all other instances, the pool id is used, and the - /// accounts are deterministically derived from it. + /// This is only used for slashing and on automatic withdraw update. In all other instances, the + /// pool id is used, and the accounts are deterministically derived from it. #[pallet::storage] pub type ReversePoolIdLookup = CountedStorageMap<_, Twox64Concat, T::AccountId, PoolId, OptionQuery>; @@ -2223,7 +2202,7 @@ pub mod pallet { // For now we only allow a pool to withdraw unbonded if its not destroying. If the pool // is destroying then `withdraw_unbonded` can be used. ensure!(pool.state != PoolState::Destroying, Error::::NotDestroying); - pool.withdraw_from_staking(num_slashing_spans)?; + T::Staking::withdraw_unbonded(pool.bonded_account(), num_slashing_spans)?; Ok(()) } @@ -2275,7 +2254,8 @@ pub mod pallet { // Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the // `transferrable_balance` is correct. - let stash_killed = bonded_pool.withdraw_from_staking(num_slashing_spans)?; + let stash_killed = + T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?; // defensive-only: the depositor puts enough funds into the stash so that it will only // be destroyed when they are leaving. @@ -2421,6 +2401,11 @@ pub mod pallet { /// /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. + /// + /// # Note + /// + /// In addition to a `root` or `nominator` role of `origin`, pool's depositor needs to have + /// at least `depositor_min_bond` in the pool to start nominating. #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))] pub fn nominate( @@ -2431,6 +2416,16 @@ pub mod pallet { let who = ensure_signed(origin)?; let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + + let depositor_points = PoolMembers::::get(&bonded_pool.roles.depositor) + .ok_or(Error::::PoolMemberNotFound)? + .active_points(); + + ensure!( + bonded_pool.points_to_balance(depositor_points) >= Self::depositor_min_bond(), + Error::::MinimumBondNotMet + ); + T::Staking::nominate(&bonded_pool.bonded_account(), validators) } @@ -2593,17 +2588,37 @@ pub mod pallet { /// Chill on behalf of the pool. /// - /// The dispatch origin of this call must be signed by the pool nominator or the pool + /// The dispatch origin of this call can be signed by the pool nominator or the pool /// root role, same as [`Pallet::nominate`]. /// + /// Under certain conditions, this call can be dispatched permissionlessly (i.e. by any + /// account). + /// + /// # Conditions for a permissionless dispatch: + /// * When pool depositor has less than `MinNominatorBond` staked, otherwise pool members + /// are unable to unbond. + /// + /// # Conditions for permissioned dispatch: + /// * The caller has a nominator or root role of the pool. /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::chill())] pub fn chill(origin: OriginFor, pool_id: PoolId) -> DispatchResult { let who = ensure_signed(origin)?; + let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; - ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + + let depositor_points = PoolMembers::::get(&bonded_pool.roles.depositor) + .ok_or(Error::::PoolMemberNotFound)? + .active_points(); + + if bonded_pool.points_to_balance(depositor_points) >= + T::Staking::minimum_nominator_bond() + { + ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + } + T::Staking::chill(&bonded_pool.bonded_account()) } @@ -3628,4 +3643,14 @@ impl sp_staking::OnStakingUpdate> for Pall } Self::deposit_event(Event::::PoolSlashed { pool_id, balance: slashed_bonded }); } + + /// Reduces the overall `TotalValueLocked` if a withdrawal happened for a pool involved in the + /// staking withdraw. + fn on_withdraw(pool_account: &T::AccountId, amount: BalanceOf) { + if ReversePoolIdLookup::::get(pool_account).is_some() { + TotalValueLocked::::mutate(|tvl| { + tvl.saturating_reduce(amount); + }); + } + } } diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index 559baf76e4c64c5893d44c15d3505a9083ed76db..14410339f59a4dc809187feb6d289b16ec52f79c 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -56,6 +56,59 @@ pub mod versioned { >; } +pub mod unversioned { + use super::*; + + /// Checks and updates `TotalValueLocked` if out of sync. + pub struct TotalValueLockedSync(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for TotalValueLockedSync { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + let migrated = BondedPools::::count(); + + // recalcuate the `TotalValueLocked` to compare with the current on-chain TVL which may + // be out of sync. + let tvl: BalanceOf = helpers::calculate_tvl_by_total_stake::(); + let onchain_tvl = TotalValueLocked::::get(); + + let writes = if tvl != onchain_tvl { + TotalValueLocked::::set(tvl); + + log!( + info, + "on-chain TVL was out of sync, update. Old: {:?}, new: {:?}", + onchain_tvl, + tvl + ); + + // writes: onchain version + set total value locked. + 2 + } else { + log!(info, "on-chain TVL was OK: {:?}", tvl); + + // writes: onchain version write. + 1 + }; + + // reads: migrated * (BondedPools + Staking::total_stake) + count + onchain + // version + // + // writes: current version + (maybe) TVL + T::DbWeight::get() + .reads_writes(migrated.saturating_mul(2).saturating_add(2).into(), writes) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { + Ok(()) + } + } +} + pub mod v8 { use super::{v7::V7BondedPoolInner, *}; @@ -146,6 +199,7 @@ pub(crate) mod v7 { } impl V7BondedPool { + #[allow(dead_code)] fn bonded_account(&self) -> T::AccountId { Pallet::::create_bonded_account(self.id) } @@ -157,26 +211,12 @@ pub(crate) mod v7 { CountedStorageMap, Twox64Concat, PoolId, V7BondedPoolInner>; pub struct VersionUncheckedMigrateV6ToV7(sp_std::marker::PhantomData); - impl VersionUncheckedMigrateV6ToV7 { - fn calculate_tvl_by_total_stake() -> BalanceOf { - BondedPools::::iter() - .map(|(id, inner)| { - T::Staking::total_stake( - &V7BondedPool { id, inner: inner.clone() }.bonded_account(), - ) - .unwrap_or_default() - }) - .reduce(|acc, total_balance| acc + total_balance) - .unwrap_or_default() - } - } - impl OnRuntimeUpgrade for VersionUncheckedMigrateV6ToV7 { fn on_runtime_upgrade() -> Weight { let migrated = BondedPools::::count(); // The TVL should be the sum of all the funds that are actively staked and in the // unbonding process of the account of each pool. - let tvl: BalanceOf = Self::calculate_tvl_by_total_stake(); + let tvl: BalanceOf = helpers::calculate_tvl_by_total_stake::(); TotalValueLocked::::set(tvl); @@ -198,7 +238,7 @@ pub(crate) mod v7 { fn post_upgrade(_data: Vec) -> Result<(), TryRuntimeError> { // check that the `TotalValueLocked` written is actually the sum of `total_stake` of the // `BondedPools`` - let tvl: BalanceOf = Self::calculate_tvl_by_total_stake(); + let tvl: BalanceOf = helpers::calculate_tvl_by_total_stake::(); ensure!( TotalValueLocked::::get() == tvl, "TVL written is not equal to `Staking::total_stake` of all `BondedPools`." @@ -302,25 +342,25 @@ pub mod v5 { pub struct MigrateToV5(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV5 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let in_code = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); log!( info, - "Running migration with current storage version {:?} / onchain {:?}", - current, + "Running migration with in-code storage version {:?} / onchain {:?}", + in_code, onchain ); - if current == 5 && onchain == 4 { + if in_code == 5 && onchain == 4 { let mut translated = 0u64; RewardPools::::translate::, _>(|_id, old_value| { translated.saturating_inc(); Some(old_value.migrate_to_v5()) }); - current.put::>(); - log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); + in_code.put::>(); + log!(info, "Upgraded {} pools, storage to version {:?}", translated, in_code); // reads: translated + onchain version. // writes: translated + current.put. @@ -458,12 +498,12 @@ pub mod v4 { #[allow(deprecated)] impl> OnRuntimeUpgrade for MigrateToV4 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); log!( info, - "Running migration with current storage version {:?} / onchain {:?}", + "Running migration with in-code storage version {:?} / onchain {:?}", current, onchain ); @@ -539,13 +579,13 @@ pub mod v3 { pub struct MigrateToV3(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV3 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); if onchain == 2 { log!( info, - "Running migration with current storage version {:?} / onchain {:?}", + "Running migration with in-code storage version {:?} / onchain {:?}", current, onchain ); @@ -819,12 +859,12 @@ pub mod v2 { impl OnRuntimeUpgrade for MigrateToV2 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); log!( info, - "Running migration with current storage version {:?} / onchain {:?}", + "Running migration with in-code storage version {:?} / onchain {:?}", current, onchain ); @@ -936,12 +976,12 @@ pub mod v1 { pub struct MigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); log!( info, - "Running migration with current storage version {:?} / onchain {:?}", + "Running migration with in-code storage version {:?} / onchain {:?}", current, onchain ); @@ -977,3 +1017,17 @@ pub mod v1 { } } } + +mod helpers { + use super::*; + + pub(crate) fn calculate_tvl_by_total_stake() -> BalanceOf { + BondedPools::::iter() + .map(|(id, inner)| { + T::Staking::total_stake(&BondedPool { id, inner: inner.clone() }.bonded_account()) + .unwrap_or_default() + }) + .reduce(|acc, total_balance| acc + total_balance) + .unwrap_or_default() + } +} diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 84c41a15b201052cd03b3c67fff4cb0c8980a92f..f982b72c63564c0cff6106ded6ad934fec10f48c 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -134,11 +134,24 @@ impl sp_staking::StakingInterface for StakingMock { fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result { let mut unbonding_map = UnbondingBalanceMap::get(); + + // closure to calculate the current unlocking funds across all eras/accounts. + let unlocking = |pair: &Vec<(EraIndex, Balance)>| -> Balance { + pair.iter() + .try_fold(Zero::zero(), |acc: Balance, (_at, amount)| acc.checked_add(*amount)) + .unwrap() + }; + let staker_map = unbonding_map.get_mut(&who).ok_or("Nothing to unbond")?; + let unlocking_before = unlocking(&staker_map); let current_era = Self::current_era(); + staker_map.retain(|(unlocking_at, _amount)| *unlocking_at > current_era); + // if there was a withdrawal, notify the pallet. + Pools::on_withdraw(&who, unlocking_before.saturating_sub(unlocking(&staker_map))); + UnbondingBalanceMap::set(&unbonding_map); Ok(UnbondingBalanceMap::get().is_empty() && BondedBalanceMap::get().is_empty()) } diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 13298fa64f54c0439384fcb8fba7b512678ff687..8fb2b41b88a190df444162a58d0a134936d81272 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -4848,6 +4848,18 @@ mod nominate { Error::::NotNominator ); + // if `depositor` stake is less than the `MinimumNominatorBond`, they can't nominate + StakingMinBond::set(20); + + // Can't nominate if depositor's stake is less than the `MinimumNominatorBond` + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(900), 1, vec![21]), + Error::::MinimumBondNotMet + ); + + // restore `MinimumNominatorBond` + StakingMinBond::set(10); + // Root can nominate assert_ok!(Pools::nominate(RuntimeOrigin::signed(900), 1, vec![21])); assert_eq!(Nominations::get().unwrap(), vec![21]); @@ -7338,3 +7350,33 @@ mod slash { }); } } + +mod chill { + use super::*; + + #[test] + fn chill_works() { + ExtBuilder::default().build_and_execute(|| { + // only nominator or root can chill + assert_noop!( + Pools::chill(RuntimeOrigin::signed(10), 1), + Error::::NotNominator + ); + + // root can chill and re-nominate + assert_ok!(Pools::chill(RuntimeOrigin::signed(900), 1)); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(900), 1, vec![31])); + + // nominator can chill and re-nominate + assert_ok!(Pools::chill(RuntimeOrigin::signed(901), 1)); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(901), 1, vec![31])); + + // if `depositor` stake is less than the `MinimumNominatorBond`, then this call + // becomes permissionless; + StakingMinBond::set(20); + + // any account can chill + assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); + }) + } +} diff --git a/substrate/frame/nomination-pools/src/weights.rs b/substrate/frame/nomination-pools/src/weights.rs index 047a17c3f9a278ac9564562edf318f13ecc2f7ca..987ddd7170310a315ad6ad93dc43062b60f563ac 100644 --- a/substrate/frame/nomination-pools/src/weights.rs +++ b/substrate/frame/nomination-pools/src/weights.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_nomination_pools` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-07, 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-p5qp1txx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -112,8 +112,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3425` // Estimated: `8877` - // Minimum execution time: 184_295_000 picoseconds. - Weight::from_parts(188_860_000, 8877) + // Minimum execution time: 182_643_000 picoseconds. + Weight::from_parts(186_106_000, 8877) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -145,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3435` // Estimated: `8877` - // Minimum execution time: 188_777_000 picoseconds. - Weight::from_parts(192_646_000, 8877) + // Minimum execution time: 181_464_000 picoseconds. + Weight::from_parts(184_672_000, 8877) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -180,8 +180,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3500` // Estimated: `8877` - // Minimum execution time: 221_728_000 picoseconds. - Weight::from_parts(227_569_000, 8877) + // Minimum execution time: 216_182_000 picoseconds. + Weight::from_parts(218_448_000, 8877) .saturating_add(T::DbWeight::get().reads(18_u64)) .saturating_add(T::DbWeight::get().writes(14_u64)) } @@ -201,8 +201,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1172` // Estimated: `3719` - // Minimum execution time: 75_310_000 picoseconds. - Weight::from_parts(77_709_000, 3719) + // Minimum execution time: 73_830_000 picoseconds. + Weight::from_parts(75_271_000, 3719) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -242,8 +242,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3622` // Estimated: `27847` - // Minimum execution time: 170_656_000 picoseconds. - Weight::from_parts(174_950_000, 27847) + // Minimum execution time: 166_099_000 picoseconds. + Weight::from_parts(170_355_000, 27847) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -259,18 +259,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: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1817` + // Measured: `1848` // Estimated: `4764` - // Minimum execution time: 68_866_000 picoseconds. - Weight::from_parts(72_312_887, 4764) - // Standard Error: 1_635 - .saturating_add(Weight::from_parts(41_679, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(7_u64)) + // Minimum execution time: 64_787_000 picoseconds. + Weight::from_parts(67_920_914, 4764) + // Standard Error: 1_482 + .saturating_add(Weight::from_parts(43_264, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `NominationPools::PoolMembers` (r:1 w:1) @@ -291,6 +293,8 @@ impl WeightInfo for SubstrateWeight { /// 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`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) @@ -300,13 +304,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2207` + // Measured: `2238` // Estimated: `27847` - // Minimum execution time: 131_383_000 picoseconds. - Weight::from_parts(136_595_971, 27847) - // Standard Error: 2_715 - .saturating_add(Weight::from_parts(52_351, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) + // Minimum execution time: 124_990_000 picoseconds. + Weight::from_parts(129_041_398, 27847) + // Standard Error: 2_335 + .saturating_add(Weight::from_parts(67_889, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } /// Storage: `NominationPools::PoolMembers` (r:1 w:1) @@ -333,12 +337,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::RewardPools` (r:1 w:1) @@ -356,12 +360,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2525` // Estimated: `27847` - // Minimum execution time: 233_314_000 picoseconds. - Weight::from_parts(241_694_316, 27847) + // Minimum execution time: 221_955_000 picoseconds. + Weight::from_parts(230_244_437, 27847) + // Standard Error: 4_059 + .saturating_add(Weight::from_parts(7_522, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(24_u64)) .saturating_add(T::DbWeight::get().writes(20_u64)) } @@ -413,19 +419,25 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1169` // Estimated: `8538` - // Minimum execution time: 171_465_000 picoseconds. - Weight::from_parts(176_478_000, 8538) + // Minimum execution time: 165_358_000 picoseconds. + Weight::from_parts(169_683_000, 8538) .saturating_add(T::DbWeight::get().reads(23_u64)) .saturating_add(T::DbWeight::get().writes(17_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:1 w:0) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) @@ -445,13 +457,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1808` + // Measured: `1976` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 63_588_000 picoseconds. - Weight::from_parts(64_930_584, 4556) - // Standard Error: 9_167 - .saturating_add(Weight::from_parts(1_595_779, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Minimum execution time: 74_483_000 picoseconds. + Weight::from_parts(76_611_288, 4556) + // Standard Error: 9_013 + .saturating_add(Weight::from_parts(1_475_128, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) @@ -466,8 +478,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1434` // Estimated: `4556` - // Minimum execution time: 32_899_000 picoseconds. - Weight::from_parts(33_955_000, 4556) + // Minimum execution time: 32_598_000 picoseconds. + Weight::from_parts(33_350_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -482,10 +494,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3735` - // Minimum execution time: 13_778_000 picoseconds. - Weight::from_parts(14_770_006, 3735) - // Standard Error: 151 - .saturating_add(Weight::from_parts(1_900, 0).saturating_mul(n.into())) + // Minimum execution time: 13_705_000 picoseconds. + Weight::from_parts(14_594_211, 3735) + // Standard Error: 141 + .saturating_add(Weight::from_parts(2_119, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -505,8 +517,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_550_000 picoseconds. - Weight::from_parts(4_935_000, 0) + // Minimum execution time: 4_222_000 picoseconds. + Weight::from_parts(4_527_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -515,17 +527,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_759_000 picoseconds. - Weight::from_parts(17_346_000, 3719) + // Minimum execution time: 16_106_000 picoseconds. + Weight::from_parts(17_365_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -540,11 +556,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1971` + // Measured: `2143` // Estimated: `4556` - // Minimum execution time: 61_970_000 picoseconds. - Weight::from_parts(63_738_000, 4556) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Minimum execution time: 71_301_000 picoseconds. + Weight::from_parts(73_626_000, 4556) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -559,8 +575,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `804` // Estimated: `3719` - // Minimum execution time: 31_950_000 picoseconds. - Weight::from_parts(33_190_000, 3719) + // Minimum execution time: 32_363_000 picoseconds. + Weight::from_parts(33_400_000, 3719) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -572,8 +588,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `572` // Estimated: `3719` - // Minimum execution time: 16_807_000 picoseconds. - Weight::from_parts(17_733_000, 3719) + // Minimum execution time: 16_686_000 picoseconds. + Weight::from_parts(17_294_000, 3719) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -583,8 +599,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_710_000 picoseconds. - Weight::from_parts(17_563_000, 3719) + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_028_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -594,8 +610,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_493_000 picoseconds. - Weight::from_parts(17_022_000, 3719) + // Minimum execution time: 16_350_000 picoseconds. + Weight::from_parts(16_905_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -607,8 +623,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 14_248_000 picoseconds. - Weight::from_parts(15_095_000, 3702) + // Minimum execution time: 14_081_000 picoseconds. + Weight::from_parts(14_608_000, 3702) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -624,8 +640,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1002` // Estimated: `3719` - // Minimum execution time: 61_969_000 picoseconds. - Weight::from_parts(63_965_000, 3719) + // Minimum execution time: 62_178_000 picoseconds. + Weight::from_parts(64_039_000, 3719) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -641,8 +657,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `901` // Estimated: `4764` - // Minimum execution time: 65_462_000 picoseconds. - Weight::from_parts(67_250_000, 4764) + // Minimum execution time: 64_880_000 picoseconds. + Weight::from_parts(66_541_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -686,8 +702,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3425` // Estimated: `8877` - // Minimum execution time: 184_295_000 picoseconds. - Weight::from_parts(188_860_000, 8877) + // Minimum execution time: 182_643_000 picoseconds. + Weight::from_parts(186_106_000, 8877) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -719,8 +735,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3435` // Estimated: `8877` - // Minimum execution time: 188_777_000 picoseconds. - Weight::from_parts(192_646_000, 8877) + // Minimum execution time: 181_464_000 picoseconds. + Weight::from_parts(184_672_000, 8877) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -754,8 +770,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3500` // Estimated: `8877` - // Minimum execution time: 221_728_000 picoseconds. - Weight::from_parts(227_569_000, 8877) + // Minimum execution time: 216_182_000 picoseconds. + Weight::from_parts(218_448_000, 8877) .saturating_add(RocksDbWeight::get().reads(18_u64)) .saturating_add(RocksDbWeight::get().writes(14_u64)) } @@ -775,8 +791,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1172` // Estimated: `3719` - // Minimum execution time: 75_310_000 picoseconds. - Weight::from_parts(77_709_000, 3719) + // Minimum execution time: 73_830_000 picoseconds. + Weight::from_parts(75_271_000, 3719) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -816,8 +832,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3622` // Estimated: `27847` - // Minimum execution time: 170_656_000 picoseconds. - Weight::from_parts(174_950_000, 27847) + // Minimum execution time: 166_099_000 picoseconds. + Weight::from_parts(170_355_000, 27847) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -833,18 +849,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: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1817` + // Measured: `1848` // Estimated: `4764` - // Minimum execution time: 68_866_000 picoseconds. - Weight::from_parts(72_312_887, 4764) - // Standard Error: 1_635 - .saturating_add(Weight::from_parts(41_679, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(7_u64)) + // Minimum execution time: 64_787_000 picoseconds. + Weight::from_parts(67_920_914, 4764) + // Standard Error: 1_482 + .saturating_add(Weight::from_parts(43_264, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `NominationPools::PoolMembers` (r:1 w:1) @@ -865,6 +883,8 @@ impl WeightInfo for () { /// 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`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) @@ -874,13 +894,13 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2207` + // Measured: `2238` // Estimated: `27847` - // Minimum execution time: 131_383_000 picoseconds. - Weight::from_parts(136_595_971, 27847) - // Standard Error: 2_715 - .saturating_add(Weight::from_parts(52_351, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) + // Minimum execution time: 124_990_000 picoseconds. + Weight::from_parts(129_041_398, 27847) + // Standard Error: 2_335 + .saturating_add(Weight::from_parts(67_889, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } /// Storage: `NominationPools::PoolMembers` (r:1 w:1) @@ -907,12 +927,12 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::RewardPools` (r:1 w:1) @@ -930,12 +950,14 @@ impl WeightInfo for () { /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2525` // Estimated: `27847` - // Minimum execution time: 233_314_000 picoseconds. - Weight::from_parts(241_694_316, 27847) + // Minimum execution time: 221_955_000 picoseconds. + Weight::from_parts(230_244_437, 27847) + // Standard Error: 4_059 + .saturating_add(Weight::from_parts(7_522, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(24_u64)) .saturating_add(RocksDbWeight::get().writes(20_u64)) } @@ -987,19 +1009,25 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1169` // Estimated: `8538` - // Minimum execution time: 171_465_000 picoseconds. - Weight::from_parts(176_478_000, 8538) + // Minimum execution time: 165_358_000 picoseconds. + Weight::from_parts(169_683_000, 8538) .saturating_add(RocksDbWeight::get().reads(23_u64)) .saturating_add(RocksDbWeight::get().writes(17_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:1 w:0) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) @@ -1019,13 +1047,13 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1808` + // Measured: `1976` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 63_588_000 picoseconds. - Weight::from_parts(64_930_584, 4556) - // Standard Error: 9_167 - .saturating_add(Weight::from_parts(1_595_779, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Minimum execution time: 74_483_000 picoseconds. + Weight::from_parts(76_611_288, 4556) + // Standard Error: 9_013 + .saturating_add(Weight::from_parts(1_475_128, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) @@ -1040,8 +1068,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1434` // Estimated: `4556` - // Minimum execution time: 32_899_000 picoseconds. - Weight::from_parts(33_955_000, 4556) + // Minimum execution time: 32_598_000 picoseconds. + Weight::from_parts(33_350_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1056,10 +1084,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3735` - // Minimum execution time: 13_778_000 picoseconds. - Weight::from_parts(14_770_006, 3735) - // Standard Error: 151 - .saturating_add(Weight::from_parts(1_900, 0).saturating_mul(n.into())) + // Minimum execution time: 13_705_000 picoseconds. + Weight::from_parts(14_594_211, 3735) + // Standard Error: 141 + .saturating_add(Weight::from_parts(2_119, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1079,8 +1107,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_550_000 picoseconds. - Weight::from_parts(4_935_000, 0) + // Minimum execution time: 4_222_000 picoseconds. + Weight::from_parts(4_527_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -1089,17 +1117,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_759_000 picoseconds. - Weight::from_parts(17_346_000, 3719) + // Minimum execution time: 16_106_000 picoseconds. + Weight::from_parts(17_365_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -1114,11 +1146,11 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1971` + // Measured: `2143` // Estimated: `4556` - // Minimum execution time: 61_970_000 picoseconds. - Weight::from_parts(63_738_000, 4556) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Minimum execution time: 71_301_000 picoseconds. + Weight::from_parts(73_626_000, 4556) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -1133,8 +1165,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `804` // Estimated: `3719` - // Minimum execution time: 31_950_000 picoseconds. - Weight::from_parts(33_190_000, 3719) + // Minimum execution time: 32_363_000 picoseconds. + Weight::from_parts(33_400_000, 3719) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1146,8 +1178,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `572` // Estimated: `3719` - // Minimum execution time: 16_807_000 picoseconds. - Weight::from_parts(17_733_000, 3719) + // Minimum execution time: 16_686_000 picoseconds. + Weight::from_parts(17_294_000, 3719) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1157,8 +1189,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_710_000 picoseconds. - Weight::from_parts(17_563_000, 3719) + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_028_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1168,8 +1200,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_493_000 picoseconds. - Weight::from_parts(17_022_000, 3719) + // Minimum execution time: 16_350_000 picoseconds. + Weight::from_parts(16_905_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1181,8 +1213,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 14_248_000 picoseconds. - Weight::from_parts(15_095_000, 3702) + // Minimum execution time: 14_081_000 picoseconds. + Weight::from_parts(14_608_000, 3702) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1198,8 +1230,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1002` // Estimated: `3719` - // Minimum execution time: 61_969_000 picoseconds. - Weight::from_parts(63_965_000, 3719) + // Minimum execution time: 62_178_000 picoseconds. + Weight::from_parts(64_039_000, 3719) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1215,8 +1247,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `901` // Estimated: `4764` - // Minimum execution time: 65_462_000 picoseconds. - Weight::from_parts(67_250_000, 4764) + // Minimum execution time: 64_880_000 picoseconds. + Weight::from_parts(66_541_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml index 845535ae04f567bbe5fa4c4c7f22854b077176b5..9c7b12e4c6345b2080ef4b989171929c505c8a40 100644 --- a/substrate/frame/nomination-pools/test-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml @@ -37,4 +37,4 @@ pallet-staking-reward-curve = { path = "../../staking/reward-curve" } pallet-nomination-pools = { path = ".." } sp-tracing = { path = "../../../primitives/tracing" } -log = { version = "0.4.0" } +log = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-staking/src/lib.rs b/substrate/frame/nomination-pools/test-staking/src/lib.rs index 865b7a71e68840d00b42c7cf11e6916c8debf5ad..98bff537c90819be34625d099cb55abcaafb10ae 100644 --- a/substrate/frame/nomination-pools/test-staking/src/lib.rs +++ b/substrate/frame/nomination-pools/test-staking/src/lib.rs @@ -22,10 +22,12 @@ mod mock; use frame_support::{assert_noop, assert_ok, traits::Currency}; use mock::*; use pallet_nomination_pools::{ - BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, - PoolState, + BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, + PoolMembers, PoolState, +}; +use pallet_staking::{ + CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, }; -use pallet_staking::{CurrentEra, Event as StakingEvent, Payee, RewardDestination}; use sp_runtime::{bounded_btree_map, traits::Zero}; #[test] @@ -191,6 +193,131 @@ fn pool_lifecycle_e2e() { }) } +#[test] +fn pool_chill_e2e() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // in case depositor does not have more than `MinNominatorBond` staked, we can end up in + // situation where a member unbonding would cause pool balance to drop below + // `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is + // increased after the pool is created. + assert_ok!(Staking::set_staking_configs( + RuntimeOrigin::root(), + pallet_staking::ConfigOp::Set(55), // minimum nominator bond + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + )); + + // members can unbond as long as total stake of the pool is above min nominator bond + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 0); + + // this member cannot unbond since it will cause `pool stake < MinNominatorBond` + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(21), 21, 10), + StakingError::::InsufficientBond, + ); + + // members can call `chill` permissionlessly now + assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1)); + + // now another member can unbond. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(21).unwrap().points, 0); + + // nominator can not resume nomination until depositor have enough stake + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // other members joining pool does not affect the depositor's ability to resume nomination + assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); + + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // depositor can bond extra stake + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); + + // `chill` can not be called permissionlessly anymore + assert_noop!( + Pools::chill(RuntimeOrigin::signed(20), 1), + PoolsError::::NotNominator, + ); + + // now nominator can resume nomination + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + // skip to make the unbonding period end. + CurrentEra::::set(Some(BondingDuration::get())); + + // members can now withdraw. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra + StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 }, + ] + ); + }) +} + #[test] fn pool_slash_e2e() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index d1b50b9f7aed0573b8351ff34d4f68eecf66c02c..ce97e13d640b63ed7da25ad36f8d2625e58d3c50 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -236,6 +236,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, )); }); diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index 73842c696af294adb729c7621e239fe7dcd7e4d8..b3ef4671ce56f4b66d7e7cb4ce7ec7faec05d3fe 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-balances = { path = "../balances", default-features = false } diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index fc3fb076f1f9ecf4652cfa64f3daa7ca1e5d4478..8dcce84d257e596609e4062f8a46d684a72b2683 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -32,7 +32,7 @@ pallet-staking = { path = "../../staking", default-features = false } sp-runtime = { path = "../../../primitives/runtime", default-features = false } sp-staking = { path = "../../../primitives/staking", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] pallet-staking-reward-curve = { path = "../../staking/reward-curve" } diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index 01ad8d64f100672dc36929d28af22e41f8a88c60..b3260f0841f06490246a0c0f079864d5f1224a0e 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -148,7 +148,7 @@ parameter_types! { pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); } -pub type Extrinsic = sp_runtime::testing::TestXt; +pub type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..07ebeea52d5298be0db8b00c09ab73641d20080b --- /dev/null +++ b/substrate/frame/parameters/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "pallet-parameters" +description = "Pallet to store and configure parameters." +repository.workspace = true +license = "Apache-2.0" +version = "0.0.1" +authors = ["Acala Developers", "Parity Technologies "] +edition.workspace = true + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } +scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +paste = { version = "1.0.14", default-features = false } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } +docify = "0.2.5" + +frame-support = { path = "../support", default-features = false, features = ["experimental"] } +frame-system = { path = "../system", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } + +[dev-dependencies] +sp-core = { path = "../../primitives/core", features = ["std"] } +sp-io = { path = "../../primitives/io", features = ["std"] } +pallet-example-basic = { path = "../examples/basic", features = ["std"] } +pallet-balances = { path = "../balances", features = ["std"] } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "serde", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-example-basic/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "pallet-example-basic/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/parameters/src/benchmarking.rs b/substrate/frame/parameters/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..1f22e026cbca07b236c4680570a3312d8c4b85e5 --- /dev/null +++ b/substrate/frame/parameters/src/benchmarking.rs @@ -0,0 +1,51 @@ +// 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. + +//! Parameters pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +#[cfg(test)] +use crate::Pallet as Parameters; + +use frame_benchmarking::v2::*; + +#[benchmarks(where T::RuntimeParameters: Default)] +mod benchmarks { + use super::*; + + #[benchmark] + fn set_parameter() -> Result<(), BenchmarkError> { + let kv = T::RuntimeParameters::default(); + let k = kv.clone().into_parts().0; + + let origin = + T::AdminOrigin::try_successful_origin(&k).map_err(|_| BenchmarkError::Weightless)?; + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, kv); + + Ok(()) + } + + impl_benchmark_test_suite! { + Parameters, + crate::tests::mock::new_test_ext(), + crate::tests::mock::Runtime, + } +} diff --git a/substrate/frame/parameters/src/lib.rs b/substrate/frame/parameters/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..91cf10ba93f7f9ebf03363cfe3bf8a9b4ff89172 --- /dev/null +++ b/substrate/frame/parameters/src/lib.rs @@ -0,0 +1,270 @@ +// 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_attr(not(feature = "std"), no_std)] +#![deny(missing_docs)] +// Need to enable this one since we document feature-gated stuff. +#![allow(rustdoc::broken_intra_doc_links)] + +//! # **⚠️ WARNING ⚠️** +//! +//!
+//! THIS CRATE IS NOT AUDITED AND SHOULD NOT BE USED IN PRODUCTION. +//!
+//! +//! # Parameters +//! +//! Allows to update configuration parameters at runtime. +//! +//! ## Pallet API +//! +//! This pallet exposes two APIs; one *inbound* side to update parameters, and one *outbound* side +//! to access said parameters. Parameters themselves are defined in the runtime config and will be +//! aggregated into an enum. Each parameter is addressed by a `key` and can have a default value. +//! This is not done by the pallet but through the [`frame_support::dynamic_params::dynamic_params`] +//! macro or alternatives. +//! +//! Note that this is incurring one storage read per access. This should not be a problem in most +//! cases but must be considered in weight-restrained code. +//! +//! ### Inbound +//! +//! The inbound side solely consists of the [`Pallet::set_parameter`] extrinsic to update the value +//! of a parameter. Each parameter can have their own admin origin as given by the +//! [`Config::AdminOrigin`]. +//! +//! ### Outbound +//! +//! The outbound side is runtime facing for the most part. More general, it provides a `Get` +//! implementation and can be used in every spot where that is accepted. Two macros are in place: +//! [`frame_support::dynamic_params::define_parameters` and +//! [`frame_support::dynamic_params:dynamic_pallet_params`] to define and expose parameters in a +//! typed manner. +//! +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events and errors. +//! +//! ## Overview +//! +//! This pallet is a good fit for updating parameters without a runtime upgrade. It is very handy to +//! not require a runtime upgrade for a simple parameter change since runtime upgrades require a lot +//! of diligence and always bear risks. It seems overkill to update the whole runtime for a simple +//! parameter change. This pallet allows for fine-grained control over who can update what. +//! The only down-side is that it trades off performance with convenience and should therefore only +//! be used in places where that is proven to be uncritical. Values that are rarely accessed but +//! change often would be a perfect fit. +//! +//! ### Example Configuration +//! +//! Here is an example of how to define some parameters, including their default values: +#![doc = docify::embed!("src/tests/mock.rs", dynamic_params)] +//! +//! A permissioned origin can be define on a per-key basis like this: +#![doc = docify::embed!("src/tests/mock.rs", custom_origin)] +//! +//! The pallet will also require a default value for benchmarking. Ideally this is the variant with +//! the longest encoded length. Although in either case the PoV benchmarking will take the worst +//! case over the whole enum. +#![doc = docify::embed!("src/tests/mock.rs", benchmarking_default)] +//! +//! Now the aggregated parameter needs to be injected into the pallet config: +#![doc = docify::embed!("src/tests/mock.rs", impl_config)] +//! +//! As last step, the parameters can now be used in other pallets 🙌 +#![doc = docify::embed!("src/tests/mock.rs", usage)] +//! +//! ### Examples Usage +//! +//! Now to demonstrate how the values can be updated: +#![doc = docify::embed!("src/tests/unit.rs", set_parameters_example)] +//! +//! ## Low Level / Implementation Details +//! +//! The pallet stores the parameters in a storage map and implements the matching `Get` for +//! each `Key` type. The `Get` then accesses the `Parameters` map to retrieve the value. An event is +//! emitted every time that a value was updated. It is even emitted when the value is changed to the +//! same. +//! +//! The key and value types themselves are defined by macros and aggregated into a runtime wide +//! enum. This enum is then injected into the pallet. This allows it to be used without any changes +//! to the pallet that the parameter will be utilized by. +//! +//! ### Design Goals +//! +//! 1. Easy to update without runtime upgrade. +//! 2. Exposes metadata and docs for user convenience. +//! 3. Can be permissioned on a per-key base. +//! +//! ### Design +//! +//! 1. Everything is done at runtime without the need for `const` values. `Get` allows for this - +//! which is coincidentally an upside and a downside. 2. The types are defined through macros, which +//! allows to expose metadata and docs. 3. Access control is done through the `EnsureOriginWithArg` +//! trait, that allows to pass data along to the origin check. It gets passed in the key. The +//! implementor can then match on the key and the origin to decide whether the origin is +//! permissioned to set the value. + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +use frame_support::traits::{ + dynamic_params::{AggregratedKeyValue, IntoKey, Key, RuntimeParameterStore, TryIntoKey}, + EnsureOriginWithArg, +}; + +mod benchmarking; +#[cfg(test)] +mod tests; +mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +/// The key type of a parameter. +type KeyOf = <::RuntimeParameters as AggregratedKeyValue>::Key; + +/// The value type of a parameter. +type ValueOf = <::RuntimeParameters as AggregratedKeyValue>::Value; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config { + /// The overarching event type. + #[pallet::no_default_bounds] + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The overarching KV type of the parameters. + /// + /// Usually created by [`frame_support::dynamic_params`] or equivalent. + #[pallet::no_default_bounds] + type RuntimeParameters: AggregratedKeyValue; + + /// The origin which may update a parameter. + /// + /// The key of the parameter is passed in as second argument to allow for fine grained + /// control. + #[pallet::no_default_bounds] + type AdminOrigin: EnsureOriginWithArg>; + + /// Weight information for extrinsics in this module. + type WeightInfo: WeightInfo; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// A Parameter was set. + /// + /// Is also emitted when the value was not changed. + Updated { + /// The key that was updated. + key: ::Key, + /// The old value before this call. + old_value: Option<::Value>, + /// The new value after this call. + new_value: Option<::Value>, + }, + } + + /// Stored parameters. + #[pallet::storage] + pub type Parameters = + StorageMap<_, Blake2_128Concat, KeyOf, ValueOf, OptionQuery>; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + /// Set the value of a parameter. + /// + /// The dispatch origin of this call must be `AdminOrigin` for the given `key`. Values be + /// deleted by setting them to `None`. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::set_parameter())] + pub fn set_parameter( + origin: OriginFor, + key_value: T::RuntimeParameters, + ) -> DispatchResult { + let (key, new) = key_value.into_parts(); + T::AdminOrigin::ensure_origin(origin, &key)?; + + let mut old = None; + Parameters::::mutate(&key, |v| { + old = v.clone(); + *v = new.clone(); + }); + + Self::deposit_event(Event::Updated { key, old_value: old, new_value: new }); + + Ok(()) + } + } + /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. + pub mod config_preludes { + use super::*; + use frame_support::derive_impl; + + /// A configuration for testing. + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + #[inject_runtime_type] + type RuntimeEvent = (); + #[inject_runtime_type] + type RuntimeParameters = (); + + type AdminOrigin = frame_support::traits::AsEnsureOriginWithArg< + frame_system::EnsureRoot, + >; + + type WeightInfo = (); + } + } +} + +impl RuntimeParameterStore for Pallet { + type AggregratedKeyValue = T::RuntimeParameters; + + fn get(key: K) -> Option + where + KV: AggregratedKeyValue, + K: Key + Into<::Key>, + ::Key: IntoKey< + <::AggregratedKeyValue as AggregratedKeyValue>::Key, + >, + <::AggregratedKeyValue as AggregratedKeyValue>::Value: + TryIntoKey<::Value>, + ::Value: TryInto, + { + let key: ::Key = key.into(); + let val = Parameters::::get(key.into_key()); + val.and_then(|v| { + let val: ::Value = v.try_into_key().ok()?; + let val: K::WrappedValue = val.try_into().ok()?; + let val = val.into(); + Some(val) + }) + } +} diff --git a/substrate/frame/parameters/src/tests/mock.rs b/substrate/frame/parameters/src/tests/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..98612dc6a6d959c91b78570f562bce9074c43f61 --- /dev/null +++ b/substrate/frame/parameters/src/tests/mock.rs @@ -0,0 +1,152 @@ +// 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(any(test, feature = "runtime-benchmarks"))] + +//! Mock runtime that configures the `pallet_example_basic` to use dynamic params for testing. + +use frame_support::{ + construct_runtime, derive_impl, + dynamic_params::{dynamic_pallet_params, dynamic_params}, + traits::EnsureOriginWithArg, +}; + +use crate as pallet_parameters; +use crate::*; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = frame_system::mocking::MockBlock; + type AccountData = pallet_balances::AccountData<::Balance>; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for Runtime { + type ReserveIdentifier = [u8; 8]; + type AccountStore = System; +} + +#[docify::export] +#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::)] +pub mod dynamic_params { + use super::*; + + #[dynamic_pallet_params] + #[codec(index = 3)] + pub mod pallet1 { + #[codec(index = 0)] + pub static Key1: u64 = 0; + #[codec(index = 1)] + pub static Key2: u32 = 1; + #[codec(index = 2)] + pub static Key3: u128 = 2; + } + + #[dynamic_pallet_params] + #[codec(index = 1)] + pub mod pallet2 { + #[codec(index = 2)] + pub static Key1: u64 = 0; + #[codec(index = 1)] + pub static Key2: u32 = 2; + #[codec(index = 0)] + pub static Key3: u128 = 4; + } +} + +#[docify::export(benchmarking_default)] +#[cfg(feature = "runtime-benchmarks")] +impl Default for RuntimeParameters { + fn default() -> Self { + RuntimeParameters::Pallet1(dynamic_params::pallet1::Parameters::Key1( + dynamic_params::pallet1::Key1, + Some(123), + )) + } +} + +#[docify::export] +mod custom_origin { + use super::*; + pub struct ParamsManager; + + impl EnsureOriginWithArg for ParamsManager { + type Success = (); + + fn try_origin( + origin: RuntimeOrigin, + key: &RuntimeParametersKey, + ) -> Result { + // Account 123 is allowed to set parameters in benchmarking only: + #[cfg(feature = "runtime-benchmarks")] + if ensure_signed(origin.clone()).map_or(false, |acc| acc == 123) { + return Ok(()); + } + + match key { + RuntimeParametersKey::Pallet1(_) => ensure_root(origin.clone()), + RuntimeParametersKey::Pallet2(_) => ensure_signed(origin.clone()).map(|_| ()), + } + .map_err(|_| origin) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(_key: &RuntimeParametersKey) -> Result { + Ok(RuntimeOrigin::signed(123)) + } + } +} + +#[docify::export(impl_config)] +#[derive_impl(pallet_parameters::config_preludes::TestDefaultConfig as pallet_parameters::DefaultConfig)] +impl Config for Runtime { + type AdminOrigin = custom_origin::ParamsManager; + // RuntimeParameters is injected by the `derive_impl` macro. + // RuntimeEvent is injected by the `derive_impl` macro. + // WeightInfo is injected by the `derive_impl` macro. +} + +#[docify::export(usage)] +impl pallet_example_basic::Config for Runtime { + // Use the dynamic key in the pallet config: + type MagicNumber = dynamic_params::pallet1::Key1; + + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + PalletParameters: crate, + Example: pallet_example_basic, + Balances: pallet_balances, + } +); + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut ext = sp_io::TestExternalities::new(Default::default()); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +pub(crate) fn assert_last_event(generic_event: RuntimeEvent) { + let events = frame_system::Pallet::::events(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events.last().expect("Event expected"); + assert_eq!(event, &generic_event); +} diff --git a/substrate/frame/parameters/src/tests/mod.rs b/substrate/frame/parameters/src/tests/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..0a2d16906aadd394c5facb8c2bdbf45195574246 --- /dev/null +++ b/substrate/frame/parameters/src/tests/mod.rs @@ -0,0 +1,20 @@ +// 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. + +pub(crate) mod mock; +mod test_renamed; +mod unit; diff --git a/substrate/frame/parameters/src/tests/test_renamed.rs b/substrate/frame/parameters/src/tests/test_renamed.rs new file mode 100644 index 0000000000000000000000000000000000000000..b2e0c1fd9661b4122663a4633e1d4500ac6fad1c --- /dev/null +++ b/substrate/frame/parameters/src/tests/test_renamed.rs @@ -0,0 +1,168 @@ +// 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(any(test, feature = "runtime-benchmarks"))] + +//! Tests that the runtime params can be renamed. + +use frame_support::{ + assert_noop, assert_ok, construct_runtime, derive_impl, + dynamic_params::{dynamic_pallet_params, dynamic_params}, + traits::AsEnsureOriginWithArg, +}; +use frame_system::EnsureRoot; + +use crate as pallet_parameters; +use crate::*; +use dynamic_params::*; +use RuntimeParametersRenamed::*; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = frame_system::mocking::MockBlock; + type AccountData = pallet_balances::AccountData<::Balance>; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for Runtime { + type ReserveIdentifier = [u8; 8]; + type AccountStore = System; +} + +#[dynamic_params(RuntimeParametersRenamed, pallet_parameters::Parameters::)] +pub mod dynamic_params { + use super::*; + + #[dynamic_pallet_params] + #[codec(index = 3)] + pub mod pallet1 { + #[codec(index = 0)] + pub static Key1: u64 = 0; + #[codec(index = 1)] + pub static Key2: u32 = 1; + #[codec(index = 2)] + pub static Key3: u128 = 2; + } + + #[dynamic_pallet_params] + #[codec(index = 1)] + pub mod pallet2 { + #[codec(index = 2)] + pub static Key1: u64 = 0; + #[codec(index = 1)] + pub static Key2: u32 = 2; + #[codec(index = 0)] + pub static Key3: u128 = 4; + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl Default for RuntimeParametersRenamed { + fn default() -> Self { + RuntimeParametersRenamed::Pallet1(dynamic_params::pallet1::Parameters::Key1( + dynamic_params::pallet1::Key1, + Some(123), + )) + } +} + +#[derive_impl(pallet_parameters::config_preludes::TestDefaultConfig as pallet_parameters::DefaultConfig)] +impl Config for Runtime { + type AdminOrigin = AsEnsureOriginWithArg>; + type RuntimeParameters = RuntimeParametersRenamed; + // RuntimeEvent is injected by the `derive_impl` macro. + // WeightInfo is injected by the `derive_impl` macro. +} + +impl pallet_example_basic::Config for Runtime { + // Use the dynamic key in the pallet config: + type MagicNumber = dynamic_params::pallet1::Key1; + + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + PalletParameters: crate, + Example: pallet_example_basic, + Balances: pallet_balances, + } +); + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut ext = sp_io::TestExternalities::new(Default::default()); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +pub(crate) fn assert_last_event(generic_event: RuntimeEvent) { + let events = frame_system::Pallet::::events(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events.last().expect("Event expected"); + assert_eq!(event, &generic_event); +} + +#[test] +fn set_parameters_example() { + new_test_ext().execute_with(|| { + assert_eq!(pallet1::Key3::get(), 2, "Default works"); + + // This gets rejected since the origin is not root. + assert_noop!( + PalletParameters::set_parameter( + RuntimeOrigin::signed(1), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + ), + DispatchError::BadOrigin + ); + + assert_ok!(PalletParameters::set_parameter( + RuntimeOrigin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + )); + + assert_eq!(pallet1::Key3::get(), 123, "Update works"); + assert_last_event( + crate::Event::Updated { + key: RuntimeParametersRenamedKey::Pallet1(pallet1::ParametersKey::Key3( + pallet1::Key3, + )), + old_value: None, + new_value: Some(RuntimeParametersRenamedValue::Pallet1( + pallet1::ParametersValue::Key3(123), + )), + } + .into(), + ); + }); +} + +#[test] +fn get_through_external_pallet_works() { + new_test_ext().execute_with(|| { + assert_eq!(::MagicNumber::get(), 0); + + assert_ok!(PalletParameters::set_parameter( + RuntimeOrigin::root(), + Pallet1(pallet1::Parameters::Key1(pallet1::Key1, Some(123))), + )); + + assert_eq!(::MagicNumber::get(), 123); + }); +} diff --git a/substrate/frame/parameters/src/tests/unit.rs b/substrate/frame/parameters/src/tests/unit.rs new file mode 100644 index 0000000000000000000000000000000000000000..d3f11ba96403514fbe77ba89f57872e85cbf655a --- /dev/null +++ b/substrate/frame/parameters/src/tests/unit.rs @@ -0,0 +1,311 @@ +// 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. + +//! Unit tests for the parameters pallet. + +#![cfg(test)] + +use crate::tests::mock::{ + assert_last_event, dynamic_params::*, new_test_ext, PalletParameters, Runtime, + RuntimeOrigin as Origin, RuntimeParameters, RuntimeParameters::*, RuntimeParametersKey, + RuntimeParametersValue, +}; +use codec::Encode; +use frame_support::{assert_noop, assert_ok, traits::dynamic_params::AggregratedKeyValue}; +use sp_core::Get; +use sp_runtime::DispatchError; + +#[docify::export] +#[test] +fn set_parameters_example() { + new_test_ext().execute_with(|| { + assert_eq!(pallet1::Key3::get(), 2, "Default works"); + + // This gets rejected since the origin is not root. + assert_noop!( + PalletParameters::set_parameter( + Origin::signed(1), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + ), + DispatchError::BadOrigin + ); + + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + )); + + assert_eq!(pallet1::Key3::get(), 123, "Update works"); + assert_last_event( + crate::Event::Updated { + key: RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key3(pallet1::Key3)), + old_value: None, + new_value: Some(RuntimeParametersValue::Pallet1(pallet1::ParametersValue::Key3( + 123, + ))), + } + .into(), + ); + }); +} + +#[test] +fn set_parameters_same_is_noop() { + new_test_ext().execute_with(|| { + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + )); + + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + )); + + assert_eq!(pallet1::Key3::get(), 123, "Update works"); + }); +} + +#[test] +fn set_parameters_twice_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + )); + + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(432))), + )); + + assert_eq!(pallet1::Key3::get(), 432, "Update works"); + }); +} + +#[test] +fn set_parameters_removing_restores_default_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + )); + + assert_eq!(pallet1::Key3::get(), 123, "Update works"); + assert!( + crate::Parameters::::contains_key(RuntimeParametersKey::Pallet1( + pallet1::ParametersKey::Key3(pallet1::Key3) + )), + "Key inserted" + ); + + // Removing the value restores the default. + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, None)), + )); + + assert_eq!(pallet1::Key3::get(), 2, "Default restored"); + assert!( + !crate::Parameters::::contains_key(RuntimeParametersKey::Pallet1( + pallet1::ParametersKey::Key3(pallet1::Key3) + )), + "Key removed" + ); + }); +} + +#[test] +fn set_parameters_to_default_emits_events_works() { + new_test_ext().execute_with(|| { + assert_eq!(pallet1::Key3::get(), 2); + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(2))), + )); + assert_eq!(pallet1::Key3::get(), 2); + + assert!( + crate::Parameters::::contains_key(RuntimeParametersKey::Pallet1( + pallet1::ParametersKey::Key3(pallet1::Key3) + )), + "Key inserted" + ); + assert_last_event( + crate::Event::Updated { + key: RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key3(pallet1::Key3)), + old_value: None, + new_value: Some(RuntimeParametersValue::Pallet1(pallet1::ParametersValue::Key3(2))), + } + .into(), + ); + + // It will also emit a second event: + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(2))), + )); + assert_eq!(frame_system::Pallet::::events().len(), 2); + }); +} + +#[test] +fn set_parameters_wrong_origin_errors() { + new_test_ext().execute_with(|| { + // Pallet1 is root origin only: + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(123))), + )); + + assert_noop!( + PalletParameters::set_parameter( + Origin::signed(1), + Pallet1(pallet1::Parameters::Key3(pallet1::Key3, Some(432))), + ), + DispatchError::BadOrigin + ); + + // Pallet2 is signed origin only: + assert_ok!(PalletParameters::set_parameter( + Origin::signed(1), + Pallet2(pallet2::Parameters::Key3(pallet2::Key3, Some(123))), + )); + + assert_noop!( + PalletParameters::set_parameter( + Origin::root(), + Pallet2(pallet2::Parameters::Key3(pallet2::Key3, Some(432))), + ), + DispatchError::BadOrigin + ); + }); +} + +#[test] +fn get_through_external_pallet_works() { + new_test_ext().execute_with(|| { + assert_eq!(::MagicNumber::get(), 0); + + assert_ok!(PalletParameters::set_parameter( + Origin::root(), + Pallet1(pallet1::Parameters::Key1(pallet1::Key1, Some(123))), + )); + + assert_eq!(::MagicNumber::get(), 123); + }); +} + +#[test] +fn test_define_parameters_key_convert() { + let key1 = pallet1::Key1; + let parameter_key: pallet1::ParametersKey = key1.clone().into(); + let key1_2: pallet1::Key1 = parameter_key.clone().try_into().unwrap(); + + assert_eq!(key1, key1_2); + assert_eq!(parameter_key, pallet1::ParametersKey::Key1(key1)); + + let key2 = pallet1::Key2; + let parameter_key: pallet1::ParametersKey = key2.clone().into(); + let key2_2: pallet1::Key2 = parameter_key.clone().try_into().unwrap(); + + assert_eq!(key2, key2_2); + assert_eq!(parameter_key, pallet1::ParametersKey::Key2(key2)); +} + +#[test] +fn test_define_parameters_value_convert() { + let value1 = pallet1::Key1Value(1); + let parameter_value: pallet1::ParametersValue = value1.clone().into(); + let value1_2: pallet1::Key1Value = parameter_value.clone().try_into().unwrap(); + + assert_eq!(value1, value1_2); + assert_eq!(parameter_value, pallet1::ParametersValue::Key1(1)); + + let value2 = pallet1::Key2Value(2); + let parameter_value: pallet1::ParametersValue = value2.clone().into(); + let value2_2: pallet1::Key2Value = parameter_value.clone().try_into().unwrap(); + + assert_eq!(value2, value2_2); + assert_eq!(parameter_value, pallet1::ParametersValue::Key2(2)); +} + +#[test] +fn test_define_parameters_aggregrated_key_value() { + let kv1 = pallet1::Parameters::Key1(pallet1::Key1, None); + let (key1, value1) = kv1.clone().into_parts(); + + assert_eq!(key1, pallet1::ParametersKey::Key1(pallet1::Key1)); + assert_eq!(value1, None); + + let kv2 = pallet1::Parameters::Key2(pallet1::Key2, Some(2)); + let (key2, value2) = kv2.clone().into_parts(); + + assert_eq!(key2, pallet1::ParametersKey::Key2(pallet1::Key2)); + assert_eq!(value2, Some(pallet1::ParametersValue::Key2(2))); +} + +#[test] +fn test_define_aggregrated_parameters_key_convert() { + use codec::Encode; + + let key1 = pallet1::Key1; + let parameter_key: pallet1::ParametersKey = key1.clone().into(); + let runtime_key: RuntimeParametersKey = parameter_key.clone().into(); + + assert_eq!(runtime_key, RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key1(key1))); + assert_eq!(runtime_key.encode(), vec![3, 0]); + + let key2 = pallet2::Key2; + let parameter_key: pallet2::ParametersKey = key2.clone().into(); + let runtime_key: RuntimeParametersKey = parameter_key.clone().into(); + + assert_eq!(runtime_key, RuntimeParametersKey::Pallet2(pallet2::ParametersKey::Key2(key2))); + assert_eq!(runtime_key.encode(), vec![1, 1]); +} + +#[test] +fn test_define_aggregrated_parameters_aggregrated_key_value() { + let kv1 = RuntimeParameters::Pallet1(pallet1::Parameters::Key1(pallet1::Key1, None)); + let (key1, value1) = kv1.clone().into_parts(); + + assert_eq!(key1, RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key1(pallet1::Key1))); + assert_eq!(value1, None); + + let kv2 = RuntimeParameters::Pallet2(pallet2::Parameters::Key2(pallet2::Key2, Some(2))); + let (key2, value2) = kv2.clone().into_parts(); + + assert_eq!(key2, RuntimeParametersKey::Pallet2(pallet2::ParametersKey::Key2(pallet2::Key2))); + assert_eq!(value2, Some(RuntimeParametersValue::Pallet2(pallet2::ParametersValue::Key2(2)))); +} + +#[test] +fn codec_index_works() { + let enc = RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key1(pallet1::Key1)).encode(); + assert_eq!(enc, vec![3, 0]); + let enc = RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key2(pallet1::Key2)).encode(); + assert_eq!(enc, vec![3, 1]); + let enc = RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key3(pallet1::Key3)).encode(); + assert_eq!(enc, vec![3, 2]); + + let enc = RuntimeParametersKey::Pallet2(pallet2::ParametersKey::Key1(pallet2::Key1)).encode(); + assert_eq!(enc, vec![1, 2]); + let enc = RuntimeParametersKey::Pallet2(pallet2::ParametersKey::Key2(pallet2::Key2)).encode(); + assert_eq!(enc, vec![1, 1]); + let enc = RuntimeParametersKey::Pallet2(pallet2::ParametersKey::Key3(pallet2::Key3)).encode(); + assert_eq!(enc, vec![1, 0]); +} diff --git a/substrate/frame/parameters/src/weights.rs b/substrate/frame/parameters/src/weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..340eb9e31b77c507deb1d81794980f856d01971d --- /dev/null +++ b/substrate/frame/parameters/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_parameters` +//! +//! 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_parameters +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/parameters/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_parameters`. +pub trait WeightInfo { + fn set_parameter() -> Weight; +} + +/// Weights for `pallet_parameters` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `Parameters::Parameters` (r:1 w:1) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + fn set_parameter() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3501` + // Minimum execution time: 8_400_000 picoseconds. + Weight::from_parts(8_682_000, 3501) + .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: `Parameters::Parameters` (r:1 w:1) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + fn set_parameter() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3501` + // Minimum execution time: 8_400_000 picoseconds. + Weight::from_parts(8_682_000, 3501) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index 5951663d291423bc5b41213531578d816bc0de4e..10a15f97bd5a72417243b86c81cc7b3ddf1db2a6 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -21,7 +21,7 @@ sp-core = { path = "../../primitives/core", default-features = false, optional = sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] pallet-balances = { path = "../balances" } diff --git a/substrate/frame/preimage/src/lib.rs b/substrate/frame/preimage/src/lib.rs index e344bdfe2d8feff5a25ed686d7301f462fa41189..4e474685166631ba41eed644d3754a332a290663 100644 --- a/substrate/frame/preimage/src/lib.rs +++ b/substrate/frame/preimage/src/lib.rs @@ -102,7 +102,7 @@ pub const MAX_HASH_UPGRADE_BULK_COUNT: u32 = 1024; pub mod pallet { use super::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::config] diff --git a/substrate/frame/preimage/src/mock.rs b/substrate/frame/preimage/src/mock.rs index 60ffecbb448059a375b0778dbfd3d38a3f88c846..a43e8347d76bf219c2f2fe3a36e4505f1d48c4a0 100644 --- a/substrate/frame/preimage/src/mock.rs +++ b/substrate/frame/preimage/src/mock.rs @@ -22,13 +22,12 @@ use super::*; use crate as pallet_preimage; use frame_support::{ derive_impl, ord_parameter_types, parameter_types, - traits::{fungible::HoldConsideration, ConstU32, ConstU64, Everything}, - weights::constants::RocksDbWeight, + traits::{fungible::HoldConsideration, ConstU32, ConstU64}, }; use frame_system::EnsureSignedBy; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, Convert, IdentityLookup}, + traits::{BlakeTwo256, Convert}, BuildStorage, }; @@ -45,29 +44,8 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = RocksDbWeight; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/preimage/src/weights.rs b/substrate/frame/preimage/src/weights.rs index c11ab74c1e551a0fcdd6e239a657ab5df0809aad..6167cd5302918ab0da7f1a243ccfeb4743f23540 100644 --- a/substrate/frame/preimage/src/weights.rs +++ b/substrate/frame/preimage/src/weights.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_preimage` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-06, STEPS: `50`, REPEAT: `20`, 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: `runner-mia4uyug-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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_preimage +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_preimage -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/preimage/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,200 +72,209 @@ impl WeightInfo for SubstrateWeight { /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// 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`) /// 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: `42` - // Estimated: `3556` - // Minimum execution time: 15_936_000 picoseconds. - Weight::from_parts(16_271_000, 3556) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_916, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `112` + // Estimated: `6012` + // Minimum execution time: 48_893_000 picoseconds. + Weight::from_parts(44_072_327, 6012) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_684, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 16_468_000 picoseconds. - Weight::from_parts(17_031_000, 3556) + // Minimum execution time: 15_675_000 picoseconds. + Weight::from_parts(4_564_145, 3556) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_948, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_678, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 16_342_000 picoseconds. - Weight::from_parts(16_535_000, 3556) + // Minimum execution time: 14_959_000 picoseconds. + Weight::from_parts(15_335_000, 3556) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_906, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_687, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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`) /// 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: `172` - // Estimated: `3556` - // Minimum execution time: 31_047_000 picoseconds. - Weight::from_parts(34_099_000, 3556) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `311` + // Estimated: `3658` + // Minimum execution time: 47_378_000 picoseconds. + Weight::from_parts(48_776_000, 3658) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 32_559_000 picoseconds. - Weight::from_parts(36_677_000, 3556) + // Minimum execution time: 20_939_000 picoseconds. + Weight::from_parts(21_577_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `172` + // Measured: `255` // Estimated: `3556` - // Minimum execution time: 27_887_000 picoseconds. - Weight::from_parts(30_303_000, 3556) + // Minimum execution time: 17_945_000 picoseconds. + Weight::from_parts(18_448_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 17_256_000 picoseconds. - Weight::from_parts(19_481_000, 3556) + // Minimum execution time: 12_132_000 picoseconds. + Weight::from_parts(12_710_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `42` + // Measured: `109` // Estimated: `3556` - // Minimum execution time: 22_344_000 picoseconds. - Weight::from_parts(23_868_000, 3556) + // Minimum execution time: 13_014_000 picoseconds. + Weight::from_parts(13_726_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 10_542_000 picoseconds. - Weight::from_parts(11_571_000, 3556) + // Minimum execution time: 9_785_000 picoseconds. + Weight::from_parts(10_266_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 29_054_000 picoseconds. - Weight::from_parts(32_996_000, 3556) + // Minimum execution time: 18_764_000 picoseconds. + Weight::from_parts(19_635_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 10_775_000 picoseconds. - Weight::from_parts(11_937_000, 3556) + // Minimum execution time: 9_624_000 picoseconds. + Weight::from_parts(10_044_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 10_696_000 picoseconds. - Weight::from_parts(11_717_000, 3556) + // Minimum execution time: 9_432_000 picoseconds. + Weight::from_parts(9_991_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Preimage::StatusFor` (r:1024 w:1024) + /// 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:1 w:1) + /// Storage: `System::Account` (r:1023 w:1023) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:0 w:1024) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 1024]`. + /// 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`) + /// 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: `193 + n * (91 ±0)` - // Estimated: `3593 + n * (2566 ±0)` - // Minimum execution time: 2_452_000 picoseconds. - Weight::from_parts(2_641_000, 3593) - // Standard Error: 19_797 - .saturating_add(Weight::from_parts(15_620_946, 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())) + // Measured: `0 + n * (227 ±0)` + // Estimated: `6012 + n * (2668 ±0)` + // Minimum execution time: 54_056_000 picoseconds. + Weight::from_parts(54_912_000, 6012) + // Standard Error: 42_469 + .saturating_add(Weight::from_parts(50_710_258, 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())) } } @@ -272,199 +283,208 @@ impl WeightInfo for () { /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// 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`) /// 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: `42` - // Estimated: `3556` - // Minimum execution time: 15_936_000 picoseconds. - Weight::from_parts(16_271_000, 3556) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_916, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `112` + // Estimated: `6012` + // Minimum execution time: 48_893_000 picoseconds. + Weight::from_parts(44_072_327, 6012) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_684, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 16_468_000 picoseconds. - Weight::from_parts(17_031_000, 3556) + // Minimum execution time: 15_675_000 picoseconds. + Weight::from_parts(4_564_145, 3556) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_948, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_678, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 16_342_000 picoseconds. - Weight::from_parts(16_535_000, 3556) + // Minimum execution time: 14_959_000 picoseconds. + Weight::from_parts(15_335_000, 3556) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_906, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_687, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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`) /// 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: `172` - // Estimated: `3556` - // Minimum execution time: 31_047_000 picoseconds. - Weight::from_parts(34_099_000, 3556) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `311` + // Estimated: `3658` + // Minimum execution time: 47_378_000 picoseconds. + Weight::from_parts(48_776_000, 3658) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 32_559_000 picoseconds. - Weight::from_parts(36_677_000, 3556) + // Minimum execution time: 20_939_000 picoseconds. + Weight::from_parts(21_577_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `172` + // Measured: `255` // Estimated: `3556` - // Minimum execution time: 27_887_000 picoseconds. - Weight::from_parts(30_303_000, 3556) + // Minimum execution time: 17_945_000 picoseconds. + Weight::from_parts(18_448_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 17_256_000 picoseconds. - Weight::from_parts(19_481_000, 3556) + // Minimum execution time: 12_132_000 picoseconds. + Weight::from_parts(12_710_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `42` + // Measured: `109` // Estimated: `3556` - // Minimum execution time: 22_344_000 picoseconds. - Weight::from_parts(23_868_000, 3556) + // Minimum execution time: 13_014_000 picoseconds. + Weight::from_parts(13_726_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 10_542_000 picoseconds. - Weight::from_parts(11_571_000, 3556) + // Minimum execution time: 9_785_000 picoseconds. + Weight::from_parts(10_266_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `144` + // Measured: `211` // Estimated: `3556` - // Minimum execution time: 29_054_000 picoseconds. - Weight::from_parts(32_996_000, 3556) + // Minimum execution time: 18_764_000 picoseconds. + Weight::from_parts(19_635_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 10_775_000 picoseconds. - Weight::from_parts(11_937_000, 3556) + // Minimum execution time: 9_624_000 picoseconds. + Weight::from_parts(10_044_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// 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(75), added: 2550, mode: `MaxEncodedLen`) + /// 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: `106` + // Measured: `173` // Estimated: `3556` - // Minimum execution time: 10_696_000 picoseconds. - Weight::from_parts(11_717_000, 3556) + // Minimum execution time: 9_432_000 picoseconds. + Weight::from_parts(9_991_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Preimage::StatusFor` (r:1024 w:1024) + /// 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:1 w:1) + /// Storage: `System::Account` (r:1023 w:1023) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:0 w:1024) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 1024]`. + /// 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`) + /// 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: `193 + n * (91 ±0)` - // Estimated: `3593 + n * (2566 ±0)` - // Minimum execution time: 2_452_000 picoseconds. - Weight::from_parts(2_641_000, 3593) - // Standard Error: 19_797 - .saturating_add(Weight::from_parts(15_620_946, 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_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) + // Measured: `0 + n * (227 ±0)` + // Estimated: `6012 + n * (2668 ±0)` + // Minimum execution time: 54_056_000 picoseconds. + Weight::from_parts(54_912_000, 6012) + // Standard Error: 42_469 + .saturating_add(Weight::from_parts(50_710_258, 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())) } } diff --git a/substrate/frame/proxy/src/weights.rs b/substrate/frame/proxy/src/weights.rs index f30fe73d27ae665fca89761585226d906fd5112c..3c37c91d500e640d7c36e9b056f193e48162630b 100644 --- a/substrate/frame/proxy/src/weights.rs +++ b/substrate/frame/proxy/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_proxy +//! Autogenerated weights for `pallet_proxy` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/proxy/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/proxy/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_proxy. +/// Weight functions needed for `pallet_proxy`. pub trait WeightInfo { fn proxy(p: u32, ) -> Weight; fn proxy_announced(a: u32, p: u32, ) -> Weight; @@ -64,336 +63,352 @@ pub trait WeightInfo { fn kill_pure(p: u32, ) -> Weight; } -/// Weights for pallet_proxy using the Substrate node and recommended hardware. +/// Weights for `pallet_proxy` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` + // Measured: `306 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 15_182_000 picoseconds. - Weight::from_parts(15_919_146, 4706) - // Standard Error: 1_586 - .saturating_add(Weight::from_parts(31_768, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 18_437_000 picoseconds. + Weight::from_parts(19_610_577, 4706) + // Standard Error: 2_531 + .saturating_add(Weight::from_parts(26_001, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) } - /// 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`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, 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: `488 + a * (68 ±0) + p * (37 ±0)` + // Measured: `633 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 40_256_000 picoseconds. - Weight::from_parts(40_373_648, 5698) - // Standard Error: 3_978 - .saturating_add(Weight::from_parts(166_936, 0).saturating_mul(a.into())) - // Standard Error: 4_110 - .saturating_add(Weight::from_parts(54_329, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 40_426_000 picoseconds. + Weight::from_parts(40_200_295, 5698) + // Standard Error: 2_922 + .saturating_add(Weight::from_parts(161_885, 0).saturating_mul(a.into())) + // Standard Error: 3_019 + .saturating_add(Weight::from_parts(69_710, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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 { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 25_040_000 picoseconds. - Weight::from_parts(25_112_188, 5698) - // Standard Error: 2_143 - .saturating_add(Weight::from_parts(189_027, 0).saturating_mul(a.into())) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(26_683, 0).saturating_mul(p.into())) + // Minimum execution time: 21_905_000 picoseconds. + Weight::from_parts(22_717_430, 5698) + // Standard Error: 2_004 + .saturating_add(Weight::from_parts(153_390, 0).saturating_mul(a.into())) + // Standard Error: 2_071 + .saturating_add(Weight::from_parts(5_676, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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 { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 24_884_000 picoseconds. - Weight::from_parts(25_359_291, 5698) - // Standard Error: 2_019 - .saturating_add(Weight::from_parts(181_470, 0).saturating_mul(a.into())) - // Standard Error: 2_086 - .saturating_add(Weight::from_parts(17_725, 0).saturating_mul(p.into())) + // Minimum execution time: 21_974_000 picoseconds. + Weight::from_parts(22_484_324, 5698) + // Standard Error: 1_846 + .saturating_add(Weight::from_parts(153_904, 0).saturating_mul(a.into())) + // Standard Error: 1_907 + .saturating_add(Weight::from_parts(9_616, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `420 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 35_039_000 picoseconds. - Weight::from_parts(36_727_868, 5698) - // Standard Error: 4_463 - .saturating_add(Weight::from_parts(167_060, 0).saturating_mul(a.into())) - // Standard Error: 4_611 - .saturating_add(Weight::from_parts(59_836, 0).saturating_mul(p.into())) + // Minimum execution time: 30_454_000 picoseconds. + Weight::from_parts(32_128_158, 5698) + // Standard Error: 3_778 + .saturating_add(Weight::from_parts(137_366, 0).saturating_mul(a.into())) + // Standard Error: 3_904 + .saturating_add(Weight::from_parts(53_040, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_697_000 picoseconds. - Weight::from_parts(26_611_090, 4706) - // Standard Error: 2_306 - .saturating_add(Weight::from_parts(85_165, 0).saturating_mul(p.into())) + // Minimum execution time: 21_391_000 picoseconds. + Weight::from_parts(22_202_614, 4706) + // Standard Error: 1_750 + .saturating_add(Weight::from_parts(49_639, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_638_000 picoseconds. - Weight::from_parts(26_904_510, 4706) - // Standard Error: 2_669 - .saturating_add(Weight::from_parts(61_668, 0).saturating_mul(p.into())) + // Minimum execution time: 21_375_000 picoseconds. + Weight::from_parts(22_392_601, 4706) + // Standard Error: 2_415 + .saturating_add(Weight::from_parts(40_345, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 22_737_000 picoseconds. - Weight::from_parts(23_618_441, 4706) - // Standard Error: 1_729 - .saturating_add(Weight::from_parts(44_009, 0).saturating_mul(p.into())) + // Minimum execution time: 19_833_000 picoseconds. + Weight::from_parts(20_839_747, 4706) + // Standard Error: 1_742 + .saturating_add(Weight::from_parts(40_874, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `173` // Estimated: `4706` - // Minimum execution time: 27_364_000 picoseconds. - Weight::from_parts(28_632_271, 4706) - // Standard Error: 1_613 - .saturating_add(Weight::from_parts(2_453, 0).saturating_mul(p.into())) + // Minimum execution time: 22_231_000 picoseconds. + Weight::from_parts(23_370_995, 4706) + // Standard Error: 1_521 + .saturating_add(Weight::from_parts(4_892, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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: `198 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 23_552_000 picoseconds. - Weight::from_parts(24_874_553, 4706) - // Standard Error: 1_919 - .saturating_add(Weight::from_parts(38_799, 0).saturating_mul(p.into())) + // Minimum execution time: 20_614_000 picoseconds. + Weight::from_parts(21_845_970, 4706) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(34_480, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` + // Measured: `306 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 15_182_000 picoseconds. - Weight::from_parts(15_919_146, 4706) - // Standard Error: 1_586 - .saturating_add(Weight::from_parts(31_768, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 18_437_000 picoseconds. + Weight::from_parts(19_610_577, 4706) + // Standard Error: 2_531 + .saturating_add(Weight::from_parts(26_001, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) } - /// 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`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, 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: `488 + a * (68 ±0) + p * (37 ±0)` + // Measured: `633 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 40_256_000 picoseconds. - Weight::from_parts(40_373_648, 5698) - // Standard Error: 3_978 - .saturating_add(Weight::from_parts(166_936, 0).saturating_mul(a.into())) - // Standard Error: 4_110 - .saturating_add(Weight::from_parts(54_329, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 40_426_000 picoseconds. + Weight::from_parts(40_200_295, 5698) + // Standard Error: 2_922 + .saturating_add(Weight::from_parts(161_885, 0).saturating_mul(a.into())) + // Standard Error: 3_019 + .saturating_add(Weight::from_parts(69_710, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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 { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 25_040_000 picoseconds. - Weight::from_parts(25_112_188, 5698) - // Standard Error: 2_143 - .saturating_add(Weight::from_parts(189_027, 0).saturating_mul(a.into())) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(26_683, 0).saturating_mul(p.into())) + // Minimum execution time: 21_905_000 picoseconds. + Weight::from_parts(22_717_430, 5698) + // Standard Error: 2_004 + .saturating_add(Weight::from_parts(153_390, 0).saturating_mul(a.into())) + // Standard Error: 2_071 + .saturating_add(Weight::from_parts(5_676, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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 { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 24_884_000 picoseconds. - Weight::from_parts(25_359_291, 5698) - // Standard Error: 2_019 - .saturating_add(Weight::from_parts(181_470, 0).saturating_mul(a.into())) - // Standard Error: 2_086 - .saturating_add(Weight::from_parts(17_725, 0).saturating_mul(p.into())) + // Minimum execution time: 21_974_000 picoseconds. + Weight::from_parts(22_484_324, 5698) + // Standard Error: 1_846 + .saturating_add(Weight::from_parts(153_904, 0).saturating_mul(a.into())) + // Standard Error: 1_907 + .saturating_add(Weight::from_parts(9_616, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `420 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 35_039_000 picoseconds. - Weight::from_parts(36_727_868, 5698) - // Standard Error: 4_463 - .saturating_add(Weight::from_parts(167_060, 0).saturating_mul(a.into())) - // Standard Error: 4_611 - .saturating_add(Weight::from_parts(59_836, 0).saturating_mul(p.into())) + // Minimum execution time: 30_454_000 picoseconds. + Weight::from_parts(32_128_158, 5698) + // Standard Error: 3_778 + .saturating_add(Weight::from_parts(137_366, 0).saturating_mul(a.into())) + // Standard Error: 3_904 + .saturating_add(Weight::from_parts(53_040, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_697_000 picoseconds. - Weight::from_parts(26_611_090, 4706) - // Standard Error: 2_306 - .saturating_add(Weight::from_parts(85_165, 0).saturating_mul(p.into())) + // Minimum execution time: 21_391_000 picoseconds. + Weight::from_parts(22_202_614, 4706) + // Standard Error: 1_750 + .saturating_add(Weight::from_parts(49_639, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_638_000 picoseconds. - Weight::from_parts(26_904_510, 4706) - // Standard Error: 2_669 - .saturating_add(Weight::from_parts(61_668, 0).saturating_mul(p.into())) + // Minimum execution time: 21_375_000 picoseconds. + Weight::from_parts(22_392_601, 4706) + // Standard Error: 2_415 + .saturating_add(Weight::from_parts(40_345, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 22_737_000 picoseconds. - Weight::from_parts(23_618_441, 4706) - // Standard Error: 1_729 - .saturating_add(Weight::from_parts(44_009, 0).saturating_mul(p.into())) + // Minimum execution time: 19_833_000 picoseconds. + Weight::from_parts(20_839_747, 4706) + // Standard Error: 1_742 + .saturating_add(Weight::from_parts(40_874, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `173` // Estimated: `4706` - // Minimum execution time: 27_364_000 picoseconds. - Weight::from_parts(28_632_271, 4706) - // Standard Error: 1_613 - .saturating_add(Weight::from_parts(2_453, 0).saturating_mul(p.into())) + // Minimum execution time: 22_231_000 picoseconds. + Weight::from_parts(23_370_995, 4706) + // Standard Error: 1_521 + .saturating_add(Weight::from_parts(4_892, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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: `198 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 23_552_000 picoseconds. - Weight::from_parts(24_874_553, 4706) - // Standard Error: 1_919 - .saturating_add(Weight::from_parts(38_799, 0).saturating_mul(p.into())) + // Minimum execution time: 20_614_000 picoseconds. + Weight::from_parts(21_845_970, 4706) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(34_480, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 62e01df372bdef15e9f2ee3e43ce4dc5a06044eb..54e84c0b55887d55017f8c16447424a594185f10 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/ranked-collective/src/benchmarking.rs b/substrate/frame/ranked-collective/src/benchmarking.rs index f093fd93e6e2b7b991de3f4b41e8c9b2004d47f6..462f55a238d2a867f900e4653369e5fa9368d874 100644 --- a/substrate/frame/ranked-collective/src/benchmarking.rs +++ b/substrate/frame/ranked-collective/src/benchmarking.rs @@ -181,5 +181,5 @@ benchmarks_instance_pallet! { assert_has_event::(Event::MemberExchanged { who, new_who }.into()); } - impl_benchmark_test_suite!(RankedCollective, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(RankedCollective, crate::tests::ExtBuilder::default().build(), crate::tests::Test); } diff --git a/substrate/frame/ranked-collective/src/lib.rs b/substrate/frame/ranked-collective/src/lib.rs index 65ea886acc4fa099af9496a015412a98b6150e2f..ceaf03de211008ee49bf4a4a1fc961bf8825971a 100644 --- a/substrate/frame/ranked-collective/src/lib.rs +++ b/substrate/frame/ranked-collective/src/lib.rs @@ -39,7 +39,6 @@ //! least a particular rank. #![cfg_attr(not(feature = "std"), no_std)] -#![recursion_limit = "128"] use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -716,6 +715,14 @@ pub mod pallet { } } + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } + } + impl, I: 'static> Pallet { fn ensure_member(who: &T::AccountId) -> Result { Members::::get(who).ok_or(Error::::NotMember.into()) @@ -847,6 +854,132 @@ pub mod pallet { } } + #[cfg(any(feature = "try-runtime", test))] + impl, I: 'static> Pallet { + /// Ensure the correctness of the state of this pallet. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + Self::try_state_members()?; + Self::try_state_index()?; + + Ok(()) + } + + /// ### Invariants of Member storage items + /// + /// Total number of [`Members`] in storage should be >= [`MemberIndex`] of a [`Rank`] in + /// [`MemberCount`]. + /// [`Rank`] in Members should be in [`MemberCount`] + /// [`Sum`] of [`MemberCount`] index should be the same as the sum of all the index attained + /// for rank possessed by [`Members`] + fn try_state_members() -> Result<(), sp_runtime::TryRuntimeError> { + MemberCount::::iter().try_for_each(|(_, member_index)| -> DispatchResult { + let total_members = Members::::iter().count(); + ensure!( + total_members as u32 >= member_index, + "Total count of `Members` should be greater than or equal to the number of `MemberIndex` of a particular `Rank` in `MemberCount`." + ); + + Ok(()) + })?; + + let mut sum_of_member_rank_indexes = 0; + Members::::iter().try_for_each(|(_, member_record)| -> DispatchResult { + ensure!( + Self::is_rank_in_member_count(member_record.rank.into()), + "`Rank` in Members should be in `MemberCount`" + ); + + sum_of_member_rank_indexes += Self::determine_index_of_a_rank(member_record.rank); + + Ok(()) + })?; + + let sum_of_all_member_count_indexes = + MemberCount::::iter_values().fold(0, |sum, index| sum + index); + ensure!( + sum_of_all_member_count_indexes == sum_of_member_rank_indexes as u32, + "Sum of `MemberCount` index should be the same as the sum of all the index attained for rank possessed by `Members`" + ); + Ok(()) + } + + /// ### Invariants of Index storage items + /// [`Member`] in storage of [`IdToIndex`] should be the same as [`Member`] in [`IndexToId`] + /// [`Rank`] in [`IdToIndex`] should be the same as the the [`Rank`] in [`IndexToId`] + /// [`Rank`] of the member [`who`] in [`IdToIndex`] should be the same as the [`Rank`] of + /// the member [`who`] in [`Members`] + fn try_state_index() -> Result<(), sp_runtime::TryRuntimeError> { + IdToIndex::::iter().try_for_each( + |(rank, who, member_index)| -> DispatchResult { + let who_from_index = IndexToId::::get(rank, member_index).unwrap(); + ensure!( + who == who_from_index, + "`Member` in storage of `IdToIndex` should be the same as `Member` in `IndexToId`." + ); + + ensure!( + Self::is_rank_in_index_to_id_storage(rank.into()), + "`Rank` in `IdToIndex` should be the same as the `Rank` in `IndexToId`" + ); + Ok(()) + }, + )?; + + Members::::iter().try_for_each(|(who, member_record)| -> DispatchResult { + ensure!( + Self::is_who_rank_in_id_to_index_storage(who, member_record.rank), + "`Rank` of the member `who` in `IdToIndex` should be the same as the `Rank` of the member `who` in `Members`" + ); + + Ok(()) + })?; + + Ok(()) + } + + /// Checks if a rank is part of the `MemberCount` + fn is_rank_in_member_count(rank: u32) -> bool { + for (r, _) in MemberCount::::iter() { + if r as u32 == rank { + return true; + } + } + + return false; + } + + /// Checks if a rank is the same as the rank `IndexToId` + fn is_rank_in_index_to_id_storage(rank: u32) -> bool { + for (r, _, _) in IndexToId::::iter() { + if r as u32 == rank { + return true; + } + } + + return false; + } + + /// Checks if a member(who) rank is the same as the rank of a member(who) in `IdToIndex` + fn is_who_rank_in_id_to_index_storage(who: T::AccountId, rank: u16) -> bool { + for (rank_, who_, _) in IdToIndex::::iter() { + if who == who_ && rank == rank_ { + return true; + } + } + + return false; + } + + /// Determines the total index for a rank + fn determine_index_of_a_rank(rank: u16) -> u16 { + let mut sum = 0; + for _ in 0..rank + 1 { + sum += 1; + } + sum + } + } + impl, I: 'static> RankedMembers for Pallet { type AccountId = T::AccountId; type Rank = Rank; diff --git a/substrate/frame/ranked-collective/src/tests.rs b/substrate/frame/ranked-collective/src/tests.rs index c5fccd3f7724550fcc9ae12eabef6bf492c5abe4..31add52d90afa9c8756be88b425a08b453b60892 100644 --- a/substrate/frame/ranked-collective/src/tests.rs +++ b/substrate/frame/ranked-collective/src/tests.rs @@ -183,11 +183,28 @@ impl Config for Test { type BenchmarkSetup = (); } -pub fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext +pub struct ExtBuilder {} + +impl Default for ExtBuilder { + fn default() -> Self { + Self {} + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + 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 + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + Club::do_try_state().expect("All invariants must hold after a test"); + }) + } } fn next_block() { @@ -225,14 +242,14 @@ fn completed_poll_should_panic() { #[test] fn basic_stuff() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); }); } #[test] fn member_lifecycle_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); @@ -244,7 +261,7 @@ fn member_lifecycle_works() { #[test] fn add_remove_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_noop!(Club::add_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); @@ -274,7 +291,7 @@ fn add_remove_works() { #[test] fn promote_demote_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_noop!(Club::add_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); @@ -305,7 +322,7 @@ fn promote_demote_works() { #[test] fn promote_demote_by_rank_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); for _ in 0..7 { assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); @@ -372,7 +389,7 @@ fn promote_demote_by_rank_works() { #[test] fn voting_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 0)); assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); @@ -406,7 +423,7 @@ fn voting_works() { #[test] fn cleanup_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); @@ -433,7 +450,7 @@ fn cleanup_works() { #[test] fn remove_member_cleanup_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); @@ -459,7 +476,7 @@ fn remove_member_cleanup_works() { #[test] fn ensure_ranked_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); @@ -528,7 +545,7 @@ fn ensure_ranked_works() { #[test] fn do_add_member_to_rank_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let max_rank = 9u16; assert_ok!(Club::do_add_member_to_rank(69, max_rank / 2, true)); assert_ok!(Club::do_add_member_to_rank(1337, max_rank, true)); @@ -545,7 +562,7 @@ fn do_add_member_to_rank_works() { #[test] fn tally_support_correct() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { // add members, // rank 1: accounts 1, 2, 3 // rank 2: accounts 2, 3 @@ -585,7 +602,7 @@ fn tally_support_correct() { #[test] fn exchange_member_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); @@ -613,7 +630,7 @@ fn exchange_member_works() { #[test] fn exchange_member_same_noops() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); diff --git a/substrate/frame/ranked-collective/src/weights.rs b/substrate/frame/ranked-collective/src/weights.rs index 4ff0c3337d503fd66de4400ca40631cfcca300d9..5721858f7e2f1d53ada65c2adc689dc9bd8c5a3d 100644 --- a/substrate/frame/ranked-collective/src/weights.rs +++ b/substrate/frame/ranked-collective/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_ranked_collective +//! Autogenerated weights for `pallet_ranked_collective` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/ranked-collective/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/ranked-collective/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_ranked_collective. +/// Weight functions needed for `pallet_ranked_collective`. pub trait WeightInfo { fn add_member() -> Weight; fn remove_member(r: u32, ) -> Weight; @@ -61,283 +60,295 @@ pub trait WeightInfo { fn exchange_member() -> Weight; } -/// Weights for pallet_ranked_collective using the Substrate node and recommended hardware. +/// Weights for `pallet_ranked_collective` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3507` - // Minimum execution time: 17_245_000 picoseconds. - Weight::from_parts(17_930_000, 3507) + // Minimum execution time: 15_389_000 picoseconds. + Weight::from_parts(15_901_000, 3507) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:11 w:11) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:11 w:11) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:11 w:11) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:11 w:11) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:11 w:22) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:11 w:22) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `616 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 29_534_000 picoseconds. - Weight::from_parts(32_847_495, 3519) - // Standard Error: 24_211 - .saturating_add(Weight::from_parts(13_949_639, 0).saturating_mul(r.into())) + // Minimum execution time: 29_541_000 picoseconds. + Weight::from_parts(32_239_358, 3519) + // Standard Error: 23_406 + .saturating_add(Weight::from_parts(16_030_191, 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(4_u64)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `314 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 20_333_000 picoseconds. - Weight::from_parts(21_592_224, 3507) - // Standard Error: 6_423 - .saturating_add(Weight::from_parts(321_314, 0).saturating_mul(r.into())) + // Minimum execution time: 17_939_000 picoseconds. + Weight::from_parts(19_290_416, 3507) + // Standard Error: 5_710 + .saturating_add(Weight::from_parts(374_399, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:1 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:1 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:1 w:2) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:1 w:2) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `632 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 29_446_000 picoseconds. - Weight::from_parts(32_447_715, 3519) - // Standard Error: 28_791 - .saturating_add(Weight::from_parts(822_890, 0).saturating_mul(r.into())) + // Minimum execution time: 29_609_000 picoseconds. + Weight::from_parts(32_686_167, 3519) + // Standard Error: 27_588 + .saturating_add(Weight::from_parts(789_212, 0).saturating_mul(r.into())) .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: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedPolls ReferendumInfoFor (r:1 w:1) - /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) - /// Storage: RankedCollective Voting (r:1 w:1) - /// Proof: RankedCollective 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:1) + /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Voting` (r:1 w:1) + /// Proof: `RankedCollective::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(107022), added: 109497, 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: `628` // Estimated: `219984` - // Minimum execution time: 45_474_000 picoseconds. - Weight::from_parts(47_228_000, 219984) + // Minimum execution time: 41_151_000 picoseconds. + Weight::from_parts(42_435_000, 219984) .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: RankedPolls ReferendumInfoFor (r:1 w:0) - /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) - /// Storage: RankedCollective VotingCleanup (r:1 w:0) - /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: RankedCollective Voting (r:100 w:100) - /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:0) + /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::VotingCleanup` (r:1 w:0) + /// Proof: `RankedCollective::VotingCleanup` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Voting` (r:100 w:100) + /// Proof: `RankedCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `462 + n * (50 ±0)` // Estimated: `3795 + n * (2540 ±0)` - // Minimum execution time: 13_903_000 picoseconds. - Weight::from_parts(18_209_102, 3795) - // Standard Error: 2_556 - .saturating_add(Weight::from_parts(1_237_454, 0).saturating_mul(n.into())) + // Minimum execution time: 13_563_000 picoseconds. + Weight::from_parts(17_495_215, 3795) + // Standard Error: 2_294 + .saturating_add(Weight::from_parts(1_207_393, 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()))) .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) } - /// Storage: `RankedCollective::Members` (r:2 w:2) /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::MemberCount` (r:2 w:2) /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:2 w:2) + /// Storage: `RankedCollective::IdToIndex` (r:2 w:4) /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:2 w:2) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:0) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:2 w:2) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::IndexToId` (r:0 w:2) /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn exchange_member() -> Weight { // Proof Size summary in bytes: - // Measured: `437` - // Estimated: `6048` - // Minimum execution time: 138_000_000 picoseconds. - Weight::from_parts(141_000_000, 0) - .saturating_add(Weight::from_parts(0, 6048)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `625` + // Estimated: `19894` + // Minimum execution time: 70_713_000 picoseconds. + Weight::from_parts(72_831_000, 19894) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(14_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3507` - // Minimum execution time: 17_245_000 picoseconds. - Weight::from_parts(17_930_000, 3507) + // Minimum execution time: 15_389_000 picoseconds. + Weight::from_parts(15_901_000, 3507) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:11 w:11) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:11 w:11) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:11 w:11) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:11 w:11) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:11 w:22) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:11 w:22) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `616 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 29_534_000 picoseconds. - Weight::from_parts(32_847_495, 3519) - // Standard Error: 24_211 - .saturating_add(Weight::from_parts(13_949_639, 0).saturating_mul(r.into())) + // Minimum execution time: 29_541_000 picoseconds. + Weight::from_parts(32_239_358, 3519) + // Standard Error: 23_406 + .saturating_add(Weight::from_parts(16_030_191, 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(4_u64)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:0 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:0 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:0 w:1) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `314 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 20_333_000 picoseconds. - Weight::from_parts(21_592_224, 3507) - // Standard Error: 6_423 - .saturating_add(Weight::from_parts(321_314, 0).saturating_mul(r.into())) + // Minimum execution time: 17_939_000 picoseconds. + Weight::from_parts(19_290_416, 3507) + // Standard Error: 5_710 + .saturating_add(Weight::from_parts(374_399, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: RankedCollective Members (r:1 w:1) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedCollective MemberCount (r:1 w:1) - /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: RankedCollective IdToIndex (r:1 w:1) - /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: RankedCollective IndexToId (r:1 w:1) - /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:1) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::MemberCount` (r:1 w:1) + /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IdToIndex` (r:1 w:2) + /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::IndexToId` (r:1 w:2) + /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `632 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 29_446_000 picoseconds. - Weight::from_parts(32_447_715, 3519) - // Standard Error: 28_791 - .saturating_add(Weight::from_parts(822_890, 0).saturating_mul(r.into())) + // Minimum execution time: 29_609_000 picoseconds. + Weight::from_parts(32_686_167, 3519) + // Standard Error: 27_588 + .saturating_add(Weight::from_parts(789_212, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: RankedPolls ReferendumInfoFor (r:1 w:1) - /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) - /// Storage: RankedCollective Voting (r:1 w:1) - /// Proof: RankedCollective 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:1) + /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Voting` (r:1 w:1) + /// Proof: `RankedCollective::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(107022), added: 109497, 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: `628` // Estimated: `219984` - // Minimum execution time: 45_474_000 picoseconds. - Weight::from_parts(47_228_000, 219984) + // Minimum execution time: 41_151_000 picoseconds. + Weight::from_parts(42_435_000, 219984) .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: RankedPolls ReferendumInfoFor (r:1 w:0) - /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) - /// Storage: RankedCollective VotingCleanup (r:1 w:0) - /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: RankedCollective Voting (r:100 w:100) - /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:0) + /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::VotingCleanup` (r:1 w:0) + /// Proof: `RankedCollective::VotingCleanup` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Voting` (r:100 w:100) + /// Proof: `RankedCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `462 + n * (50 ±0)` // Estimated: `3795 + n * (2540 ±0)` - // Minimum execution time: 13_903_000 picoseconds. - Weight::from_parts(18_209_102, 3795) - // Standard Error: 2_556 - .saturating_add(Weight::from_parts(1_237_454, 0).saturating_mul(n.into())) + // Minimum execution time: 13_563_000 picoseconds. + Weight::from_parts(17_495_215, 3795) + // Standard Error: 2_294 + .saturating_add(Weight::from_parts(1_207_393, 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()))) .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) } - /// Storage: `RankedCollective::Members` (r:2 w:2) /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::MemberCount` (r:2 w:2) /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:2 w:2) + /// Storage: `RankedCollective::IdToIndex` (r:2 w:4) /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::Member` (r:2 w:2) + /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:0) + /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:2 w:2) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::IndexToId` (r:0 w:2) /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn exchange_member() -> Weight { // Proof Size summary in bytes: - // Measured: `437` - // Estimated: `6048` - // Minimum execution time: 138_000_000 picoseconds. - Weight::from_parts(141_000_000, 0) - .saturating_add(Weight::from_parts(0, 6048)) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(8)) + // Measured: `625` + // Estimated: `19894` + // Minimum execution time: 70_713_000 picoseconds. + Weight::from_parts(72_831_000, 19894) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(14_u64)) } } diff --git a/substrate/frame/recovery/src/mock.rs b/substrate/frame/recovery/src/mock.rs index ba7958f7dd460af9c6d7f3831c73d41f363268a2..89374527e069c4eac7eac1173502768d1cef684d 100644 --- a/substrate/frame/recovery/src/mock.rs +++ b/substrate/frame/recovery/src/mock.rs @@ -22,13 +22,9 @@ use super::*; use crate as recovery; use frame_support::{ derive_impl, parameter_types, - traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, -}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + traits::{OnFinalize, OnInitialize}, }; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -43,29 +39,8 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } parameter_types! { diff --git a/substrate/frame/recovery/src/weights.rs b/substrate/frame/recovery/src/weights.rs index 84b19ae694eec1107b9229c1894646cb8368bc0d..fe5dbcfc2222d2a53cf1f6d7438bb2175470d1f2 100644 --- a/substrate/frame/recovery/src/weights.rs +++ b/substrate/frame/recovery/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_recovery +//! Autogenerated weights for `pallet_recovery` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/recovery/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/recovery/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_recovery. +/// Weight functions needed for `pallet_recovery`. pub trait WeightInfo { fn as_recovered() -> Weight; fn set_recovered() -> Weight; @@ -63,258 +62,266 @@ pub trait WeightInfo { fn cancel_recovered() -> Weight; } -/// Weights for pallet_recovery using the Substrate node and recommended hardware. +/// Weights for `pallet_recovery` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Recovery Proxy (r:1 w:0) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: `Recovery::Proxy` (r:1 w:0) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `3545` - // Minimum execution time: 9_360_000 picoseconds. - Weight::from_parts(9_773_000, 3545) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `497` + // Estimated: `3997` + // Minimum execution time: 14_898_000 picoseconds. + Weight::from_parts(15_464_000, 3997) + .saturating_add(T::DbWeight::get().reads(3_u64)) } - /// Storage: Recovery Proxy (r:0 w:1) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: 9_146_000 picoseconds. - Weight::from_parts(9_507_000, 0) + // Minimum execution time: 7_424_000 picoseconds. + Weight::from_parts(7_830_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Recovery Recoverable (r:1 w:1) - /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, 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 create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `175` + // Measured: `246` // Estimated: `3816` - // Minimum execution time: 26_472_000 picoseconds. - Weight::from_parts(27_917_651, 3816) - // Standard Error: 7_129 - .saturating_add(Weight::from_parts(59_239, 0).saturating_mul(n.into())) + // Minimum execution time: 21_968_000 picoseconds. + Weight::from_parts(23_594_232, 3816) + // Standard Error: 5_848 + .saturating_add(Weight::from_parts(24_843, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `272` + // Measured: `343` // Estimated: `3854` - // Minimum execution time: 29_618_000 picoseconds. - Weight::from_parts(30_192_000, 3854) + // Minimum execution time: 25_494_000 picoseconds. + Weight::from_parts(26_290_000, 3854) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `360 + n * (64 ±0)` + // Measured: `431 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 19_464_000 picoseconds. - Weight::from_parts(20_642_522, 3854) - // Standard Error: 5_974 - .saturating_add(Weight::from_parts(142_308, 0).saturating_mul(n.into())) + // Minimum execution time: 17_044_000 picoseconds. + Weight::from_parts(18_299_617, 3854) + // Standard Error: 5_580 + .saturating_add(Weight::from_parts(187_568, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `392 + n * (64 ±0)` + // Measured: `463 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 23_656_000 picoseconds. - Weight::from_parts(24_903_269, 3854) - // Standard Error: 5_771 - .saturating_add(Weight::from_parts(117_343, 0).saturating_mul(n.into())) + // Minimum execution time: 22_186_000 picoseconds. + Weight::from_parts(23_476_807, 3854) + // Standard Error: 6_392 + .saturating_add(Weight::from_parts(89_770, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `513 + n * (32 ±0)` + // Measured: `584 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 34_866_000 picoseconds. - Weight::from_parts(36_368_748, 3854) - // Standard Error: 6_600 - .saturating_add(Weight::from_parts(118_610, 0).saturating_mul(n.into())) + // Minimum execution time: 31_045_000 picoseconds. + Weight::from_parts(32_623_578, 3854) + // Standard Error: 7_203 + .saturating_add(Weight::from_parts(61_466, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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) + /// 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: `270 + n * (32 ±0)` + // Measured: `341 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 31_405_000 picoseconds. - Weight::from_parts(32_552_838, 3854) - // Standard Error: 8_043 - .saturating_add(Weight::from_parts(171_605, 0).saturating_mul(n.into())) + // Minimum execution time: 27_925_000 picoseconds. + Weight::from_parts(29_258_264, 3854) + // Standard Error: 8_192 + .saturating_add(Weight::from_parts(128_124, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Recovery Proxy (r:1 w:1) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: `281` + // Measured: `352` // Estimated: `3545` - // Minimum execution time: 11_530_000 picoseconds. - Weight::from_parts(11_851_000, 3545) + // Minimum execution time: 11_623_000 picoseconds. + Weight::from_parts(12_043_000, 3545) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Recovery Proxy (r:1 w:0) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: `Recovery::Proxy` (r:1 w:0) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `3545` - // Minimum execution time: 9_360_000 picoseconds. - Weight::from_parts(9_773_000, 3545) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `497` + // Estimated: `3997` + // Minimum execution time: 14_898_000 picoseconds. + Weight::from_parts(15_464_000, 3997) + .saturating_add(RocksDbWeight::get().reads(3_u64)) } - /// Storage: Recovery Proxy (r:0 w:1) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: 9_146_000 picoseconds. - Weight::from_parts(9_507_000, 0) + // Minimum execution time: 7_424_000 picoseconds. + Weight::from_parts(7_830_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Recovery Recoverable (r:1 w:1) - /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, 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 create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `175` + // Measured: `246` // Estimated: `3816` - // Minimum execution time: 26_472_000 picoseconds. - Weight::from_parts(27_917_651, 3816) - // Standard Error: 7_129 - .saturating_add(Weight::from_parts(59_239, 0).saturating_mul(n.into())) + // Minimum execution time: 21_968_000 picoseconds. + Weight::from_parts(23_594_232, 3816) + // Standard Error: 5_848 + .saturating_add(Weight::from_parts(24_843, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `272` + // Measured: `343` // Estimated: `3854` - // Minimum execution time: 29_618_000 picoseconds. - Weight::from_parts(30_192_000, 3854) + // Minimum execution time: 25_494_000 picoseconds. + Weight::from_parts(26_290_000, 3854) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `360 + n * (64 ±0)` + // Measured: `431 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 19_464_000 picoseconds. - Weight::from_parts(20_642_522, 3854) - // Standard Error: 5_974 - .saturating_add(Weight::from_parts(142_308, 0).saturating_mul(n.into())) + // Minimum execution time: 17_044_000 picoseconds. + Weight::from_parts(18_299_617, 3854) + // Standard Error: 5_580 + .saturating_add(Weight::from_parts(187_568, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `392 + n * (64 ±0)` + // Measured: `463 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 23_656_000 picoseconds. - Weight::from_parts(24_903_269, 3854) - // Standard Error: 5_771 - .saturating_add(Weight::from_parts(117_343, 0).saturating_mul(n.into())) + // Minimum execution time: 22_186_000 picoseconds. + Weight::from_parts(23_476_807, 3854) + // Standard Error: 6_392 + .saturating_add(Weight::from_parts(89_770, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// 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: `513 + n * (32 ±0)` + // Measured: `584 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 34_866_000 picoseconds. - Weight::from_parts(36_368_748, 3854) - // Standard Error: 6_600 - .saturating_add(Weight::from_parts(118_610, 0).saturating_mul(n.into())) + // Minimum execution time: 31_045_000 picoseconds. + Weight::from_parts(32_623_578, 3854) + // Standard Error: 7_203 + .saturating_add(Weight::from_parts(61_466, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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) + /// 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: `270 + n * (32 ±0)` + // Measured: `341 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 31_405_000 picoseconds. - Weight::from_parts(32_552_838, 3854) - // Standard Error: 8_043 - .saturating_add(Weight::from_parts(171_605, 0).saturating_mul(n.into())) + // Minimum execution time: 27_925_000 picoseconds. + Weight::from_parts(29_258_264, 3854) + // Standard Error: 8_192 + .saturating_add(Weight::from_parts(128_124, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Recovery Proxy (r:1 w:1) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: `281` + // Measured: `352` // Estimated: `3545` - // Minimum execution time: 11_530_000 picoseconds. - Weight::from_parts(11_851_000, 3545) + // Minimum execution time: 11_623_000 picoseconds. + Weight::from_parts(12_043_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 0f8a92ff72a6ebb7094e6dca9634f853346f2e6c..2dfb25a2fd3a5b50bdc7828e50c8e247cd7f936a 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", features = ["derive"], optional = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } @@ -29,7 +29,7 @@ frame-system = { path = "../system", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] assert_matches = { version = "1.5" } diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs index 8912f9ad217371846fc193f495ff1e49b0d18f00..e616056c3022abe796cd494e91fa4e9565843e60 100644 --- a/substrate/frame/referenda/src/lib.rs +++ b/substrate/frame/referenda/src/lib.rs @@ -143,7 +143,7 @@ pub mod pallet { use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg}; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] @@ -433,6 +433,11 @@ pub mod pallet { Self::do_try_state()?; Ok(()) } + + #[cfg(any(feature = "std", test))] + fn integrity_test() { + T::Tracks::check_integrity().expect("Static tracks configuration is valid."); + } } #[pallet::call] diff --git a/substrate/frame/referenda/src/migration.rs b/substrate/frame/referenda/src/migration.rs index a80897242eec67aad194f8deaf1cd6527533eab9..631eb7340e567e8115e1755d513980fb148700c5 100644 --- a/substrate/frame/referenda/src/migration.rs +++ b/substrate/frame/referenda/src/migration.rs @@ -109,16 +109,16 @@ pub mod v1 { } fn on_runtime_upgrade() -> Weight { - let current_version = Pallet::::current_storage_version(); - let onchain_version = Pallet::::on_chain_storage_version(); + let in_code_version = Pallet::::in_code_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); let mut weight = T::DbWeight::get().reads(1); log::info!( target: TARGET, - "running migration with current storage version {:?} / onchain {:?}.", - current_version, - onchain_version + "running migration with in-code storage version {:?} / onchain {:?}.", + in_code_version, + on_chain_version ); - if onchain_version != 0 { + if on_chain_version != 0 { log::warn!(target: TARGET, "skipping migration from v0 to v1."); return weight } @@ -149,8 +149,8 @@ pub mod v1 { #[cfg(feature = "try-runtime")] fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { - let onchain_version = Pallet::::on_chain_storage_version(); - ensure!(onchain_version == 1, "must upgrade from version 0 to 1."); + let on_chain_version = Pallet::::on_chain_storage_version(); + ensure!(on_chain_version == 1, "must upgrade from version 0 to 1."); let pre_referendum_count: u32 = Decode::decode(&mut &state[..]) .expect("failed to decode the state from pre-upgrade."); let post_referendum_count = ReferendumInfoFor::::iter().count() as u32; diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index d9f9042fefc9fd9104feea2637224ad496b04590..bfafc107c28bc4ba422d6409b861f60a6c1d26d9 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -29,9 +29,8 @@ use frame_support::{ weights::Weight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, Hash, IdentityLookup}, + traits::{BlakeTwo256, Hash}, BuildStorage, DispatchResult, Perbill, }; @@ -62,28 +61,8 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_preimage::Config for Test { type RuntimeEvent = RuntimeEvent; diff --git a/substrate/frame/referenda/src/types.rs b/substrate/frame/referenda/src/types.rs index 0a8fb4ff8200d2074a35bec00227466bd3fbc842..b3c583322cce384bae7e2a9340071d5af6b2f455 100644 --- a/substrate/frame/referenda/src/types.rs +++ b/substrate/frame/referenda/src/types.rs @@ -144,7 +144,10 @@ pub trait TracksInfo { /// The origin type from which a track is implied. type RuntimeOrigin; - /// Return the array of known tracks and their information. + /// Sorted array of known tracks and their information. + /// + /// The array MUST be sorted by `Id`. Consumers of this trait are advised to assert + /// [`Self::check_integrity`] prior to any use. fn tracks() -> &'static [(Self::Id, TrackInfo)]; /// Determine the voting track for the given `origin`. @@ -152,7 +155,23 @@ pub trait TracksInfo { /// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`. fn info(id: Self::Id) -> Option<&'static TrackInfo> { - Self::tracks().iter().find(|x| x.0 == id).map(|x| &x.1) + let tracks = Self::tracks(); + let maybe_index = tracks.binary_search_by_key(&id, |t| t.0).ok()?; + + tracks.get(maybe_index).map(|(_, info)| info) + } + + /// Check assumptions about the static data that this trait provides. + fn check_integrity() -> Result<(), &'static str> + where + Balance: 'static, + Moment: 'static, + { + if Self::tracks().windows(2).all(|w| w[0].0 < w[1].0) { + Ok(()) + } else { + Err("The tracks that were returned by `tracks` were not sorted by `Id`") + } } } @@ -670,4 +689,72 @@ mod tests { assert_eq!(c.delay(pc(30).less_epsilon()), pc(100)); assert_eq!(c.delay(pc(0)), pc(100)); } + + #[test] + fn tracks_integrity_check_detects_unsorted() { + use crate::mock::RuntimeOrigin; + + pub struct BadTracksInfo; + impl TracksInfo for BadTracksInfo { + type Id = u8; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, TrackInfo)] { + static DATA: [(u8, TrackInfo); 2] = [ + ( + 1u8, + TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 10, + prepare_period: 4, + decision_period: 4, + confirm_period: 2, + min_enactment_period: 4, + min_approval: Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(0), + ceil: Perbill::from_percent(100), + }, + }, + ), + ( + 0u8, + TrackInfo { + name: "none", + max_deciding: 3, + decision_deposit: 1, + prepare_period: 2, + decision_period: 2, + confirm_period: 1, + min_enactment_period: 2, + min_approval: Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(95), + ceil: Perbill::from_percent(100), + }, + min_support: Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(90), + ceil: Perbill::from_percent(100), + }, + }, + ), + ]; + &DATA[..] + } + fn track_for(_: &Self::RuntimeOrigin) -> Result { + unimplemented!() + } + } + + assert_eq!( + BadTracksInfo::check_integrity(), + Err("The tracks that were returned by `tracks` were not sorted by `Id`") + ); + } } diff --git a/substrate/frame/referenda/src/weights.rs b/substrate/frame/referenda/src/weights.rs index 4b89379b311da6ac8cd10fd84a127e3693ab00de..1f1b69873ebc44fc045ac8f7864e8c2397e927cf 100644 --- a/substrate/frame/referenda/src/weights.rs +++ b/substrate/frame/referenda/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_referenda +//! Autogenerated weights for `pallet_referenda` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/referenda/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/referenda/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_referenda. +/// Weight functions needed for `pallet_referenda`. pub trait WeightInfo { fn submit() -> Weight; fn place_decision_deposit_preparing() -> Weight; @@ -84,842 +83,874 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; } -/// Weights for pallet_referenda using the Substrate node and recommended hardware. +/// Weights for `pallet_referenda` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Referenda ReferendumCount (r:1 w:1) - /// Proof: Referenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:0 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumCount` (r:1 w:1) + /// Proof: `Referenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:0 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `220` + // Measured: `286` // Estimated: `110487` - // Minimum execution time: 40_175_000 picoseconds. - Weight::from_parts(41_107_000, 110487) + // Minimum execution time: 31_536_000 picoseconds. + Weight::from_parts(32_797_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `473` + // Measured: `539` // Estimated: `219984` - // Minimum execution time: 50_922_000 picoseconds. - Weight::from_parts(52_179_000, 219984) + // Minimum execution time: 42_579_000 picoseconds. + Weight::from_parts(43_877_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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(107022), added: 109497, 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: `3260` + // Measured: `3326` // Estimated: `110487` - // Minimum execution time: 69_559_000 picoseconds. - Weight::from_parts(72_143_000, 110487) + // Minimum execution time: 61_439_000 picoseconds. + Weight::from_parts(63_681_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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(107022), added: 109497, 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: `3280` + // Measured: `3346` // Estimated: `110487` - // Minimum execution time: 68_833_000 picoseconds. - Weight::from_parts(70_987_000, 110487) + // Minimum execution time: 60_136_000 picoseconds. + Weight::from_parts(61_841_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`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(107022), added: 109497, 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: `473` + // Measured: `539` // Estimated: `219984` - // Minimum execution time: 61_794_000 picoseconds. - Weight::from_parts(62_846_000, 219984) + // Minimum execution time: 49_865_000 picoseconds. + Weight::from_parts(51_347_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (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(107022), added: 109497, mode: MaxEncodedLen) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`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(107022), added: 109497, 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: `473` + // Measured: `539` // Estimated: `219984` - // Minimum execution time: 58_664_000 picoseconds. - Weight::from_parts(60_195_000, 219984) + // Minimum execution time: 47_887_000 picoseconds. + Weight::from_parts(49_927_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `351` + // Measured: `417` // Estimated: `3831` - // Minimum execution time: 30_850_000 picoseconds. - Weight::from_parts(32_130_000, 3831) + // Minimum execution time: 25_721_000 picoseconds. + Weight::from_parts(26_922_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `341` + // Measured: `407` // Estimated: `3831` - // Minimum execution time: 30_747_000 picoseconds. - Weight::from_parts(32_196_000, 3831) + // Minimum execution time: 25_840_000 picoseconds. + Weight::from_parts(26_498_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `381` + // Measured: `447` // Estimated: `219984` - // Minimum execution time: 36_139_000 picoseconds. - Weight::from_parts(37_252_000, 219984) + // Minimum execution time: 30_530_000 picoseconds. + Weight::from_parts(31_547_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: Referenda MetadataOf (r:1 w:0) - /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `622` + // Measured: `688` // Estimated: `219984` - // Minimum execution time: 80_862_000 picoseconds. - Weight::from_parts(83_045_000, 219984) + // Minimum execution time: 64_011_000 picoseconds. + Weight::from_parts(65_240_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Referenda TrackQueue (r:1 w:0) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: `Referenda::TrackQueue` (r:1 w:0) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// 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: `174` + // Measured: `240` // Estimated: `5477` - // Minimum execution time: 10_136_000 picoseconds. - Weight::from_parts(10_638_000, 5477) + // Minimum execution time: 9_568_000 picoseconds. + Weight::from_parts(10_004_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `3150` + // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 52_022_000 picoseconds. - Weight::from_parts(53_910_000, 110487) + // Minimum execution time: 43_325_000 picoseconds. + Weight::from_parts(45_335_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// 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(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `3150` + // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 53_683_000 picoseconds. - Weight::from_parts(55_707_000, 110487) + // Minimum execution time: 44_287_000 picoseconds. + Weight::from_parts(45_164_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// 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:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3011` + // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 24_043_000 picoseconds. - Weight::from_parts(24_512_000, 5477) + // Minimum execution time: 21_909_000 picoseconds. + Weight::from_parts(22_641_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// 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:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3011` + // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 23_588_000 picoseconds. - Weight::from_parts(24_422_000, 5477) + // Minimum execution time: 21_626_000 picoseconds. + Weight::from_parts(22_338_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3015` + // Measured: `3081` // Estimated: `5477` - // Minimum execution time: 31_443_000 picoseconds. - Weight::from_parts(32_725_000, 5477) + // Minimum execution time: 29_245_000 picoseconds. + Weight::from_parts(30_147_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3035` + // Measured: `3101` // Estimated: `5477` - // Minimum execution time: 30_319_000 picoseconds. - Weight::from_parts(31_652_000, 5477) + // Minimum execution time: 28_512_000 picoseconds. + Weight::from_parts(29_781_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `333` + // Measured: `399` // Estimated: `110487` - // Minimum execution time: 23_062_000 picoseconds. - Weight::from_parts(23_614_000, 110487) + // Minimum execution time: 19_208_000 picoseconds. + Weight::from_parts(19_947_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `381` + // Measured: `447` // Estimated: `110487` - // Minimum execution time: 23_537_000 picoseconds. - Weight::from_parts(24_267_000, 110487) + // Minimum execution time: 19_708_000 picoseconds. + Weight::from_parts(20_783_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `278` + // Measured: `344` // Estimated: `3831` - // Minimum execution time: 16_388_000 picoseconds. - Weight::from_parts(16_676_000, 3831) + // Minimum execution time: 12_947_000 picoseconds. + Weight::from_parts(13_582_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `381` + // Measured: `447` // Estimated: `110487` - // Minimum execution time: 32_801_000 picoseconds. - Weight::from_parts(34_053_000, 110487) + // Minimum execution time: 26_699_000 picoseconds. + Weight::from_parts(28_048_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `381` + // Measured: `447` // Estimated: `110487` - // Minimum execution time: 35_704_000 picoseconds. - Weight::from_parts(36_451_000, 110487) + // Minimum execution time: 28_132_000 picoseconds. + Weight::from_parts(29_520_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `500` // Estimated: `110487` - // Minimum execution time: 29_151_000 picoseconds. - Weight::from_parts(30_055_000, 110487) + // Minimum execution time: 23_212_000 picoseconds. + Weight::from_parts(24_200_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `483` // Estimated: `110487` - // Minimum execution time: 29_265_000 picoseconds. - Weight::from_parts(30_213_000, 110487) + // Minimum execution time: 22_807_000 picoseconds. + Weight::from_parts(23_858_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `500` // Estimated: `110487` - // Minimum execution time: 27_760_000 picoseconds. - Weight::from_parts(28_381_000, 110487) + // Minimum execution time: 22_862_000 picoseconds. + Weight::from_parts(23_627_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `438` + // Measured: `504` // Estimated: `110487` - // Minimum execution time: 25_464_000 picoseconds. - Weight::from_parts(26_348_000, 110487) + // Minimum execution time: 21_030_000 picoseconds. + Weight::from_parts(21_710_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `438` + // Measured: `504` // Estimated: `219984` - // Minimum execution time: 42_629_000 picoseconds. - Weight::from_parts(43_732_000, 219984) + // Minimum execution time: 33_031_000 picoseconds. + Weight::from_parts(34_518_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `500` // Estimated: `110487` - // Minimum execution time: 30_015_000 picoseconds. - Weight::from_parts(30_827_000, 110487) + // Minimum execution time: 23_198_000 picoseconds. + Weight::from_parts(24_238_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (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) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, 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: `422` + // Measured: `555` // Estimated: `3831` - // Minimum execution time: 19_901_000 picoseconds. - Weight::from_parts(20_681_000, 3831) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 19_502_000 picoseconds. + Weight::from_parts(20_105_000, 3831) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda MetadataOf (r:1 w:1) - /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `355` + // Measured: `421` // Estimated: `3831` - // Minimum execution time: 17_323_000 picoseconds. - Weight::from_parts(18_227_000, 3831) + // Minimum execution time: 15_417_000 picoseconds. + Weight::from_parts(15_916_000, 3831) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Referenda ReferendumCount (r:1 w:1) - /// Proof: Referenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:0 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumCount` (r:1 w:1) + /// Proof: `Referenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:0 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `220` + // Measured: `286` // Estimated: `110487` - // Minimum execution time: 40_175_000 picoseconds. - Weight::from_parts(41_107_000, 110487) + // Minimum execution time: 31_536_000 picoseconds. + Weight::from_parts(32_797_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `473` + // Measured: `539` // Estimated: `219984` - // Minimum execution time: 50_922_000 picoseconds. - Weight::from_parts(52_179_000, 219984) + // Minimum execution time: 42_579_000 picoseconds. + Weight::from_parts(43_877_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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(107022), added: 109497, 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: `3260` + // Measured: `3326` // Estimated: `110487` - // Minimum execution time: 69_559_000 picoseconds. - Weight::from_parts(72_143_000, 110487) + // Minimum execution time: 61_439_000 picoseconds. + Weight::from_parts(63_681_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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(107022), added: 109497, 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: `3280` + // Measured: `3346` // Estimated: `110487` - // Minimum execution time: 68_833_000 picoseconds. - Weight::from_parts(70_987_000, 110487) + // Minimum execution time: 60_136_000 picoseconds. + Weight::from_parts(61_841_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`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(107022), added: 109497, 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: `473` + // Measured: `539` // Estimated: `219984` - // Minimum execution time: 61_794_000 picoseconds. - Weight::from_parts(62_846_000, 219984) + // Minimum execution time: 49_865_000 picoseconds. + Weight::from_parts(51_347_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (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(107022), added: 109497, mode: MaxEncodedLen) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`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(107022), added: 109497, 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: `473` + // Measured: `539` // Estimated: `219984` - // Minimum execution time: 58_664_000 picoseconds. - Weight::from_parts(60_195_000, 219984) + // Minimum execution time: 47_887_000 picoseconds. + Weight::from_parts(49_927_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `351` + // Measured: `417` // Estimated: `3831` - // Minimum execution time: 30_850_000 picoseconds. - Weight::from_parts(32_130_000, 3831) + // Minimum execution time: 25_721_000 picoseconds. + Weight::from_parts(26_922_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `341` + // Measured: `407` // Estimated: `3831` - // Minimum execution time: 30_747_000 picoseconds. - Weight::from_parts(32_196_000, 3831) + // Minimum execution time: 25_840_000 picoseconds. + Weight::from_parts(26_498_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `381` + // Measured: `447` // Estimated: `219984` - // Minimum execution time: 36_139_000 picoseconds. - Weight::from_parts(37_252_000, 219984) + // Minimum execution time: 30_530_000 picoseconds. + Weight::from_parts(31_547_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: Referenda MetadataOf (r:1 w:0) - /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `622` + // Measured: `688` // Estimated: `219984` - // Minimum execution time: 80_862_000 picoseconds. - Weight::from_parts(83_045_000, 219984) + // Minimum execution time: 64_011_000 picoseconds. + Weight::from_parts(65_240_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Referenda TrackQueue (r:1 w:0) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: `Referenda::TrackQueue` (r:1 w:0) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// 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: `174` + // Measured: `240` // Estimated: `5477` - // Minimum execution time: 10_136_000 picoseconds. - Weight::from_parts(10_638_000, 5477) + // Minimum execution time: 9_568_000 picoseconds. + Weight::from_parts(10_004_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `3150` + // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 52_022_000 picoseconds. - Weight::from_parts(53_910_000, 110487) + // Minimum execution time: 43_325_000 picoseconds. + Weight::from_parts(45_335_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// 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(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `3150` + // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 53_683_000 picoseconds. - Weight::from_parts(55_707_000, 110487) + // Minimum execution time: 44_287_000 picoseconds. + Weight::from_parts(45_164_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// 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:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3011` + // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 24_043_000 picoseconds. - Weight::from_parts(24_512_000, 5477) + // Minimum execution time: 21_909_000 picoseconds. + Weight::from_parts(22_641_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// 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:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3011` + // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 23_588_000 picoseconds. - Weight::from_parts(24_422_000, 5477) + // Minimum execution time: 21_626_000 picoseconds. + Weight::from_parts(22_338_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3015` + // Measured: `3081` // Estimated: `5477` - // Minimum execution time: 31_443_000 picoseconds. - Weight::from_parts(32_725_000, 5477) + // Minimum execution time: 29_245_000 picoseconds. + Weight::from_parts(30_147_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// 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(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// 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: `3035` + // Measured: `3101` // Estimated: `5477` - // Minimum execution time: 30_319_000 picoseconds. - Weight::from_parts(31_652_000, 5477) + // Minimum execution time: 28_512_000 picoseconds. + Weight::from_parts(29_781_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `333` + // Measured: `399` // Estimated: `110487` - // Minimum execution time: 23_062_000 picoseconds. - Weight::from_parts(23_614_000, 110487) + // Minimum execution time: 19_208_000 picoseconds. + Weight::from_parts(19_947_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `381` + // Measured: `447` // Estimated: `110487` - // Minimum execution time: 23_537_000 picoseconds. - Weight::from_parts(24_267_000, 110487) + // Minimum execution time: 19_708_000 picoseconds. + Weight::from_parts(20_783_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `278` + // Measured: `344` // Estimated: `3831` - // Minimum execution time: 16_388_000 picoseconds. - Weight::from_parts(16_676_000, 3831) + // Minimum execution time: 12_947_000 picoseconds. + Weight::from_parts(13_582_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `381` + // Measured: `447` // Estimated: `110487` - // Minimum execution time: 32_801_000 picoseconds. - Weight::from_parts(34_053_000, 110487) + // Minimum execution time: 26_699_000 picoseconds. + Weight::from_parts(28_048_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `381` + // Measured: `447` // Estimated: `110487` - // Minimum execution time: 35_704_000 picoseconds. - Weight::from_parts(36_451_000, 110487) + // Minimum execution time: 28_132_000 picoseconds. + Weight::from_parts(29_520_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `500` // Estimated: `110487` - // Minimum execution time: 29_151_000 picoseconds. - Weight::from_parts(30_055_000, 110487) + // Minimum execution time: 23_212_000 picoseconds. + Weight::from_parts(24_200_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `483` // Estimated: `110487` - // Minimum execution time: 29_265_000 picoseconds. - Weight::from_parts(30_213_000, 110487) + // Minimum execution time: 22_807_000 picoseconds. + Weight::from_parts(23_858_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `500` // Estimated: `110487` - // Minimum execution time: 27_760_000 picoseconds. - Weight::from_parts(28_381_000, 110487) + // Minimum execution time: 22_862_000 picoseconds. + Weight::from_parts(23_627_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `438` + // Measured: `504` // Estimated: `110487` - // Minimum execution time: 25_464_000 picoseconds. - Weight::from_parts(26_348_000, 110487) + // Minimum execution time: 21_030_000 picoseconds. + Weight::from_parts(21_710_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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: `438` + // Measured: `504` // Estimated: `219984` - // Minimum execution time: 42_629_000 picoseconds. - Weight::from_parts(43_732_000, 219984) + // Minimum execution time: 33_031_000 picoseconds. + Weight::from_parts(34_518_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `434` + // Measured: `500` // Estimated: `110487` - // Minimum execution time: 30_015_000 picoseconds. - Weight::from_parts(30_827_000, 110487) + // Minimum execution time: 23_198_000 picoseconds. + Weight::from_parts(24_238_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (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) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, 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: `422` + // Measured: `555` // Estimated: `3831` - // Minimum execution time: 19_901_000 picoseconds. - Weight::from_parts(20_681_000, 3831) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 19_502_000 picoseconds. + Weight::from_parts(20_105_000, 3831) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) - /// Storage: Referenda MetadataOf (r:1 w:1) - /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `355` + // Measured: `421` // Estimated: `3831` - // Minimum execution time: 17_323_000 picoseconds. - Weight::from_parts(18_227_000, 3831) + // Minimum execution time: 15_417_000 picoseconds. + Weight::from_parts(15_916_000, 3831) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index 582f5958a6925c601d5b1e90c765131fc8605eca..45710f0539e255b48caf4e7dce9a99f46600d4e5 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/remark/src/mock.rs b/substrate/frame/remark/src/mock.rs index 5a5e6a3ccdff28ff29799ed7c31cf2c1c73c77bb..d89583513b60d16a79aa076fb963fdc0e1459b76 100644 --- a/substrate/frame/remark/src/mock.rs +++ b/substrate/frame/remark/src/mock.rs @@ -18,15 +18,8 @@ //! Test environment for remarks pallet. use crate as pallet_remark; -use frame_support::{ - derive_impl, - traits::{ConstU16, ConstU32, ConstU64}, -}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use frame_support::derive_impl; +use sp_runtime::BuildStorage; pub type Block = frame_system::mocking::MockBlock; @@ -41,29 +34,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_remark::Config for Test { diff --git a/substrate/frame/remark/src/weights.rs b/substrate/frame/remark/src/weights.rs index 46475db163ffd5827486f8ad562c2f3ecc6deb3d..61cca5b7d05643c200b8d9c79ccc44bde9901bf2 100644 --- a/substrate/frame/remark/src/weights.rs +++ b/substrate/frame/remark/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_remark +//! Autogenerated weights for `pallet_remark` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/remark/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/remark/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,12 +49,12 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_remark. +/// Weight functions needed for `pallet_remark`. pub trait WeightInfo { fn store(l: u32, ) -> Weight; } -/// Weights for pallet_remark using the Substrate node and recommended hardware. +/// Weights for `pallet_remark` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 1048576]`. @@ -63,23 +62,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_471_000 picoseconds. - Weight::from_parts(8_586_000, 0) + // Minimum execution time: 6_623_000 picoseconds. + Weight::from_parts(6_757_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_359, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_368, 0).saturating_mul(l.into())) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { /// The range of component `l` is `[1, 1048576]`. fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_471_000 picoseconds. - Weight::from_parts(8_586_000, 0) + // Minimum execution time: 6_623_000 picoseconds. + Weight::from_parts(6_757_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_359, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_368, 0).saturating_mul(l.into())) } } diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index b0f346032b95e79fafa189c04fb612a8f7728fa6..1f7cce27769f17b9965774300070d62e78bcaabd 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -27,13 +27,7 @@ use frame_support::{ traits::{ConstU32, ConstU64, Hooks, OneSessionHandler}, }; use pallet_staking::StakerStatus; -use sp_core::H256; -use sp_runtime::{ - curve::PiecewiseLinear, - testing::UintAuthorityId, - traits::{BlakeTwo256, IdentityLookup, Zero}, - BuildStorage, -}; +use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{EraIndex, SessionIndex}; use sp_std::collections::btree_map::BTreeMap; @@ -86,29 +80,8 @@ impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/safe-mode/src/weights.rs b/substrate/frame/safe-mode/src/weights.rs index f72bebcab9a4db74fba3ef282692324e32858fc3..d326fab0f0f41d3d383a613cbfe9c6dab2ebd981 100644 --- a/substrate/frame/safe-mode/src/weights.rs +++ b/substrate/frame/safe-mode/src/weights.rs @@ -17,27 +17,29 @@ //! Autogenerated weights for `pallet_safe_mode` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-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-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-aahe6cbd-project-145-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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_safe_mode +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_safe_mode -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/safe-mode/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/safe-mode/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -70,8 +72,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 2_500_000 picoseconds. - Weight::from_parts(2_594_000, 1489) + // Minimum execution time: 2_216_000 picoseconds. + Weight::from_parts(2_309_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) @@ -80,23 +82,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_868_000 picoseconds. - Weight::from_parts(9_415_000, 1489) + // Minimum execution time: 6_124_000 picoseconds. + Weight::from_parts(6_601_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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3550` - // Minimum execution time: 50_541_000 picoseconds. - Weight::from_parts(51_558_000, 3550) + // Estimated: `3658` + // Minimum execution time: 44_825_000 picoseconds. + Weight::from_parts(45_845_000, 3658) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -106,23 +108,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 10_489_000 picoseconds. - Weight::from_parts(10_833_000, 1489) + // Minimum execution time: 7_603_000 picoseconds. + Weight::from_parts(7_954_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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3550` - // Minimum execution time: 50_818_000 picoseconds. - Weight::from_parts(51_873_000, 3550) + // Estimated: `3658` + // Minimum execution time: 44_716_000 picoseconds. + Weight::from_parts(46_039_000, 3658) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -132,8 +134,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 10_843_000 picoseconds. - Weight::from_parts(11_314_000, 1489) + // Minimum execution time: 8_231_000 picoseconds. + Weight::from_parts(8_731_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -143,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 10_382_000 picoseconds. - Weight::from_parts(10_814_000, 1489) + // Minimum execution time: 8_015_000 picoseconds. + Weight::from_parts(8_247_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -153,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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3550` - // Minimum execution time: 42_828_000 picoseconds. - Weight::from_parts(43_752_000, 3550) + // Estimated: `3658` + // Minimum execution time: 39_149_000 picoseconds. + Weight::from_parts(40_005_000, 3658) .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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn force_release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3550` - // Minimum execution time: 40_196_000 picoseconds. - Weight::from_parts(41_298_000, 3550) + // Estimated: `3658` + // Minimum execution time: 37_528_000 picoseconds. + Weight::from_parts(38_473_000, 3658) .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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn force_slash_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3550` - // Minimum execution time: 33_660_000 picoseconds. - Weight::from_parts(34_426_000, 3550) + // Estimated: `3658` + // Minimum execution time: 29_417_000 picoseconds. + Weight::from_parts(30_195_000, 3658) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -199,8 +201,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 2_500_000 picoseconds. - Weight::from_parts(2_594_000, 1489) + // Minimum execution time: 2_216_000 picoseconds. + Weight::from_parts(2_309_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) @@ -209,23 +211,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_868_000 picoseconds. - Weight::from_parts(9_415_000, 1489) + // Minimum execution time: 6_124_000 picoseconds. + Weight::from_parts(6_601_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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3550` - // Minimum execution time: 50_541_000 picoseconds. - Weight::from_parts(51_558_000, 3550) + // Estimated: `3658` + // Minimum execution time: 44_825_000 picoseconds. + Weight::from_parts(45_845_000, 3658) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -235,23 +237,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 10_489_000 picoseconds. - Weight::from_parts(10_833_000, 1489) + // Minimum execution time: 7_603_000 picoseconds. + Weight::from_parts(7_954_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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3550` - // Minimum execution time: 50_818_000 picoseconds. - Weight::from_parts(51_873_000, 3550) + // Estimated: `3658` + // Minimum execution time: 44_716_000 picoseconds. + Weight::from_parts(46_039_000, 3658) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -261,8 +263,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 10_843_000 picoseconds. - Weight::from_parts(11_314_000, 1489) + // Minimum execution time: 8_231_000 picoseconds. + Weight::from_parts(8_731_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -272,8 +274,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 10_382_000 picoseconds. - Weight::from_parts(10_814_000, 1489) + // Minimum execution time: 8_015_000 picoseconds. + Weight::from_parts(8_247_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -282,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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3550` - // Minimum execution time: 42_828_000 picoseconds. - Weight::from_parts(43_752_000, 3550) + // Estimated: `3658` + // Minimum execution time: 39_149_000 picoseconds. + Weight::from_parts(40_005_000, 3658) .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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn force_release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3550` - // Minimum execution time: 40_196_000 picoseconds. - Weight::from_parts(41_298_000, 3550) + // Estimated: `3658` + // Minimum execution time: 37_528_000 picoseconds. + Weight::from_parts(38_473_000, 3658) .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(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn force_slash_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3550` - // Minimum execution time: 33_660_000 picoseconds. - Weight::from_parts(34_426_000, 3550) + // Estimated: `3658` + // Minimum execution time: 29_417_000 picoseconds. + Weight::from_parts(30_195_000, 3658) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index 90a44da1a10459410240506b22c944efab35a6e7..ba57fd46eebb44f0164ffd8aa2a5edf936ab3835 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.16", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/salary/src/lib.rs b/substrate/frame/salary/src/lib.rs index f83a75dd97dc8774b28253a0435c713a15c661b0..efb4f5d3c5422d96b2b2038122de8c2d391cc855 100644 --- a/substrate/frame/salary/src/lib.rs +++ b/substrate/frame/salary/src/lib.rs @@ -18,7 +18,6 @@ //! Make periodic payment to members of a ranked collective according to rank. #![cfg_attr(not(feature = "std"), no_std)] -#![recursion_limit = "128"] use codec::{Decode, Encode, MaxEncodedLen}; use core::marker::PhantomData; diff --git a/substrate/frame/salary/src/weights.rs b/substrate/frame/salary/src/weights.rs index 3d3b9e315959be023cfe09ae00e993cabedea99a..c4f22a027eb42f011c98900571fc9dae2cb5d503 100644 --- a/substrate/frame/salary/src/weights.rs +++ b/substrate/frame/salary/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_salary +//! Autogenerated weights for `pallet_salary` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/salary/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/salary/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_salary. +/// Weight functions needed for `pallet_salary`. pub trait WeightInfo { fn init() -> Weight; fn bump() -> Weight; @@ -61,204 +60,204 @@ pub trait WeightInfo { fn check_payment() -> Weight; } -/// Weights for pallet_salary using the Substrate node and recommended hardware. +/// Weights for `pallet_salary` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) fn init() -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 10_778_000 picoseconds. - Weight::from_parts(11_084_000, 1541) + // Minimum execution time: 7_421_000 picoseconds. + Weight::from_parts(7_819_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) fn bump() -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_645_000, 1541) + // Minimum execution time: 8_651_000 picoseconds. + Weight::from_parts(9_056_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Salary Status (r:1 w:0) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:0) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3543` - // Minimum execution time: 18_374_000 picoseconds. - Weight::from_parts(19_200_000, 3543) + // Minimum execution time: 16_513_000 picoseconds. + Weight::from_parts(17_305_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) fn register() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 22_696_000 picoseconds. - Weight::from_parts(23_275_000, 3543) + // Minimum execution time: 18_913_000 picoseconds. + Weight::from_parts(19_867_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 63_660_000 picoseconds. - Weight::from_parts(65_006_000, 3543) + // Minimum execution time: 53_297_000 picoseconds. + Weight::from_parts(55_144_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// 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` // Estimated: `3593` - // Minimum execution time: 64_706_000 picoseconds. - Weight::from_parts(65_763_000, 3593) + // Minimum execution time: 53_638_000 picoseconds. + Weight::from_parts(55_328_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) fn check_payment() -> Weight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3543` - // Minimum execution time: 11_838_000 picoseconds. - Weight::from_parts(12_323_000, 3543) + // Minimum execution time: 10_557_000 picoseconds. + Weight::from_parts(11_145_000, 3543) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) fn init() -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 10_778_000 picoseconds. - Weight::from_parts(11_084_000, 1541) + // Minimum execution time: 7_421_000 picoseconds. + Weight::from_parts(7_819_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) fn bump() -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_645_000, 1541) + // Minimum execution time: 8_651_000 picoseconds. + Weight::from_parts(9_056_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Salary Status (r:1 w:0) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:0) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3543` - // Minimum execution time: 18_374_000 picoseconds. - Weight::from_parts(19_200_000, 3543) + // Minimum execution time: 16_513_000 picoseconds. + Weight::from_parts(17_305_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) fn register() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 22_696_000 picoseconds. - Weight::from_parts(23_275_000, 3543) + // Minimum execution time: 18_913_000 picoseconds. + Weight::from_parts(19_867_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 63_660_000 picoseconds. - Weight::from_parts(65_006_000, 3543) + // Minimum execution time: 53_297_000 picoseconds. + Weight::from_parts(55_144_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) - /// Storage: RankedCollective Members (r:1 w:0) - /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: `RankedCollective::Members` (r:1 w:0) + /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// 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` // Estimated: `3593` - // Minimum execution time: 64_706_000 picoseconds. - Weight::from_parts(65_763_000, 3593) + // Minimum execution time: 53_638_000 picoseconds. + Weight::from_parts(55_328_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Salary Status (r:1 w:1) - /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) - /// Storage: Salary Claimant (r:1 w:1) - /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: `Salary::Status` (r:1 w:1) + /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `Salary::Claimant` (r:1 w:1) + /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) fn check_payment() -> Weight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3543` - // Minimum execution time: 11_838_000 picoseconds. - Weight::from_parts(12_323_000, 3543) + // Minimum execution time: 10_557_000 picoseconds. + Weight::from_parts(11_145_000, 3543) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/sassafras/Cargo.toml b/substrate/frame/sassafras/Cargo.toml index 5f4900b5a29d4514ab8621e8689aba1a63bcb640..325a39bf59799f6b314d54ad131b892eec61ec44 100644 --- a/substrate/frame/sassafras/Cargo.toml +++ b/substrate/frame/sassafras/Cargo.toml @@ -22,7 +22,7 @@ scale-info = { version = "2.5.0", default-features = false, features = ["derive" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } sp-consensus-sassafras = { path = "../../primitives/consensus/sassafras", default-features = false, features = ["serde"] } sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/sassafras/src/mock.rs b/substrate/frame/sassafras/src/mock.rs index 5e5909fcb0d6e0d4db41ce96035fa9322cf65bbd..4c6efaa63a9ea46bdda14f0d5114184c5c42c43b 100644 --- a/substrate/frame/sassafras/src/mock.rs +++ b/substrate/frame/sassafras/src/mock.rs @@ -34,7 +34,8 @@ use sp_core::{ H256, U256, }; use sp_runtime::{ - testing::{Digest, DigestItem, Header, TestXt}, + generic::UncheckedExtrinsic, + testing::{Digest, DigestItem, Header}, BuildStorage, }; @@ -53,7 +54,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = TestXt; + type Extrinsic = UncheckedExtrinsic; } impl pallet_sassafras::Config for Test { diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index bca17242d2071e22c232baab294d8dba0a27d77c..f50f6afdc06379f0ffaca3460df314e1eb0e4945 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/scheduler/src/benchmarking.rs b/substrate/frame/scheduler/src/benchmarking.rs index cc86a17973780870970a7b604b4fd5d30cffe263..18441d54b39a2244f1eb9677d38be2576e141d94 100644 --- a/substrate/frame/scheduler/src/benchmarking.rs +++ b/substrate/frame/scheduler/src/benchmarking.rs @@ -22,12 +22,13 @@ use frame_benchmarking::v1::{account, benchmarks, BenchmarkError}; use frame_support::{ ensure, traits::{schedule::Priority, BoundedInline}, + weights::WeightMeter, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use sp_std::{prelude::*, vec}; use crate::Pallet as Scheduler; -use frame_system::Call as SystemCall; +use frame_system::{Call as SystemCall, EventRecord}; const SEED: u32 = 0; @@ -35,6 +36,14 @@ const BLOCK_NUMBER: u32 = 2; type SystemOrigin = ::RuntimeOrigin; +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + /// Add `n` items to the schedule. /// /// For `resolved`: @@ -306,5 +315,105 @@ benchmarks! { ); } + schedule_retry { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + let name = u32_to_name(s - 1); + let address = Lookup::::get(name).unwrap(); + let period: BlockNumberFor = 1u32.into(); + let root: ::PalletsOrigin = frame_system::RawOrigin::Root.into(); + let retry_config = RetryConfig { total_retries: 10, remaining: 10, period }; + Retries::::insert(address, retry_config); + let (mut when, index) = address; + let task = Agenda::::get(when)[index as usize].clone().unwrap(); + let mut weight_counter = WeightMeter::with_limit(T::MaximumWeight::get()); + }: { + Scheduler::::schedule_retry(&mut weight_counter, when, when, index, &task, retry_config); + } verify { + when = when + BlockNumberFor::::one(); + assert_eq!( + Retries::::get((when, 0)), + Some(RetryConfig { total_retries: 10, remaining: 9, period }) + ); + } + + set_retry { + let s = T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + let name = u32_to_name(s - 1); + let address = Lookup::::get(name).unwrap(); + let (when, index) = address; + let period = BlockNumberFor::::one(); + }: _(RawOrigin::Root, (when, index), 10, period) + verify { + assert_eq!( + Retries::::get((when, index)), + Some(RetryConfig { total_retries: 10, remaining: 10, period }) + ); + assert_last_event::( + Event::RetrySet { task: address, id: None, period, retries: 10 }.into(), + ); + } + + set_retry_named { + let s = T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + let name = u32_to_name(s - 1); + let address = Lookup::::get(name).unwrap(); + let (when, index) = address; + let period = BlockNumberFor::::one(); + }: _(RawOrigin::Root, name, 10, period) + verify { + assert_eq!( + Retries::::get((when, index)), + Some(RetryConfig { total_retries: 10, remaining: 10, period }) + ); + assert_last_event::( + Event::RetrySet { task: address, id: Some(name), period, retries: 10 }.into(), + ); + } + + cancel_retry { + let s = T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + let name = u32_to_name(s - 1); + let address = Lookup::::get(name).unwrap(); + let (when, index) = address; + let period = BlockNumberFor::::one(); + assert!(Scheduler::::set_retry(RawOrigin::Root.into(), (when, index), 10, period).is_ok()); + }: _(RawOrigin::Root, (when, index)) + verify { + assert!(!Retries::::contains_key((when, index))); + assert_last_event::( + Event::RetryCancelled { task: address, id: None }.into(), + ); + } + + cancel_retry_named { + let s = T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + let name = u32_to_name(s - 1); + let address = Lookup::::get(name).unwrap(); + let (when, index) = address; + let period = BlockNumberFor::::one(); + assert!(Scheduler::::set_retry_named(RawOrigin::Root.into(), name, 10, period).is_ok()); + }: _(RawOrigin::Root, name) + verify { + assert!(!Retries::::contains_key((when, index))); + assert_last_event::( + Event::RetryCancelled { task: address, id: Some(name) }.into(), + ); + } + impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index e94f154eee32f908dc449ba7ff9e54853cc4b915..af3abd8ac4f2a81b363c4553f3652a2cba972212 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -122,6 +122,17 @@ pub type CallOrHashOf = pub type BoundedCallOf = Bounded<::RuntimeCall, ::Hashing>; +/// The configuration of the retry mechanism for a given task along with its current state. +#[derive(Clone, Copy, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct RetryConfig { + /// Initial amount of retries allowed. + total_retries: u8, + /// Amount of retries left. + remaining: u8, + /// Period of time between retry attempts. + period: Period, +} + #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode)] struct ScheduledV1 { @@ -148,6 +159,26 @@ pub struct Scheduled { _phantom: PhantomData, } +impl + Scheduled +where + Call: Clone, + PalletsOrigin: Clone, +{ + /// Create a new task to be used for retry attempts of the original one. The cloned task will + /// have the same `priority`, `call` and `origin`, but will always be non-periodic and unnamed. + pub fn as_retry(&self) -> Self { + Self { + maybe_id: None, + priority: self.priority, + call: self.call.clone(), + maybe_periodic: None, + origin: self.origin.clone(), + _phantom: Default::default(), + } + } +} + use crate::{Scheduled as ScheduledV3, Scheduled as ScheduledV2}; pub type ScheduledV2Of = ScheduledV2< @@ -198,7 +229,7 @@ pub mod pallet { use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] @@ -273,6 +304,16 @@ pub mod pallet { ValueQuery, >; + /// Retry configurations for items to be executed, indexed by task address. + #[pallet::storage] + pub type Retries = StorageMap< + _, + Blake2_128Concat, + TaskAddress>, + RetryConfig>, + OptionQuery, + >; + /// Lookup from a name to the block number and index of the task. /// /// For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4 @@ -295,10 +336,22 @@ pub mod pallet { id: Option, result: DispatchResult, }, + /// Set a retry configuration for some task. + RetrySet { + task: TaskAddress>, + id: Option, + period: BlockNumberFor, + retries: u8, + }, + /// Cancel a retry configuration for some task. + RetryCancelled { task: TaskAddress>, id: Option }, /// The call for the provided hash was not found so the task has been aborted. CallUnavailable { task: TaskAddress>, id: Option }, /// The given task was unable to be renewed since the agenda is full at that block. PeriodicFailed { task: TaskAddress>, id: Option }, + /// The given task was unable to be retried since the agenda is full at that block or there + /// was not enough weight to reschedule it. + RetryFailed { task: TaskAddress>, id: Option }, /// The given task can never be executed since it is overweight. PermanentlyOverweight { task: TaskAddress>, id: Option }, } @@ -440,6 +493,111 @@ pub mod pallet { )?; Ok(()) } + + /// Set a retry configuration for a task so that, in case its scheduled run fails, it will + /// be retried after `period` blocks, for a total amount of `retries` retries or until it + /// succeeds. + /// + /// Tasks which need to be scheduled for a retry are still subject to weight metering and + /// agenda space, same as a regular task. If a periodic task fails, it will be scheduled + /// normally while the task is retrying. + /// + /// Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic + /// clones of the original task. Their retry configuration will be derived from the + /// original task's configuration, but will have a lower value for `remaining` than the + /// original `total_retries`. + #[pallet::call_index(6)] + #[pallet::weight(::WeightInfo::set_retry())] + pub fn set_retry( + origin: OriginFor, + task: TaskAddress>, + retries: u8, + period: BlockNumberFor, + ) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + let origin = ::RuntimeOrigin::from(origin); + let (when, index) = task; + let agenda = Agenda::::get(when); + let scheduled = agenda + .get(index as usize) + .and_then(Option::as_ref) + .ok_or(Error::::NotFound)?; + Self::ensure_privilege(origin.caller(), &scheduled.origin)?; + Retries::::insert( + (when, index), + RetryConfig { total_retries: retries, remaining: retries, period }, + ); + Self::deposit_event(Event::RetrySet { task, id: None, period, retries }); + Ok(()) + } + + /// Set a retry configuration for a named task so that, in case its scheduled run fails, it + /// will be retried after `period` blocks, for a total amount of `retries` retries or until + /// it succeeds. + /// + /// Tasks which need to be scheduled for a retry are still subject to weight metering and + /// agenda space, same as a regular task. If a periodic task fails, it will be scheduled + /// normally while the task is retrying. + /// + /// Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic + /// clones of the original task. Their retry configuration will be derived from the + /// original task's configuration, but will have a lower value for `remaining` than the + /// original `total_retries`. + #[pallet::call_index(7)] + #[pallet::weight(::WeightInfo::set_retry_named())] + pub fn set_retry_named( + origin: OriginFor, + id: TaskName, + retries: u8, + period: BlockNumberFor, + ) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + let origin = ::RuntimeOrigin::from(origin); + let (when, agenda_index) = Lookup::::get(&id).ok_or(Error::::NotFound)?; + let agenda = Agenda::::get(when); + let scheduled = agenda + .get(agenda_index as usize) + .and_then(Option::as_ref) + .ok_or(Error::::NotFound)?; + Self::ensure_privilege(origin.caller(), &scheduled.origin)?; + Retries::::insert( + (when, agenda_index), + RetryConfig { total_retries: retries, remaining: retries, period }, + ); + Self::deposit_event(Event::RetrySet { + task: (when, agenda_index), + id: Some(id), + period, + retries, + }); + Ok(()) + } + + /// Removes the retry configuration of a task. + #[pallet::call_index(8)] + #[pallet::weight(::WeightInfo::cancel_retry())] + pub fn cancel_retry( + origin: OriginFor, + task: TaskAddress>, + ) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + let origin = ::RuntimeOrigin::from(origin); + Self::do_cancel_retry(origin.caller(), task)?; + Self::deposit_event(Event::RetryCancelled { task, id: None }); + Ok(()) + } + + /// Cancel the retry configuration of a named task. + #[pallet::call_index(9)] + #[pallet::weight(::WeightInfo::cancel_retry_named())] + pub fn cancel_retry_named(origin: OriginFor, id: TaskName) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + let origin = ::RuntimeOrigin::from(origin); + let task = Lookup::::get(&id).ok_or(Error::::NotFound)?; + Self::do_cancel_retry(origin.caller(), task)?; + Self::deposit_event(Event::RetryCancelled { task, id: Some(id) }); + Ok(()) + } } } @@ -838,12 +996,7 @@ impl Pallet { Ok(None), |s| -> Result>, DispatchError> { if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { - if matches!( - T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), - Some(Ordering::Less) | None - ) { - return Err(BadOrigin.into()) - } + Self::ensure_privilege(o, &s.origin)?; }; Ok(s.take()) }, @@ -854,6 +1007,7 @@ impl Pallet { if let Some(id) = s.maybe_id { Lookup::::remove(id); } + Retries::::remove((when, index)); Self::cleanup_agenda(when); Self::deposit_event(Event::Canceled { when, index }); Ok(()) @@ -931,12 +1085,8 @@ impl Pallet { Agenda::::try_mutate(when, |agenda| -> DispatchResult { if let Some(s) = agenda.get_mut(i) { if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { - if matches!( - T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), - Some(Ordering::Less) | None - ) { - return Err(BadOrigin.into()) - } + Self::ensure_privilege(o, &s.origin)?; + Retries::::remove((when, index)); T::Preimages::drop(&s.call); } *s = None; @@ -973,6 +1123,20 @@ impl Pallet { Self::deposit_event(Event::Canceled { when, index }); Self::place_task(new_time, task).map_err(|x| x.0) } + + fn do_cancel_retry( + origin: &T::PalletsOrigin, + (when, index): TaskAddress>, + ) -> Result<(), DispatchError> { + let agenda = Agenda::::get(when); + let scheduled = agenda + .get(index as usize) + .and_then(Option::as_ref) + .ok_or(Error::::NotFound)?; + Self::ensure_privilege(origin, &scheduled.origin)?; + Retries::::remove((when, index)); + Ok(()) + } } enum ServiceTaskError { @@ -1124,11 +1288,21 @@ impl Pallet { }, Err(()) => Err((Overweight, Some(task))), Ok(result) => { + let failed = result.is_err(); + let maybe_retry_config = Retries::::take((when, agenda_index)); Self::deposit_event(Event::Dispatched { task: (when, agenda_index), id: task.maybe_id, result, }); + + match maybe_retry_config { + Some(retry_config) if failed => { + Self::schedule_retry(weight, now, when, agenda_index, &task, retry_config); + }, + _ => {}, + } + if let &Some((period, count)) = &task.maybe_periodic { if count > 1 { task.maybe_periodic = Some((period, count - 1)); @@ -1137,7 +1311,10 @@ impl Pallet { } let wake = now.saturating_add(period); match Self::place_task(wake, task) { - Ok(_) => {}, + Ok(new_address) => + if let Some(retry_config) = maybe_retry_config { + Retries::::insert(new_address, retry_config); + }, Err((_, task)) => { // TODO: Leave task in storage somewhere for it to be rescheduled // manually. @@ -1192,6 +1369,70 @@ impl Pallet { let _ = weight.try_consume(call_weight); Ok(result) } + + /// Check if a task has a retry configuration in place and, if so, try to reschedule it. + /// + /// Possible causes for failure to schedule a retry for a task: + /// - there wasn't enough weight to run the task reschedule logic + /// - there was no retry configuration in place + /// - there were no more retry attempts left + /// - the agenda was full. + fn schedule_retry( + weight: &mut WeightMeter, + now: BlockNumberFor, + when: BlockNumberFor, + agenda_index: u32, + task: &ScheduledOf, + retry_config: RetryConfig>, + ) { + if weight + .try_consume(T::WeightInfo::schedule_retry(T::MaxScheduledPerBlock::get())) + .is_err() + { + Self::deposit_event(Event::RetryFailed { + task: (when, agenda_index), + id: task.maybe_id, + }); + return; + } + + let RetryConfig { total_retries, mut remaining, period } = retry_config; + remaining = match remaining.checked_sub(1) { + Some(n) => n, + None => return, + }; + let wake = now.saturating_add(period); + match Self::place_task(wake, task.as_retry()) { + Ok(address) => { + // Reinsert the retry config to the new address of the task after it was + // placed. + Retries::::insert(address, RetryConfig { total_retries, remaining, period }); + }, + Err((_, task)) => { + // TODO: Leave task in storage somewhere for it to be + // rescheduled manually. + T::Preimages::drop(&task.call); + Self::deposit_event(Event::RetryFailed { + task: (when, agenda_index), + id: task.maybe_id, + }); + }, + } + } + + /// Ensure that `left` has at least the same level of privilege or higher than `right`. + /// + /// Returns an error if `left` has a lower level of privilege or the two cannot be compared. + fn ensure_privilege( + left: &::PalletsOrigin, + right: &::PalletsOrigin, + ) -> Result<(), DispatchError> { + if matches!(T::OriginPrivilegeCmp::cmp_privilege(left, right), Some(Ordering::Less) | None) + { + return Err(BadOrigin.into()); + } + Ok(()) + } } impl schedule::v2::Anon, ::RuntimeCall, T::PalletsOrigin> diff --git a/substrate/frame/scheduler/src/mock.rs b/substrate/frame/scheduler/src/mock.rs index d22b9fcf8d99e35ecc7a39ff2097676eb788eee6..bf7dac0d53ae2596f6e9672e1753d96879b7c2be 100644 --- a/substrate/frame/scheduler/src/mock.rs +++ b/substrate/frame/scheduler/src/mock.rs @@ -22,17 +22,10 @@ use super::*; use crate as scheduler; use frame_support::{ derive_impl, ord_parameter_types, parameter_types, - traits::{ - ConstU32, ConstU64, Contains, EitherOfDiverse, EqualPrivilegeOnly, OnFinalize, OnInitialize, - }, - weights::constants::RocksDbWeight, + traits::{ConstU32, Contains, EitherOfDiverse, EqualPrivilegeOnly, OnFinalize, OnInitialize}, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, Perbill, -}; +use sp_runtime::{BuildStorage, Perbill}; // Logger module to track execution. #[frame_support::pallet] @@ -51,6 +44,17 @@ pub mod logger { #[pallet::pallet] pub struct Pallet(_); + #[pallet::storage] + pub type Threshold = StorageValue<_, (BlockNumberFor, BlockNumberFor)>; + + #[pallet::error] + pub enum Error { + /// Under the threshold. + TooEarly, + /// Over the threshold. + TooLate, + } + #[pallet::hooks] impl Hooks> for Pallet {} @@ -89,6 +93,20 @@ pub mod logger { }); Ok(()) } + + #[pallet::call_index(2)] + #[pallet::weight(*weight)] + pub fn timed_log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + let now = frame_system::Pallet::::block_number(); + let (start, end) = Threshold::::get().unwrap_or((0u32.into(), u32::MAX.into())); + ensure!(now >= start, Error::::TooEarly); + ensure!(now <= end, Error::::TooLate); + Self::deposit_event(Event::Logged(i, weight)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); + }); + Ok(()) + } } } @@ -122,28 +140,7 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl system::Config for Test { type BaseCallFilter = BaseFilter; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = RocksDbWeight; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl logger::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -198,6 +195,21 @@ impl WeightInfo for TestWeightInfo { fn cancel_named(_s: u32) -> Weight { Weight::from_parts(50, 0) } + fn schedule_retry(_s: u32) -> Weight { + Weight::from_parts(100000, 0) + } + fn set_retry() -> Weight { + Weight::from_parts(50, 0) + } + fn set_retry_named() -> Weight { + Weight::from_parts(50, 0) + } + fn cancel_retry() -> Weight { + Weight::from_parts(50, 0) + } + fn cancel_retry_named() -> Weight { + Weight::from_parts(50, 0) + } } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index 1bf8b3e5f3a03bd2c9d233a24351d1ae2d923c45..1ed2ca9e2f36d0b3bf4b3a02983ab1ab7539c30b 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -19,7 +19,8 @@ use super::*; use crate::mock::{ - logger, new_test_ext, root, run_to_block, LoggerCall, RuntimeCall, Scheduler, Test, *, + logger::{self, Threshold}, + new_test_ext, root, run_to_block, LoggerCall, RuntimeCall, Scheduler, Test, *, }; use frame_support::{ assert_err, assert_noop, assert_ok, @@ -179,6 +180,865 @@ fn periodic_scheduling_works() { }); } +#[test] +fn retry_scheduling_works() { + new_test_ext().execute_with(|| { + // task fails until block 8 is reached + Threshold::::put((8, 100)); + // task 42 at #4 + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + assert!(Agenda::::get(4)[0].is_some()); + // retry 10 times every 3 blocks + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 10, 3)); + assert_eq!(Retries::::iter().count(), 1); + run_to_block(3); + assert!(logger::log().is_empty()); + assert!(Agenda::::get(4)[0].is_some()); + // task should be retried in block 7 + run_to_block(4); + assert!(Agenda::::get(4).is_empty()); + assert!(Agenda::::get(7)[0].is_some()); + assert!(logger::log().is_empty()); + run_to_block(6); + assert!(Agenda::::get(7)[0].is_some()); + assert!(logger::log().is_empty()); + // task still fails, should be retried in block 10 + run_to_block(7); + assert!(Agenda::::get(7).is_empty()); + assert!(Agenda::::get(10)[0].is_some()); + assert!(logger::log().is_empty()); + run_to_block(8); + assert!(Agenda::::get(10)[0].is_some()); + assert!(logger::log().is_empty()); + run_to_block(9); + assert!(logger::log().is_empty()); + assert_eq!(Retries::::iter().count(), 1); + // finally it should succeed + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + assert_eq!(Retries::::iter().count(), 0); + run_to_block(11); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(12); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn named_retry_scheduling_works() { + new_test_ext().execute_with(|| { + // task fails until block 8 is reached + Threshold::::put((8, 100)); + // task 42 at #4 + let call = RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0), + }); + assert_eq!( + Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(), + (4, 0) + ); + assert!(Agenda::::get(4)[0].is_some()); + // retry 10 times every 3 blocks + assert_ok!(Scheduler::set_retry_named(root().into(), [1u8; 32], 10, 3)); + assert_eq!(Retries::::iter().count(), 1); + run_to_block(3); + assert!(logger::log().is_empty()); + assert!(Agenda::::get(4)[0].is_some()); + // task should be retried in block 7 + run_to_block(4); + assert!(Agenda::::get(4).is_empty()); + assert!(Agenda::::get(7)[0].is_some()); + assert!(logger::log().is_empty()); + run_to_block(6); + assert!(Agenda::::get(7)[0].is_some()); + assert!(logger::log().is_empty()); + // task still fails, should be retried in block 10 + run_to_block(7); + assert!(Agenda::::get(7).is_empty()); + assert!(Agenda::::get(10)[0].is_some()); + assert!(logger::log().is_empty()); + run_to_block(8); + assert!(Agenda::::get(10)[0].is_some()); + assert!(logger::log().is_empty()); + run_to_block(9); + assert!(logger::log().is_empty()); + assert_eq!(Retries::::iter().count(), 1); + // finally it should succeed + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + assert_eq!(Retries::::iter().count(), 0); + run_to_block(11); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(12); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn retry_scheduling_multiple_tasks_works() { + new_test_ext().execute_with(|| { + // task fails until block 8 is reached + Threshold::::put((8, 100)); + // task 20 at #4 + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 20, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + // task 42 at #4 + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert_eq!(Agenda::::get(4).len(), 2); + // task 20 will be retried 3 times every block + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 3, 1)); + // task 42 will be retried 10 times every 3 blocks + assert_ok!(Scheduler::set_retry(root().into(), (4, 1), 10, 3)); + assert_eq!(Retries::::iter().count(), 2); + run_to_block(3); + assert!(logger::log().is_empty()); + assert_eq!(Agenda::::get(4).len(), 2); + // both tasks fail + run_to_block(4); + assert!(Agenda::::get(4).is_empty()); + // 20 is rescheduled for next block + assert_eq!(Agenda::::get(5).len(), 1); + // 42 is rescheduled for block 7 + assert_eq!(Agenda::::get(7).len(), 1); + assert!(logger::log().is_empty()); + // 20 still fails + run_to_block(5); + // 20 rescheduled for next block + assert_eq!(Agenda::::get(6).len(), 1); + assert_eq!(Agenda::::get(7).len(), 1); + assert_eq!(Retries::::iter().count(), 2); + assert!(logger::log().is_empty()); + // 20 still fails + run_to_block(6); + // rescheduled for next block together with 42 + assert_eq!(Agenda::::get(7).len(), 2); + assert_eq!(Retries::::iter().count(), 2); + assert!(logger::log().is_empty()); + // both tasks will fail, for 20 it was the last retry so it's dropped + run_to_block(7); + assert!(Agenda::::get(7).is_empty()); + assert!(Agenda::::get(8).is_empty()); + // 42 is rescheduled for block 10 + assert_eq!(Agenda::::get(10).len(), 1); + assert_eq!(Retries::::iter().count(), 1); + assert!(logger::log().is_empty()); + run_to_block(8); + assert_eq!(Agenda::::get(10).len(), 1); + assert!(logger::log().is_empty()); + run_to_block(9); + assert!(logger::log().is_empty()); + assert_eq!(Retries::::iter().count(), 1); + // 42 runs successfully + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + assert_eq!(Retries::::iter().count(), 0); + run_to_block(11); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(12); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn retry_scheduling_multiple_named_tasks_works() { + new_test_ext().execute_with(|| { + // task fails until we reach block 8 + Threshold::::put((8, 100)); + // task 20 at #4 + assert_ok!(Scheduler::do_schedule_named( + [20u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 20, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + // task 42 at #4 + assert_ok!(Scheduler::do_schedule_named( + [42u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert_eq!(Agenda::::get(4).len(), 2); + // task 20 will be retried 3 times every block + assert_ok!(Scheduler::set_retry_named(root().into(), [20u8; 32], 3, 1)); + // task 42 will be retried 10 times every 3 block + assert_ok!(Scheduler::set_retry_named(root().into(), [42u8; 32], 10, 3)); + assert_eq!(Retries::::iter().count(), 2); + run_to_block(3); + assert!(logger::log().is_empty()); + assert_eq!(Agenda::::get(4).len(), 2); + // both tasks fail + run_to_block(4); + assert!(Agenda::::get(4).is_empty()); + // 42 is rescheduled for block 7 + assert_eq!(Agenda::::get(7).len(), 1); + // 20 is rescheduled for next block + assert_eq!(Agenda::::get(5).len(), 1); + assert!(logger::log().is_empty()); + // 20 still fails + run_to_block(5); + // 20 rescheduled for next block + assert_eq!(Agenda::::get(6).len(), 1); + assert_eq!(Agenda::::get(7).len(), 1); + assert_eq!(Retries::::iter().count(), 2); + assert!(logger::log().is_empty()); + // 20 still fails + run_to_block(6); + // 20 rescheduled for next block together with 42 + assert_eq!(Agenda::::get(7).len(), 2); + assert_eq!(Retries::::iter().count(), 2); + assert!(logger::log().is_empty()); + // both tasks will fail, for 20 it was the last retry so it's dropped + run_to_block(7); + assert!(Agenda::::get(7).is_empty()); + assert!(Agenda::::get(8).is_empty()); + // 42 is rescheduled for block 10 + assert_eq!(Agenda::::get(10).len(), 1); + assert_eq!(Retries::::iter().count(), 1); + assert!(logger::log().is_empty()); + run_to_block(8); + assert_eq!(Agenda::::get(10).len(), 1); + assert!(logger::log().is_empty()); + run_to_block(9); + assert!(logger::log().is_empty()); + assert_eq!(Retries::::iter().count(), 1); + // 42 runs successfully + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + assert_eq!(Retries::::iter().count(), 0); + run_to_block(11); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(12); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn retry_scheduling_with_period_works() { + new_test_ext().execute_with(|| { + // tasks fail until we reach block 4 and after we're past block 8 + Threshold::::put((4, 8)); + // task 42 at #4, every 3 blocks, 6 times + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + Some((3, 6)), + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert!(Agenda::::get(4)[0].is_some()); + // 42 will be retried 10 times every 2 blocks + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 10, 2)); + assert_eq!(Retries::::iter().count(), 1); + run_to_block(3); + assert!(logger::log().is_empty()); + assert!(Agenda::::get(4)[0].is_some()); + // 42 runs successfully once, it will run again at block 7 + run_to_block(4); + assert!(Agenda::::get(4).is_empty()); + assert!(Agenda::::get(7)[0].is_some()); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // nothing changed + run_to_block(6); + assert!(Agenda::::get(7)[0].is_some()); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // 42 runs successfully again, it will run again at block 10 + run_to_block(7); + assert!(Agenda::::get(7).is_empty()); + assert!(Agenda::::get(10)[0].is_some()); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(9); + assert!(Agenda::::get(10)[0].is_some()); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // 42 has 10 retries left out of a total of 10 + assert_eq!(Retries::::get((10, 0)).unwrap().remaining, 10); + // 42 will fail because we're outside the set threshold (block number in `4..8`), so it + // should be retried in 2 blocks (at block 12) + run_to_block(10); + // should be queued for the normal period of 3 blocks + assert!(Agenda::::get(13)[0].is_some()); + // should also be queued to be retried in 2 blocks + assert!(Agenda::::get(12)[0].is_some()); + // 42 has consumed one retry attempt + assert_eq!(Retries::::get((12, 0)).unwrap().remaining, 9); + assert_eq!(Retries::::get((13, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // 42 will fail again + run_to_block(12); + // should still be queued for the normal period + assert!(Agenda::::get(13)[0].is_some()); + // should be queued to be retried in 2 blocks + assert!(Agenda::::get(14)[0].is_some()); + // 42 has consumed another retry attempt + assert_eq!(Retries::::get((14, 0)).unwrap().remaining, 8); + assert_eq!(Retries::::get((13, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // 42 will fail for the regular periodic run + run_to_block(13); + // should still be queued for the normal period + assert!(Agenda::::get(16)[0].is_some()); + // should still be queued to be retried next block + assert!(Agenda::::get(14)[0].is_some()); + // 42 consumed another periodic run, which failed, so another retry is queued for block 15 + assert!(Agenda::::get(16)[0].as_ref().unwrap().maybe_periodic.is_some()); + assert!(Agenda::::get(15)[0].as_ref().unwrap().maybe_periodic.is_none()); + assert!(Agenda::::get(14)[0].as_ref().unwrap().maybe_periodic.is_none()); + assert_eq!(Retries::::iter().count(), 3); + assert!(Retries::::get((14, 0)).unwrap().remaining == 8); + assert!(Retries::::get((15, 0)).unwrap().remaining == 9); + assert!(Retries::::get((16, 0)).unwrap().remaining == 10); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // change the threshold to allow the task to succeed + Threshold::::put((14, 100)); + // first retry should now succeed + run_to_block(14); + assert!(Agenda::::get(15)[0].as_ref().unwrap().maybe_periodic.is_none()); + assert_eq!(Agenda::::get(16).iter().filter(|entry| entry.is_some()).count(), 1); + assert!(Agenda::::get(16)[0].is_some()); + assert_eq!(Retries::::get((15, 0)).unwrap().remaining, 9); + assert_eq!(Retries::::get((16, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + // second retry should also succeed + run_to_block(15); + assert_eq!(Agenda::::get(16).iter().filter(|entry| entry.is_some()).count(), 1); + assert!(Agenda::::get(16)[0].is_some()); + assert!(Agenda::::get(17).is_empty()); + assert_eq!(Retries::::get((16, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!( + logger::log(), + vec![(root(), 42u32), (root(), 42u32), (root(), 42u32), (root(), 42u32)] + ); + // normal periodic run on block 16 will succeed + run_to_block(16); + // next periodic run at block 19 + assert!(Agenda::::get(19)[0].is_some()); + assert!(Agenda::::get(18).is_empty()); + assert!(Agenda::::get(17).is_empty()); + assert_eq!(Retries::::get((19, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!( + logger::log(), + vec![ + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32) + ] + ); + // final periodic run on block 19 will succeed + run_to_block(19); + // next periodic run at block 19 + assert_eq!(Agenda::::iter().count(), 0); + assert_eq!(Retries::::iter().count(), 0); + assert_eq!( + logger::log(), + vec![ + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32) + ] + ); + }); +} + +#[test] +fn named_retry_scheduling_with_period_works() { + new_test_ext().execute_with(|| { + // tasks fail until we reach block 4 and after we're past block 8 + Threshold::::put((4, 8)); + // task 42 at #4, every 3 blocks, 6 times + assert_ok!(Scheduler::do_schedule_named( + [42u8; 32], + DispatchTime::At(4), + Some((3, 6)), + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert!(Agenda::::get(4)[0].is_some()); + // 42 will be retried 10 times every 2 blocks + assert_ok!(Scheduler::set_retry_named(root().into(), [42u8; 32], 10, 2)); + assert_eq!(Retries::::iter().count(), 1); + run_to_block(3); + assert!(logger::log().is_empty()); + assert!(Agenda::::get(4)[0].is_some()); + // 42 runs successfully once, it will run again at block 7 + run_to_block(4); + assert!(Agenda::::get(4).is_empty()); + assert!(Agenda::::get(7)[0].is_some()); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // nothing changed + run_to_block(6); + assert!(Agenda::::get(7)[0].is_some()); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // 42 runs successfully again, it will run again at block 10 + run_to_block(7); + assert!(Agenda::::get(7).is_empty()); + assert!(Agenda::::get(10)[0].is_some()); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(9); + assert!(Agenda::::get(10)[0].is_some()); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // 42 has 10 retries left out of a total of 10 + assert_eq!(Retries::::get((10, 0)).unwrap().remaining, 10); + // 42 will fail because we're outside the set threshold (block number in `4..8`), so it + // should be retried in 2 blocks (at block 12) + run_to_block(10); + // should be queued for the normal period of 3 blocks + assert!(Agenda::::get(13)[0].is_some()); + // should also be queued to be retried in 2 blocks + assert!(Agenda::::get(12)[0].is_some()); + // 42 has consumed one retry attempt + assert_eq!(Retries::::get((12, 0)).unwrap().remaining, 9); + assert_eq!(Retries::::get((13, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(Lookup::::get([42u8; 32]).unwrap(), (13, 0)); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // 42 will fail again + run_to_block(12); + // should still be queued for the normal period + assert!(Agenda::::get(13)[0].is_some()); + // should be queued to be retried in 2 blocks + assert!(Agenda::::get(14)[0].is_some()); + // 42 has consumed another retry attempt + assert_eq!(Retries::::get((14, 0)).unwrap().remaining, 8); + assert_eq!(Retries::::get((13, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // 42 will fail for the regular periodic run + run_to_block(13); + // should still be queued for the normal period + assert!(Agenda::::get(16)[0].is_some()); + // should still be queued to be retried next block + assert!(Agenda::::get(14)[0].is_some()); + // 42 consumed another periodic run, which failed, so another retry is queued for block 15 + assert!(Agenda::::get(16)[0].as_ref().unwrap().maybe_periodic.is_some()); + assert!(Agenda::::get(15)[0].as_ref().unwrap().maybe_periodic.is_none()); + assert!(Agenda::::get(14)[0].as_ref().unwrap().maybe_periodic.is_none()); + assert_eq!(Retries::::iter().count(), 3); + assert!(Retries::::get((14, 0)).unwrap().remaining == 8); + assert!(Retries::::get((15, 0)).unwrap().remaining == 9); + assert!(Retries::::get((16, 0)).unwrap().remaining == 10); + assert_eq!(Lookup::::get([42u8; 32]).unwrap(), (16, 0)); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + // change the threshold to allow the task to succeed + Threshold::::put((14, 100)); + // first retry should now succeed + run_to_block(14); + assert!(Agenda::::get(15)[0].as_ref().unwrap().maybe_periodic.is_none()); + assert_eq!(Agenda::::get(16).iter().filter(|entry| entry.is_some()).count(), 1); + assert!(Agenda::::get(16)[0].is_some()); + assert_eq!(Retries::::get((15, 0)).unwrap().remaining, 9); + assert_eq!(Retries::::get((16, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + // second retry should also succeed + run_to_block(15); + assert_eq!(Agenda::::get(16).iter().filter(|entry| entry.is_some()).count(), 1); + assert!(Agenda::::get(16)[0].is_some()); + assert!(Agenda::::get(17).is_empty()); + assert_eq!(Retries::::get((16, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(Lookup::::get([42u8; 32]).unwrap(), (16, 0)); + assert_eq!( + logger::log(), + vec![(root(), 42u32), (root(), 42u32), (root(), 42u32), (root(), 42u32)] + ); + // normal periodic run on block 16 will succeed + run_to_block(16); + // next periodic run at block 19 + assert!(Agenda::::get(19)[0].is_some()); + assert!(Agenda::::get(18).is_empty()); + assert!(Agenda::::get(17).is_empty()); + assert_eq!(Retries::::get((19, 0)).unwrap().remaining, 10); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(Lookup::::get([42u8; 32]).unwrap(), (19, 0)); + assert_eq!( + logger::log(), + vec![ + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32) + ] + ); + // final periodic run on block 19 will succeed + run_to_block(19); + // next periodic run at block 19 + assert_eq!(Agenda::::iter().count(), 0); + assert_eq!(Retries::::iter().count(), 0); + assert_eq!(Lookup::::iter().count(), 0); + assert_eq!( + logger::log(), + vec![ + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32), + (root(), 42u32) + ] + ); + }); +} + +#[test] +fn retry_scheduling_expires() { + new_test_ext().execute_with(|| { + // task will fail if we're past block 3 + Threshold::::put((1, 3)); + // task 42 at #4 + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + assert!(Agenda::::get(4)[0].is_some()); + // task 42 will be retried 3 times every block + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 3, 1)); + assert_eq!(Retries::::iter().count(), 1); + run_to_block(3); + assert!(logger::log().is_empty()); + // task 42 is scheduled for next block + assert!(Agenda::::get(4)[0].is_some()); + // task fails because we're past block 3 + run_to_block(4); + // task is scheduled for next block + assert!(Agenda::::get(4).is_empty()); + assert!(Agenda::::get(5)[0].is_some()); + // one retry attempt is consumed + assert_eq!(Retries::::get((5, 0)).unwrap().remaining, 2); + assert!(logger::log().is_empty()); + // task fails again + run_to_block(5); + // task is scheduled for next block + assert!(Agenda::::get(5).is_empty()); + assert!(Agenda::::get(6)[0].is_some()); + // another retry attempt is consumed + assert_eq!(Retries::::get((6, 0)).unwrap().remaining, 1); + assert!(logger::log().is_empty()); + // task fails again + run_to_block(6); + // task is scheduled for next block + assert!(Agenda::::get(6).is_empty()); + assert!(Agenda::::get(7)[0].is_some()); + // another retry attempt is consumed + assert_eq!(Retries::::get((7, 0)).unwrap().remaining, 0); + assert!(logger::log().is_empty()); + // task fails again + run_to_block(7); + // task ran out of retries so it gets dropped + assert_eq!(Agenda::::iter().count(), 0); + assert_eq!(Retries::::iter().count(), 0); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn set_retry_bad_origin() { + new_test_ext().execute_with(|| { + // task 42 at #4 with account 101 as origin + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + 101.into(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert!(Agenda::::get(4)[0].is_some()); + // try to change the retry config with a different (non-root) account + let res: Result<(), DispatchError> = + Scheduler::set_retry(RuntimeOrigin::signed(102), (4, 0), 10, 2); + assert_eq!(res, Err(BadOrigin.into())); + }); +} + +#[test] +fn set_named_retry_bad_origin() { + new_test_ext().execute_with(|| { + // task 42 at #4 with account 101 as origin + assert_ok!(Scheduler::do_schedule_named( + [42u8; 32], + DispatchTime::At(4), + None, + 127, + 101.into(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert!(Agenda::::get(4)[0].is_some()); + // try to change the retry config with a different (non-root) account + let res: Result<(), DispatchError> = + Scheduler::set_retry_named(RuntimeOrigin::signed(102), [42u8; 32], 10, 2); + assert_eq!(res, Err(BadOrigin.into())); + }); +} + +#[test] +fn set_retry_works() { + new_test_ext().execute_with(|| { + // task 42 at #4 + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert!(Agenda::::get(4)[0].is_some()); + // make sure the retry configuration was stored + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 10, 2)); + assert_eq!( + Retries::::get((4, 0)), + Some(RetryConfig { total_retries: 10, remaining: 10, period: 2 }) + ); + }); +} + +#[test] +fn set_named_retry_works() { + new_test_ext().execute_with(|| { + // task 42 at #4 with account 101 as origin + assert_ok!(Scheduler::do_schedule_named( + [42u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert!(Agenda::::get(4)[0].is_some()); + // make sure the retry configuration was stored + assert_ok!(Scheduler::set_retry_named(root().into(), [42u8; 32], 10, 2)); + let address = Lookup::::get([42u8; 32]).unwrap(); + assert_eq!( + Retries::::get(address), + Some(RetryConfig { total_retries: 10, remaining: 10, period: 2 }) + ); + }); +} + +#[test] +fn retry_periodic_full_cycle() { + new_test_ext().execute_with(|| { + // tasks fail after we pass block 1000 + Threshold::::put((1, 1000)); + // task 42 at #4, every 100 blocks, 4 times + assert_ok!(Scheduler::do_schedule_named( + [42u8; 32], + DispatchTime::At(10), + Some((100, 4)), + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert!(Agenda::::get(10)[0].is_some()); + // 42 will be retried 2 times every block + assert_ok!(Scheduler::set_retry_named(root().into(), [42u8; 32], 2, 1)); + assert_eq!(Retries::::iter().count(), 1); + run_to_block(9); + assert!(logger::log().is_empty()); + assert!(Agenda::::get(10)[0].is_some()); + // 42 runs successfully once, it will run again at block 110 + run_to_block(10); + assert!(Agenda::::get(10).is_empty()); + assert!(Agenda::::get(110)[0].is_some()); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // nothing changed + run_to_block(109); + assert!(Agenda::::get(110)[0].is_some()); + // original task still has 2 remaining retries + assert_eq!(Retries::::get((110, 0)).unwrap().remaining, 2); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // make 42 fail next block + Threshold::::put((1, 2)); + // 42 will fail because we're outside the set threshold (block number in `1..2`), so it + // should be retried next block (at block 111) + run_to_block(110); + // should be queued for the normal period of 100 blocks + assert!(Agenda::::get(210)[0].is_some()); + // should also be queued to be retried next block + assert!(Agenda::::get(111)[0].is_some()); + // 42 retry clone has consumed one retry attempt + assert_eq!(Retries::::get((111, 0)).unwrap().remaining, 1); + // 42 original task still has the original remaining attempts + assert_eq!(Retries::::get((210, 0)).unwrap().remaining, 2); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // 42 retry will fail again + run_to_block(111); + // should still be queued for the normal period + assert!(Agenda::::get(210)[0].is_some()); + // should be queued to be retried next block + assert!(Agenda::::get(112)[0].is_some()); + // 42 has consumed another retry attempt + assert_eq!(Retries::::get((210, 0)).unwrap().remaining, 2); + assert_eq!(Retries::::get((112, 0)).unwrap().remaining, 0); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // 42 retry will fail again + run_to_block(112); + // should still be queued for the normal period + assert!(Agenda::::get(210)[0].is_some()); + // 42 retry clone ran out of retries, must have been evicted + assert_eq!(Agenda::::iter().count(), 1); + + // advance + run_to_block(209); + // should still be queued for the normal period + assert!(Agenda::::get(210)[0].is_some()); + // 42 retry clone ran out of retries, must have been evicted + assert_eq!(Agenda::::iter().count(), 1); + // 42 should fail again and should spawn another retry clone + run_to_block(210); + // should be queued for the normal period of 100 blocks + assert!(Agenda::::get(310)[0].is_some()); + // should also be queued to be retried next block + assert!(Agenda::::get(211)[0].is_some()); + // 42 retry clone has consumed one retry attempt + assert_eq!(Retries::::get((211, 0)).unwrap().remaining, 1); + // 42 original task still has the original remaining attempts + assert_eq!(Retries::::get((310, 0)).unwrap().remaining, 2); + assert_eq!(Retries::::iter().count(), 2); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // make 42 run successfully again + Threshold::::put((1, 1000)); + // 42 retry clone should now succeed + run_to_block(211); + // should be queued for the normal period of 100 blocks + assert!(Agenda::::get(310)[0].is_some()); + // retry was successful, retry task should have been discarded + assert_eq!(Agenda::::iter().count(), 1); + // 42 original task still has the original remaining attempts + assert_eq!(Retries::::get((310, 0)).unwrap().remaining, 2); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + + // fast forward to the last periodic run of 42 + run_to_block(310); + // 42 was successful, the period ended as this was the 4th scheduled periodic run so 42 must + // have been discarded + assert_eq!(Agenda::::iter().count(), 0); + // agenda is empty so no retries should exist + assert_eq!(Retries::::iter().count(), 0); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + }); +} + #[test] fn reschedule_works() { new_test_ext().execute_with(|| { @@ -430,6 +1290,117 @@ fn scheduler_respects_weight_limits() { }); } +#[test] +fn retry_respects_weight_limits() { + let max_weight: Weight = ::MaximumWeight::get(); + new_test_ext().execute_with(|| { + // schedule 42 + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(8), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + )); + // schedule 20 with a call that will fail until we reach block 8 + Threshold::::put((8, 100)); + let call = RuntimeCall::Logger(LoggerCall::timed_log { i: 20, weight: max_weight / 3 * 2 }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + )); + // set a retry config for 20 for 10 retries every block + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 10, 1)); + // 20 should fail and be retried later + run_to_block(4); + assert!(Agenda::::get(5)[0].is_some()); + assert!(Agenda::::get(8)[0].is_some()); + assert_eq!(Retries::::iter().count(), 1); + assert!(logger::log().is_empty()); + // 20 still fails but is scheduled next block together with 42 + run_to_block(7); + assert_eq!(Agenda::::get(8).len(), 2); + assert_eq!(Retries::::iter().count(), 1); + assert!(logger::log().is_empty()); + // 20 and 42 do not fit together + // 42 is executed as it was first in the queue + // 20 is still on the 8th block's agenda + run_to_block(8); + assert!(Agenda::::get(8)[0].is_none()); + assert!(Agenda::::get(8)[1].is_some()); + assert_eq!(Retries::::iter().count(), 1); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // 20 is executed and the schedule is cleared + run_to_block(9); + assert_eq!(Agenda::::iter().count(), 0); + assert_eq!(Retries::::iter().count(), 0); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 20u32)]); + }); +} + +#[test] +fn try_schedule_retry_respects_weight_limits() { + let max_weight: Weight = ::MaximumWeight::get(); + new_test_ext().execute_with(|| { + let service_agendas_weight = ::WeightInfo::service_agendas_base(); + let service_agenda_weight = ::WeightInfo::service_agenda_base( + ::MaxScheduledPerBlock::get(), + ); + let actual_service_agenda_weight = ::WeightInfo::service_agenda_base(1); + // Some weight for `service_agenda` will be refunded, so we need to make sure the weight + // `try_schedule_retry` is going to ask for is greater than this difference, and we take a + // safety factor of 10 to make sure we're over that limit. + let meter = WeightMeter::with_limit( + ::WeightInfo::schedule_retry( + ::MaxScheduledPerBlock::get(), + ) / 10, + ); + assert!(meter.can_consume(service_agenda_weight - actual_service_agenda_weight)); + + let reference_call = + RuntimeCall::Logger(LoggerCall::timed_log { i: 20, weight: max_weight / 3 * 2 }); + let bounded = ::Preimages::bound(reference_call).unwrap(); + let base_weight = ::WeightInfo::service_task( + bounded.lookup_len().map(|x| x as usize), + false, + false, + ); + // we make the call cost enough so that all checks have enough weight to run aside from + // `try_schedule_retry` + let call_weight = max_weight - service_agendas_weight - service_agenda_weight - base_weight; + let call = RuntimeCall::Logger(LoggerCall::timed_log { i: 20, weight: call_weight }); + // schedule 20 with a call that will fail until we reach block 8 + Threshold::::put((8, 100)); + + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + )); + // set a retry config for 20 for 10 retries every block + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 10, 1)); + // 20 should fail and, because of insufficient weight, it should not be scheduled again + run_to_block(4); + // nothing else should be scheduled + assert_eq!(Agenda::::iter().count(), 0); + assert_eq!(Retries::::iter().count(), 0); + assert_eq!(logger::log(), vec![]); + // check the `RetryFailed` event happened + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = + Event::RetryFailed { task: (4, 0), id: None }.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); + }); +} + /// Permanently overweight calls are not deleted but also not executed. #[test] fn scheduler_does_not_delete_permanently_overweight_call() { @@ -877,6 +1848,134 @@ fn should_check_origin_for_cancel() { }); } +#[test] +fn cancel_removes_retry_entry() { + new_test_ext().execute_with(|| { + // task fails until block 99 is reached + Threshold::::put((99, 100)); + // task 20 at #4 + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 20, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + // named task 42 at #4 + assert_ok!(Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert_eq!(Agenda::::get(4).len(), 2); + // task 20 will be retried 3 times every block + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 10, 1)); + // task 42 will be retried 10 times every 3 blocks + assert_ok!(Scheduler::set_retry_named(root().into(), [1u8; 32], 10, 1)); + assert_eq!(Retries::::iter().count(), 2); + run_to_block(3); + assert!(logger::log().is_empty()); + assert_eq!(Agenda::::get(4).len(), 2); + // both tasks fail + run_to_block(4); + assert!(Agenda::::get(4).is_empty()); + // 42 and 20 are rescheduled for next block + assert_eq!(Agenda::::get(5).len(), 2); + assert!(logger::log().is_empty()); + // 42 and 20 still fail + run_to_block(5); + // 42 and 20 rescheduled for next block + assert_eq!(Agenda::::get(6).len(), 2); + assert_eq!(Retries::::iter().count(), 2); + assert!(logger::log().is_empty()); + + // even though 42 is being retried, the tasks scheduled for retries are not named + assert_eq!(Lookup::::iter().count(), 0); + assert!(Scheduler::cancel(root().into(), 6, 0).is_ok()); + + // 20 is removed, 42 still fails + run_to_block(6); + // 42 rescheduled for next block + assert_eq!(Agenda::::get(7).len(), 1); + // 20's retry entry is removed + assert!(!Retries::::contains_key((4, 0))); + assert_eq!(Retries::::iter().count(), 1); + assert!(logger::log().is_empty()); + + assert!(Scheduler::cancel(root().into(), 7, 0).is_ok()); + + // both tasks are canceled, everything is removed now + run_to_block(7); + assert!(Agenda::::get(8).is_empty()); + assert_eq!(Retries::::iter().count(), 0); + }); +} + +#[test] +fn cancel_retries_works() { + new_test_ext().execute_with(|| { + // task fails until block 99 is reached + Threshold::::put((99, 100)); + // task 20 at #4 + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 20, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + // named task 42 at #4 + assert_ok!(Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(RuntimeCall::Logger(logger::Call::timed_log { + i: 42, + weight: Weight::from_parts(10, 0) + })) + .unwrap() + )); + + assert_eq!(Agenda::::get(4).len(), 2); + // task 20 will be retried 3 times every block + assert_ok!(Scheduler::set_retry(root().into(), (4, 0), 10, 1)); + // task 42 will be retried 10 times every 3 blocks + assert_ok!(Scheduler::set_retry_named(root().into(), [1u8; 32], 10, 1)); + assert_eq!(Retries::::iter().count(), 2); + run_to_block(3); + assert!(logger::log().is_empty()); + assert_eq!(Agenda::::get(4).len(), 2); + // cancel the retry config for 20 + assert_ok!(Scheduler::cancel_retry(root().into(), (4, 0))); + assert_eq!(Retries::::iter().count(), 1); + // cancel the retry config for 42 + assert_ok!(Scheduler::cancel_retry_named(root().into(), [1u8; 32])); + assert_eq!(Retries::::iter().count(), 0); + run_to_block(4); + // both tasks failed and there are no more retries, so they are evicted + assert_eq!(Agenda::::get(4).len(), 0); + assert_eq!(Retries::::iter().count(), 0); + }); +} + #[test] fn migration_to_v4_works() { new_test_ext().execute_with(|| { @@ -1054,6 +2153,8 @@ fn test_migrate_origin() { match self { 3u32 => system::RawOrigin::Root.into(), 2u32 => system::RawOrigin::None.into(), + 101u32 => system::RawOrigin::Signed(101).into(), + 102u32 => system::RawOrigin::Signed(102).into(), _ => unreachable!("test make no use of it"), } } diff --git a/substrate/frame/scheduler/src/weights.rs b/substrate/frame/scheduler/src/weights.rs index 58d711862591d033b66251def364acd5ebbac7a7..6c98145d266fdd7603cbd625ef55968013b3cd32 100644 --- a/substrate/frame/scheduler/src/weights.rs +++ b/substrate/frame/scheduler/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_scheduler +//! Autogenerated weights for `pallet_scheduler` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/scheduler/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/scheduler/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_scheduler. +/// Weight functions needed for `pallet_scheduler`. pub trait WeightInfo { fn service_agendas_base() -> Weight; fn service_agenda_base(s: u32, ) -> Weight; @@ -64,33 +63,38 @@ pub trait WeightInfo { fn cancel(s: u32, ) -> Weight; fn schedule_named(s: u32, ) -> Weight; fn cancel_named(s: u32, ) -> Weight; + fn schedule_retry(s: u32, ) -> Weight; + fn set_retry() -> Weight; + fn set_retry_named() -> Weight; + fn cancel_retry() -> Weight; + fn cancel_retry_named() -> Weight; } -/// Weights for pallet_scheduler using the Substrate node and recommended hardware. +/// Weights for `pallet_scheduler` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Scheduler IncompleteSince (r:1 w:1) - /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Scheduler::IncompleteSince` (r:1 w:1) + /// Proof: `Scheduler::IncompleteSince` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn service_agendas_base() -> Weight { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_991_000 picoseconds. - Weight::from_parts(4_174_000, 1489) + // Minimum execution time: 3_128_000 picoseconds. + Weight::from_parts(3_372_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_581_000 picoseconds. - Weight::from_parts(7_413_174, 110487) - // Standard Error: 971 - .saturating_add(Weight::from_parts(348_077, 0).saturating_mul(s.into())) + // Minimum execution time: 3_560_000 picoseconds. + Weight::from_parts(6_356_795, 110487) + // Standard Error: 493 + .saturating_add(Weight::from_parts(315_098, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -98,145 +102,228 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_250_000 picoseconds. - Weight::from_parts(5_549_000, 0) + // Minimum execution time: 3_501_000 picoseconds. + Weight::from_parts(3_722_000, 0) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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: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 `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `179 + s * (1 ±0)` - // Estimated: `3644 + s * (1 ±0)` - // Minimum execution time: 20_089_000 picoseconds. - Weight::from_parts(20_376_000, 3644) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_170, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `246 + s * (1 ±0)` + // Estimated: `3711 + s * (1 ±0)` + // Minimum execution time: 17_976_000 picoseconds. + Weight::from_parts(18_137_000, 3711) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_173, 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) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn service_task_named() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_998_000 picoseconds. - Weight::from_parts(7_303_000, 0) + // Minimum execution time: 4_935_000 picoseconds. + Weight::from_parts(5_133_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: 5_078_000 picoseconds. - Weight::from_parts(5_315_000, 0) + // Minimum execution time: 3_467_000 picoseconds. + Weight::from_parts(3_654_000, 0) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_228_000 picoseconds. - Weight::from_parts(2_352_000, 0) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 6_528_000 picoseconds. + Weight::from_parts(6_820_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_226_000 picoseconds. - Weight::from_parts(2_371_000, 0) + // Minimum execution time: 2_202_000 picoseconds. + Weight::from_parts(2_360_000, 0) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 12_683_000 picoseconds. - Weight::from_parts(16_951_846, 110487) - // Standard Error: 1_046 - .saturating_add(Weight::from_parts(380_842, 0).saturating_mul(s.into())) + // Minimum execution time: 10_222_000 picoseconds. + Weight::from_parts(13_654_958, 110487) + // Standard Error: 676 + .saturating_add(Weight::from_parts(338_633, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, 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::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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, 512]`. fn cancel(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 16_201_000 picoseconds. - Weight::from_parts(18_259_422, 110487) - // Standard Error: 1_344 - .saturating_add(Weight::from_parts(545_863, 0).saturating_mul(s.into())) + // Minimum execution time: 15_517_000 picoseconds. + Weight::from_parts(17_464_075, 110487) + // Standard Error: 952 + .saturating_add(Weight::from_parts(495_806, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Scheduler Lookup (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// 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(107022), added: 109497, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 16_180_000 picoseconds. - Weight::from_parts(25_128_925, 110487) - // Standard Error: 1_118 - .saturating_add(Weight::from_parts(375_631, 0).saturating_mul(s.into())) + // Minimum execution time: 13_091_000 picoseconds. + Weight::from_parts(19_101_313, 110487) + // Standard Error: 662 + .saturating_add(Weight::from_parts(342_468, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Scheduler Lookup (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// 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(107022), added: 109497, 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, 512]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 18_244_000 picoseconds. - Weight::from_parts(21_439_366, 110487) - // Standard Error: 1_084 - .saturating_add(Weight::from_parts(557_691, 0).saturating_mul(s.into())) + // Minimum execution time: 17_579_000 picoseconds. + Weight::from_parts(20_561_921, 110487) + // Standard Error: 792 + .saturating_add(Weight::from_parts(500_463, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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, 512]`. + fn schedule_retry(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `110487` + // Minimum execution time: 8_996_000 picoseconds. + Weight::from_parts(11_393_234, 110487) + // Standard Error: 190 + .saturating_add(Weight::from_parts(6_714, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `90705` + // Estimated: `110487` + // Minimum execution time: 121_505_000 picoseconds. + Weight::from_parts(124_306_000, 110487) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `91747` + // Estimated: `110487` + // Minimum execution time: 128_070_000 picoseconds. + Weight::from_parts(132_683_000, 110487) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `90717` + // Estimated: `110487` + // Minimum execution time: 118_260_000 picoseconds. + Weight::from_parts(119_722_000, 110487) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `91759` + // Estimated: `110487` + // Minimum execution time: 129_036_000 picoseconds. + Weight::from_parts(133_975_000, 110487) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Scheduler IncompleteSince (r:1 w:1) - /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Scheduler::IncompleteSince` (r:1 w:1) + /// Proof: `Scheduler::IncompleteSince` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn service_agendas_base() -> Weight { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_991_000 picoseconds. - Weight::from_parts(4_174_000, 1489) + // Minimum execution time: 3_128_000 picoseconds. + Weight::from_parts(3_372_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_581_000 picoseconds. - Weight::from_parts(7_413_174, 110487) - // Standard Error: 971 - .saturating_add(Weight::from_parts(348_077, 0).saturating_mul(s.into())) + // Minimum execution time: 3_560_000 picoseconds. + Weight::from_parts(6_356_795, 110487) + // Standard Error: 493 + .saturating_add(Weight::from_parts(315_098, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -244,117 +331,200 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_250_000 picoseconds. - Weight::from_parts(5_549_000, 0) + // Minimum execution time: 3_501_000 picoseconds. + Weight::from_parts(3_722_000, 0) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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: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 `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `179 + s * (1 ±0)` - // Estimated: `3644 + s * (1 ±0)` - // Minimum execution time: 20_089_000 picoseconds. - Weight::from_parts(20_376_000, 3644) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_170, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `246 + s * (1 ±0)` + // Estimated: `3711 + s * (1 ±0)` + // Minimum execution time: 17_976_000 picoseconds. + Weight::from_parts(18_137_000, 3711) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_173, 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) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn service_task_named() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_998_000 picoseconds. - Weight::from_parts(7_303_000, 0) + // Minimum execution time: 4_935_000 picoseconds. + Weight::from_parts(5_133_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: 5_078_000 picoseconds. - Weight::from_parts(5_315_000, 0) + // Minimum execution time: 3_467_000 picoseconds. + Weight::from_parts(3_654_000, 0) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_228_000 picoseconds. - Weight::from_parts(2_352_000, 0) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 6_528_000 picoseconds. + Weight::from_parts(6_820_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_226_000 picoseconds. - Weight::from_parts(2_371_000, 0) + // Minimum execution time: 2_202_000 picoseconds. + Weight::from_parts(2_360_000, 0) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 12_683_000 picoseconds. - Weight::from_parts(16_951_846, 110487) - // Standard Error: 1_046 - .saturating_add(Weight::from_parts(380_842, 0).saturating_mul(s.into())) + // Minimum execution time: 10_222_000 picoseconds. + Weight::from_parts(13_654_958, 110487) + // Standard Error: 676 + .saturating_add(Weight::from_parts(338_633, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, 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::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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, 512]`. fn cancel(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 16_201_000 picoseconds. - Weight::from_parts(18_259_422, 110487) - // Standard Error: 1_344 - .saturating_add(Weight::from_parts(545_863, 0).saturating_mul(s.into())) + // Minimum execution time: 15_517_000 picoseconds. + Weight::from_parts(17_464_075, 110487) + // Standard Error: 952 + .saturating_add(Weight::from_parts(495_806, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Scheduler Lookup (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// 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(107022), added: 109497, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 16_180_000 picoseconds. - Weight::from_parts(25_128_925, 110487) - // Standard Error: 1_118 - .saturating_add(Weight::from_parts(375_631, 0).saturating_mul(s.into())) + // Minimum execution time: 13_091_000 picoseconds. + Weight::from_parts(19_101_313, 110487) + // Standard Error: 662 + .saturating_add(Weight::from_parts(342_468, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Scheduler Lookup (r:1 w:1) - /// 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(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// 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(107022), added: 109497, 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, 512]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 18_244_000 picoseconds. - Weight::from_parts(21_439_366, 110487) - // Standard Error: 1_084 - .saturating_add(Weight::from_parts(557_691, 0).saturating_mul(s.into())) + // Minimum execution time: 17_579_000 picoseconds. + Weight::from_parts(20_561_921, 110487) + // Standard Error: 792 + .saturating_add(Weight::from_parts(500_463, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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, 512]`. + fn schedule_retry(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `110487` + // Minimum execution time: 8_996_000 picoseconds. + Weight::from_parts(11_393_234, 110487) + // Standard Error: 190 + .saturating_add(Weight::from_parts(6_714, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `90705` + // Estimated: `110487` + // Minimum execution time: 121_505_000 picoseconds. + Weight::from_parts(124_306_000, 110487) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `91747` + // Estimated: `110487` + // Minimum execution time: 128_070_000 picoseconds. + Weight::from_parts(132_683_000, 110487) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `90717` + // Estimated: `110487` + // Minimum execution time: 118_260_000 picoseconds. + Weight::from_parts(119_722_000, 110487) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, 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_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `91759` + // Estimated: `110487` + // Minimum execution time: 129_036_000 picoseconds. + Weight::from_parts(133_975_000, 110487) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/substrate/frame/scored-pool/src/mock.rs b/substrate/frame/scored-pool/src/mock.rs index e767b49b983a33635ccae9086bc23fd9595f1231..6fba1bb3d5376ba13273b1133691537234791dca 100644 --- a/substrate/frame/scored-pool/src/mock.rs +++ b/substrate/frame/scored-pool/src/mock.rs @@ -25,12 +25,7 @@ use frame_support::{ traits::{ConstU32, ConstU64}, }; use frame_system::EnsureSignedBy; -use sp_core::H256; -use sp_runtime::{ - bounded_vec, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::{bounded_vec, BuildStorage}; type Block = frame_system::mocking::MockBlock; @@ -53,29 +48,8 @@ ord_parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index 91ffecbf7178ec6d241ba5f4f1d6d509c3aa307c..de041307f7022678235d98372bf7119eb4d48eaa 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/session/src/historical/mod.rs b/substrate/frame/session/src/historical/mod.rs index d74e9dd0b7c54042840c62feff0693359f97c6c9..b9cecea1a7f7144fb7f846548b827455dce0a1e5 100644 --- a/substrate/frame/session/src/historical/mod.rs +++ b/substrate/frame/session/src/historical/mod.rs @@ -58,7 +58,7 @@ pub mod pallet { use super::*; use frame_support::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] diff --git a/substrate/frame/session/src/lib.rs b/substrate/frame/session/src/lib.rs index 178d43f596b2742af69d35437592d78bd030a63d..7d8128dbc1fe64c647994f6da901d4b3bd9e008f 100644 --- a/substrate/frame/session/src/lib.rs +++ b/substrate/frame/session/src/lib.rs @@ -368,7 +368,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); #[pallet::pallet] @@ -460,27 +460,13 @@ pub mod pallet { ); self.keys.iter().map(|x| x.1.clone()).collect() }); - assert!( - !initial_validators_0.is_empty(), - "Empty validator set for session 0 in genesis block!" - ); let initial_validators_1 = T::SessionManager::new_session_genesis(1) .unwrap_or_else(|| initial_validators_0.clone()); - assert!( - !initial_validators_1.is_empty(), - "Empty validator set for session 1 in genesis block!" - ); let queued_keys: Vec<_> = initial_validators_1 - .iter() - .cloned() - .map(|v| { - ( - v.clone(), - Pallet::::load_keys(&v).expect("Validator in session 1 missing keys!"), - ) - }) + .into_iter() + .filter_map(|v| Pallet::::load_keys(&v).map(|k| (v, k))) .collect(); // Tell everyone about the genesis session keys diff --git a/substrate/frame/session/src/mock.rs b/substrate/frame/session/src/mock.rs index eb9eddfd847e6275363ff297671d4318fefd3283..89804f72cd6268314b28724329229882bf9a2103 100644 --- a/substrate/frame/session/src/mock.rs +++ b/substrate/frame/session/src/mock.rs @@ -24,20 +24,12 @@ use crate::historical as pallet_session_historical; use std::collections::BTreeMap; -use sp_core::{crypto::key_types::DUMMY, H256}; -use sp_runtime::{ - impl_opaque_keys, - testing::UintAuthorityId, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_core::crypto::key_types::DUMMY; +use sp_runtime::{impl_opaque_keys, testing::UintAuthorityId, BuildStorage}; use sp_staking::SessionIndex; use sp_state_machine::BasicExternalities; -use frame_support::{ - derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, -}; +use frame_support::{derive_impl, parameter_types, traits::ConstU64}; impl_opaque_keys! { pub struct MockSessionKeys { @@ -234,29 +226,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_timestamp::Config for Test { diff --git a/substrate/frame/session/src/weights.rs b/substrate/frame/session/src/weights.rs index dd9848fd2c177913f9121f98ab269bdae7e0f40e..09eb665ff3d815b2fe7ebc1fb363c97364f93634 100644 --- a/substrate/frame/session/src/weights.rs +++ b/substrate/frame/session/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_session +//! Autogenerated weights for `pallet_session` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/session/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/session/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,77 +49,77 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_session. +/// Weight functions needed for `pallet_session`. pub trait WeightInfo { fn set_keys() -> Weight; fn purge_keys() -> Weight; } -/// Weights for pallet_session using the Substrate node and recommended hardware. +/// Weights for `pallet_session` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:4 w:4) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:6 w:6) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1924` - // Estimated: `12814` - // Minimum execution time: 55_459_000 picoseconds. - Weight::from_parts(56_180_000, 12814) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Measured: `1919` + // Estimated: `17759` + // Minimum execution time: 57_921_000 picoseconds. + Weight::from_parts(58_960_000, 17759) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:0 w:4) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:0 w:6) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1791` - // Estimated: `5256` - // Minimum execution time: 40_194_000 picoseconds. - Weight::from_parts(41_313_000, 5256) + // Measured: `1817` + // Estimated: `5282` + // Minimum execution time: 40_983_000 picoseconds. + Weight::from_parts(42_700_000, 5282) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:4 w:4) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:6 w:6) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1924` - // Estimated: `12814` - // Minimum execution time: 55_459_000 picoseconds. - Weight::from_parts(56_180_000, 12814) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Measured: `1919` + // Estimated: `17759` + // Minimum execution time: 57_921_000 picoseconds. + Weight::from_parts(58_960_000, 17759) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:0 w:4) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:0 w:6) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1791` - // Estimated: `5256` - // Minimum execution time: 40_194_000 picoseconds. - Weight::from_parts(41_313_000, 5256) + // Measured: `1817` + // Estimated: `5282` + // Minimum execution time: 40_983_000 picoseconds. + Weight::from_parts(42_700_000, 5282) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } } diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 8b24f637f420012953233832f9701f050fca73ff..3dab082b3954b7bc1f5e20463c6df5192305550b 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { version = "0.4.17", default-features = false } +log = { workspace = true } rand_chacha = { version = "0.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/society/src/migrations.rs b/substrate/frame/society/src/migrations.rs index dafb1e0b9e5e99706de94b1a4fdd1808343af29d..6a1029114519db8c41c56301197d04de26bfb6c8 100644 --- a/substrate/frame/society/src/migrations.rs +++ b/substrate/frame/society/src/migrations.rs @@ -40,11 +40,11 @@ impl< { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { - let current = Pallet::::current_storage_version(); - let onchain = Pallet::::on_chain_storage_version(); - ensure!(onchain == 0 && current == 2, "pallet_society: invalid version"); + let in_code = Pallet::::in_code_storage_version(); + let on_chain = Pallet::::on_chain_storage_version(); + ensure!(on_chain == 0 && in_code == 2, "pallet_society: invalid version"); - Ok((old::Candidates::::get(), old::Members::::get()).encode()) + Ok((v0::Candidates::::get(), v0::Members::::get()).encode()) } fn on_runtime_upgrade() -> Weight { @@ -103,7 +103,7 @@ pub type MigrateToV2 = frame_support::migrations::VersionedMi ::DbWeight, >; -pub(crate) mod old { +pub(crate) mod v0 { use super::*; use frame_support::storage_alias; @@ -230,37 +230,37 @@ pub fn assert_internal_consistency, I: Instance + 'static>() { } // We don't use these - make sure they don't exist. - assert_eq!(old::SuspendedCandidates::::iter().count(), 0); - assert_eq!(old::Strikes::::iter().count(), 0); - assert_eq!(old::Vouching::::iter().count(), 0); - assert!(!old::Defender::::exists()); - assert!(!old::Members::::exists()); + assert_eq!(v0::SuspendedCandidates::::iter().count(), 0); + assert_eq!(v0::Strikes::::iter().count(), 0); + assert_eq!(v0::Vouching::::iter().count(), 0); + assert!(!v0::Defender::::exists()); + assert!(!v0::Members::::exists()); } pub fn from_original, I: Instance + 'static>( past_payouts: &mut [(::AccountId, BalanceOf)], ) -> Result { // Migrate Bids from old::Bids (just a trunctation). - Bids::::put(BoundedVec::<_, T::MaxBids>::truncate_from(old::Bids::::take())); + Bids::::put(BoundedVec::<_, T::MaxBids>::truncate_from(v0::Bids::::take())); // Initialise round counter. RoundCount::::put(0); // Migrate Candidates from old::Candidates - for Bid { who: candidate, kind, value } in old::Candidates::::take().into_iter() { + for Bid { who: candidate, kind, value } in v0::Candidates::::take().into_iter() { let mut tally = Tally::default(); // Migrate Votes from old::Votes // No need to drain, since we're overwriting values. - for (voter, vote) in old::Votes::::iter_prefix(&candidate) { + for (voter, vote) in v0::Votes::::iter_prefix(&candidate) { Votes::::insert( &candidate, &voter, - Vote { approve: vote == old::Vote::Approve, weight: 1 }, + Vote { approve: vote == v0::Vote::Approve, weight: 1 }, ); match vote { - old::Vote::Approve => tally.approvals.saturating_inc(), - old::Vote::Reject => tally.rejections.saturating_inc(), - old::Vote::Skeptic => Skeptic::::put(&voter), + v0::Vote::Approve => tally.approvals.saturating_inc(), + v0::Vote::Reject => tally.rejections.saturating_inc(), + v0::Vote::Skeptic => Skeptic::::put(&voter), } } Candidates::::insert( @@ -271,9 +271,9 @@ pub fn from_original, I: Instance + 'static>( // Migrate Members from old::Members old::Strikes old::Vouching let mut member_count = 0; - for member in old::Members::::take() { - let strikes = old::Strikes::::take(&member); - let vouching = old::Vouching::::take(&member); + for member in v0::Members::::take() { + let strikes = v0::Strikes::::take(&member); + let vouching = v0::Vouching::::take(&member); let record = MemberRecord { index: member_count, rank: 0, strikes, vouching }; Members::::insert(&member, record); MemberByIndex::::insert(member_count, &member); @@ -314,7 +314,7 @@ pub fn from_original, I: Instance + 'static>( // Migrate Payouts from: old::Payouts and raw info (needed since we can't query old chain // state). past_payouts.sort(); - for (who, mut payouts) in old::Payouts::::iter() { + for (who, mut payouts) in v0::Payouts::::iter() { payouts.truncate(T::MaxPayouts::get() as usize); // ^^ Safe since we already truncated. let paid = past_payouts @@ -329,19 +329,19 @@ pub fn from_original, I: Instance + 'static>( } // Migrate SuspendedMembers from old::SuspendedMembers old::Strikes old::Vouching. - for who in old::SuspendedMembers::::iter_keys() { - let strikes = old::Strikes::::take(&who); - let vouching = old::Vouching::::take(&who); + for who in v0::SuspendedMembers::::iter_keys() { + let strikes = v0::Strikes::::take(&who); + let vouching = v0::Vouching::::take(&who); let record = MemberRecord { index: 0, rank: 0, strikes, vouching }; SuspendedMembers::::insert(&who, record); } // Any suspended candidates remaining are rejected. - let _ = old::SuspendedCandidates::::clear(u32::MAX, None); + let _ = v0::SuspendedCandidates::::clear(u32::MAX, None); // We give the current defender the benefit of the doubt. - old::Defender::::kill(); - let _ = old::DefenderVotes::::clear(u32::MAX, None); + v0::Defender::::kill(); + let _ = v0::DefenderVotes::::clear(u32::MAX, None); Ok(T::BlockWeights::get().max_block) } diff --git a/substrate/frame/society/src/tests.rs b/substrate/frame/society/src/tests.rs index 940643168fb41fd723905497935b7cb543b7f7b7..411567e1dedfde46450c0e778bcb14bb00883962 100644 --- a/substrate/frame/society/src/tests.rs +++ b/substrate/frame/society/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for the module. use super::*; -use migrations::old; +use migrations::v0; use mock::*; use frame_support::{assert_noop, assert_ok}; @@ -32,41 +32,41 @@ use RuntimeOrigin as Origin; #[test] fn migration_works() { EnvBuilder::new().founded(false).execute(|| { - use old::Vote::*; + use v0::Vote::*; // Initialise the old storage items. Founder::::put(10); Head::::put(30); - old::Members::::put(vec![10, 20, 30]); - old::Vouching::::insert(30, Vouching); - old::Vouching::::insert(40, Banned); - old::Strikes::::insert(20, 1); - old::Strikes::::insert(30, 2); - old::Strikes::::insert(40, 5); - old::Payouts::::insert(20, vec![(1, 1)]); - old::Payouts::::insert( + v0::Members::::put(vec![10, 20, 30]); + v0::Vouching::::insert(30, Vouching); + v0::Vouching::::insert(40, Banned); + v0::Strikes::::insert(20, 1); + v0::Strikes::::insert(30, 2); + v0::Strikes::::insert(40, 5); + v0::Payouts::::insert(20, vec![(1, 1)]); + v0::Payouts::::insert( 30, (0..=::MaxPayouts::get()) .map(|i| (i as u64, i as u64)) .collect::>(), ); - old::SuspendedMembers::::insert(40, true); + v0::SuspendedMembers::::insert(40, true); - old::Defender::::put(20); - old::DefenderVotes::::insert(10, Approve); - old::DefenderVotes::::insert(20, Approve); - old::DefenderVotes::::insert(30, Reject); + v0::Defender::::put(20); + v0::DefenderVotes::::insert(10, Approve); + v0::DefenderVotes::::insert(20, Approve); + v0::DefenderVotes::::insert(30, Reject); - old::SuspendedCandidates::::insert(50, (10, Deposit(100))); + v0::SuspendedCandidates::::insert(50, (10, Deposit(100))); - old::Candidates::::put(vec![ + v0::Candidates::::put(vec![ Bid { who: 60, kind: Deposit(100), value: 200 }, Bid { who: 70, kind: Vouch(30, 30), value: 100 }, ]); - old::Votes::::insert(60, 10, Approve); - old::Votes::::insert(70, 10, Reject); - old::Votes::::insert(70, 20, Approve); - old::Votes::::insert(70, 30, Approve); + v0::Votes::::insert(60, 10, Approve); + v0::Votes::::insert(70, 10, Reject); + v0::Votes::::insert(70, 20, Approve); + v0::Votes::::insert(70, 30, Approve); let bids = (0..=::MaxBids::get()) .map(|i| Bid { @@ -75,7 +75,7 @@ fn migration_works() { value: 10u64 + i as u64, }) .collect::>(); - old::Bids::::put(bids); + v0::Bids::::put(bids); migrations::from_original::(&mut [][..]).expect("migration failed"); migrations::assert_internal_consistency::(); diff --git a/substrate/frame/society/src/weights.rs b/substrate/frame/society/src/weights.rs index c32c2383ac99351ae53b97bdcbea8cd5dfad7744..1245f76297216aea9bcc4c0c4b674f66d02a10c2 100644 --- a/substrate/frame/society/src/weights.rs +++ b/substrate/frame/society/src/weights.rs @@ -7,7 +7,7 @@ // 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 +// 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, @@ -15,35 +15,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_society +//! Autogenerated weights for `pallet_society` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! 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 +// ./target/production/substrate-node // benchmark // pallet // --chain=dev // --steps=50 // --repeat=20 // --pallet=pallet_society +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs -// --header=./HEADER-APACHE2 -// --output=./frame/society/src/weights.rs +// --heap-pages=4096 +// --output=./substrate/frame/society/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_society. +/// Weight functions needed for `pallet_society`. pub trait WeightInfo { fn bid() -> Weight; fn unbid() -> Weight; @@ -67,309 +73,739 @@ pub trait WeightInfo { fn cleanup_challenge() -> Weight; } -/// Weights for pallet_society using the Substrate node and recommended hardware. +/// Weights for `pallet_society` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Society Bids (r:1 w:1) - // Storage: Society Candidates (r:1 w:0) - // Storage: Society Members (r:1 w:0) - // Storage: Society SuspendedMembers (r:1 w:0) - // Storage: Society Parameters (r:1 w:0) + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:0) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::SuspendedMembers` (r:1 w:0) + /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn bid() -> Weight { - Weight::zero() - } - // Storage: Society Bids (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `444` + // Estimated: `3909` + // Minimum execution time: 29_905_000 picoseconds. + Weight::from_parts(31_031_000, 3909) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn unbid() -> Weight { - Weight::zero() - } - // Storage: Society Bids (r:1 w:1) - // Storage: Society Candidates (r:1 w:0) - // Storage: Society Members (r:2 w:1) - // Storage: Society SuspendedMembers (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `461` + // Estimated: `1946` + // Minimum execution time: 23_038_000 picoseconds. + Weight::from_parts(23_904_000, 1946) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:0) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:2 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::SuspendedMembers` (r:1 w:0) + /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn vouch() -> Weight { - Weight::zero() - } - // Storage: Society Bids (r:1 w:1) - // Storage: Society Members (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `481` + // Estimated: `6421` + // Minimum execution time: 21_197_000 picoseconds. + Weight::from_parts(22_043_000, 6421) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) fn unvouch() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society Members (r:1 w:0) - // Storage: Society Votes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `535` + // Estimated: `4000` + // Minimum execution time: 14_402_000 picoseconds. + Weight::from_parts(15_171_000, 4000) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:1 w:1) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn vote() -> Weight { - Weight::zero() - } - // Storage: Society Defending (r:1 w:1) - // Storage: Society Members (r:1 w:0) - // Storage: Society ChallengeRoundCount (r:1 w:0) - // Storage: Society DefenderVotes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `569` + // Estimated: `4034` + // Minimum execution time: 21_930_000 picoseconds. + Weight::from_parts(22_666_000, 4034) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Defending` (r:1 w:1) + /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) + /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::DefenderVotes` (r:1 w:1) + /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn defender_vote() -> Weight { - Weight::zero() - } - // Storage: Society Members (r:1 w:0) - // Storage: Society Payouts (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `561` + // Estimated: `4026` + // Minimum execution time: 18_821_000 picoseconds. + Weight::from_parts(19_633_000, 4026) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Payouts` (r:1 w:1) + /// Proof: `Society::Payouts` (`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`) fn payout() -> Weight { - Weight::zero() - } - // Storage: Society Members (r:1 w:1) - // Storage: Society Payouts (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `650` + // Estimated: `4115` + // Minimum execution time: 47_262_000 picoseconds. + Weight::from_parts(48_313_000, 4115) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Members` (r:1 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Payouts` (r:1 w:1) + /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) fn waive_repay() -> Weight { - Weight::zero() - } - // Storage: Society Head (r:1 w:1) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society MemberByIndex (r:0 w:1) - // Storage: Society Founder (r:0 w:1) - // Storage: Society Rules (r:0 w:1) - // Storage: Society Members (r:0 w:1) - // Storage: Society Parameters (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `547` + // Estimated: `4012` + // Minimum execution time: 18_189_000 picoseconds. + Weight::from_parts(19_038_000, 4012) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Head` (r:1 w:1) + /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberByIndex` (r:0 w:1) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Founder` (r:0 w:1) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Rules` (r:0 w:1) + /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:0 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:0 w:1) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn found_society() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:1) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society Head (r:0 w:1) - // Storage: Society Defending (r:0 w:1) - // Storage: Society ChallengeRoundCount (r:0 w:1) - // Storage: Society MemberByIndex (r:0 w:5) - // Storage: Society Skeptic (r:0 w:1) - // Storage: Society Candidates (r:0 w:4) - // Storage: Society Pot (r:0 w:1) - // Storage: Society Rules (r:0 w:1) - // Storage: Society Votes (r:0 w:4) - // Storage: Society Members (r:0 w:5) - // Storage: Society RoundCount (r:0 w:1) - // Storage: Society Bids (r:0 w:1) - // Storage: Society Parameters (r:0 w:1) - // Storage: Society NextHead (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `1665` + // Minimum execution time: 14_815_000 picoseconds. + Weight::from_parts(15_426_000, 1665) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: `Society::Founder` (r:1 w:1) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:5 w:5) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberByIndex` (r:5 w:5) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:4 w:4) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:4 w:4) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Head` (r:0 w:1) + /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Defending` (r:0 w:1) + /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::ChallengeRoundCount` (r:0 w:1) + /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Skeptic` (r:0 w:1) + /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Pot` (r:0 w:1) + /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Rules` (r:0 w:1) + /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:0 w:1) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Bids` (r:0 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:0 w:1) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::NextHead` (r:0 w:1) + /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn dissolve() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society SuspendedMembers (r:1 w:1) - // Storage: Society Payouts (r:1 w:0) - // Storage: Society Pot (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `1654` + // Estimated: `15019` + // Minimum execution time: 57_787_000 picoseconds. + Weight::from_parts(59_489_000, 15019) + .saturating_add(T::DbWeight::get().reads(20_u64)) + .saturating_add(T::DbWeight::get().writes(30_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::SuspendedMembers` (r:1 w:1) + /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Payouts` (r:1 w:0) + /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Pot` (r:1 w:1) + /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn judge_suspended_member() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society MemberCount (r:1 w:0) - // Storage: Society Parameters (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `3970` + // Minimum execution time: 19_262_000 picoseconds. + Weight::from_parts(19_752_000, 3970) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:0) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:0 w:1) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_parameters() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) - // Storage: Society Skeptic (r:1 w:0) - // Storage: Society Votes (r:1 w:0) - // Storage: Society Members (r:1 w:1) - // Storage: Society Parameters (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `1872` + // Minimum execution time: 10_656_000 picoseconds. + Weight::from_parts(11_063_000, 1872) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Skeptic` (r:1 w:0) + /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:1 w:0) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn punish_skeptic() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) - // Storage: Society Parameters (r:1 w:0) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society NextHead (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Society MemberByIndex (r:0 w:1) - // Storage: Society Members (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `636` + // Estimated: `4101` + // Minimum execution time: 22_837_000 picoseconds. + Weight::from_parts(23_738_000, 4101) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::NextHead` (r:1 w:1) + /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Society::MemberByIndex` (r:0 w:1) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:0 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_membership() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) - // Storage: Society Parameters (r:1 w:0) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society NextHead (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Society MemberByIndex (r:0 w:1) - // Storage: Society Members (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `632` + // Estimated: `4097` + // Minimum execution time: 35_142_000 picoseconds. + Weight::from_parts(36_811_000, 4097) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::NextHead` (r:1 w:1) + /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Society::MemberByIndex` (r:0 w:1) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:0 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) fn bestow_membership() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `650` + // Estimated: `4115` + // Minimum execution time: 37_133_000 picoseconds. + Weight::from_parts(38_366_000, 4115) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn kick_candidate() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `776` + // Estimated: `6196` + // Minimum execution time: 37_033_000 picoseconds. + Weight::from_parts(38_293_000, 6196) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn resign_candidacy() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `746` + // Estimated: `6196` + // Minimum execution time: 35_203_000 picoseconds. + Weight::from_parts(36_252_000, 6196) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_candidate() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:0) - // Storage: Society VoteClearCursor (r:1 w:0) - // Storage: Society Votes (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `758` + // Estimated: `6196` + // Minimum execution time: 35_518_000 picoseconds. + Weight::from_parts(36_508_000, 6196) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:0) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::VoteClearCursor` (r:1 w:0) + /// Proof: `Society::VoteClearCursor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:2 w:2) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cleanup_candidacy() -> Weight { - Weight::zero() - } - // Storage: Society ChallengeRoundCount (r:1 w:0) - // Storage: Society DefenderVotes (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `552` + // Estimated: `6492` + // Minimum execution time: 17_001_000 picoseconds. + Weight::from_parts(17_845_000, 6492) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) + /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::DefenderVotes` (r:1 w:1) + /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cleanup_challenge() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `3975` + // Minimum execution time: 11_583_000 picoseconds. + Weight::from_parts(12_134_000, 3975) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - // Storage: Society Bids (r:1 w:1) - // Storage: Society Candidates (r:1 w:0) - // Storage: Society Members (r:1 w:0) - // Storage: Society SuspendedMembers (r:1 w:0) - // Storage: Society Parameters (r:1 w:0) + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:0) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::SuspendedMembers` (r:1 w:0) + /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn bid() -> Weight { - Weight::zero() - } - // Storage: Society Bids (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `444` + // Estimated: `3909` + // Minimum execution time: 29_905_000 picoseconds. + Weight::from_parts(31_031_000, 3909) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn unbid() -> Weight { - Weight::zero() - } - // Storage: Society Bids (r:1 w:1) - // Storage: Society Candidates (r:1 w:0) - // Storage: Society Members (r:2 w:1) - // Storage: Society SuspendedMembers (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `461` + // Estimated: `1946` + // Minimum execution time: 23_038_000 picoseconds. + Weight::from_parts(23_904_000, 1946) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:0) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:2 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::SuspendedMembers` (r:1 w:0) + /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn vouch() -> Weight { - Weight::zero() - } - // Storage: Society Bids (r:1 w:1) - // Storage: Society Members (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `481` + // Estimated: `6421` + // Minimum execution time: 21_197_000 picoseconds. + Weight::from_parts(22_043_000, 6421) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Bids` (r:1 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) fn unvouch() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society Members (r:1 w:0) - // Storage: Society Votes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `535` + // Estimated: `4000` + // Minimum execution time: 14_402_000 picoseconds. + Weight::from_parts(15_171_000, 4000) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:1 w:1) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn vote() -> Weight { - Weight::zero() - } - // Storage: Society Defending (r:1 w:1) - // Storage: Society Members (r:1 w:0) - // Storage: Society ChallengeRoundCount (r:1 w:0) - // Storage: Society DefenderVotes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `569` + // Estimated: `4034` + // Minimum execution time: 21_930_000 picoseconds. + Weight::from_parts(22_666_000, 4034) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Defending` (r:1 w:1) + /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) + /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::DefenderVotes` (r:1 w:1) + /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn defender_vote() -> Weight { - Weight::zero() - } - // Storage: Society Members (r:1 w:0) - // Storage: Society Payouts (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `561` + // Estimated: `4026` + // Minimum execution time: 18_821_000 picoseconds. + Weight::from_parts(19_633_000, 4026) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Members` (r:1 w:0) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Payouts` (r:1 w:1) + /// Proof: `Society::Payouts` (`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`) fn payout() -> Weight { - Weight::zero() - } - // Storage: Society Members (r:1 w:1) - // Storage: Society Payouts (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `650` + // Estimated: `4115` + // Minimum execution time: 47_262_000 picoseconds. + Weight::from_parts(48_313_000, 4115) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Members` (r:1 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Payouts` (r:1 w:1) + /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) fn waive_repay() -> Weight { - Weight::zero() - } - // Storage: Society Head (r:1 w:1) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society MemberByIndex (r:0 w:1) - // Storage: Society Founder (r:0 w:1) - // Storage: Society Rules (r:0 w:1) - // Storage: Society Members (r:0 w:1) - // Storage: Society Parameters (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `547` + // Estimated: `4012` + // Minimum execution time: 18_189_000 picoseconds. + Weight::from_parts(19_038_000, 4012) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Head` (r:1 w:1) + /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberByIndex` (r:0 w:1) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Founder` (r:0 w:1) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Rules` (r:0 w:1) + /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:0 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:0 w:1) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn found_society() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:1) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society Head (r:0 w:1) - // Storage: Society Defending (r:0 w:1) - // Storage: Society ChallengeRoundCount (r:0 w:1) - // Storage: Society MemberByIndex (r:0 w:5) - // Storage: Society Skeptic (r:0 w:1) - // Storage: Society Candidates (r:0 w:4) - // Storage: Society Pot (r:0 w:1) - // Storage: Society Rules (r:0 w:1) - // Storage: Society Votes (r:0 w:4) - // Storage: Society Members (r:0 w:5) - // Storage: Society RoundCount (r:0 w:1) - // Storage: Society Bids (r:0 w:1) - // Storage: Society Parameters (r:0 w:1) - // Storage: Society NextHead (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `1665` + // Minimum execution time: 14_815_000 picoseconds. + Weight::from_parts(15_426_000, 1665) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: `Society::Founder` (r:1 w:1) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:5 w:5) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberByIndex` (r:5 w:5) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:4 w:4) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:4 w:4) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Head` (r:0 w:1) + /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Defending` (r:0 w:1) + /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::ChallengeRoundCount` (r:0 w:1) + /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Skeptic` (r:0 w:1) + /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Pot` (r:0 w:1) + /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Rules` (r:0 w:1) + /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:0 w:1) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Bids` (r:0 w:1) + /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:0 w:1) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::NextHead` (r:0 w:1) + /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn dissolve() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society SuspendedMembers (r:1 w:1) - // Storage: Society Payouts (r:1 w:0) - // Storage: Society Pot (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `1654` + // Estimated: `15019` + // Minimum execution time: 57_787_000 picoseconds. + Weight::from_parts(59_489_000, 15019) + .saturating_add(RocksDbWeight::get().reads(20_u64)) + .saturating_add(RocksDbWeight::get().writes(30_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::SuspendedMembers` (r:1 w:1) + /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Payouts` (r:1 w:0) + /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Pot` (r:1 w:1) + /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn judge_suspended_member() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society MemberCount (r:1 w:0) - // Storage: Society Parameters (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `3970` + // Minimum execution time: 19_262_000 picoseconds. + Weight::from_parts(19_752_000, 3970) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:0) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:0 w:1) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_parameters() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) - // Storage: Society Skeptic (r:1 w:0) - // Storage: Society Votes (r:1 w:0) - // Storage: Society Members (r:1 w:1) - // Storage: Society Parameters (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `1872` + // Minimum execution time: 10_656_000 picoseconds. + Weight::from_parts(11_063_000, 1872) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Skeptic` (r:1 w:0) + /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:1 w:0) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:1 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn punish_skeptic() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) - // Storage: Society Parameters (r:1 w:0) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society NextHead (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Society MemberByIndex (r:0 w:1) - // Storage: Society Members (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `636` + // Estimated: `4101` + // Minimum execution time: 22_837_000 picoseconds. + Weight::from_parts(23_738_000, 4101) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::NextHead` (r:1 w:1) + /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Society::MemberByIndex` (r:0 w:1) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:0 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_membership() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) - // Storage: Society Parameters (r:1 w:0) - // Storage: Society MemberCount (r:1 w:1) - // Storage: Society NextHead (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Society MemberByIndex (r:0 w:1) - // Storage: Society Members (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `632` + // Estimated: `4097` + // Minimum execution time: 35_142_000 picoseconds. + Weight::from_parts(36_811_000, 4097) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Parameters` (r:1 w:0) + /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::MemberCount` (r:1 w:1) + /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::NextHead` (r:1 w:1) + /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Society::MemberByIndex` (r:0 w:1) + /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Members` (r:0 w:1) + /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) fn bestow_membership() -> Weight { - Weight::zero() - } - // Storage: Society Founder (r:1 w:0) - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `650` + // Estimated: `4115` + // Minimum execution time: 37_133_000 picoseconds. + Weight::from_parts(38_366_000, 4115) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: `Society::Founder` (r:1 w:0) + /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn kick_candidate() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `776` + // Estimated: `6196` + // Minimum execution time: 37_033_000 picoseconds. + Weight::from_parts(38_293_000, 6196) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn resign_candidacy() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:1) - // Storage: Society RoundCount (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `746` + // Estimated: `6196` + // Minimum execution time: 35_203_000 picoseconds. + Weight::from_parts(36_252_000, 6196) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:1) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::RoundCount` (r:1 w:0) + /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_candidate() -> Weight { - Weight::zero() - } - // Storage: Society Candidates (r:1 w:0) - // Storage: Society VoteClearCursor (r:1 w:0) - // Storage: Society Votes (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `758` + // Estimated: `6196` + // Minimum execution time: 35_518_000 picoseconds. + Weight::from_parts(36_508_000, 6196) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: `Society::Candidates` (r:1 w:0) + /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::VoteClearCursor` (r:1 w:0) + /// Proof: `Society::VoteClearCursor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Society::Votes` (r:2 w:2) + /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cleanup_candidacy() -> Weight { - Weight::zero() - } - // Storage: Society ChallengeRoundCount (r:1 w:0) - // Storage: Society DefenderVotes (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `552` + // Estimated: `6492` + // Minimum execution time: 17_001_000 picoseconds. + Weight::from_parts(17_845_000, 6492) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) + /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Society::DefenderVotes` (r:1 w:1) + /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cleanup_challenge() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `3975` + // Minimum execution time: 11_583_000 picoseconds. + Weight::from_parts(12_134_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 a1715ba4900102595ac6ec926a0aeeb2a2be1650..549e177491d32ffa18e390a2f83027d3152f0066 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -163,6 +163,12 @@ pub mod runtime { ConstU32, ConstU64, ConstU8, }; + /// Primary types used to parameterize `EnsureOrigin` and `EnsureRootWithArg`. + pub use frame_system::{ + EnsureNever, EnsureNone, EnsureRoot, EnsureRootWithSuccess, EnsureSigned, + EnsureSignedBy, + }; + /// Types to define your runtime version. pub use sp_version::{create_runtime_str, runtime_version, RuntimeVersion}; @@ -191,7 +197,7 @@ pub mod runtime { // Types often used in the runtime APIs. pub use sp_core::OpaqueMetadata; pub use sp_inherents::{CheckInherentsResult, InherentData}; - pub use sp_runtime::ApplyExtrinsicResult; + pub use sp_runtime::{ApplyExtrinsicResult, ExtrinsicInclusionMode}; pub use frame_system_rpc_runtime_api::*; pub use sp_api::{self, *}; @@ -243,8 +249,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>; @@ -258,7 +264,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, diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 2c3f50beaeaea9981beed9d4771bc49b11d83901..d2a46146931b8863ae347277db8076850dc76d68 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"] } +serde = { features = ["alloc", "derive"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } @@ -33,7 +33,7 @@ pallet-session = { path = "../session", default-features = false, features = [ pallet-authorship = { path = "../authorship", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } frame-election-provider-support = { path = "../election-provider-support", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } # Optional imports for benchmarking frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index 26ffbd7efbcb57d85cc4f46607167c98d2b585c4..e2a2782db2da1527eff9d9948020fb72bd02e370 100644 --- a/substrate/frame/staking/reward-curve/Cargo.toml +++ b/substrate/frame/staking/reward-curve/Cargo.toml @@ -20,8 +20,8 @@ proc-macro = true [dependencies] proc-macro-crate = "3.0.0" proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = { version = "2.0.48", features = ["full", "visit"] } +quote = { workspace = true } +syn = { features = ["full", "visit"], workspace = true } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/staking/reward-fn/Cargo.toml b/substrate/frame/staking/reward-fn/Cargo.toml index 0b8903f28718cb917a9742db79380c25d62747c9..5169db5072e2fc80805605c3517d8c6e779e5620 100644 --- a/substrate/frame/staking/reward-fn/Cargo.toml +++ b/substrate/frame/staking/reward-fn/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [lib] [dependencies] -log = { version = "0.4.17", default-features = false } +log = { workspace = true } sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } [features] diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 7bcc68cdfe6f51c001959ba4f2fe2d28c9c7f0ed..a83060873973cbaf568fc729535ce514cd90fcd6 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -855,7 +855,8 @@ benchmarks! { ConfigOp::Set(u32::MAX), ConfigOp::Set(u32::MAX), ConfigOp::Set(Percent::max_value()), - ConfigOp::Set(Perbill::max_value()) + ConfigOp::Set(Perbill::max_value()), + ConfigOp::Set(Percent::max_value()) ) verify { assert_eq!(MinNominatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MinValidatorBond::::get(), BalanceOf::::max_value()); @@ -863,6 +864,7 @@ benchmarks! { assert_eq!(MaxValidatorsCount::::get(), Some(u32::MAX)); assert_eq!(ChillThreshold::::get(), Some(Percent::from_percent(100))); assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); + assert_eq!(MaxStakedRewards::::get(), Some(Percent::from_percent(100))); } set_staking_configs_all_remove { @@ -873,6 +875,7 @@ benchmarks! { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, + ConfigOp::Remove, ConfigOp::Remove ) verify { assert!(!MinNominatorBond::::exists()); @@ -881,6 +884,7 @@ benchmarks! { assert!(!MaxValidatorsCount::::exists()); assert!(!ChillThreshold::::exists()); assert!(!MinCommission::::exists()); + assert!(!MaxStakedRewards::::exists()); } chill_other { @@ -904,6 +908,7 @@ benchmarks! { ConfigOp::Set(0), ConfigOp::Set(Percent::from_percent(0)), ConfigOp::Set(Zero::zero()), + ConfigOp::Noop, )?; let caller = whitelisted_caller(); diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 09185a690be1657cc1fe749b00aad1b91baac76f..5a92b6c855f2d044e671d714d612ad1753ee3e28 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -202,6 +202,12 @@ //! ```nocompile //! remaining_payout = max_yearly_inflation * total_tokens / era_per_year - staker_payout //! ``` +//! +//! Note, however, that it is possible to set a cap on the total `staker_payout` for the era through +//! the `MaxStakersRewards` storage type. The `era_payout` implementor must ensure that the +//! `max_payout = remaining_payout + (staker_payout * max_stakers_rewards)`. The excess payout that +//! is not allocated for stakers is the era remaining reward. +//! //! The remaining reward is send to the configurable end-point [`Config::RewardRemainder`]. //! //! ### Reward Calculation @@ -897,8 +903,10 @@ impl EraPayout for () { /// Adaptor to turn a `PiecewiseLinear` curve definition into an `EraPayout` impl, used for /// backwards compatibility. pub struct ConvertCurve(sp_std::marker::PhantomData); -impl>> - EraPayout for ConvertCurve +impl EraPayout for ConvertCurve +where + Balance: AtLeast32BitUnsigned + Clone + Copy, + T: Get<&'static PiecewiseLinear<'static>>, { fn era_payout( total_staked: Balance, @@ -912,7 +920,7 @@ impl(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV14 { fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let in_code = Pallet::::in_code_storage_version(); let on_chain = Pallet::::on_chain_storage_version(); - if current == 14 && on_chain == 13 { - current.put::>(); + if in_code == 14 && on_chain == 13 { + in_code.put::>(); log!(info, "v14 applied successfully."); T::DbWeight::get().reads_writes(1, 1) @@ -108,12 +108,12 @@ pub mod v13 { } fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); + let in_code = Pallet::::in_code_storage_version(); let onchain = StorageVersion::::get(); - if current == 13 && onchain == ObsoleteReleases::V12_0_0 { + if in_code == 13 && onchain == ObsoleteReleases::V12_0_0 { StorageVersion::::kill(); - current.put::>(); + in_code.put::>(); log!(info, "v13 applied successfully"); T::DbWeight::get().reads_writes(1, 2) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 40a5be51dedf232c9a89583081f15d31f7ce159e..24311cb9e78266240f2ded70fcacfe3b4f265d3f 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -31,14 +31,8 @@ use frame_support::{ weights::constants::RocksDbWeight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use sp_core::H256; use sp_io; -use sp_runtime::{ - curve::PiecewiseLinear, - testing::UintAuthorityId, - traits::{IdentityLookup, Zero}, - BuildStorage, -}; +use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, OnStakingUpdate, @@ -49,7 +43,6 @@ pub const BLOCK_TIME: u64 = 1000; /// The AccountId alias in this test module. pub(crate) type AccountId = u64; -pub(crate) type Nonce = u64; pub(crate) type BlockNumber = u64; pub(crate) type Balance = u128; @@ -127,29 +120,9 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); type DbWeight = RocksDbWeight; - type RuntimeOrigin = RuntimeOrigin; - type Nonce = Nonce; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = frame_support::traits::ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { type MaxLocks = frame_support::traits::ConstU32<1024>; diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 8b45430c688ec69f975b47b4a079b450716939aa..757c46f4faf93d0e5ac79c21741774b2e36d2a89 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -36,12 +36,12 @@ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, - Perbill, + Perbill, Percent, }; use sp_staking::{ currency_to_vote::CurrencyToVote, offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - EraIndex, Page, SessionIndex, Stake, + EraIndex, OnStakingUpdate, Page, SessionIndex, Stake, StakingAccount::{self, Controller, Stash}, StakingInterface, }; @@ -150,6 +150,9 @@ impl Pallet { // Already checked that this won't overflow by entry condition. let value = old_total.defensive_saturating_sub(new_total); Self::deposit_event(Event::::Withdrawn { stash, amount: value }); + + // notify listeners. + T::EventListeners::on_withdraw(controller, value); } Ok(used_weight) @@ -504,9 +507,18 @@ impl Pallet { .saturated_into::(); let staked = Self::eras_total_stake(&active_era.index); let issuance = T::Currency::total_issuance(); + let (validator_payout, remainder) = T::EraPayout::era_payout(staked, issuance, era_duration); + let total_payout = validator_payout.saturating_add(remainder); + let max_staked_rewards = + MaxStakedRewards::::get().unwrap_or(Percent::from_percent(100)); + + // apply cap to validators payout and add difference to remainder. + let validator_payout = validator_payout.min(max_staked_rewards * total_payout); + let remainder = total_payout.saturating_sub(validator_payout); + Self::deposit_event(Event::::EraPaid { era_index: active_era.index, validator_payout, diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 0689418d02bd9c4863f5d5db2e2b8c546d8642cf..992a7fe2c9c6218c7d132571a2f0cab0ee6618a4 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -66,7 +66,7 @@ pub mod pallet { use super::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(14); #[pallet::pallet] @@ -275,7 +275,7 @@ pub mod pallet { /// Something that listens to staking updates and performs actions based on the data it /// receives. /// - /// WARNING: this only reports slashing events for the time being. + /// WARNING: this only reports slashing and withdraw events for the time being. type EventListeners: sp_staking::OnStakingUpdate>; /// Some parameters of the benchmarking. @@ -564,6 +564,12 @@ pub mod pallet { #[pallet::getter(fn force_era)] pub type ForceEra = StorageValue<_, Forcing, ValueQuery>; + /// Maximum staked rewards, i.e. the percentage of the era inflation that + /// is used for stake rewards. + /// See [Era payout](./index.html#era-payout). + #[pallet::storage] + pub type MaxStakedRewards = StorageValue<_, Percent, OptionQuery>; + /// The percentage of the slash that is distributed to reporters. /// /// The rest of the slashed value is handled by the `Slash`. @@ -1717,6 +1723,7 @@ pub mod pallet { max_validator_count: ConfigOp, chill_threshold: ConfigOp, min_commission: ConfigOp, + max_staked_rewards: ConfigOp, ) -> DispatchResult { ensure_root(origin)?; @@ -1736,6 +1743,7 @@ pub mod pallet { config_op_exp!(MaxValidatorsCount, max_validator_count); config_op_exp!(ChillThreshold, chill_threshold); config_op_exp!(MinCommission, min_commission); + config_op_exp!(MaxStakedRewards, max_staked_rewards); Ok(()) } /// Declare a `controller` to stop participating as either a validator or nominator. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 85ee7dd3bf59d9d96243f22b0463b465b4754fa7..3f4e28b1f6af0cdfac939cdc4e11ef5dcc1fd908 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -55,6 +55,7 @@ fn set_staking_configs_works() { ConfigOp::Set(10), ConfigOp::Set(20), ConfigOp::Set(Percent::from_percent(75)), + ConfigOp::Set(Zero::zero()), ConfigOp::Set(Zero::zero()) )); assert_eq!(MinNominatorBond::::get(), 1_500); @@ -63,6 +64,7 @@ fn set_staking_configs_works() { assert_eq!(MaxValidatorsCount::::get(), Some(20)); assert_eq!(ChillThreshold::::get(), Some(Percent::from_percent(75))); assert_eq!(MinCommission::::get(), Perbill::from_percent(0)); + assert_eq!(MaxStakedRewards::::get(), Some(Percent::from_percent(0))); // noop does nothing assert_storage_noop!(assert_ok!(Staking::set_staking_configs( @@ -72,6 +74,7 @@ fn set_staking_configs_works() { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, + ConfigOp::Noop, ConfigOp::Noop ))); @@ -83,6 +86,7 @@ fn set_staking_configs_works() { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, + ConfigOp::Remove, ConfigOp::Remove )); assert_eq!(MinNominatorBond::::get(), 0); @@ -91,6 +95,7 @@ fn set_staking_configs_works() { assert_eq!(MaxValidatorsCount::::get(), None); assert_eq!(ChillThreshold::::get(), None); assert_eq!(MinCommission::::get(), Perbill::from_percent(0)); + assert_eq!(MaxStakedRewards::::get(), None); }); } @@ -1739,6 +1744,74 @@ fn rebond_emits_right_value_in_event() { }); } +#[test] +fn max_staked_rewards_default_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(>::get(), None); + + let default_stakers_payout = current_total_payout_for_duration(reward_time_per_era()); + assert!(default_stakers_payout > 0); + start_active_era(1); + + // the final stakers reward is the same as the reward before applied the cap. + assert_eq!(ErasValidatorReward::::get(0).unwrap(), default_stakers_payout); + + // which is the same behaviour if the `MaxStakedRewards` is set to 100%. + >::set(Some(Percent::from_parts(100))); + + let default_stakers_payout = current_total_payout_for_duration(reward_time_per_era()); + assert_eq!(ErasValidatorReward::::get(0).unwrap(), default_stakers_payout); + }) +} + +#[test] +fn max_staked_rewards_works() { + ExtBuilder::default().nominate(true).build_and_execute(|| { + let max_staked_rewards = 10; + + // sets new max staked rewards through set_staking_configs. + assert_ok!(Staking::set_staking_configs( + RuntimeOrigin::root(), + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Noop, + ConfigOp::Set(Percent::from_percent(max_staked_rewards)), + )); + + assert_eq!(>::get(), Some(Percent::from_percent(10))); + + // check validators account state. + assert_eq!(Session::validators().len(), 2); + assert!(Session::validators().contains(&11) & Session::validators().contains(&21)); + // balance of the mock treasury account is 0 + assert_eq!(RewardRemainderUnbalanced::get(), 0); + + let max_stakers_payout = current_total_payout_for_duration(reward_time_per_era()); + + start_active_era(1); + + let treasury_payout = RewardRemainderUnbalanced::get(); + let validators_payout = ErasValidatorReward::::get(0).unwrap(); + let total_payout = treasury_payout + validators_payout; + + // max stakers payout (without max staked rewards cap applied) is larger than the final + // validator rewards. The final payment and remainder should be adjusted by redestributing + // the era inflation to apply the cap... + assert!(max_stakers_payout > validators_payout); + + // .. which means that the final validator payout is 10% of the total payout.. + assert_eq!(validators_payout, Percent::from_percent(max_staked_rewards) * total_payout); + // .. and the remainder 90% goes to the treasury. + assert_eq!( + treasury_payout, + Percent::from_percent(100 - max_staked_rewards) * (treasury_payout + validators_payout) + ); + }) +} + #[test] fn reward_to_stake_works() { ExtBuilder::default() @@ -5543,7 +5616,8 @@ fn chill_other_works() { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, - ConfigOp::Remove + ConfigOp::Remove, + ConfigOp::Noop, )); // Still can't chill these users @@ -5564,7 +5638,8 @@ fn chill_other_works() { ConfigOp::Set(10), ConfigOp::Set(10), ConfigOp::Noop, - ConfigOp::Noop + ConfigOp::Noop, + ConfigOp::Noop, )); // Still can't chill these users @@ -5585,7 +5660,8 @@ fn chill_other_works() { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Noop, - ConfigOp::Noop + ConfigOp::Noop, + ConfigOp::Noop, )); // Still can't chill these users @@ -5606,7 +5682,8 @@ fn chill_other_works() { ConfigOp::Set(10), ConfigOp::Set(10), ConfigOp::Set(Percent::from_percent(75)), - ConfigOp::Noop + ConfigOp::Noop, + ConfigOp::Noop, )); // 16 people total because tests start with 2 active one @@ -5652,6 +5729,7 @@ fn capped_stakers_works() { ConfigOp::Set(max), ConfigOp::Remove, ConfigOp::Remove, + ConfigOp::Noop, )); // can create `max - validator_count` validators @@ -5722,6 +5800,7 @@ fn capped_stakers_works() { ConfigOp::Remove, ConfigOp::Noop, ConfigOp::Noop, + ConfigOp::Noop, )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1])); assert_ok!(Staking::validate( @@ -5757,6 +5836,7 @@ fn min_commission_works() { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Set(Perbill::from_percent(10)), + ConfigOp::Noop, )); // can't make it less than 10 now diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 7c9a050016406a5ae5b8f98bcd98b0093858628a..8288591a787bb3f1e8df0bdb19c383f5ecfca396 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_staking` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-10, STEPS: `50`, REPEAT: `20`, 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: `runner-itmxxexx-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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_staking +// --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_staking -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/staking/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -99,8 +101,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 42_491_000 picoseconds. - Weight::from_parts(44_026_000, 4764) + // Minimum execution time: 41_318_000 picoseconds. + Weight::from_parts(43_268_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -120,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 88_756_000 picoseconds. - Weight::from_parts(91_000_000, 8877) + // Minimum execution time: 85_666_000 picoseconds. + Weight::from_parts(88_749_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -147,8 +149,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 91_331_000 picoseconds. - Weight::from_parts(94_781_000, 8877) + // Minimum execution time: 90_282_000 picoseconds. + Weight::from_parts(92_332_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -162,16 +164,18 @@ 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: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115` + // Measured: `1297` // Estimated: `4764` - // Minimum execution time: 42_495_000 picoseconds. - Weight::from_parts(44_189_470, 4764) - // Standard Error: 1_389 - .saturating_add(Weight::from_parts(47_484, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 44_626_000 picoseconds. + Weight::from_parts(47_254_657, 4764) + // Standard Error: 1_179 + .saturating_add(Weight::from_parts(57_657, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -207,10 +211,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_004_000 picoseconds. - Weight::from_parts(96_677_570, 6248) - // Standard Error: 4_635 - .saturating_add(Weight::from_parts(1_387_718, 0).saturating_mul(s.into())) + // Minimum execution time: 86_769_000 picoseconds. + Weight::from_parts(95_212_867, 6248) + // Standard Error: 3_706 + .saturating_add(Weight::from_parts(1_320_752, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -242,8 +246,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_532_000 picoseconds. - Weight::from_parts(53_308_000, 4556) + // Minimum execution time: 50_410_000 picoseconds. + Weight::from_parts(52_576_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -256,10 +260,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_955_000 picoseconds. - Weight::from_parts(29_609_869, 4556) - // Standard Error: 6_793 - .saturating_add(Weight::from_parts(6_412_124, 0).saturating_mul(k.into())) + // Minimum execution time: 29_017_000 picoseconds. + Weight::from_parts(33_019_206, 4556) + // Standard Error: 6_368 + .saturating_add(Weight::from_parts(6_158_681, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -292,10 +296,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 64_080_000 picoseconds. - Weight::from_parts(61_985_382, 6248) - // Standard Error: 13_320 - .saturating_add(Weight::from_parts(4_030_513, 0).saturating_mul(n.into())) + // Minimum execution time: 63_452_000 picoseconds. + Weight::from_parts(60_924_066, 6248) + // Standard Error: 14_416 + .saturating_add(Weight::from_parts(3_921_589, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -319,8 +323,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_194_000 picoseconds. - Weight::from_parts(55_578_000, 6248) + // Minimum execution time: 54_253_000 picoseconds. + Weight::from_parts(55_286_000, 6248) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -334,8 +338,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_597_000 picoseconds. - Weight::from_parts(16_980_000, 4556) + // Minimum execution time: 16_812_000 picoseconds. + Weight::from_parts(17_380_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -349,8 +353,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_626_000 picoseconds. - Weight::from_parts(21_242_000, 4556) + // Minimum execution time: 20_590_000 picoseconds. + Weight::from_parts(21_096_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -362,8 +366,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 19_972_000 picoseconds. - Weight::from_parts(20_470_000, 4556) + // Minimum execution time: 19_923_000 picoseconds. + Weight::from_parts(20_880_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -373,8 +377,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_571_000 picoseconds. - Weight::from_parts(2_720_000, 0) + // Minimum execution time: 2_599_000 picoseconds. + Weight::from_parts(2_751_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -383,8 +387,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_056_000 picoseconds. - Weight::from_parts(8_413_000, 0) + // Minimum execution time: 6_941_000 picoseconds. + Weight::from_parts(7_288_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -393,8 +397,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_162_000 picoseconds. - Weight::from_parts(8_497_000, 0) + // Minimum execution time: 6_757_000 picoseconds. + Weight::from_parts(7_200_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -403,8 +407,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_320_000 picoseconds. - Weight::from_parts(8_564_000, 0) + // Minimum execution time: 7_028_000 picoseconds. + Weight::from_parts(7_366_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -414,10 +418,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_470_000 picoseconds. - Weight::from_parts(3_110_242, 0) - // Standard Error: 63 - .saturating_add(Weight::from_parts(11_786, 0).saturating_mul(v.into())) + // Minimum execution time: 2_741_000 picoseconds. + Weight::from_parts(3_212_598, 0) + // Standard Error: 68 + .saturating_add(Weight::from_parts(11_695, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:5900 w:11800) @@ -431,10 +435,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1356 + i * (151 ±0)` // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_101_000 picoseconds. - Weight::from_parts(2_238_000, 990) - // Standard Error: 56_753 - .saturating_add(Weight::from_parts(18_404_902, 0).saturating_mul(i.into())) + // Minimum execution time: 2_132_000 picoseconds. + Weight::from_parts(2_289_000, 990) + // Standard Error: 34_227 + .saturating_add(Weight::from_parts(17_006_583, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) @@ -472,10 +476,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_765_000 picoseconds. - Weight::from_parts(95_173_565, 6248) - // Standard Error: 4_596 - .saturating_add(Weight::from_parts(1_354_849, 0).saturating_mul(s.into())) + // Minimum execution time: 85_308_000 picoseconds. + Weight::from_parts(93_689_468, 6248) + // Standard Error: 5_425 + .saturating_add(Weight::from_parts(1_307_604, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -488,10 +492,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 104_490_000 picoseconds. - Weight::from_parts(1_162_956_951, 70137) - // Standard Error: 76_760 - .saturating_add(Weight::from_parts(6_485_569, 0).saturating_mul(s.into())) + // Minimum execution time: 103_242_000 picoseconds. + Weight::from_parts(1_162_296_080, 70137) + // Standard Error: 76_741 + .saturating_add(Weight::from_parts(6_487_522, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -528,10 +532,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 144_790_000 picoseconds. - Weight::from_parts(36_764_791, 30944) - // Standard Error: 89_592 - .saturating_add(Weight::from_parts(49_620_105, 0).saturating_mul(n.into())) + // Minimum execution time: 140_740_000 picoseconds. + Weight::from_parts(182_886_963, 30944) + // Standard Error: 39_852 + .saturating_add(Weight::from_parts(43_140_752, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -555,10 +559,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 81_768_000 picoseconds. - Weight::from_parts(85_332_982, 8877) - // Standard Error: 5_380 - .saturating_add(Weight::from_parts(70_298, 0).saturating_mul(l.into())) + // Minimum execution time: 80_372_000 picoseconds. + Weight::from_parts(83_335_027, 8877) + // Standard Error: 4_780 + .saturating_add(Weight::from_parts(72_180, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -593,10 +597,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 96_123_000 picoseconds. - Weight::from_parts(100_278_672, 6248) - // Standard Error: 3_487 - .saturating_add(Weight::from_parts(1_326_503, 0).saturating_mul(s.into())) + // Minimum execution time: 93_920_000 picoseconds. + Weight::from_parts(98_022_911, 6248) + // Standard Error: 4_096 + .saturating_add(Weight::from_parts(1_287_745, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -642,12 +646,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 572_893_000 picoseconds. - Weight::from_parts(578_010_000, 512390) - // Standard Error: 2_094_268 - .saturating_add(Weight::from_parts(68_419_710, 0).saturating_mul(v.into())) - // Standard Error: 208_682 - .saturating_add(Weight::from_parts(18_826_175, 0).saturating_mul(n.into())) + // Minimum execution time: 556_012_000 picoseconds. + Weight::from_parts(560_339_000, 512390) + // Standard Error: 2_115_076 + .saturating_add(Weight::from_parts(69_456_497, 0).saturating_mul(v.into())) + // Standard Error: 210_755 + .saturating_add(Weight::from_parts(17_974_873, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -678,12 +682,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 33_836_205_000 picoseconds. - Weight::from_parts(34_210_443_000, 512390) - // Standard Error: 441_692 - .saturating_add(Weight::from_parts(6_122_533, 0).saturating_mul(v.into())) - // Standard Error: 441_692 - .saturating_add(Weight::from_parts(4_418_264, 0).saturating_mul(n.into())) + // Minimum execution time: 32_792_819_000 picoseconds. + Weight::from_parts(32_986_606_000, 512390) + // Standard Error: 360_905 + .saturating_add(Weight::from_parts(5_260_151, 0).saturating_mul(v.into())) + // Standard Error: 360_905 + .saturating_add(Weight::from_parts(3_599_219, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -700,10 +704,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_454_689_000 picoseconds. - Weight::from_parts(161_771_064, 3510) - // Standard Error: 31_022 - .saturating_add(Weight::from_parts(4_820_158, 0).saturating_mul(v.into())) + // Minimum execution time: 2_434_755_000 picoseconds. + Weight::from_parts(38_574_764, 3510) + // Standard Error: 14_467 + .saturating_add(Weight::from_parts(4_821_702, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -714,6 +718,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -724,9 +730,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_073_000 picoseconds. - Weight::from_parts(5_452_000, 0) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 5_765_000 picoseconds. + Weight::from_parts(6_140_000, 0) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -734,6 +740,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -744,9 +752,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_465_000 picoseconds. - Weight::from_parts(4_832_000, 0) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 5_025_000 picoseconds. + Weight::from_parts(5_354_000, 0) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -774,8 +782,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 71_239_000 picoseconds. - Weight::from_parts(74_649_000, 6248) + // Minimum execution time: 69_656_000 picoseconds. + Weight::from_parts(71_574_000, 6248) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -787,8 +795,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_525_000 picoseconds. - Weight::from_parts(13_126_000, 3510) + // Minimum execution time: 12_523_000 picoseconds. + Weight::from_parts(13_315_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -798,8 +806,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_918_000 picoseconds. - Weight::from_parts(3_176_000, 0) + // Minimum execution time: 3_125_000 picoseconds. + Weight::from_parts(3_300_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -820,8 +828,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 42_491_000 picoseconds. - Weight::from_parts(44_026_000, 4764) + // Minimum execution time: 41_318_000 picoseconds. + Weight::from_parts(43_268_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -841,8 +849,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 88_756_000 picoseconds. - Weight::from_parts(91_000_000, 8877) + // Minimum execution time: 85_666_000 picoseconds. + Weight::from_parts(88_749_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -868,8 +876,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 91_331_000 picoseconds. - Weight::from_parts(94_781_000, 8877) + // Minimum execution time: 90_282_000 picoseconds. + Weight::from_parts(92_332_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -883,16 +891,18 @@ 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: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115` + // Measured: `1297` // Estimated: `4764` - // Minimum execution time: 42_495_000 picoseconds. - Weight::from_parts(44_189_470, 4764) - // Standard Error: 1_389 - .saturating_add(Weight::from_parts(47_484, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 44_626_000 picoseconds. + Weight::from_parts(47_254_657, 4764) + // Standard Error: 1_179 + .saturating_add(Weight::from_parts(57_657, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -928,10 +938,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_004_000 picoseconds. - Weight::from_parts(96_677_570, 6248) - // Standard Error: 4_635 - .saturating_add(Weight::from_parts(1_387_718, 0).saturating_mul(s.into())) + // Minimum execution time: 86_769_000 picoseconds. + Weight::from_parts(95_212_867, 6248) + // Standard Error: 3_706 + .saturating_add(Weight::from_parts(1_320_752, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -963,8 +973,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_532_000 picoseconds. - Weight::from_parts(53_308_000, 4556) + // Minimum execution time: 50_410_000 picoseconds. + Weight::from_parts(52_576_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -977,10 +987,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_955_000 picoseconds. - Weight::from_parts(29_609_869, 4556) - // Standard Error: 6_793 - .saturating_add(Weight::from_parts(6_412_124, 0).saturating_mul(k.into())) + // Minimum execution time: 29_017_000 picoseconds. + Weight::from_parts(33_019_206, 4556) + // Standard Error: 6_368 + .saturating_add(Weight::from_parts(6_158_681, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -1013,10 +1023,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 64_080_000 picoseconds. - Weight::from_parts(61_985_382, 6248) - // Standard Error: 13_320 - .saturating_add(Weight::from_parts(4_030_513, 0).saturating_mul(n.into())) + // Minimum execution time: 63_452_000 picoseconds. + Weight::from_parts(60_924_066, 6248) + // Standard Error: 14_416 + .saturating_add(Weight::from_parts(3_921_589, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1040,8 +1050,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_194_000 picoseconds. - Weight::from_parts(55_578_000, 6248) + // Minimum execution time: 54_253_000 picoseconds. + Weight::from_parts(55_286_000, 6248) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1055,8 +1065,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_597_000 picoseconds. - Weight::from_parts(16_980_000, 4556) + // Minimum execution time: 16_812_000 picoseconds. + Weight::from_parts(17_380_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1070,8 +1080,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_626_000 picoseconds. - Weight::from_parts(21_242_000, 4556) + // Minimum execution time: 20_590_000 picoseconds. + Weight::from_parts(21_096_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1083,8 +1093,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 19_972_000 picoseconds. - Weight::from_parts(20_470_000, 4556) + // Minimum execution time: 19_923_000 picoseconds. + Weight::from_parts(20_880_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1094,8 +1104,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_571_000 picoseconds. - Weight::from_parts(2_720_000, 0) + // Minimum execution time: 2_599_000 picoseconds. + Weight::from_parts(2_751_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1104,8 +1114,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_056_000 picoseconds. - Weight::from_parts(8_413_000, 0) + // Minimum execution time: 6_941_000 picoseconds. + Weight::from_parts(7_288_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1114,8 +1124,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_162_000 picoseconds. - Weight::from_parts(8_497_000, 0) + // Minimum execution time: 6_757_000 picoseconds. + Weight::from_parts(7_200_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1124,8 +1134,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_320_000 picoseconds. - Weight::from_parts(8_564_000, 0) + // Minimum execution time: 7_028_000 picoseconds. + Weight::from_parts(7_366_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1135,10 +1145,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_470_000 picoseconds. - Weight::from_parts(3_110_242, 0) - // Standard Error: 63 - .saturating_add(Weight::from_parts(11_786, 0).saturating_mul(v.into())) + // Minimum execution time: 2_741_000 picoseconds. + Weight::from_parts(3_212_598, 0) + // Standard Error: 68 + .saturating_add(Weight::from_parts(11_695, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:5900 w:11800) @@ -1152,10 +1162,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1356 + i * (151 ±0)` // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_101_000 picoseconds. - Weight::from_parts(2_238_000, 990) - // Standard Error: 56_753 - .saturating_add(Weight::from_parts(18_404_902, 0).saturating_mul(i.into())) + // Minimum execution time: 2_132_000 picoseconds. + Weight::from_parts(2_289_000, 990) + // Standard Error: 34_227 + .saturating_add(Weight::from_parts(17_006_583, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) @@ -1193,10 +1203,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_765_000 picoseconds. - Weight::from_parts(95_173_565, 6248) - // Standard Error: 4_596 - .saturating_add(Weight::from_parts(1_354_849, 0).saturating_mul(s.into())) + // Minimum execution time: 85_308_000 picoseconds. + Weight::from_parts(93_689_468, 6248) + // Standard Error: 5_425 + .saturating_add(Weight::from_parts(1_307_604, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1209,10 +1219,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 104_490_000 picoseconds. - Weight::from_parts(1_162_956_951, 70137) - // Standard Error: 76_760 - .saturating_add(Weight::from_parts(6_485_569, 0).saturating_mul(s.into())) + // Minimum execution time: 103_242_000 picoseconds. + Weight::from_parts(1_162_296_080, 70137) + // Standard Error: 76_741 + .saturating_add(Weight::from_parts(6_487_522, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1249,10 +1259,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 144_790_000 picoseconds. - Weight::from_parts(36_764_791, 30944) - // Standard Error: 89_592 - .saturating_add(Weight::from_parts(49_620_105, 0).saturating_mul(n.into())) + // Minimum execution time: 140_740_000 picoseconds. + Weight::from_parts(182_886_963, 30944) + // Standard Error: 39_852 + .saturating_add(Weight::from_parts(43_140_752, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1276,10 +1286,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 81_768_000 picoseconds. - Weight::from_parts(85_332_982, 8877) - // Standard Error: 5_380 - .saturating_add(Weight::from_parts(70_298, 0).saturating_mul(l.into())) + // Minimum execution time: 80_372_000 picoseconds. + Weight::from_parts(83_335_027, 8877) + // Standard Error: 4_780 + .saturating_add(Weight::from_parts(72_180, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1314,10 +1324,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 96_123_000 picoseconds. - Weight::from_parts(100_278_672, 6248) - // Standard Error: 3_487 - .saturating_add(Weight::from_parts(1_326_503, 0).saturating_mul(s.into())) + // Minimum execution time: 93_920_000 picoseconds. + Weight::from_parts(98_022_911, 6248) + // Standard Error: 4_096 + .saturating_add(Weight::from_parts(1_287_745, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1363,12 +1373,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 572_893_000 picoseconds. - Weight::from_parts(578_010_000, 512390) - // Standard Error: 2_094_268 - .saturating_add(Weight::from_parts(68_419_710, 0).saturating_mul(v.into())) - // Standard Error: 208_682 - .saturating_add(Weight::from_parts(18_826_175, 0).saturating_mul(n.into())) + // Minimum execution time: 556_012_000 picoseconds. + Weight::from_parts(560_339_000, 512390) + // Standard Error: 2_115_076 + .saturating_add(Weight::from_parts(69_456_497, 0).saturating_mul(v.into())) + // Standard Error: 210_755 + .saturating_add(Weight::from_parts(17_974_873, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1399,12 +1409,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 33_836_205_000 picoseconds. - Weight::from_parts(34_210_443_000, 512390) - // Standard Error: 441_692 - .saturating_add(Weight::from_parts(6_122_533, 0).saturating_mul(v.into())) - // Standard Error: 441_692 - .saturating_add(Weight::from_parts(4_418_264, 0).saturating_mul(n.into())) + // Minimum execution time: 32_792_819_000 picoseconds. + Weight::from_parts(32_986_606_000, 512390) + // Standard Error: 360_905 + .saturating_add(Weight::from_parts(5_260_151, 0).saturating_mul(v.into())) + // Standard Error: 360_905 + .saturating_add(Weight::from_parts(3_599_219, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1421,10 +1431,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_454_689_000 picoseconds. - Weight::from_parts(161_771_064, 3510) - // Standard Error: 31_022 - .saturating_add(Weight::from_parts(4_820_158, 0).saturating_mul(v.into())) + // Minimum execution time: 2_434_755_000 picoseconds. + Weight::from_parts(38_574_764, 3510) + // Standard Error: 14_467 + .saturating_add(Weight::from_parts(4_821_702, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1435,6 +1445,8 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1445,9 +1457,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_073_000 picoseconds. - Weight::from_parts(5_452_000, 0) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 5_765_000 picoseconds. + Weight::from_parts(6_140_000, 0) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -1455,6 +1467,8 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1465,9 +1479,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_465_000 picoseconds. - Weight::from_parts(4_832_000, 0) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 5_025_000 picoseconds. + Weight::from_parts(5_354_000, 0) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -1495,8 +1509,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 71_239_000 picoseconds. - Weight::from_parts(74_649_000, 6248) + // Minimum execution time: 69_656_000 picoseconds. + Weight::from_parts(71_574_000, 6248) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1508,8 +1522,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_525_000 picoseconds. - Weight::from_parts(13_126_000, 3510) + // Minimum execution time: 12_523_000 picoseconds. + Weight::from_parts(13_315_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1519,8 +1533,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_918_000 picoseconds. - Weight::from_parts(3_176_000, 0) + // Minimum execution time: 3_125_000 picoseconds. + Weight::from_parts(3_300_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 1fb49e6256205ccc5aff3514dfa0a16ee8713265..e837956613edd2a30146bc6e41b4518d55c95095 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.12.4", default-features = false, optional = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/state-trie-migration/src/lib.rs b/substrate/frame/state-trie-migration/src/lib.rs index 6b3aa9934e070046ee694409b20faebf3934663f..b89159ef3ec44ede131eb3009a29f011082cb55d 100644 --- a/substrate/frame/state-trie-migration/src/lib.rs +++ b/substrate/frame/state-trie-migration/src/lib.rs @@ -1801,7 +1801,7 @@ mod remote_tests_local { use std::env::var as env_var; // we only use the hash type from this, so using the mock should be fine. - type Extrinsic = sp_runtime::testing::TestXt; + type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; type Block = sp_runtime::testing::Block; #[tokio::test] diff --git a/substrate/frame/state-trie-migration/src/weights.rs b/substrate/frame/state-trie-migration/src/weights.rs index 8fa80b38957d9b38a40803a261d52cfe7836a990..23dad9e33800bd307b295cdf46ad286edd3af7b7 100644 --- a/substrate/frame/state-trie-migration/src/weights.rs +++ b/substrate/frame/state-trie-migration/src/weights.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_state_trie_migration` //! -//! 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-03-01, 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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_state_trie_migration +// --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_state_trie_migration -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/state-trie-migration/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -64,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(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3640` - // Minimum execution time: 18_520_000 picoseconds. - Weight::from_parts(19_171_000, 3640) + // Estimated: `3658` + // Minimum execution time: 17_661_000 picoseconds. + Weight::from_parts(18_077_000, 3658) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -82,53 +84,53 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 3_786_000 picoseconds. - Weight::from_parts(4_038_000, 1493) + // Minimum execution time: 4_036_000 picoseconds. + Weight::from_parts(4_267_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(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3640` - // Minimum execution time: 11_144_000 picoseconds. - Weight::from_parts(11_556_000, 3640) + // Estimated: `3658` + // Minimum execution time: 11_348_000 picoseconds. + Weight::from_parts(11_899_000, 3658) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3640` - // Minimum execution time: 59_288_000 picoseconds. - Weight::from_parts(60_276_000, 3640) + // Estimated: `3658` + // Minimum execution time: 59_819_000 picoseconds. + Weight::from_parts(61_066_000, 3658) .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(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn migrate_custom_child_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3640` - // Minimum execution time: 11_258_000 picoseconds. - Weight::from_parts(11_626_000, 3640) + // Estimated: `3658` + // Minimum execution time: 11_424_000 picoseconds. + Weight::from_parts(11_765_000, 3658) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3640` - // Minimum execution time: 61_575_000 picoseconds. - Weight::from_parts(63_454_000, 3640) + // Estimated: `3658` + // Minimum execution time: 61_086_000 picoseconds. + Weight::from_parts(62_546_000, 3658) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -139,10 +141,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `197 + v * (1 ±0)` // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 5_259_000 picoseconds. - Weight::from_parts(5_433_000, 3662) + // Minimum execution time: 5_375_000 picoseconds. + Weight::from_parts(5_552_000, 3662) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_159, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_146, 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())) @@ -154,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(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3640` - // Minimum execution time: 18_520_000 picoseconds. - Weight::from_parts(19_171_000, 3640) + // Estimated: `3658` + // Minimum execution time: 17_661_000 picoseconds. + Weight::from_parts(18_077_000, 3658) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -172,53 +174,53 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 3_786_000 picoseconds. - Weight::from_parts(4_038_000, 1493) + // Minimum execution time: 4_036_000 picoseconds. + Weight::from_parts(4_267_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(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3640` - // Minimum execution time: 11_144_000 picoseconds. - Weight::from_parts(11_556_000, 3640) + // Estimated: `3658` + // Minimum execution time: 11_348_000 picoseconds. + Weight::from_parts(11_899_000, 3658) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3640` - // Minimum execution time: 59_288_000 picoseconds. - Weight::from_parts(60_276_000, 3640) + // Estimated: `3658` + // Minimum execution time: 59_819_000 picoseconds. + Weight::from_parts(61_066_000, 3658) .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(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) fn migrate_custom_child_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3640` - // Minimum execution time: 11_258_000 picoseconds. - Weight::from_parts(11_626_000, 3640) + // Estimated: `3658` + // Minimum execution time: 11_424_000 picoseconds. + Weight::from_parts(11_765_000, 3658) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, 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: `3640` - // Minimum execution time: 61_575_000 picoseconds. - Weight::from_parts(63_454_000, 3640) + // Estimated: `3658` + // Minimum execution time: 61_086_000 picoseconds. + Weight::from_parts(62_546_000, 3658) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -229,10 +231,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `197 + v * (1 ±0)` // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 5_259_000 picoseconds. - Weight::from_parts(5_433_000, 3662) + // Minimum execution time: 5_375_000 picoseconds. + Weight::from_parts(5_552_000, 3662) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_159, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_146, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index 58f8b40dc26d0ee45ebec7b9ab018b4f9b0debd3..6827dbda962b3d4973133f38b723579ab1ddfd4d 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -25,7 +25,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] pallet-balances = { path = "../balances" } diff --git a/substrate/frame/statement/src/mock.rs b/substrate/frame/statement/src/mock.rs index c5bee2639dcd704acdbec7e6dd6bae1c922e67d2..4ab9cf9e0f96a33fe70de6c019234b9a3829eb7e 100644 --- a/substrate/frame/statement/src/mock.rs +++ b/substrate/frame/statement/src/mock.rs @@ -22,14 +22,10 @@ use super::*; use crate as pallet_statement; use frame_support::{ derive_impl, ord_parameter_types, - traits::{ConstU32, ConstU64, Everything}, - weights::constants::RocksDbWeight, -}; -use sp_core::{Pair, H256}; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - AccountId32, BuildStorage, + traits::{ConstU32, ConstU64}, }; +use sp_core::Pair; +use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; type Block = frame_system::mocking::MockBlock; @@ -49,29 +45,10 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = RocksDbWeight; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = AccountId32; type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/sudo/src/benchmarking.rs b/substrate/frame/sudo/src/benchmarking.rs index e64233fe7480a9d82c9c07709dd9b403544bff6a..cdd7d707600e1d2393e989add59f16349acb3492 100644 --- a/substrate/frame/sudo/src/benchmarking.rs +++ b/substrate/frame/sudo/src/benchmarking.rs @@ -20,14 +20,23 @@ use super::*; use crate::Pallet; use frame_benchmarking::v2::*; +use frame_support::dispatch::DispatchInfo; use frame_system::RawOrigin; +use sp_runtime::traits::{AsSystemOriginSigner, 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, + <::RuntimeCall as Dispatchable>::PostInfo: From<()>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + Clone, +)] mod benchmarks { use super::*; @@ -85,5 +94,23 @@ mod benchmarks { assert_last_event::(Event::KeyRemoved {}); } + #[benchmark] + fn check_only_sudo_account() { + let caller: T::AccountId = whitelisted_caller(); + Key::::put(&caller); + + let call = frame_system::Call::remark { remark: vec![] }.into(); + let info = DispatchInfo { ..Default::default() }; + let ext = CheckOnlySudoAccount::::new(); + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(().into())) + .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 c717ff3567268ae7bf868120d6411d1abe63c712..2cd8f945eddb9e406ec16651cb436b6a60d3ade6 100644 --- a/substrate/frame/sudo/src/extension.rs +++ b/substrate/frame/sudo/src/extension.rs @@ -15,15 +15,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{Config, Pallet}; +use crate::{Config, Key}; use codec::{Decode, Encode}; use frame_support::{dispatch::DispatchInfo, ensure}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, SignedExtension}, + impl_tx_ext_default, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, TransactionExtension, + TransactionExtensionBase, + }, transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, - UnknownTransaction, ValidTransaction, + InvalidTransaction, TransactionPriority, TransactionValidityError, UnknownTransaction, + ValidTransaction, }, }; use sp_std::{fmt, marker::PhantomData}; @@ -59,49 +63,61 @@ 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 -where - ::RuntimeCall: Dispatchable, -{ +impl TransactionExtensionBase for CheckOnlySudoAccount { const IDENTIFIER: &'static str = "CheckOnlySudoAccount"; - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); + type Implicit = (); - fn additional_signed(&self) -> Result { - Ok(()) + fn weight(&self) -> frame_support::weights::Weight { + use crate::weights::WeightInfo; + T::WeightInfo::check_only_sudo_account() } +} +impl + TransactionExtension<::RuntimeCall, Context> for CheckOnlySudoAccount +where + ::RuntimeCall: Dispatchable, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + Clone, +{ + type Pre = (); + type Val = (); fn validate( &self, - who: &Self::AccountId, - _call: &Self::Call, - info: &DispatchInfoOf, + origin: <::RuntimeCall as Dispatchable>::RuntimeOrigin, + _call: &::RuntimeCall, + info: &DispatchInfoOf<::RuntimeCall>, _len: usize, - ) -> TransactionValidity { - let sudo_key: T::AccountId = >::key().ok_or(UnknownTransaction::CannotLookup)?; + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> 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.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; Context; prepare); } diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index 4f14c32ff76b0e0038597c9d715d632985eceeea..2c953368b2215981320ba7cfd9957815c8f7a519 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. @@ -329,7 +329,6 @@ pub mod pallet { /// The `AccountId` of the sudo key. #[pallet::storage] - #[pallet::getter(fn key)] pub(super) type Key = StorageValue<_, T::AccountId, OptionQuery>; #[pallet::genesis_config] @@ -352,7 +351,7 @@ pub mod pallet { let sender = ensure_signed_or_root(origin)?; if let Some(sender) = sender { - if Self::key().map_or(false, |k| k == sender) { + if Key::::get().map_or(false, |k| k == sender) { Ok(()) } else { Err(Error::::RequireSudo.into()) diff --git a/substrate/frame/sudo/src/mock.rs b/substrate/frame/sudo/src/mock.rs index 9ad14804524a9400fa5e876aa9119d44ee45857c..3b907a27168366c4b4b56ceabde60d78ff9e42fd 100644 --- a/substrate/frame/sudo/src/mock.rs +++ b/substrate/frame/sudo/src/mock.rs @@ -19,16 +19,9 @@ use super::*; use crate as sudo; -use frame_support::{ - derive_impl, - traits::{ConstU32, Contains}, -}; -use sp_core::{ConstU64, H256}; +use frame_support::{derive_impl, traits::Contains}; use sp_io; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; // Logger module to track execution. #[frame_support::pallet] @@ -113,29 +106,7 @@ impl Contains for BlockEverything { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = BlockEverything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } // Implement the logger module's `Config` on the Test runtime. diff --git a/substrate/frame/sudo/src/tests.rs b/substrate/frame/sudo/src/tests.rs index 73689415a737fd3e2acba663099f9042f88ace4c..00bb86cc2686f2410d09077d9b388750914eb74c 100644 --- a/substrate/frame/sudo/src/tests.rs +++ b/substrate/frame/sudo/src/tests.rs @@ -28,7 +28,7 @@ use mock::{ fn test_setup_works() { // Environment setup, logger storage, and sudo `key` retrieval should work as expected. new_test_ext(1).execute_with(|| { - assert_eq!(Sudo::key(), Some(1u64)); + assert_eq!(Key::::get(), Some(1u64)); assert!(Logger::i32_log().is_empty()); assert!(Logger::account_log().is_empty()); }); @@ -135,7 +135,7 @@ fn set_key_basics() { new_test_ext(1).execute_with(|| { // A root `key` can change the root `key` assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2)); - assert_eq!(Sudo::key(), Some(2u64)); + assert_eq!(Key::::get(), Some(2u64)); }); new_test_ext(1).execute_with(|| { @@ -161,7 +161,7 @@ fn set_key_emits_events_correctly() { fn remove_key_works() { new_test_ext(1).execute_with(|| { assert_ok!(Sudo::remove_key(RuntimeOrigin::signed(1))); - assert!(Sudo::key().is_none()); + assert!(Key::::get().is_none()); System::assert_has_event(TestEvent::Sudo(Event::KeyRemoved {})); assert_noop!(Sudo::remove_key(RuntimeOrigin::signed(1)), Error::::RequireSudo); @@ -173,11 +173,11 @@ fn remove_key_works() { fn using_root_origin_works() { new_test_ext(1).execute_with(|| { assert_ok!(Sudo::remove_key(RuntimeOrigin::root())); - assert!(Sudo::key().is_none()); + assert!(Key::::get().is_none()); System::assert_has_event(TestEvent::Sudo(Event::KeyRemoved {})); assert_ok!(Sudo::set_key(RuntimeOrigin::root(), 1)); - assert_eq!(Some(1), Sudo::key()); + assert_eq!(Some(1), Key::::get()); }); } diff --git a/substrate/frame/sudo/src/weights.rs b/substrate/frame/sudo/src/weights.rs index 10d1a9f7a513b7ae98947e27832842a42ab0c589..aa8f69fd4e6bfaa40a5ee791b9b1fabd47b71534 100644 --- a/substrate/frame/sudo/src/weights.rs +++ b/substrate/frame/sudo/src/weights.rs @@ -17,26 +17,28 @@ //! 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-03-01, 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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_sudo +// --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_sudo -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/sudo/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -53,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,8 +67,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 9_600_000 picoseconds. - Weight::from_parts(10_076_000, 1517) + // Minimum execution time: 9_590_000 picoseconds. + Weight::from_parts(9_924_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,8 +78,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 10_453_000 picoseconds. - Weight::from_parts(10_931_000, 1517) + // Minimum execution time: 9_825_000 picoseconds. + Weight::from_parts(10_373_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:0) @@ -85,8 +88,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 10_202_000 picoseconds. - Weight::from_parts(10_800_000, 1517) + // Minimum execution time: 10_140_000 picoseconds. + Weight::from_parts(10_382_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:1) @@ -95,11 +98,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 8_555_000 picoseconds. - Weight::from_parts(8_846_000, 1517) + // Minimum execution time: 8_610_000 picoseconds. + Weight::from_parts(8_975_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: `165` + // Estimated: `1517` + // Minimum execution time: 3_416_000 picoseconds. + Weight::from_parts(3_645_000, 1517) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } } // For backwards compatibility and tests. @@ -110,8 +123,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 9_600_000 picoseconds. - Weight::from_parts(10_076_000, 1517) + // Minimum execution time: 9_590_000 picoseconds. + Weight::from_parts(9_924_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -121,8 +134,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 10_453_000 picoseconds. - Weight::from_parts(10_931_000, 1517) + // Minimum execution time: 9_825_000 picoseconds. + Weight::from_parts(10_373_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:0) @@ -131,8 +144,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 10_202_000 picoseconds. - Weight::from_parts(10_800_000, 1517) + // Minimum execution time: 10_140_000 picoseconds. + Weight::from_parts(10_382_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:1) @@ -141,9 +154,19 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 8_555_000 picoseconds. - Weight::from_parts(8_846_000, 1517) + // Minimum execution time: 8_610_000 picoseconds. + Weight::from_parts(8_975_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: `165` + // Estimated: `1517` + // Minimum execution time: 3_416_000 picoseconds. + Weight::from_parts(3_645_000, 1517) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index ad97ad5146e7698dfe0dbac8331e089d093abc6f..be60068f1220b701e15f440b11b9775a5bcbaaf1 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -17,14 +17,25 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { version = "6.1", default-features = false } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"] } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } -sp-api = { path = "../../primitives/api", default-features = false, features = ["frame-metadata"] } +serde = { features = ["alloc", "derive"], workspace = true } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", + "max-encoded-len", +] } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } +frame-metadata = { version = "16.0.0", default-features = false, features = [ + "current", +] } +sp-api = { path = "../../primitives/api", default-features = false, features = [ + "frame-metadata", +] } sp-std = { path = "../../primitives/std", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } -sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } +sp-runtime = { path = "../../primitives/runtime", default-features = false, features = [ + "serde", +] } sp-tracing = { path = "../../primitives/tracing", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } @@ -41,12 +52,12 @@ sp-state-machine = { path = "../../primitives/state-machine", default-features = bitflags = "1.3" impl-trait-for-tuples = "0.2.2" smallvec = "1.11.0" -log = { version = "0.4.17", default-features = false } +log = { workspace = true } sp-crypto-hashing-proc-macro = { path = "../../primitives/crypto/hashing/proc-macro" } k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } -serde_json = { version = "1.0.111", default-features = false, features = ["alloc"] } +serde_json = { features = ["alloc"], workspace = true } docify = "0.2.7" static_assertions = "1.1.0" @@ -55,6 +66,7 @@ aquamarine = { version = "0.5.0" } [dev-dependencies] assert_matches = "1.3.0" pretty_assertions = "1.2.1" +sp-timestamp = { path = "../../primitives/timestamp", default-features = false } frame-system = { path = "../system" } sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } @@ -83,6 +95,7 @@ std = [ "sp-staking/std", "sp-state-machine/std", "sp-std/std", + "sp-timestamp/std", "sp-tracing/std", "sp-weights/std", ] @@ -96,7 +109,9 @@ try-runtime = [ "sp-debug-derive/force-debug", "sp-runtime/try-runtime", ] -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/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index d77f6595db3360fa4f60362cd9bff49feb9727e7..dd0688f2ad06a94332bda9f5401a5578aae04e28 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -23,8 +23,8 @@ Inflector = "0.11.4" cfg-expr = "0.15.5" itertools = "0.10.3" proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = { version = "2.0.48", features = ["full"] } +quote = { workspace = true } +syn = { features = ["full", "visit-mut"], workspace = true } frame-support-procedural-tools = { path = "tools" } macro_magic = { version = "0.5.0", features = ["proc_support"] } proc-macro-warning = { version = "1.0.0", default-features = false } @@ -38,6 +38,7 @@ regex = "1" default = ["std"] std = ["sp-crypto-hashing/std"] no-metadata-docs = [] +experimental = [] # Generate impl-trait for tuples with the given number of tuples. Will be needed as the number of # pallets in a runtime grows. Does increase the compile time! tuples-96 = [] diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index 6ded82d91aa5cd9bb9cceb4594ae9768d4948483..27c75a7f054cfbbcd71750f11985665b60cc3aed 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -65,6 +65,7 @@ struct RangeArgs { start: syn::GenericArgument, _comma: Comma, end: syn::GenericArgument, + _trailing_comma: Option, _gt_token: Gt, } @@ -431,7 +432,7 @@ pub fn benchmarks( let mut benchmarks_by_name_mappings: Vec = Vec::new(); let test_idents: Vec = benchmark_names_str .iter() - .map(|n| Ident::new(format!("test_{}", n).as_str(), Span::call_site())) + .map(|n| Ident::new(format!("test_benchmark_{}", n).as_str(), Span::call_site())) .collect(); for i in 0..benchmark_names.len() { let name_ident = &benchmark_names[i]; @@ -441,6 +442,37 @@ pub fn benchmarks( benchmarks_by_name_mappings.push(quote!(#name_str => Self::#test_ident())) } + let impl_test_function = content + .iter_mut() + .find_map(|item| { + let Item::Macro(item_macro) = item else { + return None; + }; + + if !item_macro + .mac + .path + .segments + .iter() + .any(|s| s.ident == "impl_benchmark_test_suite") + { + return None; + } + + let tokens = item_macro.mac.tokens.clone(); + *item = Item::Verbatim(quote! {}); + + Some(quote! { + impl_test_function!( + (#( {} #benchmark_names )*) + (#( #extra_benchmark_names )*) + (#( #skip_meta_benchmark_names )*) + #tokens + ); + }) + }) + .unwrap_or(quote! {}); + // emit final quoted tokens let res = quote! { #(#mod_attrs) @@ -676,6 +708,8 @@ pub fn benchmarks( } } } + + #impl_test_function } #mod_vis use #mod_name::*; }; @@ -733,7 +767,8 @@ fn expand_benchmark( let setup_stmts = benchmark_def.setup_stmts; let verify_stmts = benchmark_def.verify_stmts; let last_stmt = benchmark_def.last_stmt; - let test_ident = Ident::new(format!("test_{}", name.to_string()).as_str(), Span::call_site()); + let test_ident = + Ident::new(format!("test_benchmark_{}", name.to_string()).as_str(), Span::call_site()); // unroll params (prepare for quoting) let unrolled = UnrolledParams::from(&benchmark_def.params); diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/config.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/config.rs index ffe55bceb80ef96bc9e7814cfbd8bec6c62ab562..dbbe6ba6e6c32ec09a8514033108617883075243 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/config.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/config.rs @@ -76,10 +76,6 @@ pub fn expand_outer_config( #fields } - #[cfg(any(feature = "std", test))] - #[deprecated(note = "GenesisConfig is planned to be removed in December 2023. Use `RuntimeGenesisConfig` instead.")] - pub type GenesisConfig = RuntimeGenesisConfig; - #[cfg(any(feature = "std", test))] impl #scrate::sp_runtime::BuildStorage for RuntimeGenesisConfig { fn assimilate_storage( @@ -99,6 +95,17 @@ pub fn expand_outer_config( ::on_genesis(); } } + + /// Test the `Default` derive impl of the `RuntimeGenesisConfig`. + #[cfg(test)] + #[test] + fn test_genesis_config_builds() { + #scrate::__private::sp_io::TestExternalities::default().execute_with(|| { + ::build( + &RuntimeGenesisConfig::default() + ); + }); + } } } 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 34b9d21d8ce84fafb7958278227a3f572d8d2f74..d21cfef4a927c8033c393719247d9c5a09d83e1a 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs @@ -73,11 +73,9 @@ pub fn expand_outer_inherent( #( #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 #scrate::sp_runtime::traits::Extrinsic>::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::Extrinsic::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::Extrinsic::is_bare(xt); - if !is_signed { + if is_bare { let call = < #unchecked_extrinsic as ExtrinsicCall >::call(xt); @@ -204,47 +201,51 @@ pub fn expand_outer_inherent( } } + impl #scrate::traits::IsInherent<<#block as #scrate::sp_runtime::traits::Block>::Extrinsic> for #runtime { + fn is_inherent(ext: &<#block as #scrate::sp_runtime::traits::Block>::Extrinsic) -> bool { + use #scrate::inherent::ProvideInherent; + use #scrate::traits::{IsSubType, ExtrinsicCall}; + + let is_bare = #scrate::sp_runtime::traits::Extrinsic::is_bare(ext); + if !is_bare { + // Signed extrinsics are not inherents. + return false + } + + #( + #pallet_attrs + { + let call = <#unchecked_extrinsic as ExtrinsicCall>::call(ext); + if let Some(call) = IsSubType::<_>::is_sub_type(call) { + if <#pallet_names as ProvideInherent>::is_inherent(&call) { + return true; + } + } + } + )* + false + } + } + impl #scrate::traits::EnsureInherentsAreFirst<#block> for #runtime { - fn ensure_inherents_are_first(block: &#block) -> Result<(), u32> { + fn ensure_inherents_are_first(block: &#block) -> Result { use #scrate::inherent::ProvideInherent; use #scrate::traits::{IsSubType, ExtrinsicCall}; use #scrate::sp_runtime::traits::Block as _; - let mut first_signed_observed = false; + let mut num_inherents = 0u32; for (i, xt) in block.extrinsics().iter().enumerate() { - let is_signed = #scrate::sp_runtime::traits::Extrinsic::is_signed(xt) - .unwrap_or(false); - - let is_inherent = if is_signed { - // Signed extrinsics are not inherents. - false - } else { - let mut is_inherent = false; - #( - #pallet_attrs - { - let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); - if let Some(call) = IsSubType::<_>::is_sub_type(call) { - if #pallet_names::is_inherent(&call) { - is_inherent = true; - } - } - } - )* - is_inherent - }; - - if !is_inherent { - first_signed_observed = true; - } + if >::is_inherent(xt) { + if num_inherents != i as u32 { + return Err(i as u32); + } - if first_signed_observed && is_inherent { - return Err(i as u32) + num_inherents += 1; // Safe since we are in an `enumerate` loop. } } - Ok(()) + Ok(num_inherents) } } } 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 0e76f9a92469a73d3a616da454dc46ded5034afc..f55ca677d89c372261a885572d48b36f395d1a5b 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -119,13 +119,13 @@ 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 + >::Extra as #scrate::sp_runtime::traits::TransactionExtensionBase >::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, 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 b421d2aaffabe077450d81e3396976f3067b264a..341621deb098c1905557bd953d750283dc45ae51 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -104,7 +104,7 @@ pub fn expand_outer_origin( #[doc = #doc_string] #[derive(Clone)] pub struct RuntimeOrigin { - caller: OriginCaller, + pub caller: OriginCaller, filter: #scrate::__private::sp_std::rc::Rc::RuntimeCall) -> bool>>, } @@ -153,6 +153,10 @@ pub fn expand_outer_origin( self.filter = #scrate::__private::sp_std::rc::Rc::new(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,16 @@ 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 + } + } + } + #pallet_conversions }) } diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index 54ed15f7b1d36d6ee5eb724381152af03bef60c8..1937dfa9ca4d0e966aa1c46e1b240fe53dc2ab54 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -208,8 +208,8 @@ //! This macro returns the ` :: expanded { Error }` list of additional parts we would like to //! expose. -mod expand; -mod parse; +pub(crate) mod expand; +pub(crate) mod parse; use crate::pallet::parse::helper::two128_str; use cfg_expr::Predicate; @@ -233,25 +233,38 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { let input_copy = input.clone(); let definition = syn::parse_macro_input!(input as RuntimeDeclaration); - let res = match definition { - RuntimeDeclaration::Implicit(implicit_def) => - check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()).and_then( - |_| construct_runtime_implicit_to_explicit(input_copy.into(), implicit_def), - ), - RuntimeDeclaration::Explicit(explicit_decl) => check_pallet_number( - input_copy.clone().into(), - explicit_decl.pallets.len(), - ) - .and_then(|_| { - construct_runtime_explicit_to_explicit_expanded(input_copy.into(), explicit_decl) - }), - RuntimeDeclaration::ExplicitExpanded(explicit_decl) => - check_pallet_number(input_copy.into(), explicit_decl.pallets.len()) - .and_then(|_| construct_runtime_final_expansion(explicit_decl)), + let (check_pallet_number_res, res) = match definition { + RuntimeDeclaration::Implicit(implicit_def) => ( + check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()), + construct_runtime_implicit_to_explicit(input_copy.into(), implicit_def), + ), + RuntimeDeclaration::Explicit(explicit_decl) => ( + check_pallet_number(input_copy.clone().into(), explicit_decl.pallets.len()), + construct_runtime_explicit_to_explicit_expanded(input_copy.into(), explicit_decl), + ), + RuntimeDeclaration::ExplicitExpanded(explicit_decl) => ( + check_pallet_number(input_copy.into(), explicit_decl.pallets.len()), + construct_runtime_final_expansion(explicit_decl), + ), }; let res = res.unwrap_or_else(|e| e.to_compile_error()); + // We want to provide better error messages to the user and thus, handle the error here + // separately. If there is an error, we print the error and still generate all of the code to + // get in overall less errors for the user. + let res = if let Err(error) = check_pallet_number_res { + let error = error.to_compile_error(); + + quote! { + #error + + #res + } + } else { + res + }; + let res = expander::Expander::new("construct_runtime") .dry(std::env::var("EXPAND_MACROS").is_err()) .verbose(true) @@ -502,7 +515,7 @@ fn construct_runtime_final_expansion( Ok(res) } -fn decl_all_pallets<'a>( +pub(crate) fn decl_all_pallets<'a>( runtime: &'a Ident, pallet_declarations: impl Iterator, features: &HashSet<&str>, @@ -611,7 +624,8 @@ fn decl_all_pallets<'a>( #( #all_pallets_without_system )* ) } -fn decl_pallet_runtime_setup( + +pub(crate) fn decl_pallet_runtime_setup( runtime: &Ident, pallet_declarations: &[Pallet], scrate: &TokenStream2, @@ -717,7 +731,7 @@ fn decl_pallet_runtime_setup( ) } -fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { +pub(crate) fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { quote!( #[cfg(test)] mod __construct_runtime_integrity_test { @@ -732,7 +746,7 @@ fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { ) } -fn decl_static_assertions( +pub(crate) fn decl_static_assertions( runtime: &Ident, pallet_decls: &[Pallet], scrate: &TokenStream2, @@ -763,7 +777,7 @@ fn decl_static_assertions( } } -fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> { +pub(crate) fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> { let max_pallet_num = { if cfg!(feature = "tuples-96") { 96 diff --git a/substrate/frame/support/procedural/src/derive_impl.rs b/substrate/frame/support/procedural/src/derive_impl.rs index d6d5bf68efd5689af2e96250e24cef3cd7faf47b..8740ccd401abedcbcb27e19c77ef3e885207342a 100644 --- a/substrate/frame/support/procedural/src/derive_impl.rs +++ b/substrate/frame/support/procedural/src/derive_impl.rs @@ -172,6 +172,33 @@ fn combine_impls( final_impl } +/// Computes the disambiguation path for the `derive_impl` attribute macro. +/// +/// When specified explicitly using `as [disambiguation_path]` in the macro attr, the +/// disambiguation is used as is. If not, we infer the disambiguation path from the +/// `foreign_impl_path` and the computed scope. +fn compute_disambiguation_path( + disambiguation_path: Option, + foreign_impl: ItemImpl, + default_impl_path: Path, +) -> Result { + match (disambiguation_path, foreign_impl.clone().trait_) { + (Some(disambiguation_path), _) => Ok(disambiguation_path), + (None, Some((_, foreign_impl_path, _))) => + if default_impl_path.segments.len() > 1 { + let scope = default_impl_path.segments.first(); + Ok(parse_quote!(#scope :: #foreign_impl_path)) + } else { + Ok(foreign_impl_path) + }, + _ => Err(syn::Error::new( + default_impl_path.span(), + "Impl statement must have a defined type being implemented \ + for a defined type such as `impl A for B`", + )), + } +} + /// Internal implementation behind [`#[derive_impl(..)]`](`macro@crate::derive_impl`). /// /// `default_impl_path`: the module path of the external `impl` statement whose tokens we are @@ -194,18 +221,11 @@ pub fn derive_impl( let foreign_impl = parse2::(foreign_tokens)?; let default_impl_path = parse2::(default_impl_path)?; - // have disambiguation_path default to the item being impl'd in the foreign impl if we - // don't specify an `as [disambiguation_path]` in the macro attr - let disambiguation_path = match (disambiguation_path, foreign_impl.clone().trait_) { - (Some(disambiguation_path), _) => disambiguation_path, - (None, Some((_, foreign_impl_path, _))) => foreign_impl_path, - _ => - return Err(syn::Error::new( - foreign_impl.span(), - "Impl statement must have a defined type being implemented \ - for a defined type such as `impl A for B`", - )), - }; + let disambiguation_path = compute_disambiguation_path( + disambiguation_path, + foreign_impl.clone(), + default_impl_path.clone(), + )?; // generate the combined impl let combined_impl = combine_impls( @@ -257,3 +277,27 @@ fn test_runtime_type_with_doc() { } } } + +#[test] +fn test_disambugation_path() { + let foreign_impl: ItemImpl = parse_quote!(impl SomeTrait for SomeType {}); + let default_impl_path: Path = parse_quote!(SomeScope::SomeType); + + // disambiguation path is specified + let disambiguation_path = compute_disambiguation_path( + Some(parse_quote!(SomeScope::SomePath)), + foreign_impl.clone(), + default_impl_path.clone(), + ); + assert_eq!(disambiguation_path.unwrap(), parse_quote!(SomeScope::SomePath)); + + // disambiguation path is not specified and the default_impl_path has more than one segment + let disambiguation_path = + compute_disambiguation_path(None, foreign_impl.clone(), default_impl_path.clone()); + assert_eq!(disambiguation_path.unwrap(), parse_quote!(SomeScope::SomeTrait)); + + // disambiguation path is not specified and the default_impl_path has only one segment + let disambiguation_path = + compute_disambiguation_path(None, foreign_impl.clone(), parse_quote!(SomeType)); + assert_eq!(disambiguation_path.unwrap(), parse_quote!(SomeTrait)); +} diff --git a/substrate/frame/support/procedural/src/dynamic_params.rs b/substrate/frame/support/procedural/src/dynamic_params.rs new file mode 100644 index 0000000000000000000000000000000000000000..b718ccbc9558480587a1f50f4e85a992e5c750da --- /dev/null +++ b/substrate/frame/support/procedural/src/dynamic_params.rs @@ -0,0 +1,563 @@ +// 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. + +//! Code for the `#[dynamic_params]`, `#[dynamic_pallet_params]` and +//! `#[dynamic_aggregated_params_internal]` macros. + +use frame_support_procedural_tools::generate_access_from_frame_or_crate; +use inflector::Inflector; +use proc_macro2::{Span, TokenStream}; +use quote::{format_ident, quote, ToTokens}; +use syn::{parse2, spanned::Spanned, visit_mut, visit_mut::VisitMut, Result, Token}; + +/// Parse and expand a `#[dynamic_params(..)]` module. +pub fn dynamic_params(attr: TokenStream, item: TokenStream) -> Result { + DynamicParamModAttr::parse(attr, item).map(ToTokens::into_token_stream) +} + +/// Parse and expand `#[dynamic_pallet_params(..)]` attribute. +pub fn dynamic_pallet_params(attr: TokenStream, item: TokenStream) -> Result { + DynamicPalletParamAttr::parse(attr, item).map(ToTokens::into_token_stream) +} + +/// Parse and expand `#[dynamic_aggregated_params_internal]` attribute. +pub fn dynamic_aggregated_params_internal( + _attr: TokenStream, + item: TokenStream, +) -> Result { + parse2::(item).map(ToTokens::into_token_stream) +} + +/// A top `#[dynamic_params(..)]` attribute together with a mod. +#[derive(derive_syn_parse::Parse)] +pub struct DynamicParamModAttr { + params_mod: syn::ItemMod, + meta: DynamicParamModAttrMeta, +} + +/// The inner meta of a `#[dynamic_params(..)]` attribute. +#[derive(derive_syn_parse::Parse)] +pub struct DynamicParamModAttrMeta { + name: syn::Ident, + _comma: Option, + #[parse_if(_comma.is_some())] + params_pallet: Option, +} + +impl DynamicParamModAttr { + pub fn parse(attr: TokenStream, item: TokenStream) -> Result { + let params_mod = parse2(item)?; + let meta = parse2(attr)?; + Ok(Self { params_mod, meta }) + } + + pub fn inner_mods(&self) -> Vec { + self.params_mod.content.as_ref().map_or(Vec::new(), |(_, items)| { + items + .iter() + .filter_map(|i| match i { + syn::Item::Mod(m) => Some(m), + _ => None, + }) + .cloned() + .collect() + }) + } +} + +impl ToTokens for DynamicParamModAttr { + fn to_tokens(&self, tokens: &mut TokenStream) { + let scrate = match crate_access() { + Ok(path) => path, + Err(err) => return tokens.extend(err), + }; + let (mut params_mod, name) = (self.params_mod.clone(), &self.meta.name); + let dynam_params_ident = ¶ms_mod.ident; + + let mut quoted_enum = quote! {}; + for m in self.inner_mods() { + let aggregate_name = + syn::Ident::new(&m.ident.to_string().to_class_case(), m.ident.span()); + let mod_name = &m.ident; + + let mut attrs = m.attrs.clone(); + attrs.retain(|attr| !attr.path().is_ident("dynamic_pallet_params")); + if let Err(err) = ensure_codec_index(&attrs, m.span()) { + tokens.extend(err.into_compile_error()); + return + } + + quoted_enum.extend(quote! { + #(#attrs)* + #aggregate_name(#dynam_params_ident::#mod_name::Parameters), + }); + } + + // Inject the outer args into the inner `#[dynamic_pallet_params(..)]` attribute. + if let Some(params_pallet) = &self.meta.params_pallet { + MacroInjectArgs { runtime_params: name.clone(), params_pallet: params_pallet.clone() } + .visit_item_mod_mut(&mut params_mod); + } + + tokens.extend(quote! { + #params_mod + + #[#scrate::dynamic_params::dynamic_aggregated_params_internal] + pub enum #name { + #quoted_enum + } + }); + } +} + +/// Ensure there is a `#[codec(index = ..)]` attribute. +fn ensure_codec_index(attrs: &Vec, span: Span) -> Result<()> { + let mut found = false; + + for attr in attrs.iter() { + if attr.path().is_ident("codec") { + let meta: syn::ExprAssign = attr.parse_args()?; + if meta.left.to_token_stream().to_string() == "index" { + found = true; + break + } + } + } + + if !found { + Err(syn::Error::new(span, "Missing explicit `#[codec(index = ..)]` attribute")) + } else { + Ok(()) + } +} + +/// Used to inject arguments into the inner `#[dynamic_pallet_params(..)]` attribute. +/// +/// This allows the outer `#[dynamic_params(..)]` attribute to specify some arguments that dont need +/// to be repeated every time. +struct MacroInjectArgs { + runtime_params: syn::Ident, + params_pallet: syn::Type, +} +impl VisitMut for MacroInjectArgs { + fn visit_item_mod_mut(&mut self, item: &mut syn::ItemMod) { + // Check if the mod has a `#[dynamic_pallet_params(..)]` attribute. + let attr = item.attrs.iter_mut().find(|attr| attr.path().is_ident("dynamic_pallet_params")); + + if let Some(attr) = attr { + match &attr.meta { + syn::Meta::Path(path) => + assert_eq!(path.to_token_stream().to_string(), "dynamic_pallet_params"), + _ => (), + } + + let runtime_params = &self.runtime_params; + let params_pallet = &self.params_pallet; + + attr.meta = syn::parse2::(quote! { + dynamic_pallet_params(#runtime_params, #params_pallet) + }) + .unwrap() + .into(); + } + + visit_mut::visit_item_mod_mut(self, item); + } +} +/// The helper attribute of a `#[dynamic_pallet_params(runtime_params, params_pallet)]` +/// attribute. +#[derive(derive_syn_parse::Parse)] +pub struct DynamicPalletParamAttr { + inner_mod: syn::ItemMod, + meta: DynamicPalletParamAttrMeta, +} + +/// The inner meta of a `#[dynamic_pallet_params(..)]` attribute. +#[derive(derive_syn_parse::Parse)] +pub struct DynamicPalletParamAttrMeta { + runtime_params: syn::Ident, + _comma: Token![,], + parameter_pallet: syn::Type, +} + +impl DynamicPalletParamAttr { + pub fn parse(attr: TokenStream, item: TokenStream) -> Result { + Ok(Self { inner_mod: parse2(item)?, meta: parse2(attr)? }) + } + + pub fn statics(&self) -> Vec { + self.inner_mod.content.as_ref().map_or(Vec::new(), |(_, items)| { + items + .iter() + .filter_map(|i| match i { + syn::Item::Static(s) => Some(s), + _ => None, + }) + .cloned() + .collect() + }) + } +} + +impl ToTokens for DynamicPalletParamAttr { + fn to_tokens(&self, tokens: &mut TokenStream) { + let scrate = match crate_access() { + Ok(path) => path, + Err(err) => return tokens.extend(err), + }; + let (params_mod, parameter_pallet, runtime_params) = + (&self.inner_mod, &self.meta.parameter_pallet, &self.meta.runtime_params); + + let aggregate_name = + syn::Ident::new(¶ms_mod.ident.to_string().to_class_case(), params_mod.ident.span()); + let (mod_name, vis) = (¶ms_mod.ident, ¶ms_mod.vis); + let statics = self.statics(); + + let (mut key_names, mut key_values, mut defaults, mut attrs, mut value_types): ( + Vec<_>, + Vec<_>, + Vec<_>, + Vec<_>, + Vec<_>, + ) = Default::default(); + + for s in statics.iter() { + if let Err(err) = ensure_codec_index(&s.attrs, s.span()) { + tokens.extend(err.into_compile_error()); + return + } + + key_names.push(&s.ident); + key_values.push(format_ident!("{}Value", &s.ident)); + defaults.push(&s.expr); + attrs.push(&s.attrs); + value_types.push(&s.ty); + } + + let key_ident = syn::Ident::new("ParametersKey", params_mod.ident.span()); + let value_ident = syn::Ident::new("ParametersValue", params_mod.ident.span()); + let runtime_key_ident = format_ident!("{}Key", runtime_params); + let runtime_value_ident = format_ident!("{}Value", runtime_params); + + tokens.extend(quote! { + pub mod #mod_name { + use super::*; + + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::codec::MaxEncodedLen, + #scrate::__private::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + #vis enum Parameters { + #( + #(#attrs)* + #key_names(#key_names, Option<#value_types>), + )* + } + + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::codec::MaxEncodedLen, + #scrate::__private::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + #vis enum #key_ident { + #( + #(#attrs)* + #key_names(#key_names), + )* + } + + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::codec::MaxEncodedLen, + #scrate::__private::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + #vis enum #value_ident { + #( + #(#attrs)* + #key_names(#value_types), + )* + } + + impl #scrate::traits::dynamic_params::AggregratedKeyValue for Parameters { + type Key = #key_ident; + type Value = #value_ident; + + fn into_parts(self) -> (Self::Key, Option) { + match self { + #( + Parameters::#key_names(key, value) => { + (#key_ident::#key_names(key), value.map(#value_ident::#key_names)) + }, + )* + } + } + } + + #( + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::codec::MaxEncodedLen, + #scrate::__private::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + #vis struct #key_names; + + impl #scrate::__private::Get<#value_types> for #key_names { + fn get() -> #value_types { + match + <#parameter_pallet as + #scrate::storage::StorageMap<#runtime_key_ident, #runtime_value_ident> + >::get(#runtime_key_ident::#aggregate_name(#key_ident::#key_names(#key_names))) + { + Some(#runtime_value_ident::#aggregate_name( + #value_ident::#key_names(inner))) => inner, + Some(_) => { + #scrate::defensive!("Unexpected value type at key - returning default"); + #defaults + }, + None => #defaults, + } + } + } + + impl #scrate::traits::dynamic_params::Key for #key_names { + type Value = #value_types; + type WrappedValue = #key_values; + } + + impl From<#key_names> for #key_ident { + fn from(key: #key_names) -> Self { + #key_ident::#key_names(key) + } + } + + impl TryFrom<#key_ident> for #key_names { + type Error = (); + + fn try_from(key: #key_ident) -> Result { + match key { + #key_ident::#key_names(key) => Ok(key), + _ => Err(()), + } + } + } + + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::sp_runtime::RuntimeDebug, + )] + #vis struct #key_values(pub #value_types); + + impl From<#key_values> for #value_ident { + fn from(value: #key_values) -> Self { + #value_ident::#key_names(value.0) + } + } + + impl From<(#key_names, #value_types)> for Parameters { + fn from((key, value): (#key_names, #value_types)) -> Self { + Parameters::#key_names(key, Some(value)) + } + } + + impl From<#key_names> for Parameters { + fn from(key: #key_names) -> Self { + Parameters::#key_names(key, None) + } + } + + impl TryFrom<#value_ident> for #key_values { + type Error = (); + + fn try_from(value: #value_ident) -> Result { + match value { + #value_ident::#key_names(value) => Ok(#key_values(value)), + _ => Err(()), + } + } + } + + impl From<#key_values> for #value_types { + fn from(value: #key_values) -> Self { + value.0 + } + } + )* + } + }); + } +} + +#[derive(derive_syn_parse::Parse)] +pub struct DynamicParamAggregatedEnum { + aggregated_enum: syn::ItemEnum, +} + +impl ToTokens for DynamicParamAggregatedEnum { + fn to_tokens(&self, tokens: &mut TokenStream) { + let scrate = match crate_access() { + Ok(path) => path, + Err(err) => return tokens.extend(err), + }; + let params_enum = &self.aggregated_enum; + let (name, vis) = (¶ms_enum.ident, ¶ms_enum.vis); + + let (mut indices, mut param_names, mut param_types): (Vec<_>, Vec<_>, Vec<_>) = + Default::default(); + let mut attributes = Vec::new(); + for (i, variant) in params_enum.variants.iter().enumerate() { + indices.push(i); + param_names.push(&variant.ident); + attributes.push(&variant.attrs); + + param_types.push(match &variant.fields { + syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, + _ => { + *tokens = quote! { compile_error!("Only unnamed enum variants with one inner item are supported") }; + return + }, + }); + } + + let params_key_ident = format_ident!("{}Key", params_enum.ident); + let params_value_ident = format_ident!("{}Value", params_enum.ident); + + tokens.extend(quote! { + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::codec::MaxEncodedLen, + #scrate::sp_runtime::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + #vis enum #name { + #( + //#[codec(index = #indices)] + #(#attributes)* + #param_names(#param_types), + )* + } + + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::codec::MaxEncodedLen, + #scrate::sp_runtime::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + #vis enum #params_key_ident { + #( + #(#attributes)* + #param_names(<#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Key), + )* + } + + #[doc(hidden)] + #[derive( + Clone, + PartialEq, + Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::codec::MaxEncodedLen, + #scrate::sp_runtime::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + #vis enum #params_value_ident { + #( + #(#attributes)* + #param_names(<#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Value), + )* + } + + impl #scrate::traits::dynamic_params::AggregratedKeyValue for #name { + type Key = #params_key_ident; + type Value = #params_value_ident; + + fn into_parts(self) -> (Self::Key, Option) { + match self { + #( + #name::#param_names(parameter) => { + let (key, value) = parameter.into_parts(); + (#params_key_ident::#param_names(key), value.map(#params_value_ident::#param_names)) + }, + )* + } + } + } + + #( + impl ::core::convert::From<<#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Key> for #params_key_ident { + fn from(key: <#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Key) -> Self { + #params_key_ident::#param_names(key) + } + } + + impl ::core::convert::TryFrom<#params_value_ident> for <#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Value { + type Error = (); + + fn try_from(value: #params_value_ident) -> Result { + match value { + #params_value_ident::#param_names(value) => Ok(value), + _ => Err(()), + } + } + } + )* + }); + } +} + +/// Get access to the current crate and convert the error to a compile error. +fn crate_access() -> core::result::Result { + generate_access_from_frame_or_crate("frame-support").map_err(|e| e.to_compile_error()) +} diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 34e68966b82333f56c91c0c32b7573f2fd8284e8..dee6d522d25ce90fe7ab254147fd31dc46ed3f3d 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -18,17 +18,20 @@ //! Proc macro of Support code for the runtime. #![recursion_limit = "512"] +#![deny(rustdoc::broken_intra_doc_links)] mod benchmark; mod construct_runtime; mod crate_version; mod derive_impl; mod dummy_part_checker; +mod dynamic_params; mod key_prefix; mod match_and_insert; mod no_bound; mod pallet; mod pallet_error; +mod runtime; mod storage_alias; mod transactional; mod tt_macro; @@ -186,133 +189,11 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { construct_runtime::construct_runtime(input) } -/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify -/// pallet information. /// -/// The struct must be defined as follows: -/// ```ignore -/// #[pallet::pallet] -/// pub struct Pallet(_); -/// ``` -/// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. -/// -/// ## Macro expansion: -/// -/// The macro adds this attribute to the struct definition: -/// ```ignore -/// #[derive( -/// frame_support::CloneNoBound, -/// frame_support::EqNoBound, -/// frame_support::PartialEqNoBound, -/// frame_support::RuntimeDebugNoBound, -/// )] -/// ``` -/// and replaces the type `_` with `PhantomData`. It also implements on the pallet: -/// * `GetStorageVersion` -/// * `OnGenesis`: contains some logic to write the pallet version into storage. -/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. -/// -/// It declares `type Module` type alias for `Pallet`, used by `construct_runtime`. -/// -/// It implements `PalletInfoAccess` on `Pallet` to ease access to pallet information given by -/// `frame_support::traits::PalletInfo`. (The implementation uses the associated type -/// `frame_system::Config::PalletInfo`). -/// -/// It implements `StorageInfoTrait` on `Pallet` which give information about all storages. -/// -/// If the attribute `generate_store` is set then the macro creates the trait `Store` and -/// implements it on `Pallet`. -/// -/// If the attribute `set_storage_max_encoded_len` is set then the macro calls -/// `StorageInfoTrait` for each storage in the implementation of `StorageInfoTrait` for the -/// pallet. Otherwise it implements `StorageInfoTrait` for the pallet using the -/// `PartialStorageInfoTrait` implementation of storages. -/// -/// ## Dev Mode (`#[pallet(dev_mode)]`) -/// -/// Specifying the argument `dev_mode` will allow you to enable dev mode for a pallet. The aim -/// of dev mode is to loosen some of the restrictions and requirements placed on production -/// pallets for easy tinkering and development. Dev mode pallets should not be used in -/// production. Enabling dev mode has the following effects: -/// -/// * Weights no longer need to be specified on every `#[pallet::call]` declaration. By default, dev -/// mode pallets will assume a weight of zero (`0`) if a weight is not specified. This is -/// equivalent to specifying `#[weight(0)]` on all calls that do not specify a weight. -/// * Call indices no longer need to be specified on every `#[pallet::call]` declaration. By -/// default, dev mode pallets will assume a call index based on the order of the call. -/// * All storages are marked as unbounded, meaning you do not need to implement `MaxEncodedLen` on -/// storage types. This is equivalent to specifying `#[pallet::unbounded]` on all storage type -/// definitions. -/// * Storage hashers no longer need to be specified and can be replaced by `_`. In dev mode, these -/// will be replaced by `Blake2_128Concat`. In case of explicit key-binding, `Hasher` can simply -/// be ignored when in `dev_mode`. -/// -/// Note that the `dev_mode` argument can only be supplied to the `#[pallet]` or -/// `#[frame_support::pallet]` attribute macro that encloses your pallet module. This argument -/// cannot be specified anywhere else, including but not limited to the `#[pallet::pallet]` -/// attribute macro. -/// -///
-/// WARNING:
-/// You should not deploy or use dev mode pallets in production. Doing so can break your chain
-/// and therefore should never be done. Once you are done tinkering, you should remove the
-/// 'dev_mode' argument from your #[pallet] declaration and fix any compile errors before
-/// attempting to use your pallet in a production scenario.
-/// 
-/// -/// See `frame_support::pallet` docs for more info. -/// -/// ## Runtime Metadata Documentation -/// -/// The documentation added to this pallet is included in the runtime metadata. -/// -/// The documentation can be defined in the following ways: -/// -/// ```ignore -/// #[pallet::pallet] -/// /// Documentation for pallet 1 -/// #[doc = "Documentation for pallet 2"] -/// #[doc = include_str!("../README.md")] -/// #[pallet_doc("../doc1.md")] -/// #[pallet_doc("../doc2.md")] -/// pub mod pallet {} -/// ``` -/// -/// The runtime metadata for this pallet contains the following -/// - " Documentation for pallet 1" (captured from `///`) -/// - "Documentation for pallet 2" (captured from `#[doc]`) -/// - content of ../README.md (captured from `#[doc]` with `include_str!`) -/// - content of "../doc1.md" (captured from `pallet_doc`) -/// - content of "../doc2.md" (captured from `pallet_doc`) -/// -/// ### `doc` attribute -/// -/// The value of the `doc` attribute is included in the runtime metadata, as well as -/// expanded on the pallet module. The previous example is expanded to: -/// -/// ```ignore -/// /// Documentation for pallet 1 -/// /// Documentation for pallet 2 -/// /// Content of README.md -/// pub mod pallet {} -/// ``` -/// -/// If you want to specify the file from which the documentation is loaded, you can use the -/// `include_str` macro. However, if you only want the documentation to be included in the -/// runtime metadata, use the `pallet_doc` attribute. -/// -/// ### `pallet_doc` attribute -/// -/// Unlike the `doc` attribute, the documentation provided to the `pallet_doc` attribute is -/// not inserted on the module. -/// -/// The `pallet_doc` attribute can only be provided with one argument, -/// which is the file path that holds the documentation to be added to the metadata. +/// --- /// -/// This approach is beneficial when you use the `include_str` macro at the beginning of the file -/// and want that documentation to extend to the runtime metadata, without reiterating the -/// documentation on the pallet module itself. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet`. #[proc_macro_attribute] pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { pallet::pallet(attr, item) @@ -406,19 +287,28 @@ pub fn transactional(attr: TokenStream, input: TokenStream) -> TokenStream { transactional::transactional(attr, input).unwrap_or_else(|e| e.to_compile_error().into()) } +/// +/// --- +/// +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::require_transactional`. #[proc_macro_attribute] pub fn require_transactional(attr: TokenStream, input: TokenStream) -> TokenStream { transactional::require_transactional(attr, input) .unwrap_or_else(|e| e.to_compile_error().into()) } -/// Derive [`Clone`] but do not bound any generic. Docs are at `frame_support::CloneNoBound`. +/// Derive [`Clone`] but do not bound any generic. +/// +/// Docs at `frame_support::CloneNoBound`. #[proc_macro_derive(CloneNoBound)] pub fn derive_clone_no_bound(input: TokenStream) -> TokenStream { no_bound::clone::derive_clone_no_bound(input) } -/// Derive [`Debug`] but do not bound any generics. Docs are at `frame_support::DebugNoBound`. +/// Derive [`Debug`] but do not bound any generics. +/// +/// Docs at `frame_support::DebugNoBound`. #[proc_macro_derive(DebugNoBound)] pub fn derive_debug_no_bound(input: TokenStream) -> TokenStream { no_bound::debug::derive_debug_no_bound(input) @@ -450,14 +340,17 @@ pub fn derive_runtime_debug_no_bound(input: TokenStream) -> TokenStream { } } -/// Derive [`PartialEq`] but do not bound any generic. Docs are at -/// `frame_support::PartialEqNoBound`. +/// Derive [`PartialEq`] but do not bound any generic. +/// +/// Docs at `frame_support::PartialEqNoBound`. #[proc_macro_derive(PartialEqNoBound)] pub fn derive_partial_eq_no_bound(input: TokenStream) -> TokenStream { no_bound::partial_eq::derive_partial_eq_no_bound(input) } -/// Derive [`Eq`] but do no bound any generic. Docs are at `frame_support::EqNoBound`. +/// DeriveEq but do no bound any generic. +/// +/// Docs at `frame_support::EqNoBound`. #[proc_macro_derive(EqNoBound)] pub fn derive_eq_no_bound(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); @@ -492,6 +385,7 @@ pub fn derive_default_no_bound(input: TokenStream) -> TokenStream { no_bound::default::derive_default_no_bound(input) } +/// Macro used internally in FRAME to generate the crate version for a pallet. #[proc_macro] pub fn crate_to_crate_version(input: TokenStream) -> TokenStream { crate_version::crate_to_crate_version(input) @@ -553,6 +447,11 @@ pub fn __create_tt_macro(input: TokenStream) -> TokenStream { tt_macro::create_tt_return_macro(input) } +/// +/// --- +/// +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::storage_alias`. #[proc_macro_attribute] pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream { storage_alias::storage_alias(attributes.into(), input.into()) @@ -601,6 +500,11 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream /// default to `A` from the `impl A for B` part of the default impl. This is useful for scenarios /// where all of the relevant types are already in scope via `use` statements. /// +/// In case the `default_impl_path` is scoped to a different module such as +/// `some::path::TestTraitImpl`, the same scope is assumed for the `disambiguation_path`, i.e. +/// `some::A`. This enables the use of `derive_impl` attribute without having to specify the +/// `disambiguation_path` in most (if not all) uses within FRAME's context. +/// /// Conversely, the `default_impl_path` argument is required and cannot be omitted. /// /// Optionally, `no_aggregated_types` can be specified as follows: @@ -783,24 +687,21 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { .into() } -/// The optional attribute `#[pallet::no_default]` can be attached to trait items within a -/// `Config` trait impl that has [`#[pallet::config(with_default)]`](`macro@config`) attached. /// -/// Attaching this attribute to a trait item ensures that that trait item will not be used as a -/// default with the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. +/// --- +/// +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::no_default`. #[proc_macro_attribute] pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The optional attribute `#[pallet::no_default_bounds]` can be attached to trait items within a -/// `Config` trait impl that has [`#[pallet::config(with_default)]`](`macro@config`) attached. /// -/// Attaching this attribute to a trait item ensures that the generated trait `DefaultConfig` -/// will not have any bounds for this trait item. +/// --- /// -/// As an example, if you have a trait item `type AccountId: SomeTrait;` in your `Config` trait, -/// the generated `DefaultConfig` will only have `type AccountId;` with no trait bound. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::no_default_bounds`. #[proc_macro_attribute] pub fn no_default_bounds(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -880,6 +781,11 @@ pub fn register_default_impl(attrs: TokenStream, tokens: TokenStream) -> TokenSt } } +/// +/// --- +/// +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_prelude::inject_runtime_type`. #[proc_macro_attribute] pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { let item = tokens.clone(); @@ -890,12 +796,13 @@ pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { item.ident != "RuntimeOrigin" && item.ident != "RuntimeHoldReason" && item.ident != "RuntimeFreezeReason" && + item.ident != "RuntimeParameters" && item.ident != "PalletInfo" { return syn::Error::new_spanned( item, "`#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, \ - `RuntimeTask`, `RuntimeOrigin` or `PalletInfo`", + `RuntimeTask`, `RuntimeOrigin`, `RuntimeParameters` or `PalletInfo`", ) .to_compile_error() .into() @@ -912,75 +819,11 @@ fn pallet_macro_stub() -> TokenStream { .into() } -/// The mandatory attribute `#[pallet::config]` defines the configurable options for the pallet. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::config] -/// pub trait Config: frame_system::Config + $optionally_some_other_supertraits -/// $optional_where_clause -/// { -/// ... -/// } -/// ``` -/// -/// I.e. a regular trait definition named `Config`, with the supertrait -/// `frame_system::pallet::Config`, and optionally other supertraits and a where clause. -/// (Specifying other supertraits here is known as [tight -/// coupling](https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/)) -/// -/// The associated type `RuntimeEvent` is reserved. If defined, it must have the bounds -/// `From` and `IsType<::RuntimeEvent>`. -/// -/// [`pallet::event`](`macro@event`) must be present if `RuntimeEvent` exists as a config item -/// in your `#[pallet::config]`. -/// -/// ## Optional: `with_default` -/// -/// An optional `with_default` argument may also be specified. Doing so will automatically -/// generate a `DefaultConfig` trait inside your pallet which is suitable for use with -/// [`[#[derive_impl(..)]`](`macro@derive_impl`) to derive a default testing config: -/// -/// ```ignore -/// #[pallet::config(with_default)] -/// pub trait Config: frame_system::Config { -/// type RuntimeEvent: Parameter -/// + Member -/// + From> -/// + Debug -/// + IsType<::RuntimeEvent>; -/// -/// #[pallet::no_default] -/// type BaseCallFilter: Contains; -/// // ... -/// } -/// ``` -/// -/// As shown above, you may also attach the [`#[pallet::no_default]`](`macro@no_default`) -/// attribute to specify that a particular trait item _cannot_ be used as a default when a test -/// `Config` is derived using the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. -/// This will cause that particular trait item to simply not appear in default testing configs -/// based on this config (the trait item will not be included in `DefaultConfig`). /// -/// ### `DefaultConfig` Caveats -/// -/// The auto-generated `DefaultConfig` trait: -/// - is always a _subset_ of your pallet's `Config` trait. -/// - can only contain items that don't rely on externalities, such as `frame_system::Config`. -/// -/// Trait items that _do_ rely on externalities should be marked with -/// [`#[pallet::no_default]`](`macro@no_default`) -/// -/// Consequently: -/// - Any items that rely on externalities _must_ be marked with -/// [`#[pallet::no_default]`](`macro@no_default`) or your trait will fail to compile when used -/// with [`derive_impl`](`macro@derive_impl`). -/// - Items marked with [`#[pallet::no_default]`](`macro@no_default`) are entirely excluded from the -/// `DefaultConfig` trait, and therefore any impl of `DefaultConfig` doesn't need to implement -/// such items. +/// --- /// -/// For more information, see [`macro@derive_impl`]. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::config`. #[proc_macro_attribute] pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -989,7 +832,7 @@ pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// Rust-Analyzer Users: Documentation for this macro can be found at /// `frame_support::pallet_macros::constant`. #[proc_macro_attribute] pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { @@ -999,106 +842,48 @@ pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// Rust-Analyzer Users: Documentation for this macro can be found at /// `frame_support::pallet_macros::constant_name`. #[proc_macro_attribute] pub fn constant_name(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// To bypass the `frame_system::Config` supertrait check, use the attribute -/// `pallet::disable_frame_system_supertrait_check`, e.g.: /// -/// ```ignore -/// #[pallet::config] -/// #[pallet::disable_frame_system_supertrait_check] -/// pub trait Config: pallet_timestamp::Config {} -/// ``` +/// --- /// -/// NOTE: Bypassing the `frame_system::Config` supertrait check is typically desirable when you -/// want to write an alternative to the `frame_system` pallet. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::disable_frame_system_supertrait_check`. #[proc_macro_attribute] pub fn disable_frame_system_supertrait_check(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// To generate a `Store` trait associating all storages, annotate your `Pallet` struct with -/// the attribute `#[pallet::generate_store($vis trait Store)]`, e.g.: /// -/// ```ignore -/// #[pallet::pallet] -/// #[pallet::generate_store(pub(super) trait Store)] -/// pub struct Pallet(_); -/// ``` -/// More precisely, the `Store` trait contains an associated type for each storage. It is -/// implemented for `Pallet` allowing access to the storage from pallet struct. -/// -/// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using -/// `::Foo`. -/// -/// NOTE: this attribute is only valid when applied _directly_ to your `Pallet` struct -/// definition. -#[proc_macro_attribute] -pub fn generate_store(_: TokenStream, _: TokenStream) -> TokenStream { - pallet_macro_stub() -} - -/// Because the `pallet::pallet` macro implements `GetStorageVersion`, the current storage -/// version needs to be communicated to the macro. This can be done by using the -/// `pallet::storage_version` attribute: -/// -/// ```ignore -/// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); -/// -/// #[pallet::pallet] -/// #[pallet::storage_version(STORAGE_VERSION)] -/// pub struct Pallet(_); -/// ``` +/// --- /// -/// If not present, the current storage version is set to the default value. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::storage_version`. #[proc_macro_attribute] pub fn storage_version(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::hooks]` attribute allows you to specify a `Hooks` implementation for -/// `Pallet` that specifies pallet-specific logic. -/// -/// The item the attribute attaches to must be defined as follows: -/// ```ignore -/// #[pallet::hooks] -/// impl Hooks> for Pallet $optional_where_clause { -/// ... -/// } -/// ``` -/// I.e. a regular trait implementation with generic bound: `T: Config`, for the trait -/// `Hooks>` (they are defined in preludes), for the type `Pallet` and -/// with an optional where clause. -/// -/// If no `#[pallet::hooks]` exists, then the following default implementation is -/// automatically generated: -/// ```ignore -/// #[pallet::hooks] -/// impl Hooks> for Pallet {} -/// ``` -/// -/// ## Macro expansion /// -/// The macro implements the traits `OnInitialize`, `OnIdle`, `OnFinalize`, `OnRuntimeUpgrade`, -/// `OffchainWorker`, and `IntegrityTest` using the provided `Hooks` implementation. -/// -/// NOTE: `OnRuntimeUpgrade` is implemented with `Hooks::on_runtime_upgrade` and some -/// additional logic. E.g. logic to write the pallet version into storage. +/// --- /// -/// NOTE: The macro also adds some tracing logic when implementing the above traits. The -/// following hooks emit traces: `on_initialize`, `on_finalize` and `on_runtime_upgrade`. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::hooks`. #[proc_macro_attribute] pub fn hooks(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, the -/// first argument must be `origin: OriginFor`. +/// +/// --- +/// +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::weight`. #[proc_macro_attribute] pub fn weight(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1107,8 +892,8 @@ pub fn weight(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in -/// [`frame_support::pallet_macros::call`](../../frame_support/pallet_macros/attr.call.html). +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::compact`. #[proc_macro_attribute] pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1117,8 +902,8 @@ pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in -/// [`frame_support::pallet_macros::call`](../../frame_support/pallet_macros/attr.call.html). +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::call`. #[proc_macro_attribute] pub fn call(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1129,164 +914,60 @@ pub fn call(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in -/// [`frame_support::pallet_macros::call`](../../frame_support/pallet_macros/attr.call.html). +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::call_index`. #[proc_macro_attribute] pub fn call_index(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Each dispatchable may be annotated with the `#[pallet::feeless_if($closure)]` attribute, -/// which explicitly defines the condition for the dispatchable to be feeless. -/// -/// The arguments for the closure must be the referenced arguments of the dispatchable function. /// -/// The closure must return `bool`. -/// -/// ### Example -/// ```ignore -/// #[pallet::feeless_if(|_origin: &OriginFor, something: &u32| -> bool { -/// *something == 0 -/// })] -/// pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { -/// .... -/// } -/// ``` -/// -/// Please note that this only works for signed dispatchables and requires a signed extension -/// such as `SkipCheckIfFeeless` as defined in `pallet-skip-feeless-payment` to wrap the existing -/// payment extension. Else, this is completely ignored and the dispatchable is still charged. +/// --- /// -/// ### Macro expansion +/// Rust-Analyzer Users: Documentation for this macro can be found at /// -/// The macro implements the `CheckIfFeeless` trait on the dispatchable and calls the corresponding -/// closure in the implementation. +/// `frame_support::pallet_macros::feeless_if`. #[proc_macro_attribute] pub fn feeless_if(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Allows you to define some extra constants to be added into constant metadata. /// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::extra_constants] -/// impl Pallet where $optional_where_clause { -/// /// $some_doc -/// $vis fn $fn_name() -> $some_return_type { -/// ... -/// } -/// ... -/// } -/// ``` -/// I.e. a regular rust `impl` block with some optional where clause and functions with 0 args, -/// 0 generics, and some return type. +/// --- /// -/// ## Macro expansion +/// Rust-Analyzer Users: Documentation for this macro can be found at /// -/// The macro add some extra constants to pallet constant metadata. +/// `frame_support::pallet_macros::extra_constants`. #[proc_macro_attribute] pub fn extra_constants(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::error]` attribute allows you to define an error enum that will be returned -/// from the dispatchable when an error occurs. The information for this error type is then -/// stored in metadata. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::error] -/// pub enum Error { -/// /// $some_optional_doc -/// $SomeFieldLessVariant, -/// /// $some_more_optional_doc -/// $SomeVariantWithOneField(FieldType), -/// ... -/// } -/// ``` -/// I.e. a regular enum named `Error`, with generic `T` and fieldless or multiple-field -/// variants. /// -/// Any field type in the enum variants must implement `TypeInfo` in order to be properly used -/// in the metadata, and its encoded size should be as small as possible, preferably 1 byte in -/// size in order to reduce storage size. The error enum itself has an absolute maximum encoded -/// size specified by `MAX_MODULE_ERROR_ENCODED_SIZE`. -/// -/// (1 byte can still be 256 different errors. The more specific the error, the easier it is to -/// diagnose problems and give a better experience to the user. Don't skimp on having lots of -/// individual error conditions.) -/// -/// Field types in enum variants must also implement `PalletError`, otherwise the pallet will -/// fail to compile. Rust primitive types have already implemented the `PalletError` trait -/// along with some commonly used stdlib types such as [`Option`] and `PhantomData`, and hence -/// in most use cases, a manual implementation is not necessary and is discouraged. -/// -/// The generic `T` must not bound anything and a `where` clause is not allowed. That said, -/// bounds and/or a where clause should not needed for any use-case. -/// -/// ## Macro expansion -/// -/// The macro implements the [`Debug`] trait and functions `as_u8` using variant position, and -/// `as_str` using variant doc. +/// --- /// -/// The macro also implements `From>` for `&'static str` and `From>` for -/// `DispatchError`. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::error`. #[proc_macro_attribute] pub fn error(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::event]` attribute allows you to define pallet events. Pallet events are -/// stored under the `system` / `events` key when the block is applied (and then replaced when -/// the next block writes it's events). -/// -/// The Event enum must be defined as follows: -/// -/// ```ignore -/// #[pallet::event] -/// #[pallet::generate_deposit($visibility fn deposit_event)] // Optional -/// pub enum Event<$some_generic> $optional_where_clause { -/// /// Some doc -/// $SomeName($SomeType, $YetanotherType, ...), -/// ... -/// } -/// ``` /// -/// I.e. an enum (with named or unnamed fields variant), named `Event`, with generic: none or -/// `T` or `T: Config`, and optional w here clause. +/// --- /// -/// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], `Encode`, `Decode`, and -/// [`Debug`] (on std only). For ease of use, bound by the trait `Member`, available in -/// `frame_support::pallet_prelude`. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::event`. #[proc_macro_attribute] pub fn event(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generates a -/// helper function on `Pallet` that handles deposit events. -/// -/// NOTE: For instantiable pallets, the event must be generic over `T` and `I`. -/// -/// ## Macro expansion -/// -/// The macro will add on enum `Event` the attributes: -/// * `#[derive(frame_support::CloneNoBound)]` -/// * `#[derive(frame_support::EqNoBound)]` -/// * `#[derive(frame_support::PartialEqNoBound)]` -/// * `#[derive(frame_support::RuntimeDebugNoBound)]` -/// * `#[derive(codec::Encode)]` -/// * `#[derive(codec::Decode)]` -/// -/// The macro implements `From>` for (). /// -/// The macro implements a metadata function on `Event` returning the `EventMetadata`. +/// --- /// -/// If `#[pallet::generate_deposit]` is present then the macro implements `fn deposit_event` on -/// `Pallet`. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::generate_deposit`. #[proc_macro_attribute] pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1295,105 +976,68 @@ pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// Rust-Analyzer Users: Documentation for this macro can be found at /// `frame_support::pallet_macros::storage`. #[proc_macro_attribute] pub fn storage(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows you to define a -/// getter function on `Pallet`. /// -/// Also see [`pallet::storage`](`macro@storage`) +/// --- +/// +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::getter`. #[proc_macro_attribute] pub fn getter(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allows you to define the -/// storage prefix to use. This is helpful if you wish to rename the storage field but don't -/// want to perform a migration. -/// -/// E.g: -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::storage_prefix = "foo"] -/// #[pallet::getter(fn my_storage)] -/// pub(super) type MyStorage = StorageMap; -/// ``` /// -/// or +/// --- /// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn my_storage)] -/// pub(super) type MyStorage = StorageMap<_, Blake2_128Concat, u32, u32>; -/// ``` +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::storage_prefix`. #[proc_macro_attribute] pub fn storage_prefix(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The optional attribute `#[pallet::unbounded]` declares the storage as unbounded. When -/// implementating the storage info (when `#[pallet::generate_storage_info]` is specified on -/// the pallet struct placeholder), the size of the storage will be declared as unbounded. This -/// can be useful for storage which can never go into PoV (Proof of Validity). +/// +/// --- +/// +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::unbounded`. #[proc_macro_attribute] pub fn unbounded(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The optional attribute `#[pallet::whitelist_storage]` will declare the -/// storage as whitelisted from benchmarking. Doing so will exclude reads of -/// that value's storage key from counting towards weight calculations during -/// benchmarking. /// -/// This attribute should only be attached to storages that are known to be -/// read/used in every block. This will result in a more accurate benchmarking weight. -/// -/// ### Example -/// ```ignore -/// #[pallet::storage] -/// #[pallet::whitelist_storage] -/// pub(super) type Number = StorageValue<_, frame_system::pallet_prelude::BlockNumberFor::, ValueQuery>; -/// ``` +/// --- /// -/// NOTE: As with all `pallet::*` attributes, this one _must_ be written as -/// `#[pallet::whitelist_storage]` and can only be placed inside a `pallet` module in order for -/// it to work properly. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::whitelist_storage`. #[proc_macro_attribute] pub fn whitelist_storage(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::type_value]` attribute lets you define a struct implementing the `Get` trait -/// to ease the use of storage types. This attribute is meant to be used alongside -/// [`#[pallet::storage]`](`macro@storage`) to define a storage's default value. This attribute -/// can be used multiple times. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::type_value] -/// fn $MyDefaultName<$some_generic>() -> $default_type $optional_where_clause { $expr } -/// ``` /// -/// I.e.: a function definition with generics none or `T: Config` and a returned type. -/// -/// E.g.: +/// --- /// -/// ```ignore -/// #[pallet::type_value] -/// fn MyDefault() -> T::Balance { 3.into() } -/// ``` +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::disable_try_decode_storage`. +#[proc_macro_attribute] +pub fn disable_try_decode_storage(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// -/// ## Macro expansion +/// --- /// -/// The macro renames the function to some internal name, generates a struct with the original -/// name of the function and its generic, and implements `Get<$ReturnType>` by calling the user -/// defined function. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::type_value`. #[proc_macro_attribute] pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1402,7 +1046,7 @@ pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// Rust-Analyzer Users: Documentation for this macro can be found at /// `frame_support::pallet_macros::genesis_config`. #[proc_macro_attribute] pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { @@ -1412,115 +1056,48 @@ pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { /// /// --- /// -/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// Rust-Analyzer Users: Documentation for this macro can be found at /// `frame_support::pallet_macros::genesis_build`. #[proc_macro_attribute] pub fn genesis_build(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::inherent]` attribute allows the pallet to provide some -/// [inherent](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions). -/// An inherent is some piece of data that is inserted by a block authoring node at block -/// creation time and can either be accepted or rejected by validators based on whether the -/// data falls within an acceptable range. /// -/// The most common inherent is the `timestamp` that is inserted into every block. Since there -/// is no way to validate timestamps, validators simply check that the timestamp reported by -/// the block authoring node falls within an acceptable range. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::inherent] -/// impl ProvideInherent for Pallet { -/// // ... regular trait implementation -/// } -/// ``` -/// -/// I.e. a trait implementation with bound `T: Config`, of trait `ProvideInherent` for type -/// `Pallet`, and some optional where clause. -/// -/// ## Macro expansion +/// --- /// -/// The macro currently makes no use of this information, but it might use this information in -/// the future to give information directly to `construct_runtime`. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::inherent`. #[proc_macro_attribute] pub fn inherent(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::validate_unsigned]` attribute allows the pallet to validate some unsigned -/// transaction: /// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::validate_unsigned] -/// impl ValidateUnsigned for Pallet { -/// // ... regular trait implementation -/// } -/// ``` -/// -/// I.e. a trait implementation with bound `T: Config`, of trait `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. -/// -/// ## Macro expansion +/// --- /// -/// The macro currently makes no use of this information, but it might use this information in -/// the future to give information directly to `construct_runtime`. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::validate_unsigned`. #[proc_macro_attribute] pub fn validate_unsigned(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::origin]` attribute allows you to define some origin for the pallet. /// -/// Item must be either a type alias, an enum, or a struct. It needs to be public. -/// -/// E.g.: -/// -/// ```ignore -/// #[pallet::origin] -/// pub struct Origin(PhantomData<(T)>); -/// ``` -/// -/// **WARNING**: modifying origin changes the outer runtime origin. This outer runtime origin -/// can be stored on-chain (e.g. in `pallet-scheduler`), thus any change must be done with care -/// as it might require some migration. +/// --- /// -/// NOTE: for instantiable pallets, the origin must be generic over `T` and `I`. +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::origin`. #[proc_macro_attribute] pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::composite_enum]` attribute allows you to define an enum that gets composed as an -/// aggregate enum by `construct_runtime`. This is similar in principle with `#[pallet::event]` and -/// `#[pallet::error]`. -/// -/// The attribute currently only supports enum definitions, and identifiers that are named -/// `FreezeReason`, `HoldReason`, `LockId` or `SlashReason`. Arbitrary identifiers for the enum are -/// not supported. The aggregate enum generated by `construct_runtime` will have the name of -/// `RuntimeFreezeReason`, `RuntimeHoldReason`, `RuntimeLockId` and `RuntimeSlashReason` -/// respectively. -/// -/// NOTE: The aggregate enum generated by `construct_runtime` generates a conversion function from -/// the pallet enum to the aggregate enum, and automatically derives the following traits: /// -/// ```ignore -/// Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo, -/// RuntimeDebug -/// ``` +/// --- /// -/// For ease of usage, when no `#[derive]` attributes are found for the enum under -/// `#[pallet::composite_enum]`, the aforementioned traits are automatically derived for it. The -/// inverse is also true: if there are any `#[derive]` attributes found for the enum, then no traits -/// will automatically be derived for it (this implies that you need to provide the -/// `frame_support::traits::VariantCount` implementation). +/// Rust-Analyzer Users: Documentation for this macro can be found at +/// `frame_support::pallet_macros::composite_enum`. #[proc_macro_attribute] pub fn composite_enum(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1576,25 +1153,11 @@ pub fn task_index(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Can be attached to a module. Doing so will declare that module as importable into a pallet -/// via [`#[import_section]`](`macro@import_section`). -/// -/// Note that sections are imported by their module name/ident, and should be referred to by -/// their _full path_ from the perspective of the target pallet. Do not attempt to make use -/// of `use` statements to bring pallet sections into scope, as this will not work (unless -/// you do so as part of a wildcard import, in which case it will work). -/// -/// ## Naming Logistics /// -/// Also note that because of how `#[pallet_section]` works, pallet section names must be -/// globally unique _within the crate in which they are defined_. For more information on -/// why this must be the case, see macro_magic's -/// [`#[export_tokens]`](https://docs.rs/macro_magic/latest/macro_magic/attr.export_tokens.html) macro. +/// --- /// -/// Optionally, you may provide an argument to `#[pallet_section]` such as -/// `#[pallet_section(some_ident)]`, in the event that there is another pallet section in -/// same crate with the same ident/name. The ident you specify can then be used instead of -/// the module's ident name when you go to import it via `#[import_section]`. +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::pallet_section`. #[proc_macro_attribute] pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { let tokens_clone = tokens.clone(); @@ -1608,39 +1171,11 @@ pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { } } -/// An attribute macro that can be attached to a module declaration. Doing so will -/// Imports the contents of the specified external pallet section that was defined -/// previously using [`#[pallet_section]`](`macro@pallet_section`). /// -/// ## Example -/// ```ignore -/// #[import_section(some_section)] -/// #[pallet] -/// pub mod pallet { -/// // ... -/// } -/// ``` -/// where `some_section` was defined elsewhere via: -/// ```ignore -/// #[pallet_section] -/// pub mod some_section { -/// // ... -/// } -/// ``` -/// -/// This will result in the contents of `some_section` being _verbatim_ imported into -/// the pallet above. Note that since the tokens for `some_section` are essentially -/// copy-pasted into the target pallet, you cannot refer to imports that don't also -/// exist in the target pallet, but this is easily resolved by including all relevant -/// `use` statements within your pallet section, so they are imported as well, or by -/// otherwise ensuring that you have the same imports on the target pallet. -/// -/// It is perfectly permissible to import multiple pallet sections into the same pallet, -/// which can be done by having multiple `#[import_section(something)]` attributes -/// attached to the pallet. +/// --- /// -/// Note that sections are imported by their module name/ident, and should be referred to by -/// their _full path_ from the perspective of the target pallet. +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::import_section`. #[import_tokens_attr { format!( "{}::macro_magic", @@ -1685,3 +1220,119 @@ pub fn import_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { } .into() } + +/// Construct a runtime, with the given name and the given pallets. +/// +/// # Example: +/// +/// ```ignore +/// #[frame_support::runtime] +/// mod runtime { +/// // The main runtime +/// #[runtime::runtime] +/// // Runtime Types to be generated +/// #[runtime::derive( +/// RuntimeCall, +/// RuntimeEvent, +/// RuntimeError, +/// RuntimeOrigin, +/// RuntimeFreezeReason, +/// RuntimeHoldReason, +/// RuntimeSlashReason, +/// RuntimeLockId, +/// RuntimeTask, +/// )] +/// pub struct Runtime; +/// +/// #[runtime::pallet_index(0)] +/// pub type System = frame_system; +/// +/// #[runtime::pallet_index(1)] +/// pub type Test = path::to::test; +/// +/// // Pallet with instance. +/// #[runtime::pallet_index(2)] +/// pub type Test2_Instance1 = test2; +/// +/// // Pallet with calls disabled. +/// #[runtime::pallet_index(3)] +/// #[runtime::disable_call] +/// pub type Test3 = test3; +/// +/// // Pallet with unsigned extrinsics disabled. +/// #[runtime::pallet_index(4)] +/// #[runtime::disable_unsigned] +/// pub type Test4 = test4; +/// } +/// ``` +/// +/// # Legacy Ordering +/// +/// An optional attribute can be defined as #[frame_support::runtime(legacy_ordering)] to +/// ensure that the order of hooks is same as the order of pallets (and not based on the +/// pallet_index). This is to support legacy runtimes and should be avoided for new ones. +/// +/// # Note +/// +/// The population of the genesis storage depends on the order of pallets. So, if one of your +/// pallets depends on another pallet, the pallet that is depended upon needs to come before +/// the pallet depending on it. +/// +/// # Type definitions +/// +/// * The macro generates a type alias for each pallet to their `Pallet`. E.g. `type System = +/// frame_system::Pallet` +#[cfg(feature = "experimental")] +#[proc_macro_attribute] +pub fn runtime(attr: TokenStream, item: TokenStream) -> TokenStream { + runtime::runtime(attr, item) +} + +/// Mark a module that contains dynamic parameters. +/// +/// See the `pallet_parameters` for a full example. +/// +/// # Arguments +/// +/// The macro accepts two positional arguments, of which the second is optional. +/// +/// ## Aggregated Enum Name +/// +/// This sets the name that the aggregated Key-Value enum will be named after. Common names would be +/// `RuntimeParameters`, akin to `RuntimeCall`, `RuntimeOrigin` etc. There is no default value for +/// this argument. +/// +/// ## Parameter Storage Backend +/// +/// The second argument provides access to the storage of the parameters. It can either be set on +/// on this attribute, or on the inner ones. If set on both, the inner one takes precedence. +#[proc_macro_attribute] +pub fn dynamic_params(attrs: TokenStream, input: TokenStream) -> TokenStream { + dynamic_params::dynamic_params(attrs.into(), input.into()) + .unwrap_or_else(|r| r.into_compile_error()) + .into() +} + +/// Define a module inside a [`macro@dynamic_params`] module that contains dynamic parameters. +/// +/// See the `pallet_parameters` for a full example. +/// +/// # Argument +/// +/// This attribute takes one optional argument. The argument can either be put here or on the +/// surrounding `#[dynamic_params]` attribute. If set on both, the inner one takes precedence. +#[proc_macro_attribute] +pub fn dynamic_pallet_params(attrs: TokenStream, input: TokenStream) -> TokenStream { + dynamic_params::dynamic_pallet_params(attrs.into(), input.into()) + .unwrap_or_else(|r| r.into_compile_error()) + .into() +} + +/// Used internally by [`dynamic_params`]. +#[doc(hidden)] +#[proc_macro_attribute] +pub fn dynamic_aggregated_params_internal(attrs: TokenStream, input: TokenStream) -> TokenStream { + dynamic_params::dynamic_aggregated_params_internal(attrs.into(), input.into()) + .unwrap_or_else(|r| r.into_compile_error()) + .into() +} diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index f43faba1ee0c8c14cb808b2f64f58446ebe7ffae..f395872c8a80a6b9a2ddd391ea106284140d53ba 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/call.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/call.rs @@ -18,7 +18,7 @@ use crate::{ pallet::{ expand::warnings::{weight_constant_warning, weight_witness_warning}, - parse::call::{CallVariantDef, CallWeightDef}, + parse::call::CallWeightDef, Def, }, COUNTER, @@ -112,22 +112,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } debug_assert_eq!(fn_weight.len(), methods.len()); - let map_fn_docs = if !def.dev_mode { - // Emit the [`Pallet::method`] documentation only for non-dev modes. - |method: &CallVariantDef| { - let reference = format!("See [`Pallet::{}`].", method.name); - quote!(#reference) - } - } else { - // For the dev-mode do not provide a documenation link as it will break the - // `cargo doc` if the pallet is private inside a test. - |method: &CallVariantDef| { - let reference = format!("See `Pallet::{}`.", method.name); - quote!(#reference) - } - }; - - let fn_doc = methods.iter().map(map_fn_docs).collect::>(); + let fn_doc = methods.iter().map(|method| &method.docs).collect::>(); let args_name = methods .iter() @@ -309,7 +294,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { ), #( #cfg_attrs - #[doc = #fn_doc] + #( #[doc = #fn_doc] )* #[codec(index = #call_index)] #fn_name { #( diff --git a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs index 5044d4285bb64aceeccd14959743a494f3c94f85..3623b595268d081ee7b5750a5431f208383f8517 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs @@ -42,7 +42,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { >::name::().unwrap_or("") }; - let initialize_on_chain_storage_version = if let Some(current_version) = + let initialize_on_chain_storage_version = if let Some(in_code_version) = &def.pallet_struct.storage_version { quote::quote! { @@ -50,9 +50,9 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { target: #frame_support::LOG_TARGET, "🐥 New pallet {:?} detected in the runtime. Initializing the on-chain storage version to match the storage version defined in the pallet: {:?}", #pallet_name, - #current_version + #in_code_version ); - #current_version.put::(); + #in_code_version.put::(); } } else { quote::quote! { @@ -73,10 +73,10 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::__private::log::info!( target: #frame_support::LOG_TARGET, "⚠️ {} declares internal migrations (which *might* execute). \ - On-chain `{:?}` vs current storage version `{:?}`", + On-chain `{:?}` vs in-code storage version `{:?}`", #pallet_name, ::on_chain_storage_version(), - ::current_storage_version(), + ::in_code_storage_version(), ); } } else { @@ -102,23 +102,23 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { }; // If a storage version is set, we should ensure that the storage version on chain matches the - // current storage version. This assumes that `Executive` is running custom migrations before + // in-code storage version. This assumes that `Executive` is running custom migrations before // the pallets are called. let post_storage_version_check = if def.pallet_struct.storage_version.is_some() { quote::quote! { let on_chain_version = ::on_chain_storage_version(); - let current_version = ::current_storage_version(); + let in_code_version = ::in_code_storage_version(); - if on_chain_version != current_version { + if on_chain_version != in_code_version { #frame_support::__private::log::error!( target: #frame_support::LOG_TARGET, - "{}: On chain storage version {:?} doesn't match current storage version {:?}.", + "{}: On chain storage version {:?} doesn't match in-code storage version {:?}.", #pallet_name, on_chain_version, - current_version, + in_code_version, ); - return Err("On chain and current storage version do not match. Missing runtime upgrade?".into()); + return Err("On chain and in-code storage version do not match. Missing runtime upgrade?".into()); } } } else { @@ -175,6 +175,22 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } } + impl<#type_impl_gen> + #frame_support::traits::OnPoll<#frame_system::pallet_prelude::BlockNumberFor::> + for #pallet_ident<#type_use_gen> #where_clause + { + fn on_poll( + n: #frame_system::pallet_prelude::BlockNumberFor::, + weight: &mut #frame_support::weights::WeightMeter + ) { + < + Self as #frame_support::traits::Hooks< + #frame_system::pallet_prelude::BlockNumberFor:: + > + >::on_poll(n, weight); + } + } + impl<#type_impl_gen> #frame_support::traits::OnInitialize<#frame_system::pallet_prelude::BlockNumberFor::> for #pallet_ident<#type_use_gen> #where_clause diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 3da7d9293c7cc1a1676e5cb0e4afe9ab08b25948..067839c2846353cb995d4c160ac2f38313c19d01 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -31,7 +31,6 @@ mod instances; mod origin; mod pallet_struct; mod storage; -mod store_trait; mod tasks; mod tt_default_parts; mod type_value; @@ -68,7 +67,6 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let storages = storage::expand_storages(&mut def); let inherents = inherent::expand_inherents(&mut def); let instances = instances::expand_instances(&mut def); - let store_trait = store_trait::expand_store_trait(&mut def); let hooks = hooks::expand_hooks(&mut def); let genesis_build = genesis_build::expand_genesis_build(&mut def); let genesis_config = genesis_config::expand_genesis_config(&mut def); @@ -110,7 +108,6 @@ storage item. Otherwise, all storage items are listed among [*Type Definitions*] #storages #inherents #instances - #store_trait #hooks #genesis_build #genesis_config 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 c2102f0284dbeeadb08fc9122e5fe824032dfb82..7cdf6bde9de87d0bd4eed70de93173bc9bf4e3ff 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -160,7 +160,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { } ); - let (storage_version, current_storage_version_ty) = + let (storage_version, in_code_storage_version_ty) = if let Some(v) = def.pallet_struct.storage_version.as_ref() { (quote::quote! { #v }, quote::quote! { #frame_support::traits::StorageVersion }) } else { @@ -203,9 +203,9 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { for #pallet_ident<#type_use_gen> #config_where_clause { - type CurrentStorageVersion = #current_storage_version_ty; + type InCodeStorageVersion = #in_code_storage_version_ty; - fn current_storage_version() -> Self::CurrentStorageVersion { + fn in_code_storage_version() -> Self::InCodeStorageVersion { #storage_version } diff --git a/substrate/frame/support/procedural/src/pallet/expand/storage.rs b/substrate/frame/support/procedural/src/pallet/expand/storage.rs index 96c2c8e3120b8f8fb76e8ee10b067ce3f13f62e9..937b068cfabd14e04b05177be2f0242eccd3abec 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/storage.rs @@ -834,7 +834,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { .storages .iter() .filter_map(|storage| { - if storage.cfg_attrs.is_empty() { + // A little hacky; don't generate for cfg gated storages to not get compile errors + // when building "frame-feature-testing" gated storages in the "frame-support-test" + // crate. + if storage.try_decode && storage.cfg_attrs.is_empty() { let ident = &storage.ident; let gen = &def.type_use_generics(storage.attr_span); Some(quote::quote_spanned!(storage.attr_span => #ident<#gen> )) diff --git a/substrate/frame/support/procedural/src/pallet/expand/store_trait.rs b/substrate/frame/support/procedural/src/pallet/expand/store_trait.rs deleted file mode 100644 index 6635adc988157361a1478a5ec06589f7988b9676..0000000000000000000000000000000000000000 --- a/substrate/frame/support/procedural/src/pallet/expand/store_trait.rs +++ /dev/null @@ -1,67 +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 crate::pallet::Def; -use syn::spanned::Spanned; - -/// If attribute `#[pallet::generate_store(..)]` is defined then: -/// * generate Store trait with all storages, -/// * implement Store trait for Pallet. -pub fn expand_store_trait(def: &mut Def) -> proc_macro2::TokenStream { - let (trait_vis, trait_store, attribute_span) = - if let Some(store) = &def.pallet_struct.store { store } else { return Default::default() }; - - let type_impl_gen = &def.type_impl_generics(trait_store.span()); - let type_use_gen = &def.type_use_generics(trait_store.span()); - let pallet_ident = &def.pallet_struct.pallet; - - let mut where_clauses = vec![&def.config.where_clause]; - where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause)); - let completed_where_clause = super::merge_where_clauses(&where_clauses); - - let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::>(); - let storage_cfg_attrs = - &def.storages.iter().map(|storage| &storage.cfg_attrs).collect::>(); - let warnig_struct_name = syn::Ident::new("Store", *attribute_span); - let warning: syn::ItemStruct = syn::parse_quote!( - #[deprecated(note = r" - Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. - Check https://github.com/paritytech/substrate/pull/13535 for more details.")] - struct #warnig_struct_name; - ); - - quote::quote_spanned!(trait_store.span() => - const _:() = { - #warning - const _: Option<#warnig_struct_name> = None; - }; - #trait_vis trait #trait_store { - #( - #(#storage_cfg_attrs)* - type #storage_names; - )* - } - impl<#type_impl_gen> #trait_store for #pallet_ident<#type_use_gen> - #completed_where_clause - { - #( - #(#storage_cfg_attrs)* - type #storage_names = #storage_names<#type_use_gen>; - )* - } - ) -} 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 7cc1415dfddf1514cf398555c650f4892097aefd..99364aaa96cd7808def45563392be207604151d7 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 @@ -28,6 +28,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { syn::Ident::new(&format!("__tt_default_parts_{}", count), def.item.span()); let extra_parts_unique_id = syn::Ident::new(&format!("__tt_extra_parts_{}", count), def.item.span()); + let default_parts_unique_id_v2 = + syn::Ident::new(&format!("__tt_default_parts_v2_{}", count), def.item.span()); let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); @@ -81,6 +83,58 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) .then_some(quote::quote!(SlashReason,)); + 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 storage_part_v2 = (!def.storages.is_empty()).then(|| quote::quote!(+ Storage)); + + let event_part_v2 = def.event.as_ref().map(|event| { + let gen = event.gen_kind.is_generic().then(|| quote::quote!()); + quote::quote!(+ Event #gen) + }); + + let error_part_v2 = def.error.as_ref().map(|_| quote::quote!(+ Error)); + + let origin_part_v2 = def.origin.as_ref().map(|origin| { + let gen = origin.is_generic.then(|| quote::quote!()); + quote::quote!(+ Origin #gen) + }); + + let config_part_v2 = def.genesis_config.as_ref().map(|genesis_config| { + let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!()); + quote::quote!(+ Config #gen) + }); + + let inherent_part_v2 = def.inherent.as_ref().map(|_| quote::quote!(+ Inherent)); + + let validate_unsigned_part_v2 = + def.validate_unsigned.as_ref().map(|_| quote::quote!(+ ValidateUnsigned)); + + let freeze_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_))) + .then_some(quote::quote!(+ FreezeReason)); + + let hold_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_))) + .then_some(quote::quote!(+ HoldReason)); + + let lock_id_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_))) + .then_some(quote::quote!(+ LockId)); + + let slash_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) + .then_some(quote::quote!(+ SlashReason)); + quote::quote!( // This macro follows the conventions as laid out by the `tt-call` crate. It does not // accept any arguments and simply returns the pallet parts, separated by commas, then @@ -138,5 +192,25 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { } pub use #extra_parts_unique_id as tt_extra_parts; + + #[macro_export] + #[doc(hidden)] + macro_rules! #default_parts_unique_id_v2 { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support)*::__private::tt_return! { + $caller + tokens = [{ + + Pallet #call_part_v2 #storage_part_v2 #event_part_v2 #error_part_v2 #origin_part_v2 #config_part_v2 + #inherent_part_v2 #validate_unsigned_part_v2 #freeze_reason_part_v2 #task_part_v2 + #hold_reason_part_v2 #lock_id_part_v2 #slash_reason_part_v2 + }] + } + }; + } + + pub use #default_parts_unique_id_v2 as tt_default_parts_v2; ) } diff --git a/substrate/frame/support/procedural/src/pallet/parse/helper.rs b/substrate/frame/support/procedural/src/pallet/parse/helper.rs index 538226a8745fe4d0792e36b9aaad9cbed9d4f88e..3187c9139c8f46c7664e96edb6870f68979146ae 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/helper.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/helper.rs @@ -148,6 +148,12 @@ impl MutItemAttrs for syn::ImplItemFn { } } +impl MutItemAttrs for syn::ItemType { + fn mut_item_attrs(&mut self) -> Option<&mut Vec> { + Some(&mut self.attrs) + } +} + /// Parse for `()` struct Unit; impl syn::parse::Parse for Unit { diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index e1efdbcc2027975d89a00b1037bd5d0af68998a3..b55f130a93a7ee7eef377678c4fc1ea664644601 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -558,8 +558,6 @@ mod keyword { syn::custom_keyword!(validate_unsigned); syn::custom_keyword!(type_value); syn::custom_keyword!(pallet); - syn::custom_keyword!(generate_store); - syn::custom_keyword!(Store); syn::custom_keyword!(extra_constants); syn::custom_keyword!(composite_enum); } diff --git a/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs index f4af86aa3e9936a3e77036f062ba8d4bf1a6c601..b645760998fe1c27e48c724dcde7cfcc658bb594 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -23,10 +23,8 @@ use syn::spanned::Spanned; mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(Pallet); - syn::custom_keyword!(generate_store); syn::custom_keyword!(without_storage_info); syn::custom_keyword!(storage_version); - syn::custom_keyword!(Store); } /// Definition of the pallet pallet. @@ -37,23 +35,19 @@ pub struct PalletStructDef { pub instances: Vec, /// The keyword Pallet used (contains span). pub pallet: keyword::Pallet, - /// Whether the trait `Store` must be generated. - pub store: Option<(syn::Visibility, keyword::Store, proc_macro2::Span)>, /// The span of the pallet::pallet attribute. pub attr_span: proc_macro2::Span, /// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`. /// Contains the span of the attribute. pub without_storage_info: Option, - /// The current storage version of the pallet. + /// The in-code storage version of the pallet. pub storage_version: Option, } /// Parse for one variant of: -/// * `#[pallet::generate_store($vis trait Store)]` /// * `#[pallet::without_storage_info]` /// * `#[pallet::storage_version(STORAGE_VERSION)]` pub enum PalletStructAttr { - GenerateStore { span: proc_macro2::Span, vis: syn::Visibility, keyword: keyword::Store }, WithoutStorageInfoTrait(proc_macro2::Span), StorageVersion { storage_version: syn::Path, span: proc_macro2::Span }, } @@ -61,9 +55,7 @@ pub enum PalletStructAttr { impl PalletStructAttr { fn span(&self) -> proc_macro2::Span { match self { - Self::GenerateStore { span, .. } | - Self::WithoutStorageInfoTrait(span) | - Self::StorageVersion { span, .. } => *span, + Self::WithoutStorageInfoTrait(span) | Self::StorageVersion { span, .. } => *span, } } } @@ -77,16 +69,7 @@ impl syn::parse::Parse for PalletStructAttr { content.parse::()?; let lookahead = content.lookahead1(); - if lookahead.peek(keyword::generate_store) { - content.parse::()?; - let generate_content; - syn::parenthesized!(generate_content in content); - let vis = generate_content.parse::()?; - generate_content.parse::()?; - let keyword = generate_content.parse::()?; - let span = content.span(); - Ok(Self::GenerateStore { vis, keyword, span }) - } else if lookahead.peek(keyword::without_storage_info) { + if lookahead.peek(keyword::without_storage_info) { let span = content.parse::()?.span(); Ok(Self::WithoutStorageInfoTrait(span)) } else if lookahead.peek(keyword::storage_version) { @@ -116,16 +99,12 @@ impl PalletStructDef { return Err(syn::Error::new(item.span(), msg)) }; - let mut store = None; let mut without_storage_info = None; let mut storage_version_found = None; let struct_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; for attr in struct_attrs { match attr { - PalletStructAttr::GenerateStore { vis, keyword, span } if store.is_none() => { - store = Some((vis, keyword, span)); - }, PalletStructAttr::WithoutStorageInfoTrait(span) if without_storage_info.is_none() => { @@ -162,7 +141,6 @@ impl PalletStructDef { index, instances, pallet, - store, attr_span, without_storage_info, storage_version: storage_version_found, diff --git a/substrate/frame/support/procedural/src/pallet/parse/storage.rs b/substrate/frame/support/procedural/src/pallet/parse/storage.rs index d1c7ba2e5e3c6788827577dfa843205d0be69174..9d96a18b56943db4715fabd30e8bc0f1c0aa7d28 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/storage.rs @@ -29,6 +29,7 @@ mod keyword { syn::custom_keyword!(storage_prefix); syn::custom_keyword!(unbounded); syn::custom_keyword!(whitelist_storage); + syn::custom_keyword!(disable_try_decode_storage); syn::custom_keyword!(OptionQuery); syn::custom_keyword!(ResultQuery); syn::custom_keyword!(ValueQuery); @@ -39,11 +40,13 @@ mod keyword { /// * `#[pallet::storage_prefix = "CustomName"]` /// * `#[pallet::unbounded]` /// * `#[pallet::whitelist_storage] +/// * `#[pallet::disable_try_decode_storage]` pub enum PalletStorageAttr { Getter(syn::Ident, proc_macro2::Span), StorageName(syn::LitStr, proc_macro2::Span), Unbounded(proc_macro2::Span), WhitelistStorage(proc_macro2::Span), + DisableTryDecodeStorage(proc_macro2::Span), } impl PalletStorageAttr { @@ -53,6 +56,7 @@ impl PalletStorageAttr { Self::StorageName(_, span) | Self::Unbounded(span) | Self::WhitelistStorage(span) => *span, + Self::DisableTryDecodeStorage(span) => *span, } } } @@ -93,6 +97,9 @@ impl syn::parse::Parse for PalletStorageAttr { } else if lookahead.peek(keyword::whitelist_storage) { content.parse::()?; Ok(Self::WhitelistStorage(attr_span)) + } else if lookahead.peek(keyword::disable_try_decode_storage) { + content.parse::()?; + Ok(Self::DisableTryDecodeStorage(attr_span)) } else { Err(lookahead.error()) } @@ -104,6 +111,7 @@ struct PalletStorageAttrInfo { rename_as: Option, unbounded: bool, whitelisted: bool, + try_decode: bool, } impl PalletStorageAttrInfo { @@ -112,6 +120,7 @@ impl PalletStorageAttrInfo { let mut rename_as = None; let mut unbounded = false; let mut whitelisted = false; + let mut disable_try_decode_storage = false; for attr in attrs { match attr { PalletStorageAttr::Getter(ident, ..) if getter.is_none() => getter = Some(ident), @@ -119,6 +128,8 @@ impl PalletStorageAttrInfo { rename_as = Some(name), PalletStorageAttr::Unbounded(..) if !unbounded => unbounded = true, PalletStorageAttr::WhitelistStorage(..) if !whitelisted => whitelisted = true, + PalletStorageAttr::DisableTryDecodeStorage(..) if !disable_try_decode_storage => + disable_try_decode_storage = true, attr => return Err(syn::Error::new( attr.attr_span(), @@ -127,7 +138,13 @@ impl PalletStorageAttrInfo { } } - Ok(PalletStorageAttrInfo { getter, rename_as, unbounded, whitelisted }) + Ok(PalletStorageAttrInfo { + getter, + rename_as, + unbounded, + whitelisted, + try_decode: !disable_try_decode_storage, + }) } } @@ -186,6 +203,8 @@ pub struct StorageDef { pub unbounded: bool, /// Whether or not reads to this storage key will be ignored by benchmarking pub whitelisted: bool, + /// Whether or not to try to decode the storage key when running try-runtime checks. + pub try_decode: bool, /// Whether or not a default hasher is allowed to replace `_` pub use_default_hasher: bool, } @@ -775,7 +794,7 @@ impl StorageDef { }; let attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; - let PalletStorageAttrInfo { getter, rename_as, mut unbounded, whitelisted } = + let PalletStorageAttrInfo { getter, rename_as, mut unbounded, whitelisted, try_decode } = PalletStorageAttrInfo::from_attrs(attrs)?; // set all storages to be unbounded if dev_mode is enabled @@ -921,6 +940,7 @@ impl StorageDef { named_generics, unbounded, whitelisted, + try_decode, use_default_hasher, }) } diff --git a/substrate/frame/support/procedural/src/runtime/expand/mod.rs b/substrate/frame/support/procedural/src/runtime/expand/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..93c88fce94b73665efa7912b36056b661b12be1e --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/expand/mod.rs @@ -0,0 +1,320 @@ +// 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::parse::runtime_types::RuntimeType; +use crate::{ + construct_runtime::{ + check_pallet_number, decl_all_pallets, decl_integrity_test, decl_pallet_runtime_setup, + decl_static_assertions, expand, + }, + runtime::{ + parse::{ + AllPalletsDeclaration, ExplicitAllPalletsDeclaration, ImplicitAllPalletsDeclaration, + }, + Def, + }, +}; +use cfg_expr::Predicate; +use frame_support_procedural_tools::{ + generate_access_from_frame_or_crate, generate_crate_access, generate_hidden_includes, +}; +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use std::collections::HashSet; +use syn::{Ident, Result}; + +/// The fixed name of the system pallet. +const SYSTEM_PALLET_NAME: &str = "System"; + +pub fn expand(def: Def, legacy_ordering: bool) -> TokenStream2 { + let input = def.input; + + let (check_pallet_number_res, res) = match def.pallets { + AllPalletsDeclaration::Implicit(ref decl) => ( + check_pallet_number(input.clone(), decl.pallet_count), + construct_runtime_implicit_to_explicit(input.into(), decl.clone(), legacy_ordering), + ), + AllPalletsDeclaration::Explicit(ref decl) => ( + check_pallet_number(input, decl.pallets.len()), + construct_runtime_final_expansion( + def.runtime_struct.ident.clone(), + decl.clone(), + def.runtime_types.clone(), + legacy_ordering, + ), + ), + }; + + let res = res.unwrap_or_else(|e| e.to_compile_error()); + + // We want to provide better error messages to the user and thus, handle the error here + // separately. If there is an error, we print the error and still generate all of the code to + // get in overall less errors for the user. + let res = if let Err(error) = check_pallet_number_res { + let error = error.to_compile_error(); + + quote! { + #error + + #res + } + } else { + res + }; + + let res = expander::Expander::new("construct_runtime") + .dry(std::env::var("FRAME_EXPAND").is_err()) + .verbose(true) + .write_to_out_dir(res) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + res.into() +} + +fn construct_runtime_implicit_to_explicit( + input: TokenStream2, + definition: ImplicitAllPalletsDeclaration, + legacy_ordering: bool, +) -> Result { + let frame_support = generate_access_from_frame_or_crate("frame-support")?; + let attr = if legacy_ordering { quote!((legacy_ordering)) } else { quote!() }; + let mut expansion = quote::quote!( + #[frame_support::runtime #attr] + #input + ); + for pallet in definition.pallet_decls.iter() { + let pallet_path = &pallet.path; + let pallet_name = &pallet.name; + let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(<#instance>)); + expansion = quote::quote!( + #frame_support::__private::tt_call! { + macro = [{ #pallet_path::tt_default_parts_v2 }] + frame_support = [{ #frame_support }] + ~~> #frame_support::match_and_insert! { + target = [{ #expansion }] + pattern = [{ #pallet_name = #pallet_path #pallet_instance }] + } + } + ); + } + + Ok(expansion) +} + +fn construct_runtime_final_expansion( + name: Ident, + definition: ExplicitAllPalletsDeclaration, + runtime_types: Vec, + legacy_ordering: bool, +) -> Result { + let ExplicitAllPalletsDeclaration { mut pallets, name: pallets_name } = definition; + + if !legacy_ordering { + // Ensure that order of hooks is based on the pallet index + pallets.sort_by_key(|p| p.index); + } + + let system_pallet = + pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| { + syn::Error::new( + pallets_name.span(), + "`System` pallet declaration is missing. \ + Please add this line: `pub type System = frame_system;`", + ) + })?; + if !system_pallet.cfg_pattern.is_empty() { + return Err(syn::Error::new( + system_pallet.name.span(), + "`System` pallet declaration is feature gated, please remove any `#[cfg]` attributes", + )) + } + + let features = pallets + .iter() + .filter_map(|decl| { + (!decl.cfg_pattern.is_empty()).then(|| { + decl.cfg_pattern.iter().flat_map(|attr| { + attr.predicates().filter_map(|pred| match pred { + Predicate::Feature(feat) => Some(feat), + Predicate::Test => Some("test"), + _ => None, + }) + }) + }) + }) + .flatten() + .collect::>(); + + let hidden_crate_name = "construct_runtime"; + let scrate = generate_crate_access(hidden_crate_name, "frame-support"); + let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support"); + + let frame_system = generate_access_from_frame_or_crate("frame-system")?; + let block = quote!(<#name as #frame_system::Config>::Block); + let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic); + + let mut dispatch = None; + let mut outer_event = None; + let mut outer_error = None; + let mut outer_origin = None; + let mut freeze_reason = None; + let mut hold_reason = None; + let mut slash_reason = None; + let mut lock_id = None; + let mut task = None; + + for runtime_type in runtime_types.iter() { + match runtime_type { + RuntimeType::RuntimeCall(_) => { + dispatch = + Some(expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate)); + }, + RuntimeType::RuntimeEvent(_) => { + outer_event = Some(expand::expand_outer_enum( + &name, + &pallets, + &scrate, + expand::OuterEnumType::Event, + )?); + }, + RuntimeType::RuntimeError(_) => { + outer_error = Some(expand::expand_outer_enum( + &name, + &pallets, + &scrate, + expand::OuterEnumType::Error, + )?); + }, + RuntimeType::RuntimeOrigin(_) => { + outer_origin = + Some(expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?); + }, + RuntimeType::RuntimeFreezeReason(_) => { + freeze_reason = Some(expand::expand_outer_freeze_reason(&pallets, &scrate)); + }, + RuntimeType::RuntimeHoldReason(_) => { + hold_reason = Some(expand::expand_outer_hold_reason(&pallets, &scrate)); + }, + RuntimeType::RuntimeSlashReason(_) => { + slash_reason = Some(expand::expand_outer_slash_reason(&pallets, &scrate)); + }, + RuntimeType::RuntimeLockId(_) => { + lock_id = Some(expand::expand_outer_lock_id(&pallets, &scrate)); + }, + RuntimeType::RuntimeTask(_) => { + task = Some(expand::expand_outer_task(&name, &pallets, &scrate)); + }, + } + } + + let all_pallets = decl_all_pallets(&name, pallets.iter(), &features); + let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate); + + let metadata = expand::expand_runtime_metadata( + &name, + &pallets, + &scrate, + &unchecked_extrinsic, + &system_pallet.path, + ); + let outer_config = expand::expand_outer_config(&name, &pallets, &scrate); + let inherent = + expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); + let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate); + let integrity_test = decl_integrity_test(&scrate); + let static_assertions = decl_static_assertions(&name, &pallets, &scrate); + + let res = quote!( + #scrate_decl + + // Prevent UncheckedExtrinsic to print unused warning. + const _: () = { + #[allow(unused)] + type __hidden_use_of_unchecked_extrinsic = #unchecked_extrinsic; + }; + + #[derive( + Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + pub struct #name; + impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name { + type RuntimeBlock = #block; + } + + // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. + // The function is implemented by calling `impl_runtime_apis!`. + // + // However, the `runtime` may be used without calling `impl_runtime_apis!`. + // Rely on the `Deref` trait to differentiate between a runtime that implements + // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro runtime). + // + // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function. + // `InternalConstructRuntime` is implemented by the `runtime` for Runtime references (`& Runtime`), + // while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`). + // + // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` + // when both macros are called; and will resolve an empty `runtime_metadata` when only the `runtime` + // is used. + + #[doc(hidden)] + trait InternalConstructRuntime { + #[inline(always)] + fn runtime_metadata(&self) -> #scrate::__private::sp_std::vec::Vec<#scrate::__private::metadata_ir::RuntimeApiMetadataIR> { + Default::default() + } + } + #[doc(hidden)] + impl InternalConstructRuntime for &#name {} + + #outer_event + + #outer_error + + #outer_origin + + #all_pallets + + #pallet_to_index + + #dispatch + + #task + + #metadata + + #outer_config + + #inherent + + #validate_unsigned + + #freeze_reason + + #hold_reason + + #lock_id + + #slash_reason + + #integrity_test + + #static_assertions + ); + + Ok(res) +} diff --git a/substrate/frame/support/procedural/src/runtime/mod.rs b/substrate/frame/support/procedural/src/runtime/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..aaae579eb086638f1bfacf02105a8fcd0e3d01b5 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/mod.rs @@ -0,0 +1,236 @@ +// 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. + +//! Implementation of `runtime`. +//! +//! `runtime` implementation is recursive and can generate code which will call itself +//! in order to get all the pallet parts for each pallet. +//! +//! Pallets can define their parts: +//! - Implicitly: `pub type System = frame_system;` +//! - Explicitly: `pub type System = frame_system + Pallet + Call;` +//! +//! The `runtime` transitions from the implicit definition to the explicit one. +//! From the explicit state, Substrate expands the pallets with additional information +//! that is to be included in the runtime metadata. +//! +//! Pallets must provide the `tt_default_parts_v2` macro for these transitions. +//! These are automatically implemented by the `#[pallet::pallet]` macro. +//! +//! This macro also generates the following enums for ease of decoding if the respective type +//! is defined inside `#[runtime::derive]`: +//! - `enum RuntimeCall`: This type contains the information needed to decode extrinsics. +//! - `enum RuntimeEvent`: This type contains the information needed to decode events. +//! - `enum RuntimeError`: While this cannot be used directly to decode `sp_runtime::DispatchError` +//! from the chain, it contains the information needed to decode the +//! `sp_runtime::DispatchError::Module`. +//! +//! # State Transitions +//! +//! ```ignore +//! +----------+ +//! | Implicit | +//! +----------+ +//! | +//! v +//! +----------+ +//! | Explicit | +//! +----------+ +//! ``` +//! +//! The `runtime` macro transforms the implicit declaration of each pallet +//! `System: frame_system` to an explicit one `System: frame_system + Pallet + Call` using the +//! `tt_default_parts_v2` macro. +//! +//! The `tt_default_parts_v2` macro exposes a plus separated list of pallet parts. For example, the +//! `Event` part is exposed only if the pallet implements an event via `#[pallet::event]` macro. +//! The tokens generated by this macro are `+ Pallet + Call` for our example. +//! +//! The `match_and_insert` macro takes in 3 arguments: +//! - target: This is the `TokenStream` that contains the `runtime` macro. +//! - pattern: The pattern to match against in the target stream. +//! - tokens: The tokens to added after the pattern match. +//! +//! The `runtime` macro uses the `tt_call` to get the default pallet parts via +//! the `tt_default_parts_v2` macro defined by each pallet. The pallet parts are then returned as +//! input to the `match_and_replace` macro. +//! The `match_and_replace` then will modify the `runtime` to expand the implicit +//! definition to the explicit one. +//! +//! For example, +//! +//! ```ignore +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; // Implicit definition of parts +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances; // Implicit definition of parts +//! } +//! ``` +//! This call has some implicit pallet parts, thus it will expand to: +//! ```ignore +//! frame_support::__private::tt_call! { +//! macro = [{ pallet_balances::tt_default_parts_v2 }] +//! ~~> frame_support::match_and_insert! { +//! target = [{ +//! frame_support::__private::tt_call! { +//! macro = [{ frame_system::tt_default_parts_v2 }] +//! ~~> frame_support::match_and_insert! { +//! target = [{ +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances; +//! } +//! }] +//! pattern = [{ System = frame_system }] +//! } +//! } +//! }] +//! pattern = [{ Balances = pallet_balances }] +//! } +//! } +//! ``` +//! `tt_default_parts_v2` must be defined. It returns the pallet parts inside some tokens, and +//! then `tt_call` will pipe the returned pallet parts into the input of `match_and_insert`. +//! Thus `match_and_insert` will initially receive the following inputs: +//! ```ignore +//! frame_support::match_and_insert! { +//! target = [{ +//! frame_support::match_and_insert! { +//! target = [{ +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances; +//! } +//! }] +//! pattern = [{ System = frame_system }] +//! tokens = [{ ::{+ Pallet + Call} }] +//! } +//! }] +//! pattern = [{ Balances = pallet_balances }] +//! tokens = [{ ::{+ Pallet + Call} }] +//! } +//! ``` +//! After dealing with `pallet_balances`, the inner `match_and_insert` will expand to: +//! ```ignore +//! frame_support::match_and_insert! { +//! target = [{ +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; // Implicit definition of parts +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances + Pallet + Call; // Explicit definition of parts +//! } +//! }] +//! pattern = [{ System = frame_system }] +//! tokens = [{ ::{+ Pallet + Call} }] +//! } +//! ``` +//! +//! Which will then finally expand to the following: +//! ```ignore +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system + Pallet + Call; +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances + Pallet + Call; +//! } +//! ``` +//! +//! This call has no implicit pallet parts, thus it will expand to the runtime construction: +//! ```ignore +//! pub struct Runtime { ... } +//! pub struct Call { ... } +//! impl Call ... +//! pub enum Origin { ... } +//! ... +//! ``` +//! +//! Visualizing the entire flow of `#[frame_support::runtime]`, it would look like the following: +//! +//! ```ignore +//! +----------------------+ +------------------------+ +-------------------+ +//! | | | (defined in pallet) | | | +//! | runtime | --> | tt_default_parts_v2! | --> | match_and_insert! | +//! | w/ no pallet parts | | | | | +//! +----------------------+ +------------------------+ +-------------------+ +//! +//! +----------------------+ +//! | | +//! --> | runtime | +//! | w/ pallet parts | +//! +----------------------+ +//! ``` + +#![cfg(feature = "experimental")] + +pub use parse::Def; +use proc_macro::TokenStream; +use syn::spanned::Spanned; + +mod expand; +mod parse; + +mod keyword { + syn::custom_keyword!(legacy_ordering); +} + +pub fn runtime(attr: TokenStream, tokens: TokenStream) -> TokenStream { + let mut legacy_ordering = false; + if !attr.is_empty() { + if let Ok(_) = syn::parse::(attr.clone()) { + legacy_ordering = true; + } else { + let msg = "Invalid runtime macro call: unexpected attribute. Macro call must be \ + bare, such as `#[frame_support::runtime]` or `#[runtime]`, or must specify the \ + `legacy_ordering` attribute, such as `#[frame_support::runtime(legacy_ordering)]` or \ + #[runtime(legacy_ordering)]."; + let span = proc_macro2::TokenStream::from(attr).span(); + return syn::Error::new(span, msg).to_compile_error().into() + } + } + + let item = syn::parse_macro_input!(tokens as syn::ItemMod); + match parse::Def::try_from(item) { + Ok(def) => expand::expand(def, legacy_ordering).into(), + Err(e) => e.to_compile_error().into(), + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/helper.rs b/substrate/frame/support/procedural/src/runtime/parse/helper.rs new file mode 100644 index 0000000000000000000000000000000000000000..f05395f9b7abd55201cdfd49f80debac32fde9f4 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/helper.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. + +use crate::pallet::parse::helper::MutItemAttrs; +use quote::ToTokens; + +pub(crate) fn take_first_item_runtime_attr( + item: &mut impl MutItemAttrs, +) -> syn::Result> +where + Attr: syn::parse::Parse, +{ + let attrs = if let Some(attrs) = item.mut_item_attrs() { attrs } else { return Ok(None) }; + + if let Some(index) = attrs.iter().position(|attr| { + attr.path().segments.first().map_or(false, |segment| segment.ident == "runtime") + }) { + let runtime_attr = attrs.remove(index); + Ok(Some(syn::parse2(runtime_attr.into_token_stream())?)) + } else { + Ok(None) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/mod.rs b/substrate/frame/support/procedural/src/runtime/parse/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..893cb4726e2b6016fa2e728add86990e24087c42 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/mod.rs @@ -0,0 +1,266 @@ +// 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. + +pub mod helper; +pub mod pallet; +pub mod pallet_decl; +pub mod runtime_struct; +pub mod runtime_types; + +use crate::construct_runtime::parse::Pallet; +use pallet_decl::PalletDeclaration; +use proc_macro2::TokenStream as TokenStream2; +use quote::ToTokens; +use std::collections::HashMap; +use syn::{spanned::Spanned, Ident, Token}; + +use frame_support_procedural_tools::syn_ext as ext; +use runtime_types::RuntimeType; + +mod keyword { + use syn::custom_keyword; + + custom_keyword!(runtime); + custom_keyword!(derive); + custom_keyword!(pallet_index); + custom_keyword!(disable_call); + custom_keyword!(disable_unsigned); +} + +enum RuntimeAttr { + Runtime(proc_macro2::Span), + Derive(proc_macro2::Span, Vec), + PalletIndex(proc_macro2::Span, u8), + DisableCall(proc_macro2::Span), + DisableUnsigned(proc_macro2::Span), +} + +impl RuntimeAttr { + fn span(&self) -> proc_macro2::Span { + match self { + Self::Runtime(span) => *span, + Self::Derive(span, _) => *span, + Self::PalletIndex(span, _) => *span, + Self::DisableCall(span) => *span, + Self::DisableUnsigned(span) => *span, + } + } +} + +impl syn::parse::Parse for RuntimeAttr { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + + let lookahead = content.lookahead1(); + if lookahead.peek(keyword::runtime) { + Ok(RuntimeAttr::Runtime(content.parse::()?.span())) + } else if lookahead.peek(keyword::derive) { + let _ = content.parse::(); + let derive_content; + syn::parenthesized!(derive_content in content); + let runtime_types = + derive_content.parse::>()?; + let runtime_types = runtime_types.inner.into_iter().collect(); + Ok(RuntimeAttr::Derive(derive_content.span(), runtime_types)) + } else if lookahead.peek(keyword::pallet_index) { + let _ = content.parse::(); + let pallet_index_content; + syn::parenthesized!(pallet_index_content in content); + let pallet_index = pallet_index_content.parse::()?; + if !pallet_index.suffix().is_empty() { + let msg = "Number literal must not have a suffix"; + return Err(syn::Error::new(pallet_index.span(), msg)) + } + Ok(RuntimeAttr::PalletIndex(pallet_index.span(), pallet_index.base10_parse()?)) + } else if lookahead.peek(keyword::disable_call) { + Ok(RuntimeAttr::DisableCall(content.parse::()?.span())) + } else if lookahead.peek(keyword::disable_unsigned) { + Ok(RuntimeAttr::DisableUnsigned(content.parse::()?.span())) + } else { + Err(lookahead.error()) + } + } +} + +#[derive(Debug, Clone)] +pub enum AllPalletsDeclaration { + Implicit(ImplicitAllPalletsDeclaration), + Explicit(ExplicitAllPalletsDeclaration), +} + +/// Declaration of a runtime with some pallet with implicit declaration of parts. +#[derive(Debug, Clone)] +pub struct ImplicitAllPalletsDeclaration { + pub name: Ident, + pub pallet_decls: Vec, + pub pallet_count: usize, +} + +/// Declaration of a runtime with all pallet having explicit declaration of parts. +#[derive(Debug, Clone)] +pub struct ExplicitAllPalletsDeclaration { + pub name: Ident, + pub pallets: Vec, +} + +pub struct Def { + pub input: TokenStream2, + pub item: syn::ItemMod, + pub runtime_struct: runtime_struct::RuntimeStructDef, + pub pallets: AllPalletsDeclaration, + pub runtime_types: Vec, +} + +impl Def { + pub fn try_from(mut item: syn::ItemMod) -> syn::Result { + let input: TokenStream2 = item.to_token_stream().into(); + let item_span = item.span(); + let items = &mut item + .content + .as_mut() + .ok_or_else(|| { + let msg = "Invalid runtime definition, expected mod to be inlined."; + syn::Error::new(item_span, msg) + })? + .1; + + let mut runtime_struct = None; + let mut runtime_types = None; + + let mut indices = HashMap::new(); + let mut names = HashMap::new(); + + let mut pallet_decls = vec![]; + let mut pallets = vec![]; + + for item in items.iter_mut() { + let mut pallet_item = None; + let mut pallet_index = 0; + + let mut disable_call = false; + let mut disable_unsigned = false; + + while let Some(runtime_attr) = + helper::take_first_item_runtime_attr::(item)? + { + match runtime_attr { + RuntimeAttr::Runtime(span) if runtime_struct.is_none() => { + let p = runtime_struct::RuntimeStructDef::try_from(span, item)?; + runtime_struct = Some(p); + }, + RuntimeAttr::Derive(_, types) if runtime_types.is_none() => { + runtime_types = Some(types); + }, + RuntimeAttr::PalletIndex(span, index) => { + pallet_index = index; + pallet_item = if let syn::Item::Type(item) = item { + Some(item.clone()) + } else { + let msg = "Invalid runtime::pallet_index, expected type definition"; + return Err(syn::Error::new(span, msg)) + }; + }, + RuntimeAttr::DisableCall(_) => disable_call = true, + RuntimeAttr::DisableUnsigned(_) => disable_unsigned = true, + attr => { + let msg = "Invalid duplicated attribute"; + return Err(syn::Error::new(attr.span(), msg)) + }, + } + } + + if let Some(pallet_item) = pallet_item { + match *pallet_item.ty.clone() { + syn::Type::Path(ref path) => { + let pallet_decl = + PalletDeclaration::try_from(item.span(), &pallet_item, path)?; + + if let Some(used_pallet) = + names.insert(pallet_decl.name.clone(), pallet_decl.name.span()) + { + let msg = "Two pallets with the same name!"; + + let mut err = syn::Error::new(used_pallet, &msg); + err.combine(syn::Error::new(pallet_decl.name.span(), &msg)); + return Err(err) + } + + pallet_decls.push(pallet_decl); + }, + syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) => { + let pallet = Pallet::try_from( + item.span(), + &pallet_item, + pallet_index, + disable_call, + disable_unsigned, + &bounds, + )?; + + if let Some(used_pallet) = indices.insert(pallet.index, pallet.name.clone()) + { + let msg = format!( + "Pallet indices are conflicting: Both pallets {} and {} are at index {}", + used_pallet, pallet.name, pallet.index, + ); + let mut err = syn::Error::new(used_pallet.span(), &msg); + err.combine(syn::Error::new(pallet.name.span(), msg)); + return Err(err) + } + + pallets.push(pallet); + }, + _ => continue, + } + } + } + + let name = item.ident.clone(); + let decl_count = pallet_decls.len(); + let pallets = if decl_count > 0 { + AllPalletsDeclaration::Implicit(ImplicitAllPalletsDeclaration { + name, + pallet_decls, + pallet_count: decl_count.saturating_add(pallets.len()), + }) + } else { + AllPalletsDeclaration::Explicit(ExplicitAllPalletsDeclaration { name, pallets }) + }; + + let def = Def { + input, + item, + runtime_struct: runtime_struct.ok_or_else(|| { + syn::Error::new(item_span, + "Missing Runtime. Please add a struct inside the module and annotate it with `#[runtime::runtime]`" + ) + })?, + pallets, + runtime_types: runtime_types.ok_or_else(|| { + syn::Error::new(item_span, + "Missing Runtime Types. Please annotate the runtime struct with `#[runtime::derive]`" + ) + })?, + }; + + Ok(def) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs new file mode 100644 index 0000000000000000000000000000000000000000..d2f1857fb2b4feec841224f28d691076c8853427 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs @@ -0,0 +1,99 @@ +// 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::construct_runtime::parse::{Pallet, PalletPart, PalletPartKeyword, PalletPath}; +use quote::ToTokens; +use syn::{punctuated::Punctuated, spanned::Spanned, token, Error, Ident, PathArguments}; + +impl Pallet { + pub fn try_from( + attr_span: proc_macro2::Span, + item: &syn::ItemType, + pallet_index: u8, + disable_call: bool, + disable_unsigned: bool, + bounds: &Punctuated, + ) -> syn::Result { + let name = item.ident.clone(); + + let mut pallet_path = None; + let mut pallet_parts = vec![]; + + for (index, bound) in bounds.into_iter().enumerate() { + if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound { + if index == 0 { + pallet_path = Some(PalletPath { inner: path.clone() }); + } else { + let pallet_part = syn::parse2::(bound.into_token_stream())?; + pallet_parts.push(pallet_part); + } + } else { + return Err(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + )) + }; + } + + let mut path = pallet_path.ok_or(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + ))?; + + let mut instance = None; + if let Some(segment) = path.inner.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) + { + if let PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, .. + }) = segment.arguments.clone() + { + if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = + Some(Ident::new(&arg_path.to_token_stream().to_string(), arg_path.span())); + segment.arguments = PathArguments::None; + } + } + } + + pallet_parts = pallet_parts + .into_iter() + .filter(|part| { + if let (true, &PalletPartKeyword::Call(_)) = (disable_call, &part.keyword) { + false + } else if let (true, &PalletPartKeyword::ValidateUnsigned(_)) = + (disable_unsigned, &part.keyword) + { + false + } else { + true + } + }) + .collect(); + + let cfg_pattern = vec![]; + + Ok(Pallet { + is_expanded: true, + name, + index: pallet_index, + path, + instance, + cfg_pattern, + pallet_parts, + }) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs new file mode 100644 index 0000000000000000000000000000000000000000..437a163cfbc44973e753075d4a139fca5df81af8 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.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. + +use quote::ToTokens; +use syn::{spanned::Spanned, Attribute, Ident, PathArguments}; + +/// The declaration of a pallet. +#[derive(Debug, Clone)] +pub struct PalletDeclaration { + /// The name of the pallet, e.g.`System` in `System: frame_system`. + pub name: Ident, + /// Optional attributes tagged right above a pallet declaration. + pub attrs: Vec, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: syn::Path, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, +} + +impl PalletDeclaration { + pub fn try_from( + _attr_span: proc_macro2::Span, + item: &syn::ItemType, + path: &syn::TypePath, + ) -> syn::Result { + let name = item.ident.clone(); + + let mut path = path.path.clone(); + + let mut instance = None; + if let Some(segment) = path.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) { + if let PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, .. + }) = segment.arguments.clone() + { + if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = + Some(Ident::new(&arg_path.to_token_stream().to_string(), arg_path.span())); + segment.arguments = PathArguments::None; + } + } + } + + Ok(Self { name, path, instance, attrs: item.attrs.clone() }) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/runtime_struct.rs b/substrate/frame/support/procedural/src/runtime/parse/runtime_struct.rs new file mode 100644 index 0000000000000000000000000000000000000000..8fa746ee80727d7164d5dadb0f728fc7991362f7 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/runtime_struct.rs @@ -0,0 +1,35 @@ +// 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 syn::spanned::Spanned; +pub struct RuntimeStructDef { + pub ident: syn::Ident, + pub attr_span: proc_macro2::Span, +} + +impl RuntimeStructDef { + pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result { + let item = if let syn::Item::Struct(item) = item { + item + } else { + let msg = "Invalid runtime::runtime, expected struct definition"; + return Err(syn::Error::new(item.span(), msg)) + }; + + Ok(Self { ident: item.ident.clone(), attr_span }) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs b/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..a4480e2a1fd32622bea3a7f20294b4c2bee88309 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs @@ -0,0 +1,76 @@ +// 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 syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +mod keyword { + use syn::custom_keyword; + + custom_keyword!(RuntimeCall); + custom_keyword!(RuntimeEvent); + custom_keyword!(RuntimeError); + custom_keyword!(RuntimeOrigin); + custom_keyword!(RuntimeFreezeReason); + custom_keyword!(RuntimeHoldReason); + custom_keyword!(RuntimeSlashReason); + custom_keyword!(RuntimeLockId); + custom_keyword!(RuntimeTask); +} + +#[derive(Debug, Clone, PartialEq)] +pub enum RuntimeType { + RuntimeCall(keyword::RuntimeCall), + RuntimeEvent(keyword::RuntimeEvent), + RuntimeError(keyword::RuntimeError), + RuntimeOrigin(keyword::RuntimeOrigin), + RuntimeFreezeReason(keyword::RuntimeFreezeReason), + RuntimeHoldReason(keyword::RuntimeHoldReason), + RuntimeSlashReason(keyword::RuntimeSlashReason), + RuntimeLockId(keyword::RuntimeLockId), + RuntimeTask(keyword::RuntimeTask), +} + +impl Parse for RuntimeType { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + + if lookahead.peek(keyword::RuntimeCall) { + Ok(Self::RuntimeCall(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeEvent) { + Ok(Self::RuntimeEvent(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeError) { + Ok(Self::RuntimeError(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeOrigin) { + Ok(Self::RuntimeOrigin(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeFreezeReason) { + Ok(Self::RuntimeFreezeReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeHoldReason) { + Ok(Self::RuntimeHoldReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeSlashReason) { + Ok(Self::RuntimeSlashReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeLockId) { + Ok(Self::RuntimeLockId(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeTask) { + Ok(Self::RuntimeTask(input.parse()?)) + } else { + Err(lookahead.error()) + } + } +} diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 0a046a164b6e1547cf318c96c90f1e48e1b5f551..a75307aca79b6ff241611b49b60c931ee1f83373 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -17,6 +17,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] proc-macro-crate = "3.0.0" proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = { version = "2.0.48", features = ["extra-traits", "full", "visit"] } +quote = { workspace = true } +syn = { features = ["extra-traits", "full", "visit"], workspace = true } frame-support-procedural-tools-derive = { path = "derive" } diff --git a/substrate/frame/support/procedural/tools/derive/Cargo.toml b/substrate/frame/support/procedural/tools/derive/Cargo.toml index 08c6a95a34fc26c7f64286e95f729e41d46b343a..b39d99a822fb7aed533bc7795daa53c903cc2952 100644 --- a/substrate/frame/support/procedural/tools/derive/Cargo.toml +++ b/substrate/frame/support/procedural/tools/derive/Cargo.toml @@ -19,5 +19,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" -quote = { version = "1.0.28", features = ["proc-macro"] } -syn = { version = "2.0.48", features = ["extra-traits", "full", "parsing", "proc-macro"] } +quote = { features = ["proc-macro"], workspace = true } +syn = { features = ["extra-traits", "full", "parsing", "proc-macro"], workspace = true } diff --git a/substrate/frame/support/procedural/tools/derive/src/lib.rs b/substrate/frame/support/procedural/tools/derive/src/lib.rs index f7c57c08674fcee985fab90225e980675cd1096e..a3590263558f491f4629eaa8b3b7997c1919b5ea 100644 --- a/substrate/frame/support/procedural/tools/derive/src/lib.rs +++ b/substrate/frame/support/procedural/tools/derive/src/lib.rs @@ -19,8 +19,6 @@ //! Use to derive parsing for parsing struct. // end::description[] -#![recursion_limit = "128"] - use proc_macro::TokenStream; use proc_macro2::Span; use quote::quote; diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 4a313551aca634b88bed7d0f989943f7075a5050..61787a74012827f5c12b389ecedb0fd254bccae2 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -25,7 +25,7 @@ use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_runtime::{ generic::{CheckedExtrinsic, UncheckedExtrinsic}, - traits::SignedExtension, + traits::Dispatchable, DispatchError, RuntimeDebug, }; use sp_std::fmt; @@ -268,7 +268,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, @@ -368,11 +369,10 @@ 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() @@ -380,7 +380,7 @@ where } /// Implementation for checked extrinsic. -impl GetDispatchInfo for CheckedExtrinsic +impl GetDispatchInfo for CheckedExtrinsic where Call: GetDispatchInfo, { @@ -389,21 +389,6 @@ where } } -/// 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, - } - } -} - /// A struct holding value for each `DispatchClass`. #[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct PerDispatchClass { diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 0f6cf05959f5113d28a250b53deec1cc7930c67d..af8449c9697a8b94879cc13b42d46b48fdf9ca6f 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -44,7 +44,7 @@ pub mod __private { pub use paste; pub use scale_info; pub use serde; - pub use sp_core::{OpaqueMetadata, Void}; + pub use sp_core::{Get, OpaqueMetadata, Void}; pub use sp_crypto_hashing_proc_macro; pub use sp_inherents; #[cfg(feature = "std")] @@ -54,7 +54,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, Dispatchable}, + DispatchError, RuntimeDebug, StateVersion, TransactionOutcome, }; #[cfg(feature = "std")] pub use sp_state_machine::BasicExternalities; @@ -75,6 +76,7 @@ pub mod storage; #[cfg(test)] mod tests; pub mod traits; +pub mod transaction_extensions; pub mod weights; #[doc(hidden)] pub mod unsigned { @@ -175,6 +177,14 @@ pub use frame_support_procedural::storage_alias; pub use frame_support_procedural::derive_impl; +/// Experimental macros for defining dynamic params that can be used in pallet configs. +#[cfg(feature = "experimental")] +pub mod dynamic_params { + pub use frame_support_procedural::{ + dynamic_aggregated_params_internal, dynamic_pallet_params, dynamic_params, + }; +} + /// Create new implementations of the [`Get`](crate::traits::Get) trait. /// /// The so-called parameter type can be created in four different ways: @@ -500,6 +510,9 @@ pub use frame_support_procedural::{ construct_runtime, match_and_insert, transactional, PalletError, RuntimeDebugNoBound, }; +#[cfg(feature = "experimental")] +pub use frame_support_procedural::runtime; + #[doc(hidden)] pub use frame_support_procedural::{__create_tt_macro, __generate_dummy_part_checker}; @@ -692,7 +705,7 @@ pub use frame_support_procedural::crate_to_crate_version; #[macro_export] macro_rules! fail { ( $y:expr ) => {{ - return Err($y.into()) + return Err($y.into()); }}; } @@ -772,7 +785,7 @@ macro_rules! assert_err_with_weight { $crate::assert_err!($call.map(|_| ()).map_err(|e| e.error), $err); assert_eq!(dispatch_err_with_post.post_info.actual_weight, $weight); } else { - panic!("expected Err(_), got Ok(_).") + ::core::panic!("expected Err(_), got Ok(_).") } }; } @@ -892,18 +905,20 @@ pub mod pallet_prelude { }; pub use codec::{Decode, Encode, MaxEncodedLen}; pub use frame_support::pallet_macros::*; + /// The optional attribute `#[inject_runtime_type]` can be attached to `RuntimeCall`, /// `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo` in an impl statement that has /// `#[register_default_impl]` attached to indicate that this item is generated by /// `construct_runtime`. /// /// Attaching this attribute to such an item ensures that the combined impl generated via - /// [`#[derive_impl(..)]`](`macro@super::derive_impl`) will use the correct type - /// auto-generated by `construct_runtime!`. + /// [`#[derive_impl(..)]`](`frame_support::derive_impl`) will use the correct + /// type auto-generated by + /// `construct_runtime!`. #[doc = docify::embed!("src/tests/inject_runtime_type.rs", derive_impl_works_with_runtime_type_injection)] /// /// However, if `no_aggregated_types` is specified while using - /// `[`#[derive_impl(..)]`](`macro@super::derive_impl`)`, then these items are attached + /// `[`#[derive_impl(..)]`](`frame_support::derive_impl`)`, then these items are attached /// verbatim to the combined impl. #[doc = docify::embed!("src/tests/inject_runtime_type.rs", derive_impl_works_with_no_aggregated_types)] pub use frame_support_procedural::inject_runtime_type; @@ -923,129 +938,26 @@ pub mod pallet_prelude { pub use sp_weights::Weight; } -/// The `pallet` attribute macro defines a pallet that can be used with -/// [`construct_runtime!`]. It must be attached to a module named `pallet` as follows: +/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to +/// specify pallet information. /// -/// ```ignore -/// #[pallet] -/// pub mod pallet { -/// ... -/// } +/// The struct must be defined as follows: /// ``` +/// #[frame_support::pallet] +/// mod pallet { +/// #[pallet::pallet] // <- the macro +/// pub struct Pallet(_); // <- the struct definition /// -/// Note that various types can be automatically imported using -/// [`frame_support::pallet_prelude`] and `frame_system::pallet_prelude`: -/// -/// ```ignore -/// #[pallet] -/// pub mod pallet { -/// use frame_support::pallet_prelude::*; -/// use frame_system::pallet_prelude::*; -/// ... +/// #[pallet::config] +/// pub trait Config: frame_system::Config {} /// } /// ``` -/// -/// # pallet::* Attributes -/// -/// The `pallet` macro will parse any items within your `pallet` module that are annotated with -/// `#[pallet::*]` attributes. Some of these attributes are mandatory and some are optional, -/// and they can attach to different types of items within your pallet depending on the -/// attribute in question. The full list of `#[pallet::*]` attributes is shown below in the -/// order in which they are mentioned in this document: -/// -/// * [`pallet::pallet`](#pallet-struct-placeholder-palletpallet-mandatory) -/// * [`pallet::config`](#config-trait-palletconfig-mandatory) -/// * [`pallet::constant`](#palletconstant) -/// * [`pallet::disable_frame_system_supertrait_check`](#disable_supertrait_check) -/// * [`pallet::generate_store($vis trait Store)`](#palletgenerate_storevis-trait-store) -/// * [`pallet::storage_version`](#palletstorage_version) -/// * [`pallet::hooks`](#hooks-pallethooks-optional) -/// * [`pallet::call`](#call-palletcall-optional) -/// * [`pallet::weight($expr)`](#palletweightexpr) -/// * [`pallet::compact`](#palletcompact-some_arg-some_type) -/// * [`pallet::call_index($idx)`](#palletcall_indexidx) -/// * [`pallet::extra_constants`](#extra-constants-palletextra_constants-optional) -/// * [`pallet::error`](#error-palleterror-optional) -/// * [`pallet::event`](#event-palletevent-optional) -/// * [`pallet::generate_deposit($visibility fn -/// deposit_event)`](#palletgenerate_depositvisibility-fn-deposit_event) -/// * [`pallet::storage`](#storage-palletstorage-optional) -/// * [`pallet::getter(fn $my_getter_fn_name)`](#palletgetterfn-my_getter_fn_name-optional) -/// * [`pallet::storage_prefix = "SomeName"`](#palletstorage_prefix--somename-optional) -/// * [`pallet::unbounded`](#palletunbounded-optional) -/// * [`pallet::whitelist_storage`](#palletwhitelist_storage-optional) -/// * [`cfg(..)`](#cfg-for-storage) (on storage items) -/// * [`pallet::type_value`](#type-value-pallettype_value-optional) -/// * [`pallet::genesis_config`](#genesis-config-palletgenesis_config-optional) -/// * [`pallet::genesis_build`](#genesis-build-palletgenesis_build-optional) -/// * [`pallet::inherent`](#inherent-palletinherent-optional) -/// * [`pallet::validate_unsigned`](#validate-unsigned-palletvalidate_unsigned-optional) -/// * [`pallet::origin`](#origin-palletorigin-optional) -/// * [`pallet::composite_enum`](#composite-enum-palletcomposite_enum-optional) -/// -/// Note that at compile-time, the `#[pallet]` macro will analyze and expand all of these -/// attributes, ultimately removing their AST nodes before they can be parsed as real -/// attribute macro calls. This means that technically we do not need attribute macro -/// definitions for any of these attributes, however, for consistency and discoverability -/// reasons, we still maintain stub attribute macro definitions for all of these attributes in -/// the [`pallet_macros`] module which is automatically included in all pallets as part of the -/// pallet prelude. The actual "work" for all of these attribute macros can be found in the -/// macro expansion for `#[pallet]`. -/// -/// Also note that in this document, pallet attributes are explained using the syntax of -/// non-instantiable pallets. For an example of an instantiable pallet, see [this -/// example](#example-of-an-instantiable-pallet). -/// -/// # Dev Mode (`#[pallet(dev_mode)]`) -/// -/// Specifying the argument `dev_mode` on the `#[pallet]` or `#[frame_support::pallet]` -/// attribute attached to your pallet module will allow you to enable dev mode for a pallet. -/// The aim of dev mode is to loosen some of the restrictions and requirements placed on -/// production pallets for easy tinkering and development. Dev mode pallets should not be used -/// in production. Enabling dev mode has the following effects: -/// -/// * Weights no longer need to be specified on every `#[pallet::call]` declaration. By -/// default, dev mode pallets will assume a weight of zero (`0`) if a weight is not -/// specified. This is equivalent to specifying `#[weight(0)]` on all calls that do not -/// specify a weight. -/// * Call indices no longer need to be specified on every `#[pallet::call]` declaration. By -/// default, dev mode pallets will assume a call index based on the order of the call. -/// * All storages are marked as unbounded, meaning you do not need to implement -/// `MaxEncodedLen` on storage types. This is equivalent to specifying `#[pallet::unbounded]` -/// on all storage type definitions. -/// * Storage hashers no longer need to be specified and can be replaced by `_`. In dev mode, -/// these will be replaced by `Blake2_128Concat`. In case of explicit key-binding, `Hasher` -/// can simply be ignored when in `dev_mode`. -/// -/// Note that the `dev_mode` argument can only be supplied to the `#[pallet]` or -/// `#[frame_support::pallet]` attribute macro that encloses your pallet module. This argument -/// cannot be specified anywhere else, including but not limited to the `#[pallet::pallet]` -/// attribute macro. -/// -///
-/// WARNING:
-/// You should not deploy or use dev mode pallets in production. Doing so can break your chain
-/// and therefore should never be done. Once you are done tinkering, you should remove the
-/// 'dev_mode' argument from your #[pallet] declaration and fix any compile errors before
-/// attempting to use your pallet in a production scenario.
-/// 
-/// -/// # Pallet struct placeholder: `#[pallet::pallet]` (mandatory) -/// -/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify -/// pallet information. -/// -/// The struct must be defined as follows: -/// ```ignore -/// #[pallet::pallet] -/// pub struct Pallet(_); -/// ``` +// /// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. /// /// ## Macro expansion: /// -/// The macro adds this attribute to the struct definition: +/// The macro adds this attribute to the Pallet struct definition: /// ```ignore /// #[derive( /// frame_support::CloneNoBound, @@ -1054,1225 +966,926 @@ pub mod pallet_prelude { /// frame_support::RuntimeDebugNoBound, /// )] /// ``` -/// and replaces the type `_` with `PhantomData`. It also implements on the pallet: -/// * [`GetStorageVersion`](`traits::GetStorageVersion`) -/// * [`OnGenesis`](`traits::OnGenesis`): contains some logic to write the pallet version into -/// storage. -/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. -/// -/// It declares `type Module` type alias for `Pallet`, used by `construct_runtime`. +/// and replaces the type `_` with `PhantomData`. /// -/// It implements [`PalletInfoAccess`](`traits::PalletInfoAccess') on `Pallet` to ease access -/// to pallet information given by [`frame_support::traits::PalletInfo`]. (The implementation -/// uses the associated type `frame_system::Config::PalletInfo`). +/// It also implements on the pallet: /// -/// It implements [`StorageInfoTrait`](`traits::StorageInfoTrait`) on `Pallet` which give -/// information about all storages. -/// -/// If the attribute `generate_store` is set then the macro creates the trait `Store` and -/// implements it on `Pallet`. +/// * [`GetStorageVersion`](frame_support::traits::GetStorageVersion) +/// * [`OnGenesis`](frame_support::traits::OnGenesis): contains some logic to write the pallet +/// version into storage. +/// * [`PalletInfoAccess`](frame_support::traits::PalletInfoAccess) to ease access to pallet +/// information given by [`frame_support::traits::PalletInfo`]. (The implementation uses the +/// associated type [`frame_support::traits::PalletInfo`]). +/// * [`StorageInfoTrait`](frame_support::traits::StorageInfoTrait) to give information about +/// storages. /// /// If the attribute `set_storage_max_encoded_len` is set then the macro calls -/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for each storage in the implementation of -/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for the pallet. Otherwise it implements -/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for the pallet using the -/// [`PartialStorageInfoTrait`](`traits::PartialStorageInfoTrait`) implementation of storages. -/// -/// # Config trait: `#[pallet::config]` (mandatory) -/// -/// The mandatory attribute `#[pallet::config]` defines the configurable options for the -/// pallet. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::config] -/// pub trait Config: frame_system::Config + $optionally_some_other_supertraits -/// $optional_where_clause -/// { -/// ... -/// } -/// ``` -/// -/// I.e. a regular trait definition named `Config`, with the supertrait -/// `frame_system::pallet::Config`, and optionally other supertraits and a where clause. -/// (Specifying other supertraits here is known as [tight -/// coupling](https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/)) -/// -/// The associated type `RuntimeEvent` is reserved. If defined, it must have the bounds -/// `From` and `IsType<::RuntimeEvent>`. -/// -/// [`pallet::event`](`frame_support::pallet_macros::event`) must be present if `RuntimeEvent` -/// exists as a config item in your `#[pallet::config]`. -/// -/// Also see [`pallet::config`](`frame_support::pallet_macros::config`) -/// -/// ## `pallet::constant` -/// -/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by -/// [`Get`](crate::traits::Get) from [`pallet::config`](#palletconfig) into metadata, e.g.: -/// -/// ```ignore -/// #[pallet::config] -/// pub trait Config: frame_system::Config { -/// #[pallet::constant] -/// type Foo: Get; -/// } -/// ``` -/// -/// Also see [`pallet::constant`](`frame_support::pallet_macros::constant`) -/// -/// ## `pallet::disable_frame_system_supertrait_check` -/// -/// -/// To bypass the `frame_system::Config` supertrait check, use the attribute -/// `pallet::disable_frame_system_supertrait_check`, e.g.: -/// -/// ```ignore -/// #[pallet::config] -/// #[pallet::disable_frame_system_supertrait_check] -/// pub trait Config: pallet_timestamp::Config {} -/// ``` -/// -/// NOTE: Bypassing the `frame_system::Config` supertrait check is typically desirable when you -/// want to write an alternative to the `frame_system` pallet. -/// -/// Also see -/// [`pallet::disable_frame_system_supertrait_check`](`frame_support::pallet_macros::disable_frame_system_supertrait_check`) -/// -/// ## Macro expansion: -/// -/// The macro expands pallet constant metadata with the information given by -/// `#[pallet::constant]`. -/// -/// # `pallet::generate_store($vis trait Store)` -/// -/// To generate a `Store` trait associating all storages, annotate your `Pallet` struct with -/// the attribute `#[pallet::generate_store($vis trait Store)]`, e.g.: -/// -/// ```ignore -/// #[pallet::pallet] -/// #[pallet::generate_store(pub(super) trait Store)] -/// pub struct Pallet(_); -/// ``` -/// More precisely, the `Store` trait contains an associated type for each storage. It is -/// implemented for `Pallet` allowing access to the storage from pallet struct. -/// -/// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using -/// `::Foo`. -/// -/// NOTE: this attribute is only valid when applied _directly_ to your `Pallet` struct -/// definition. -/// -/// Also see [`pallet::generate_store`](`frame_support::pallet_macros::generate_store`). -/// -/// # `pallet::storage_version` -/// -/// Because the [`pallet::pallet`](#pallet-struct-placeholder-palletpallet-mandatory) macro -/// implements [`traits::GetStorageVersion`], the current storage version needs to be -/// communicated to the macro. This can be done by using the `pallet::storage_version` -/// attribute: -/// -/// ```ignore -/// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); -/// -/// #[pallet::pallet] -/// #[pallet::storage_version(STORAGE_VERSION)] -/// pub struct Pallet(_); -/// ``` -/// -/// If not present, the current storage version is set to the default value. -/// -/// Also see [`pallet::storage_version`](`frame_support::pallet_macros::storage_version`) -/// -/// # Hooks: `#[pallet::hooks]` (optional) -/// -/// The `pallet::hooks` attribute allows you to specify a `Hooks` implementation for `Pallet` -/// that specifies pallet-specific logic. -/// -/// The item the attribute attaches to must be defined as follows: -/// ```ignore -/// #[pallet::hooks] -/// impl Hooks> for Pallet $optional_where_clause { -/// ... -/// } -/// ``` -/// I.e. a regular trait implementation with generic bound: `T: Config`, for the trait -/// `Hooks>` (they are defined in preludes), for the type `Pallet` and -/// with an optional where clause. -/// -/// If no `#[pallet::hooks]` exists, then the following default implementation is -/// automatically generated: -/// ```ignore -/// #[pallet::hooks] -/// impl Hooks> for Pallet {} -/// ``` -/// -/// Also see [`pallet::hooks`](`frame_support::pallet_macros::hooks`) -/// -/// # Call: `#[pallet::call]` (optional) -/// -/// Implementation of pallet dispatchables. -/// -/// Item must be defined as: -/// ```ignore -/// #[pallet::call] -/// impl Pallet { -/// /// $some_doc -/// #[pallet::weight($ExpressionResultingInWeight)] -/// pub fn $fn_name( -/// origin: OriginFor, -/// $some_arg: $some_type, -/// // or with compact attribute: #[pallet::compact] $some_arg: $some_type, -/// ... -/// ) -> DispatchResultWithPostInfo { // or `-> DispatchResult` -/// ... -/// } -/// ... -/// } -/// ``` -/// I.e. a regular type implementation, with generic `T: Config`, on type `Pallet`, with -/// an optional where clause. -/// -/// ## `#[pallet::weight($expr)]` -/// -/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, the -/// first argument must be `origin: OriginFor`. -/// -/// Also see [`pallet::weight`](`frame_support::pallet_macros::weight`) -/// -/// ### `#[pallet::compact] $some_arg: $some_type` -/// -/// Compact encoding for arguments can be achieved via `#[pallet::compact]`. The function must -/// return a `DispatchResultWithPostInfo` or `DispatchResult`. -/// -/// Also see [`pallet::compact`](`frame_support::pallet_macros::compact`) -/// -/// ## `#[pallet::call_index($idx)]` -/// -/// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, -/// which explicitly defines the codec index for the dispatchable function in the `Call` enum. -/// -/// All call indexes start from 0, until it encounters a dispatchable function with a defined -/// call index. The dispatchable function that lexically follows the function with a defined -/// call index will have that call index, but incremented by 1, e.g. if there are 3 -/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` -/// has a call index of 10, then `fn qux` will have an index of 11, instead of 1. -/// -/// **WARNING**: modifying dispatchables, changing their order, removing some, etc., must be -/// done with care. Indeed this will change the outer runtime call type (which is an enum with -/// one variant per pallet), this outer runtime call can be stored on-chain (e.g. in -/// `pallet-scheduler`). Thus migration might be needed. To mitigate against some of this, the -/// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so -/// that the `Call` enum encoding does not change after modification. As a general rule of -/// thumb, it is therefore adventageous to always add new calls to the end so you can maintain -/// the existing order of calls. -/// -/// Also see [`pallet::call_index`](`frame_support::pallet_macros::call_index`) -/// -/// # Extra constants: `#[pallet::extra_constants]` (optional) -/// -/// Allows you to define some extra constants to be added into constant metadata. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::extra_constants] -/// impl Pallet where $optional_where_clause { -/// /// $some_doc -/// $vis fn $fn_name() -> $some_return_type { -/// ... -/// } -/// ... -/// } -/// ``` -/// I.e. a regular rust `impl` block with some optional where clause and functions with 0 args, -/// 0 generics, and some return type. -/// -/// ## Macro expansion -/// -/// The macro add some extra constants to pallet constant metadata. -/// -/// Also see: [`pallet::extra_constants`](`frame_support::pallet_macros::extra_constants`) -/// -/// # Error: `#[pallet::error]` (optional) -/// -/// The `#[pallet::error]` attribute allows you to define an error enum that will be returned -/// from the dispatchable when an error occurs. The information for this error type is then -/// stored in metadata. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::error] -/// pub enum Error { -/// /// $some_optional_doc -/// $SomeFieldLessVariant, -/// /// $some_more_optional_doc -/// $SomeVariantWithOneField(FieldType), -/// ... -/// } -/// ``` -/// I.e. a regular enum named `Error`, with generic `T` and fieldless or multiple-field -/// variants. -/// -/// Any field type in the enum variants must implement [`scale_info::TypeInfo`] in order to be -/// properly used in the metadata, and its encoded size should be as small as possible, -/// preferably 1 byte in size in order to reduce storage size. The error enum itself has an -/// absolute maximum encoded size specified by [`MAX_MODULE_ERROR_ENCODED_SIZE`]. -/// -/// (1 byte can still be 256 different errors. The more specific the error, the easier it is to -/// diagnose problems and give a better experience to the user. Don't skimp on having lots of -/// individual error conditions.) -/// -/// Field types in enum variants must also implement [`PalletError`](traits::PalletError), -/// otherwise the pallet will fail to compile. Rust primitive types have already implemented -/// the [`PalletError`](traits::PalletError) trait along with some commonly used stdlib types -/// such as [`Option`] and -/// [`PhantomData`](`frame_support::__private::sp_std::marker::PhantomData`), and hence in most -/// use cases, a manual implementation is not necessary and is discouraged. -/// -/// The generic `T` must not bound anything and a `where` clause is not allowed. That said, -/// bounds and/or a where clause should not needed for any use-case. -/// -/// Also see: [`pallet::error`](`frame_support::pallet_macros::error`) -/// -/// # Event: `#[pallet::event]` (optional) -/// -/// Allows you to define pallet events. Pallet events are stored under the `system` / `events` -/// key when the block is applied (and then replaced when the next block writes it's events). -/// -/// The Event enum must be defined as follows: -/// -/// ```ignore -/// #[pallet::event] -/// #[pallet::generate_deposit($visibility fn deposit_event)] // Optional -/// pub enum Event<$some_generic> $optional_where_clause { -/// /// Some doc -/// $SomeName($SomeType, $YetanotherType, ...), -/// ... -/// } -/// ``` -/// -/// I.e. an enum (with named or unnamed fields variant), named `Event`, with generic: none or -/// `T` or `T: Config`, and optional w here clause. -/// -/// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], [`Encode`], [`Decode`], and -/// [`Debug`] (on std only). For ease of use, bound by the trait -/// [`Member`](`frame_support::pallet_prelude::Member`), available in -/// frame_support::pallet_prelude. -/// -/// Also see [`pallet::event`](`frame_support::pallet_macros::event`) -/// -/// ## `#[pallet::generate_deposit($visibility fn deposit_event)]` -/// -/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generates a -/// helper function on `Pallet` that handles deposit events. -/// -/// NOTE: For instantiable pallets, the event must be generic over `T` and `I`. -/// -/// Also see [`pallet::generate_deposit`](`frame_support::pallet_macros::generate_deposit`) -/// -/// # Storage: `#[pallet::storage]` (optional) -/// -/// The `#[pallet::storage]` attribute lets you define some abstract storage inside of runtime -/// storage and also set its metadata. This attribute can be used multiple times. -/// -/// Item should be defined as: -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn $getter_name)] // optional -/// $vis type $StorageName<$some_generic> $optional_where_clause -/// = $StorageType<$generic_name = $some_generics, $other_name = $some_other, ...>; -/// ``` -/// -/// or with unnamed generic: -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn $getter_name)] // optional -/// $vis type $StorageName<$some_generic> $optional_where_clause -/// = $StorageType<_, $some_generics, ...>; -/// ``` -/// -/// I.e. it must be a type alias, with generics: `T` or `T: Config`. The aliased type must be -/// one of [`StorageValue`](`pallet_prelude::StorageValue`), -/// [`StorageMap`](`pallet_prelude::StorageMap`) or -/// [`StorageDoubleMap`](`pallet_prelude::StorageDoubleMap`). The generic arguments of the -/// storage type can be given in two manners: named and unnamed. For named generic arguments, -/// the name for each argument should match the name defined for it on the storage struct: -/// * [`StorageValue`](`pallet_prelude::StorageValue`) expects `Value` and optionally -/// `QueryKind` and `OnEmpty`, -/// * [`StorageMap`](`pallet_prelude::StorageMap`) expects `Hasher`, `Key`, `Value` and -/// optionally `QueryKind` and `OnEmpty`, -/// * [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`) expects `Hasher`, `Key`, -/// `Value` and optionally `QueryKind` and `OnEmpty`, -/// * [`StorageDoubleMap`](`pallet_prelude::StorageDoubleMap`) expects `Hasher1`, `Key1`, -/// `Hasher2`, `Key2`, `Value` and optionally `QueryKind` and `OnEmpty`. -/// -/// For unnamed generic arguments: Their first generic must be `_` as it is replaced by the -/// macro and other generic must declared as a normal generic type declaration. -/// -/// The `Prefix` generic written by the macro is generated using -/// `PalletInfo::name::>()` and the name of the storage type. E.g. if runtime names -/// the pallet "MyExample" then the storage `type Foo = ...` should use the prefix: -/// `Twox128(b"MyExample") ++ Twox128(b"Foo")`. -/// -/// For the [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`) variant, the `Prefix` -/// also implements -/// [`CountedStorageMapInstance`](`frame_support::storage::types::CountedStorageMapInstance`). -/// It also associates a [`CounterPrefix`](`pallet_prelude::CounterPrefix'), which is -/// implemented the same as above, but the storage prefix is prepend with `"CounterFor"`. E.g. -/// if runtime names the pallet "MyExample" then the storage `type Foo = -/// CountedStorageaMap<...>` will store its counter at the prefix: `Twox128(b"MyExample") ++ -/// Twox128(b"CounterForFoo")`. -/// -/// E.g: -/// -/// ```ignore -/// #[pallet::storage] -/// pub(super) type MyStorage = StorageMap; -/// ``` -/// -/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ -/// Twox128(b"OtherName")`. -/// -/// Also see [`pallet::storage`](`frame_support::pallet_macros::storage`) -/// -/// ## `#[pallet::getter(fn $my_getter_fn_name)]` (optional) -/// -/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows you to define a -/// getter function on `Pallet`. -/// -/// Also see [`pallet::getter`](`frame_support::pallet_macros::getter`) -/// -/// ## `#[pallet::storage_prefix = "SomeName"]` (optional) -/// -/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allows you to define the -/// storage prefix to use, see how `Prefix` generic is implemented above. This is helpful if -/// you wish to rename the storage field but don't want to perform a migration. -/// -/// E.g: -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::storage_prefix = "foo"] -/// #[pallet::getter(fn my_storage)] -/// pub(super) type MyStorage = StorageMap; -/// ``` -/// -/// or -/// -/// ```ignore -/// #[pallet::storage] -/// #[pallet::getter(fn my_storage)] -/// pub(super) type MyStorage = StorageMap<_, Blake2_128Concat, u32, u32>; -/// ``` -/// -/// Also see [`pallet::storage_prefix`](`frame_support::pallet_macros::storage_prefix`) -/// -/// ## `#[pallet::unbounded]` (optional) -/// -/// The optional attribute `#[pallet::unbounded]` declares the storage as unbounded. When -/// implementating the storage info (when `#[pallet::generate_storage_info]` is specified on -/// the pallet struct placeholder), the size of the storage will be declared as unbounded. This -/// can be useful for storage which can never go into PoV (Proof of Validity). -/// -/// Also see [`pallet::unbounded`](`frame_support::pallet_macros::unbounded`) -/// -/// ## `#[pallet::whitelist_storage]` (optional) -/// -/// The optional attribute `#[pallet::whitelist_storage]` will declare the storage as -/// whitelisted from benchmarking. -/// -/// See -/// [`pallet::whitelist_storage`](frame_support::pallet_macros::whitelist_storage) -/// for more info. -/// -/// ## `#[cfg(..)]` (for storage) -/// The optional attributes `#[cfg(..)]` allow conditional compilation for the storage. -/// -/// E.g: -/// -/// ```ignore -/// #[cfg(feature = "my-feature")] -/// #[pallet::storage] -/// pub(super) type MyStorage = StorageValue; -/// ``` -/// -/// All the `cfg` attributes are automatically copied to the items generated for the storage, -/// i.e. the getter, storage prefix, and the metadata element etc. -/// -/// Any type placed as the `QueryKind` parameter must implement -/// [`frame_support::storage::types::QueryKindTrait`]. There are 3 implementations of this -/// trait by default: -/// -/// 1. [`OptionQuery`](`frame_support::storage::types::OptionQuery`), the default `QueryKind` -/// used when this type parameter is omitted. Specifying this as the `QueryKind` would cause -/// storage map APIs that return a `QueryKind` to instead return an [`Option`], returning -/// `Some` when a value does exist under a specified storage key, and `None` otherwise. -/// 2. [`ValueQuery`](`frame_support::storage::types::ValueQuery`) causes storage map APIs that -/// return a `QueryKind` to instead return the value type. In cases where a value does not -/// exist under a specified storage key, the `OnEmpty` type parameter on `QueryKindTrait` is -/// used to return an appropriate value. -/// 3. [`ResultQuery`](`frame_support::storage::types::ResultQuery`) causes storage map APIs -/// that return a `QueryKind` to instead return a `Result`, with `T` being the value -/// type and `E` being the pallet error type specified by the `#[pallet::error]` attribute. -/// In cases where a value does not exist under a specified storage key, an `Err` with the -/// specified pallet error variant is returned. -/// -/// NOTE: If the `QueryKind` generic parameter is still generic at this stage or is using some -/// type alias then the generation of the getter might fail. In this case the getter can be -/// implemented manually. -/// -/// NOTE: The generic `Hasher` must implement the [`StorageHasher`] trait (or the type is not -/// usable at all). We use [`StorageHasher::METADATA`] for the metadata of the hasher of the -/// storage item. Thus generic hasher is supported. -/// -/// ## Macro expansion -/// -/// For each storage item the macro generates a struct named -/// `_GeneratedPrefixForStorage$NameOfStorage`, and implements -/// [`StorageInstance`](traits::StorageInstance) on it using the pallet and storage name. It -/// then uses it as the first generic of the aliased type. For -/// [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`), -/// [`CountedStorageMapInstance`](`frame_support::storage::types::CountedStorageMapInstance`) -/// is implemented, and another similar struct is generated. -/// -/// For a named generic, the macro will reorder the generics, and remove the names. -/// -/// The macro implements the function `storage_metadata` on the `Pallet` implementing the -/// metadata for all storage items based on their kind: -/// * for a storage value, the type of the value is copied into the metadata -/// * for a storage map, the type of the values and the key's type is copied into the metadata -/// * for a storage double map, the type of the values, and the types of `key1` and `key2` are -/// copied into the metadata. -/// -/// # Type value: `#[pallet::type_value]` (optional) -/// -/// The `#[pallet::type_value]` attribute lets you define a struct implementing the -/// [`Get`](crate::traits::Get) trait to ease use of storage types. This attribute is meant to -/// be used alongside [`#[pallet::storage]`](#storage-palletstorage-optional) to define a -/// storage's default value. This attribute can be used multiple times. -/// -/// Item must be defined as: +/// [`StorageInfoTrait`](frame_support::traits::StorageInfoTrait) for each storage in the +/// implementation of [`StorageInfoTrait`](frame_support::traits::StorageInfoTrait) for the +/// pallet. Otherwise it implements +/// [`StorageInfoTrait`](frame_support::traits::StorageInfoTrait) for the pallet using the +/// [`PartialStorageInfoTrait`](frame_support::traits::PartialStorageInfoTrait) +/// implementation of storages. /// -/// ```ignore -/// #[pallet::type_value] -/// fn $MyDefaultName<$some_generic>() -> $default_type $optional_where_clause { $expr } -/// ``` -/// -/// I.e.: a function definition with generics none or `T: Config` and a returned type. -/// -/// E.g.: -/// -/// ```ignore -/// #[pallet::type_value] -/// fn MyDefault() -> T::Balance { 3.into() } -/// ``` -/// -/// Also see [`pallet::type_value`](`frame_support::pallet_macros::type_value`) -/// -/// # Genesis config: `#[pallet::genesis_config]` (optional) -/// -/// The `#[pallet::genesis_config]` attribute allows you to define the genesis configuration -/// for the pallet. -/// -/// Item is defined as either an enum or a struct. It needs to be public and implement the -/// trait [`BuildGenesisConfig`](`traits::BuildGenesisConfig`) with -/// [`#[pallet::genesis_build]`](#genesis-build-palletgenesis_build-optional). The type -/// generics are constrained to be either none, or `T` or `T: Config`. -/// -/// E.g: -/// -/// ```ignore -/// #[pallet::genesis_config] -/// pub struct GenesisConfig { -/// _myfield: BalanceOf, -/// } -/// ``` -/// -/// Also see [`pallet::genesis_config`](`frame_support::pallet_macros::genesis_config`) -/// -/// # Genesis build: `#[pallet::genesis_build]` (optional) -/// -/// The `#[pallet::genesis_build]` attribute allows you to define how `genesis_configuration` -/// is built. This takes as input the `GenesisConfig` type (as `self`) and constructs the -/// pallet's initial state. -/// -/// The impl must be defined as: -/// -/// ```ignore -/// #[pallet::genesis_build] -/// impl GenesisBuild for GenesisConfig<$maybe_generics> { -/// fn build(&self) { $expr } -/// } -/// ``` -/// -/// I.e. a trait implementation with generic `T: Config`, of trait `GenesisBuild` on -/// type `GenesisConfig` with generics none or `T`. -/// -/// E.g.: -/// -/// ```ignore -/// #[pallet::genesis_build] -/// impl GenesisBuild for GenesisConfig { -/// fn build(&self) {} -/// } -/// ``` -/// -/// Also see [`pallet::genesis_build`](`frame_support::pallet_macros::genesis_build`) -/// -/// # Inherent: `#[pallet::inherent]` (optional) +/// ## Dev Mode (`#[pallet(dev_mode)]`) /// -/// The `#[pallet::inherent]` attribute allows the pallet to provide some -/// [inherent](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions). -/// An inherent is some piece of data that is inserted by a block authoring node at block -/// creation time and can either be accepted or rejected by validators based on whether the -/// data falls within an acceptable range. +/// Specifying the argument `dev_mode` will allow you to enable dev mode for a pallet. The +/// aim of dev mode is to loosen some of the restrictions and requirements placed on +/// production pallets for easy tinkering and development. Dev mode pallets should not be +/// used in production. Enabling dev mode has the following effects: /// -/// The most common inherent is the `timestamp` that is inserted into every block. Since there -/// is no way to validate timestamps, validators simply check that the timestamp reported by -/// the block authoring node falls within an acceptable range. -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::inherent] -/// impl ProvideInherent for Pallet { -/// // ... regular trait implementation -/// } -/// ``` -/// -/// I.e. a trait implementation with bound `T: Config`, of trait -/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`) for type `Pallet`, and some -/// optional where clause. -/// -/// Also see [`pallet::inherent`](`frame_support::pallet_macros::inherent`) -/// -/// # Validate unsigned: `#[pallet::validate_unsigned]` (optional) -/// -/// The `#[pallet::validate_unsigned]` attribute allows the pallet to validate some unsigned -/// transaction: -/// -/// Item must be defined as: -/// -/// ```ignore -/// #[pallet::validate_unsigned] -/// impl ValidateUnsigned for Pallet { -/// // ... regular trait implementation -/// } -/// ``` -/// -/// I.e. a trait implementation with bound `T: Config`, of trait -/// [`ValidateUnsigned`](`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. -/// -/// Also see [`pallet::validate_unsigned`](`frame_support::pallet_macros::validate_unsigned`) -/// -/// # Origin: `#[pallet::origin]` (optional) -/// -/// The `#[pallet::origin]` attribute allows you to define some origin for the pallet. -/// -/// Item must be either a type alias, an enum, or a struct. It needs to be public. +/// * Weights no longer need to be specified on every `#[pallet::call]` declaration. By +/// default, dev mode pallets will assume a weight of zero (`0`) if a weight is not +/// specified. This is equivalent to specifying `#[weight(0)]` on all calls that do not +/// specify a weight. +/// * Call indices no longer need to be specified on every `#[pallet::call]` declaration. By +/// default, dev mode pallets will assume a call index based on the order of the call. +/// * All storages are marked as unbounded, meaning you do not need to implement +/// [`MaxEncodedLen`](frame_support::pallet_prelude::MaxEncodedLen) on storage types. This is +/// equivalent to specifying `#[pallet::unbounded]` on all storage type definitions. +/// * Storage hashers no longer need to be specified and can be replaced by `_`. In dev mode, +/// these will be replaced by `Blake2_128Concat`. In case of explicit key-binding, `Hasher` +/// can simply be ignored when in `dev_mode`. /// -/// E.g.: +/// Note that the `dev_mode` argument can only be supplied to the `#[pallet]` or +/// `#[frame_support::pallet]` attribute macro that encloses your pallet module. This +/// argument cannot be specified anywhere else, including but not limited to the +/// `#[pallet::pallet]` attribute macro. /// -/// ```ignore -/// #[pallet::origin] -/// pub struct Origin(PhantomData<(T)>); -/// ``` -/// -/// **WARNING**: modifying origin changes the outer runtime origin. This outer runtime origin -/// can be stored on-chain (e.g. in `pallet-scheduler`), thus any change must be done with care -/// as it might require some migration. -/// -/// NOTE: for instantiable pallets, the origin must be generic over `T` and `I`. -/// -/// Also see [`pallet::origin`](`frame_support::pallet_macros::origin`) -/// -/// # Composite enum `#[pallet::composite_enum]` (optional) -/// -/// The `#[pallet::composite_enum]` attribute allows you to define an enum on the pallet which -/// will then instruct `construct_runtime` to amalgamate all similarly-named enums from other -/// pallets into an aggregate enum. This is similar in principle with how the aggregate enum is -/// generated for `#[pallet::event]` or `#[pallet::error]`. -/// -/// The item tagged with `#[pallet::composite_enum]` MUST be an enum declaration, and can ONLY -/// be the following identifiers: `FreezeReason`, `HoldReason`, `LockId` or `SlashReason`. -/// Custom identifiers are not supported. -/// -/// NOTE: For ease of usage, when no `#[derive]` attributes are detected, the -/// `#[pallet::composite_enum]` attribute will automatically derive the following traits for -/// the enum: -/// -/// ```ignore -/// Copy, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug -/// ``` -/// -/// The inverse is also true: if there are any #[derive] attributes present for the enum, then -/// the attribute will not automatically derive any of the traits described above. -/// -/// # General notes on instantiable pallets -/// -/// An instantiable pallet is one where Config is generic, i.e. `Config`. This allows -/// runtime to implement multiple instances of the pallet, by using different types for the -/// generic. This is the sole purpose of the generic `I`, but because -/// [`PalletInfo`](`traits::PalletInfo`) requires the `Pallet` placeholder to be static, it is -/// important to bound by `'static` whenever [`PalletInfo`](`traits::PalletInfo`) can be used. -/// Additionally, in order to make an instantiable pallet usable as a regular pallet without an -/// instance, it is important to bound by `= ()` on every type. -/// -/// Thus impl bound looks like `impl, I: 'static>`, and types look like -/// `SomeType` or `SomeType, I: 'static = ()>`. -/// -/// # Example of a non-instantiable pallet -/// -/// ``` -/// pub use pallet::*; // reexport in crate namespace for `construct_runtime!` -/// -/// #[frame_support::pallet] -/// // NOTE: The name of the pallet is provided by `construct_runtime` and is used as -/// // the unique identifier for the pallet's storage. It is not defined in the pallet itself. -/// pub mod pallet { -/// use frame_support::pallet_prelude::*; // Import various types used in the pallet definition -/// use frame_system::pallet_prelude::*; // Import some system helper types. -/// -/// type BalanceOf = ::Balance; -/// -/// // Define the generic parameter of the pallet -/// // The macro parses `#[pallet::constant]` attributes and uses them to generate metadata -/// // for the pallet's constants. -/// #[pallet::config] -/// pub trait Config: frame_system::Config { -/// #[pallet::constant] // put the constant in metadata -/// type MyGetParam: Get; -/// type Balance: Parameter + MaxEncodedLen + From; -/// type RuntimeEvent: From> + IsType<::RuntimeEvent>; -/// } -/// -/// // Define some additional constant to put into the constant metadata. -/// #[pallet::extra_constants] -/// impl Pallet { -/// /// Some description -/// fn exra_constant_name() -> u128 { 4u128 } -/// } -/// -/// // Define the pallet struct placeholder, various pallet function are implemented on it. -/// #[pallet::pallet] -/// #[pallet::generate_store(pub(super) trait Store)] -/// pub struct Pallet(_); -/// -/// // Implement the pallet hooks. -/// #[pallet::hooks] -/// impl Hooks> for Pallet { -/// fn on_initialize(_n: BlockNumberFor) -> Weight { -/// unimplemented!(); -/// } -/// -/// // can implement also: on_finalize, on_runtime_upgrade, offchain_worker, ... -/// // see `Hooks` trait -/// } -/// -/// // Declare Call struct and implement dispatchables. -/// // -/// // WARNING: Each parameter used in functions must implement: Clone, Debug, Eq, PartialEq, -/// // Codec. -/// // -/// // The macro parses `#[pallet::compact]` attributes on function arguments and implements -/// // the `Call` encoding/decoding accordingly. -/// #[pallet::call] -/// impl Pallet { -/// /// Doc comment put in metadata -/// #[pallet::weight(0)] // Defines weight for call (function parameters are in scope) -/// pub fn toto( -/// origin: OriginFor, -/// #[pallet::compact] _foo: u32, -/// ) -> DispatchResultWithPostInfo { -/// let _ = origin; -/// unimplemented!(); -/// } -/// } -/// -/// // Declare the pallet `Error` enum (this is optional). -/// // The macro generates error metadata using the doc comment on each variant. -/// #[pallet::error] -/// pub enum Error { -/// /// doc comment put into metadata -/// InsufficientProposersBalance, -/// } -/// -/// // Declare pallet Event enum (this is optional). -/// // -/// // WARNING: Each type used in variants must implement: Clone, Debug, Eq, PartialEq, Codec. -/// // -/// // The macro generates event metadata, and derive Clone, Debug, Eq, PartialEq and Codec -/// #[pallet::event] -/// // Generate a funciton on Pallet to deposit an event. -/// #[pallet::generate_deposit(pub(super) fn deposit_event)] -/// pub enum Event { -/// /// doc comment put in metadata -/// // `::AccountId` is not defined in metadata list, the last -/// // Thus the metadata is `::AccountId`. -/// Proposed(::AccountId), -/// /// doc -/// // here metadata will be `Balance` as define in metadata list -/// Spending(BalanceOf), -/// // here metadata will be `Other` as define in metadata list -/// Something(u32), -/// } -/// -/// // Define a struct which implements `frame_support::traits::Get` (optional). -/// #[pallet::type_value] -/// pub(super) fn MyDefault() -> T::Balance { 3.into() } -/// -/// // Declare a storage item. Any amount of storage items can be declared (optional). -/// // -/// // Is expected either `StorageValue`, `StorageMap` or `StorageDoubleMap`. -/// // The macro generates the prefix type and replaces the first generic `_`. -/// // -/// // The macro expands the metadata for the storage item with the type used: -/// // * for a storage value the type of the value is copied into the metadata -/// // * for a storage map the type of the values and the type of the key is copied into the metadata -/// // * for a storage double map the types of the values and keys are copied into the -/// // metadata. -/// // -/// // NOTE: The generic `Hasher` must implement the `StorageHasher` trait (or the type is not -/// // usable at all). We use [`StorageHasher::METADATA`] for the metadata of the hasher of the -/// // storage item. Thus generic hasher is supported. -/// #[pallet::storage] -/// pub(super) type MyStorageValue = -/// StorageValue>; -/// -/// // Another storage declaration -/// #[pallet::storage] -/// #[pallet::getter(fn my_storage)] -/// #[pallet::storage_prefix = "SomeOtherName"] -/// pub(super) type MyStorage = -/// StorageMap; -/// -/// // Declare the genesis config (optional). -/// // -/// // The macro accepts either a struct or an enum; it checks that generics are consistent. -/// // -/// // Type must implement the `Default` trait. -/// #[pallet::genesis_config] -/// #[derive(frame_support::DefaultNoBound)] -/// pub struct GenesisConfig { -/// _config: sp_std::marker::PhantomData, -/// _myfield: u32, -/// } -/// -/// // Declare genesis builder. (This is need only if GenesisConfig is declared) -/// #[pallet::genesis_build] -/// impl BuildGenesisConfig for GenesisConfig { -/// fn build(&self) {} -/// } -/// -/// // Declare a pallet origin (this is optional). -/// // -/// // The macro accept type alias or struct or enum, it checks generics are consistent. -/// #[pallet::origin] -/// pub struct Origin(PhantomData); -/// -/// // Declare a hold reason (this is optional). -/// // -/// // Creates a hold reason for this pallet that is aggregated by `construct_runtime`. -/// // A similar enum can be defined for `FreezeReason`, `LockId` or `SlashReason`. -/// #[pallet::composite_enum] -/// pub enum HoldReason { -/// SomeHoldReason -/// } -/// -/// // Declare validate_unsigned implementation (this is optional). -/// #[pallet::validate_unsigned] -/// impl ValidateUnsigned for Pallet { -/// type Call = Call; -/// fn validate_unsigned( -/// source: TransactionSource, -/// call: &Self::Call -/// ) -> TransactionValidity { -/// Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) -/// } -/// } -/// -/// // Declare inherent provider for pallet (this is optional). -/// #[pallet::inherent] -/// impl ProvideInherent for Pallet { -/// type Call = Call; -/// type Error = InherentError; -/// -/// const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; -/// -/// fn create_inherent(_data: &InherentData) -> Option { -/// unimplemented!(); -/// } -/// -/// fn is_inherent(_call: &Self::Call) -> bool { -/// unimplemented!(); -/// } -/// } -/// -/// // Regular rust code needed for implementing ProvideInherent trait -/// -/// #[derive(codec::Encode, sp_runtime::RuntimeDebug)] -/// #[cfg_attr(feature = "std", derive(codec::Decode))] -/// pub enum InherentError { -/// } -/// -/// impl sp_inherents::IsFatalError for InherentError { -/// fn is_fatal_error(&self) -> bool { -/// unimplemented!(); -/// } -/// } -/// -/// pub const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"testpall"; -/// } -/// ``` -/// -/// # Example of an instantiable pallet -/// -/// ``` -/// pub use pallet::*; -/// -/// #[frame_support::pallet] -/// pub mod pallet { -/// use frame_support::pallet_prelude::*; -/// use frame_system::pallet_prelude::*; -/// -/// type BalanceOf = >::Balance; -/// -/// #[pallet::config] -/// pub trait Config: frame_system::Config { -/// #[pallet::constant] -/// type MyGetParam: Get; -/// type Balance: Parameter + MaxEncodedLen + From; -/// type RuntimeEvent: From> + IsType<::RuntimeEvent>; -/// } -/// -/// #[pallet::extra_constants] -/// impl, I: 'static> Pallet { -/// /// Some description -/// fn extra_constant_name() -> u128 { 4u128 } -/// } -/// -/// #[pallet::pallet] -/// #[pallet::generate_store(pub(super) trait Store)] -/// pub struct Pallet(PhantomData<(T, I)>); -/// -/// #[pallet::hooks] -/// impl, I: 'static> Hooks> for Pallet { -/// } -/// -/// #[pallet::call] -/// impl, I: 'static> Pallet { -/// /// Doc comment put in metadata -/// #[pallet::weight(0)] -/// pub fn toto(origin: OriginFor, #[pallet::compact] _foo: u32) -> DispatchResultWithPostInfo { -/// let _ = origin; -/// unimplemented!(); -/// } -/// } -/// -/// #[pallet::error] -/// pub enum Error { -/// /// doc comment put into metadata -/// InsufficientProposersBalance, -/// } -/// -/// #[pallet::event] -/// #[pallet::generate_deposit(pub(super) fn deposit_event)] -/// pub enum Event, I: 'static = ()> { -/// /// doc comment put in metadata -/// Proposed(::AccountId), -/// /// doc -/// Spending(BalanceOf), -/// Something(u32), -/// } -/// -/// #[pallet::type_value] -/// pub(super) fn MyDefault, I: 'static>() -> T::Balance { 3.into() } -/// -/// #[pallet::storage] -/// pub(super) type MyStorageValue, I: 'static = ()> = -/// StorageValue>; -/// -/// #[pallet::storage] -/// #[pallet::getter(fn my_storage)] -/// #[pallet::storage_prefix = "SomeOtherName"] -/// pub(super) type MyStorage = -/// StorageMap; -/// -/// #[pallet::genesis_config] -/// #[derive(frame_support::DefaultNoBound)] -/// pub struct GenesisConfig, I: 'static = ()> { -/// _config: sp_std::marker::PhantomData<(T,I)>, -/// _myfield: u32, -/// } -/// -/// #[pallet::genesis_build] -/// impl, I: 'static> BuildGenesisConfig for GenesisConfig { -/// fn build(&self) {} -/// } -/// -/// #[pallet::origin] -/// pub struct Origin(PhantomData<(T, I)>); -/// -/// #[pallet::composite_enum] -/// pub enum HoldReason { -/// SomeHoldReason -/// } -/// -/// #[pallet::validate_unsigned] -/// impl, I: 'static> ValidateUnsigned for Pallet { -/// type Call = Call; -/// fn validate_unsigned( -/// source: TransactionSource, -/// call: &Self::Call -/// ) -> TransactionValidity { -/// Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) -/// } -/// } -/// -/// #[pallet::inherent] -/// impl, I: 'static> ProvideInherent for Pallet { -/// type Call = Call; -/// type Error = InherentError; -/// -/// const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; -/// -/// fn create_inherent(_data: &InherentData) -> Option { -/// unimplemented!(); -/// } -/// -/// fn is_inherent(_call: &Self::Call) -> bool { -/// unimplemented!(); -/// } -/// } -/// -/// // Regular rust code needed for implementing ProvideInherent trait -/// -/// #[derive(codec::Encode, sp_runtime::RuntimeDebug)] -/// #[cfg_attr(feature = "std", derive(codec::Decode))] -/// pub enum InherentError { -/// } -/// -/// impl sp_inherents::IsFatalError for InherentError { -/// fn is_fatal_error(&self) -> bool { -/// unimplemented!(); -/// } -/// } -/// -/// pub const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"testpall"; -/// } -/// ``` -/// -/// # Upgrade guidelines -/// -/// 1. Export the metadata of the pallet for later checks -/// - run your node with the pallet active -/// - query the metadata using the `state_getMetadata` RPC and curl, or use `subsee -p -/// > meta.json` -/// 2. Generate the template upgrade for the pallet provided by `decl_storage` with the -/// environment variable `PRINT_PALLET_UPGRADE`: `PRINT_PALLET_UPGRADE=1 cargo check -p -/// my_pallet`. This template can be used as it contains all information for storages, -/// genesis config and genesis build. -/// 3. Reorganize the pallet to have the trait `Config`, `decl_*` macros, -/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`), -/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`), and Origin` all together in one -/// file. Suggested order: -/// * `Config`, -/// * `decl_module`, -/// * `decl_event`, -/// * `decl_error`, -/// * `decl_storage`, -/// * `origin`, -/// * `validate_unsigned`, -/// * `provide_inherent`, so far it should compile and all be correct. -/// 4. start writing the new pallet module -/// ```ignore -/// pub use pallet::*; -/// -/// #[frame_support::pallet] -/// pub mod pallet { -/// use frame_support::pallet_prelude::*; -/// use frame_system::pallet_prelude::*; -/// use super::*; -/// -/// #[pallet::pallet] -/// #[pallet::generate_store($visibility_of_trait_store trait Store)] -/// // NOTE: if the visibility of trait store is private but you want to make it available -/// // in super, then use `pub(super)` or `pub(crate)` to make it available in crate. -/// pub struct Pallet(_); -/// // pub struct Pallet(PhantomData); // for instantiable pallet -/// } -/// ``` -/// 5. **migrate Config**: move trait into the module with -/// * all const in `decl_module` to [`#[pallet::constant]`](#palletconstant) -/// * add the bound `IsType<::RuntimeEvent>` to `type -/// RuntimeEvent` -/// 7. **migrate decl_module**: write: -/// ```ignore -/// #[pallet::hooks] -/// impl Hooks for Pallet { -/// } -/// ``` -/// and write inside `on_initialize`, `on_finalize`, `on_runtime_upgrade`, -/// `offchain_worker`, and `integrity_test`. -/// -/// then write: -/// ```ignore -/// #[pallet::call] -/// impl Pallet { -/// } -/// ``` -/// and write inside all the calls in `decl_module` with a few changes in the signature: -/// - origin must now be written completely, e.g. `origin: OriginFor` -/// - result type must be `DispatchResultWithPostInfo`, you need to write it and also you -/// might need to put `Ok(().into())` at the end or the function. -/// - `#[compact]` must now be written -/// [`#[pallet::compact]`](#palletcompact-some_arg-some_type) -/// - `#[weight = ..]` must now be written [`#[pallet::weight(..)]`](#palletweightexpr) -/// -/// 7. **migrate event**: rewrite as a simple enum with the attribute -/// [`#[pallet::event]`](#event-palletevent-optional), use [`#[pallet::generate_deposit($vis -/// fn deposit_event)]`](#event-palletevent-optional) to generate `deposit_event`, -/// 8. **migrate error**: rewrite it with attribute -/// [`#[pallet::error]`](#error-palleterror-optional). -/// 9. **migrate storage**: `decl_storage` provide an upgrade template (see 3.). All storages, -/// genesis config, genesis build and default implementation of genesis config can be taken -/// from it directly. -/// -/// Otherwise here is the manual process: -/// -/// first migrate the genesis logic. write: -/// ```ignore -/// #[pallet::genesis_config] -/// struct GenesisConfig { -/// // fields of add_extra_genesis -/// } -/// impl Default for GenesisConfig { -/// // type default or default provided for fields -/// } -/// #[pallet::genesis_build] -/// impl GenesisBuild for GenesisConfig { -/// // for instantiable pallet: -/// // `impl GenesisBuild for GenesisConfig { -/// fn build() { -/// // The add_extra_genesis build logic -/// } -/// } -/// ``` -/// for each storage, if it contains `config(..)` then add fields, and make it default to -/// the value in `= ..;` or the type default if none, if it contains no build then also add -/// the logic to build the value. for each storage if it contains `build(..)` then add the -/// logic to `genesis_build`. -/// -/// NOTE: within `decl_storage`: the individual config is executed first, followed by the -/// build and finally the `add_extra_genesis` build. -/// -/// Once this is done you can migrate storages individually, a few notes: -/// - for private storage use `pub(crate) type ` or `pub(super) type` or nothing, -/// - for storages with `get(fn ..)` use [`#[pallet::getter(fn -/// ...)]`](#palletgetterfn-my_getter_fn_name-optional) -/// - for storages with value being `Option<$something>` make generic `Value` being -/// `$something` and generic `QueryKind` being `OptionQuery` (note: this is default). -/// Otherwise make `Value` the complete value type and `QueryKind` being `ValueQuery`. -/// - for storages with default value: `= $expr;` provide some specific `OnEmpty` generic. -/// To do so use of `#[pallet::type_value]` to generate the wanted struct to put. -/// example: `MyStorage: u32 = 3u32` would be written: -/// -/// ```ignore -/// #[pallet::type_value] fn MyStorageOnEmpty() -> u32 { 3u32 } -/// #[pallet::storage] -/// pub(super) type MyStorage = StorageValue<_, u32, ValueQuery, MyStorageOnEmpty>; -/// ``` -/// -/// NOTE: `decl_storage` also generates the functions `assimilate_storage` and -/// `build_storage` directly on `GenesisConfig`, and these are sometimes used in tests. -/// In order not to break they can be implemented manually, one can implement those -/// functions by calling the `GenesisBuild` implementation. -/// 10. **migrate origin**: move the origin to the pallet module to be under a -/// [`#[pallet::origin]`](#origin-palletorigin-optional) attribute -/// 11. **migrate validate_unsigned**: move the -/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) implementation to the pallet -/// module under a -/// [`#[pallet::validate_unsigned]`](#validate-unsigned-palletvalidate_unsigned-optional) -/// attribute -/// 12. **migrate provide_inherent**: move the -/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`) implementation to the pallet -/// module under a [`#[pallet::inherent]`](#inherent-palletinherent-optional) attribute -/// 13. rename the usage of `Module` to `Pallet` inside the crate. -/// 14. migration is done, now double check the migration with the checking migration -/// guidelines shown below. -/// -/// # Checking upgrade guidelines: -/// -/// * compare metadata. Use [subsee](https://github.com/ascjones/subsee) to fetch the metadata -/// and do a diff of the resulting json before and after migration. This checks for: -/// * call, names, signature, docs -/// * event names, docs -/// * error names, docs -/// * storage names, hasher, prefixes, default value -/// * error, error, constant -/// * manually check that: -/// * `Origin` was moved inside the macro under -/// [`#[pallet::origin]`](#origin-palletorigin-optional) if it exists -/// * [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) was moved inside the macro -/// under -/// [`#[pallet::validate_unsigned)]`](#validate-unsigned-palletvalidate_unsigned-optional) -/// if it exists -/// * [`ProvideInherent`](`pallet_prelude::ProvideInherent`) was moved inside the macro -/// under [`#[pallet::inherent)]`](#inherent-palletinherent-optional) if it exists -/// * `on_initialize` / `on_finalize` / `on_runtime_upgrade` / `offchain_worker` were moved -/// to the `Hooks` implementation -/// * storages with `config(..)` were converted to `GenesisConfig` field, and their default -/// is `= $expr;` if the storage has a default value -/// * storages with `build($expr)` or `config(..)` were built in `GenesisBuild::build` -/// * `add_extra_genesis` fields were converted to `GenesisConfig` field with their correct -/// default if specified -/// * `add_extra_genesis` build was written into `GenesisBuild::build` -/// * storage items defined with [`pallet`] use the name of the pallet provided by -/// [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used -/// the `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`). Thus -/// a runtime using the pallet must be careful with this change. To handle this change: -/// * either ensure that the name of the pallet given to `construct_runtime!` is the same -/// as the name the pallet was giving to `decl_storage`, -/// * or do a storage migration from the old prefix used to the new prefix used. -/// -/// NOTE: The prefixes used by storage items are in metadata. Thus, ensuring the metadata -/// hasn't changed ensures that the `pallet_prefix`s used by the storage items haven't changed. -/// -/// # Notes when macro fails to show proper error message spans: -/// -/// Rustc loses span for some macro input. Some tips to fix it: -/// * do not use inner attribute: -/// ```ignore -/// #[pallet] -/// pub mod pallet { -/// //! This inner attribute will make span fail -/// .. -/// } -/// ``` -/// * use the newest nightly possible. +///
+/// WARNING:
+/// You should not deploy or use dev mode pallets in production. Doing so can break your
+/// chain and therefore should never be done. Once you are done tinkering, you should
+/// remove the 'dev_mode' argument from your #[pallet] declaration and fix any compile
+/// errors before attempting to use your pallet in a production scenario.
+/// 
pub use frame_support_procedural::pallet; -/// Contains macro stubs for all of the pallet:: macros +/// Contains macro stubs for all of the `pallet::` macros pub mod pallet_macros { - pub use frame_support_procedural::{ - composite_enum, config, disable_frame_system_supertrait_check, error, event, - extra_constants, feeless_if, generate_deposit, generate_store, getter, hooks, - import_section, inherent, no_default, no_default_bounds, origin, pallet_section, - storage_prefix, storage_version, type_value, unbounded, validate_unsigned, weight, - whitelist_storage, - }; + /// Declare the storage as whitelisted from benchmarking. + /// + /// Doing so will exclude reads of that value's storage key from counting towards weight + /// calculations during benchmarking. + /// + /// This attribute should only be attached to storages that are known to be + /// read/used in every block. This will result in a more accurate benchmarking weight. + /// + /// ### Example + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::storage] + /// #[pallet::whitelist_storage] + /// pub type MyStorage = StorageValue<_, u32>; + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + pub use frame_support_procedural::whitelist_storage; + + /// Allows specifying the weight of a call. + /// + /// Each dispatchable needs to define a weight with the `#[pallet::weight($expr)]` + /// attribute. The first argument must be `origin: OriginFor`. + /// + /// ## Example + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::call] + /// impl Pallet { + /// #[pallet::weight({0})] // <- set actual weight here + /// #[pallet::call_index(0)] + /// pub fn something( + /// _: OriginFor, + /// foo: u32, + /// ) -> DispatchResult { + /// unimplemented!() + /// } + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + pub use frame_support_procedural::weight; + + /// Allows whitelisting a storage item from decoding during try-runtime checks. + /// + /// The optional attribute `#[pallet::disable_try_decode_storage]` will declare the + /// storage as whitelisted from decoding during try-runtime checks. This should only be + /// attached to transient storage which cannot be migrated during runtime upgrades. + /// + /// ### Example + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::storage] + /// #[pallet::disable_try_decode_storage] + /// pub type MyStorage = StorageValue<_, u32>; + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + pub use frame_support_procedural::disable_try_decode_storage; + + /// Declares a storage as unbounded in potential size. + /// + /// When implementating the storage info (when `#[pallet::generate_storage_info]` is + /// specified on the pallet struct placeholder), the size of the storage will be declared + /// as unbounded. This can be useful for storage which can never go into PoV (Proof of + /// Validity). + /// + /// ## Example + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::storage] + /// #[pallet::unbounded] + /// pub type MyStorage = StorageValue<_, u32>; + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + pub use frame_support_procedural::unbounded; + + /// Defines what storage prefix to use for a storage item when building the trie. + /// + /// This is helpful if you wish to rename the storage field but don't want to perform a + /// migration. + /// + /// ## Example + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::storage] + /// #[pallet::storage_prefix = "foo"] + /// pub type MyStorage = StorageValue<_, u32>; + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + pub use frame_support_procedural::storage_prefix; + + /// Ensures the generated `DefaultConfig` will not have any bounds for + /// that trait item. + /// + /// Attaching this attribute to a trait item ensures that the generated trait + /// `DefaultConfig` will not have any bounds for this trait item. + /// + /// As an example, if you have a trait item `type AccountId: SomeTrait;` in your `Config` + /// trait, the generated `DefaultConfig` will only have `type AccountId;` with no trait + /// bound. + pub use frame_support_procedural::no_default_bounds; + + /// Ensures the trait item will not be used as a default with the + /// `#[derive_impl(..)]` attribute macro. + /// + /// The optional attribute `#[pallet::no_default]` can be attached to trait items within a + /// `Config` trait impl that has [`#[pallet::config(with_default)]`](`config`) + /// attached. + pub use frame_support_procedural::no_default; + + /// Declares a module as importable into a pallet via + /// [`#[import_section]`](`import_section`). + /// + /// Note that sections are imported by their module name/ident, and should be referred to + /// by their _full path_ from the perspective of the target pallet. Do not attempt to make + /// use of `use` statements to bring pallet sections into scope, as this will not work + /// (unless you do so as part of a wildcard import, in which case it will work). + /// + /// ## Naming Logistics + /// + /// Also note that because of how `#[pallet_section]` works, pallet section names must be + /// globally unique _within the crate in which they are defined_. For more information on + /// why this must be the case, see macro_magic's + /// [`#[export_tokens]`](https://docs.rs/macro_magic/latest/macro_magic/attr.export_tokens.html) macro. + /// + /// Optionally, you may provide an argument to `#[pallet_section]` such as + /// `#[pallet_section(some_ident)]`, in the event that there is another pallet section in + /// same crate with the same ident/name. The ident you specify can then be used instead of + /// the module's ident name when you go to import it via + /// [`#[import_section]`](`import_section`). + pub use frame_support_procedural::pallet_section; + + /// The `#[pallet::inherent]` attribute allows the pallet to provide + /// [inherents](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions). + /// + /// An inherent is some piece of data that is inserted by a block authoring node at block + /// creation time and can either be accepted or rejected by validators based on whether the + /// data falls within an acceptable range. + /// + /// The most common inherent is the `timestamp` that is inserted into every block. Since + /// there is no way to validate timestamps, validators simply check that the timestamp + /// reported by the block authoring node falls within an acceptable range. + /// + /// Example usage: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_support::inherent::IsFatalError; + /// # use sp_timestamp::InherentError; + /// # use sp_std::result; + /// # + /// // Example inherent identifier + /// pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0"; + /// + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::inherent] + /// impl ProvideInherent for Pallet { + /// type Call = Call; + /// type Error = InherentError; + /// const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + /// + /// fn create_inherent(data: &InherentData) -> Option { + /// unimplemented!() + /// } + /// + /// fn check_inherent( + /// call: &Self::Call, + /// data: &InherentData, + /// ) -> result::Result<(), Self::Error> { + /// unimplemented!() + /// } + /// + /// fn is_inherent(call: &Self::Call) -> bool { + /// unimplemented!() + /// } + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// + /// I.e. a trait implementation with bound `T: Config`, of trait `ProvideInherent` for type + /// `Pallet`, and some optional where clause. + /// + /// ## Macro expansion + /// + /// The macro currently makes no use of this information, but it might use this information + /// in the future to give information directly to `construct_runtime`. + pub use frame_support_procedural::inherent; + + /// Splits a pallet declaration into multiple parts. + /// + /// An attribute macro that can be attached to a module declaration. Doing so will + /// import the contents of the specified external pallet section that is defined + /// elsewhere using [`#[pallet_section]`](`pallet_section`). + /// + /// ## Example + /// ``` + /// # use frame_support::pallet_macros::pallet_section; + /// # use frame_support::pallet_macros::import_section; + /// # + /// /// A [`pallet_section`] that defines the events for a pallet. + /// /// This can later be imported into the pallet using [`import_section`]. + /// #[pallet_section] + /// mod events { + /// #[pallet::event] + /// #[pallet::generate_deposit(pub(super) fn deposit_event)] + /// pub enum Event { + /// /// Event documentation should end with an array that provides descriptive names for event + /// /// parameters. [something, who] + /// SomethingStored { something: u32, who: T::AccountId }, + /// } + /// } + /// + /// #[import_section(events)] + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config { + /// # type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// # } + /// } + /// ``` + /// + /// This will result in the contents of `some_section` being _verbatim_ imported into + /// the pallet above. Note that since the tokens for `some_section` are essentially + /// copy-pasted into the target pallet, you cannot refer to imports that don't also + /// exist in the target pallet, but this is easily resolved by including all relevant + /// `use` statements within your pallet section, so they are imported as well, or by + /// otherwise ensuring that you have the same imports on the target pallet. + /// + /// It is perfectly permissible to import multiple pallet sections into the same pallet, + /// which can be done by having multiple `#[import_section(something)]` attributes + /// attached to the pallet. + /// + /// Note that sections are imported by their module name/ident, and should be referred to + /// by their _full path_ from the perspective of the target pallet. + pub use frame_support_procedural::import_section; + + /// Allows defining getter functions on `Pallet` storage. + /// + /// ## Example + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::storage] + /// #[pallet::getter(fn my_getter_fn_name)] + /// pub type MyStorage = StorageValue<_, u32>; + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// + /// See [`pallet::storage`](`frame_support::pallet_macros::storage`) for more info. + pub use frame_support_procedural::getter; + + /// Defines constants that are added to the constant field of + /// [`PalletMetadata`](frame_metadata::v15::PalletMetadata) struct for this pallet. + /// + /// Must be defined like: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # + /// #[pallet::extra_constants] + /// impl Pallet // $optional_where_clause + /// { + /// #[pallet::constant_name(SomeU32ConstantName)] + /// /// Some doc + /// fn some_u32_constant() -> u32 { + /// 100u32 + /// } + /// } + /// } + /// ``` + /// + /// I.e. a regular rust `impl` block with some optional where clause and functions with 0 + /// args, 0 generics, and some return type. + pub use frame_support_procedural::extra_constants; + + #[rustfmt::skip] + /// Allows bypassing the `frame_system::Config` supertrait check. + /// + /// To bypass the syntactic `frame_system::Config` supertrait check, use the attribute + /// `pallet::disable_frame_system_supertrait_check`. + /// + /// Note this bypass is purely syntactic, and does not actually remove the requirement that your + /// pallet implements `frame_system::Config`. When using this check, your config is still required to implement + /// `frame_system::Config` either via + /// - Implementing a trait that itself implements `frame_system::Config` + /// - Tightly coupling it with another pallet which itself implements `frame_system::Config` + /// + /// e.g. + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// trait OtherTrait: frame_system::Config {} + /// + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::config] + /// #[pallet::disable_frame_system_supertrait_check] + /// pub trait Config: OtherTrait {} + /// } + /// ``` + /// + /// To learn more about supertraits, see the + /// [trait_based_programming](../../polkadot_sdk_docs/reference_docs/trait_based_programming/index.html) + /// reference doc. + pub use frame_support_procedural::disable_frame_system_supertrait_check; + + /// The mandatory attribute allowing definition of configurable types for the pallet. + /// + /// Item must be defined as: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::config] + /// pub trait Config: frame_system::Config // + $optionally_some_other_supertraits + /// // $optional_where_clause + /// { + /// // config items here + /// } + /// } + /// ``` + /// + /// I.e. a regular trait definition named `Config`, with the supertrait + /// [`frame_system::pallet::Config`](../../frame_system/pallet/trait.Config.html), and + /// optionally other supertraits and a where clause. (Specifying other supertraits here is + /// known as [tight coupling](https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/)) + /// + /// The associated type `RuntimeEvent` is reserved. If defined, it must have the bounds + /// `From` and `IsType<::RuntimeEvent>`. + /// + /// [`#[pallet::event]`](`event`) must be present if `RuntimeEvent` + /// exists as a config item in your `#[pallet::config]`. + /// + /// ## Optional: `with_default` + /// + /// An optional `with_default` argument may also be specified. Doing so will automatically + /// generate a `DefaultConfig` trait inside your pallet which is suitable for use with + /// [`#[derive_impl(..)`](`frame_support::derive_impl`) to derive a default testing + /// config: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # use core::fmt::Debug; + /// # use frame_support::traits::Contains; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::config(with_default)] // <- with_default is optional + /// pub trait Config: frame_system::Config { + /// /// The overarching event type. + /// #[pallet::no_default_bounds] // Default is not supported for RuntimeEvent + /// type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// + /// // ...other config items get default + /// } + /// + /// #[pallet::event] + /// pub enum Event { + /// SomeEvent(u16, u32), + /// } + /// } + /// ``` + /// + /// As shown above, you may also attach the [`#[pallet::no_default]`](`no_default`) + /// attribute to specify that a particular trait item _cannot_ be used as a default when a + /// test `Config` is derived using the [`#[derive_impl(..)]`](`frame_support::derive_impl`) + /// attribute macro. This will cause that particular trait item to simply not appear in + /// default testing configs based on this config (the trait item will not be included in + /// `DefaultConfig`). + /// + /// ### `DefaultConfig` Caveats + /// + /// The auto-generated `DefaultConfig` trait: + /// - is always a _subset_ of your pallet's `Config` trait. + /// - can only contain items that don't rely on externalities, such as + /// `frame_system::Config`. + /// + /// Trait items that _do_ rely on externalities should be marked with + /// [`#[pallet::no_default]`](`no_default`) + /// + /// Consequently: + /// - Any items that rely on externalities _must_ be marked with + /// [`#[pallet::no_default]`](`no_default`) or your trait will fail to compile when used + /// with [`derive_impl`](`frame_support::derive_impl`). + /// - Items marked with [`#[pallet::no_default]`](`no_default`) are entirely excluded from + /// the `DefaultConfig` trait, and therefore any impl of `DefaultConfig` doesn't need to + /// implement such items. + /// + /// For more information, see [`frame_support::derive_impl`]. + pub use frame_support_procedural::config; + + /// Allows defining an enum that gets composed as an aggregate enum by `construct_runtime`. + /// + /// The `#[pallet::composite_enum]` attribute allows you to define an enum that gets + /// composed as an aggregate enum by `construct_runtime`. This is similar in principle with + /// [frame_support_procedural::event] and [frame_support_procedural::error]. + /// + /// The attribute currently only supports enum definitions, and identifiers that are named + /// `FreezeReason`, `HoldReason`, `LockId` or `SlashReason`. Arbitrary identifiers for the + /// enum are not supported. The aggregate enum generated by + /// [`frame_support::construct_runtime`] will have the name of `RuntimeFreezeReason`, + /// `RuntimeHoldReason`, `RuntimeLockId` and `RuntimeSlashReason` respectively. + /// + /// NOTE: The aggregate enum generated by `construct_runtime` generates a conversion + /// function from the pallet enum to the aggregate enum, and automatically derives the + /// following traits: + /// + /// ```ignore + /// Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo, + /// RuntimeDebug + /// ``` + /// + /// For ease of usage, when no `#[derive]` attributes are found for the enum under + /// [`#[pallet::composite_enum]`](composite_enum), the aforementioned traits are + /// automatically derived for it. The inverse is also true: if there are any `#[derive]` + /// attributes found for the enum, then no traits will automatically be derived for it. + /// + /// e.g, defining `HoldReason` in a pallet + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::composite_enum] + /// pub enum HoldReason { + /// /// The NIS Pallet has reserved it for a non-fungible receipt. + /// #[codec(index = 0)] + /// SomeHoldReason, + /// #[codec(index = 1)] + /// SomeOtherHoldReason, + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + pub use frame_support_procedural::composite_enum; + + /// Allows the pallet to validate unsigned transactions. + /// + /// Item must be defined as: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::validate_unsigned] + /// impl sp_runtime::traits::ValidateUnsigned for Pallet { + /// type Call = Call; + /// + /// fn validate_unsigned(_source: TransactionSource, _call: &Self::Call) -> TransactionValidity { + /// // Your implementation details here + /// unimplemented!() + /// } + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// + /// I.e. a trait implementation with bound `T: Config`, of trait + /// [`ValidateUnsigned`](frame_support::pallet_prelude::ValidateUnsigned) for + /// type `Pallet`, and some optional where clause. + /// + /// NOTE: There is also the [`sp_runtime::traits::TransactionExtension`] trait that can be + /// used to add some specific logic for transaction validation. + /// + /// ## Macro expansion + /// + /// The macro currently makes no use of this information, but it might use this information + /// in the future to give information directly to [`frame_support::construct_runtime`]. + pub use frame_support_procedural::validate_unsigned; + + /// Allows defining a struct implementing the [`Get`](frame_support::traits::Get) trait to + /// ease the use of storage types. + /// + /// This attribute is meant to be used alongside [`#[pallet::storage]`](`storage`) to + /// define a storage's default value. This attribute can be used multiple times. + /// + /// Item must be defined as: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use sp_runtime::FixedU128; + /// # use frame_support::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::storage] + /// pub(super) type SomeStorage = + /// StorageValue<_, FixedU128, ValueQuery, DefaultForSomeValue>; + /// + /// // Define default for ParachainId + /// #[pallet::type_value] + /// pub fn DefaultForSomeValue() -> FixedU128 { + /// FixedU128::from_u32(1) + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// + /// ## Macro expansion + /// + /// The macro renames the function to some internal name, generates a struct with the + /// original name of the function and its generic, and implements `Get<$ReturnType>` by + /// calling the user defined function. + pub use frame_support_procedural::type_value; + + /// Allows defining a storage version for the pallet. + /// + /// Because the `pallet::pallet` macro implements + /// [`GetStorageVersion`](frame_support::traits::GetStorageVersion), the current storage + /// version needs to be communicated to the macro. This can be done by using the + /// `pallet::storage_version` attribute: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::StorageVersion; + /// # use frame_support::traits::GetStorageVersion; + /// # + /// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); + /// + /// #[pallet::pallet] + /// #[pallet::storage_version(STORAGE_VERSION)] + /// pub struct Pallet(_); + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// + /// If not present, the current storage version is set to the default value. + pub use frame_support_procedural::storage_version; + + /// The `#[pallet::hooks]` attribute allows you to specify a + /// [`frame_support::traits::Hooks`] implementation for `Pallet` that specifies + /// pallet-specific logic. + /// + /// The item the attribute attaches to must be defined as follows: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::hooks] + /// impl Hooks> for Pallet { + /// // Implement hooks here + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// I.e. a regular trait implementation with generic bound: `T: Config`, for the trait + /// `Hooks>` (they are defined in preludes), for the type `Pallet`. + /// + /// Optionally, you could add a where clause. + /// + /// ## Macro expansion + /// + /// The macro implements the traits + /// [`OnInitialize`](frame_support::traits::OnInitialize), + /// [`OnIdle`](frame_support::traits::OnIdle), + /// [`OnFinalize`](frame_support::traits::OnFinalize), + /// [`OnRuntimeUpgrade`](frame_support::traits::OnRuntimeUpgrade), + /// [`OffchainWorker`](frame_support::traits::OffchainWorker), and + /// [`IntegrityTest`](frame_support::traits::IntegrityTest) using + /// the provided [`Hooks`](frame_support::traits::Hooks) implementation. + /// + /// NOTE: `OnRuntimeUpgrade` is implemented with `Hooks::on_runtime_upgrade` and some + /// additional logic. E.g. logic to write the pallet version into storage. + /// + /// NOTE: The macro also adds some tracing logic when implementing the above traits. The + /// following hooks emit traces: `on_initialize`, `on_finalize` and `on_runtime_upgrade`. + pub use frame_support_procedural::hooks; + + /// Generates a helper function on `Pallet` that handles deposit events. + /// + /// NOTE: For instantiable pallets, the event must be generic over `T` and `I`. + /// + /// ## Macro expansion + /// + /// The macro will add on enum `Event` the attributes: + /// * `#[derive(`[`frame_support::CloneNoBound`]`)]` + /// * `#[derive(`[`frame_support::EqNoBound`]`)]` + /// * `#[derive(`[`frame_support::PartialEqNoBound`]`)]` + /// * `#[derive(`[`frame_support::RuntimeDebugNoBound`]`)]` + /// * `#[derive(`[`codec::Encode`]`)]` + /// * `#[derive(`[`codec::Decode`]`)]` + /// + /// The macro implements `From>` for (). + /// + /// The macro implements a metadata function on `Event` returning the `EventMetadata`. + /// + /// If `#[pallet::generate_deposit]` is present then the macro implements `fn + /// deposit_event` on `Pallet`. + pub use frame_support_procedural::generate_deposit; + + /// Allows defining logic to make an extrinsic call feeless. + /// + /// Each dispatchable may be annotated with the `#[pallet::feeless_if($closure)]` + /// attribute, which explicitly defines the condition for the dispatchable to be feeless. + /// + /// The arguments for the closure must be the referenced arguments of the dispatchable + /// function. + /// + /// The closure must return `bool`. + /// + /// ### Example + /// + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::call] + /// impl Pallet { + /// #[pallet::call_index(0)] + /// /// Marks this call as feeless if `foo` is zero. + /// #[pallet::feeless_if(|_origin: &OriginFor, foo: &u32| -> bool { + /// *foo == 0 + /// })] + /// pub fn something( + /// _: OriginFor, + /// foo: u32, + /// ) -> DispatchResult { + /// unimplemented!() + /// } + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// + /// Please note that this only works for signed dispatchables and requires a signed + /// 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. + /// + /// ### Macro expansion + /// + /// The macro implements the [`pallet_skip_feeless_payment::CheckIfFeeless`] trait on the + /// dispatchable and calls the corresponding closure in the implementation. + /// + /// [`pallet_skip_feeless_payment::SkipCheckIfFeeless`]: ../../pallet_skip_feeless_payment/struct.SkipCheckIfFeeless.html + /// [`pallet_skip_feeless_payment::CheckIfFeeless`]: ../../pallet_skip_feeless_payment/struct.SkipCheckIfFeeless.html + pub use frame_support_procedural::feeless_if; + + /// Allows defining an error enum that will be returned from the dispatchable when an error + /// occurs. + /// + /// The information for this error type is then stored in runtime metadata. + /// + /// Item must be defined as so: + /// + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// mod pallet { + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::error] + /// pub enum Error { + /// /// SomeFieldLessVariant doc + /// SomeFieldLessVariant, + /// /// SomeVariantWithOneField doc + /// SomeVariantWithOneField(u32), + /// } + /// # + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// } + /// ``` + /// I.e. a regular enum named `Error`, with generic `T` and fieldless or multiple-field + /// variants. + /// + /// Any field type in the enum variants must implement [`scale_info::TypeInfo`] in order to + /// be properly used in the metadata, and its encoded size should be as small as possible, + /// preferably 1 byte in size in order to reduce storage size. The error enum itself has an + /// absolute maximum encoded size specified by + /// [`frame_support::MAX_MODULE_ERROR_ENCODED_SIZE`]. + /// + /// (1 byte can still be 256 different errors. The more specific the error, the easier it + /// is to diagnose problems and give a better experience to the user. Don't skimp on having + /// lots of individual error conditions.) + /// + /// Field types in enum variants must also implement [`frame_support::PalletError`], + /// otherwise the pallet will fail to compile. Rust primitive types have already + /// implemented the [`frame_support::PalletError`] trait along with some commonly used + /// stdlib types such as [`Option`] and [`sp_std::marker::PhantomData`], and hence + /// in most use cases, a manual implementation is not necessary and is discouraged. + /// + /// The generic `T` must not bound anything and a `where` clause is not allowed. That said, + /// bounds and/or a where clause should not needed for any use-case. + /// + /// ## Macro expansion + /// + /// The macro implements the [`Debug`] trait and functions `as_u8` using variant position, + /// and `as_str` using variant doc. + /// + /// The macro also implements `From>` for `&'static str` and `From>` for + /// `DispatchError`. + pub use frame_support_procedural::error; - /// 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 pallet. + /// Allows defining pallet events. + /// + /// Pallet events are stored under the `system` / `events` key when the block is applied + /// (and then replaced when the next block writes it's events). + /// + /// The Event enum can be defined as follows: + /// + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// mod pallet { + /// # use frame_support::pallet_prelude::IsType; + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::event] + /// #[pallet::generate_deposit(fn deposit_event)] // Optional + /// pub enum Event { + /// /// SomeEvent doc + /// SomeEvent(u16, u32), // SomeEvent with two fields + /// } + /// + /// #[pallet::config] + /// pub trait Config: frame_system::Config { + /// /// The overarching runtime event type. + /// type RuntimeEvent: From> + /// + IsType<::RuntimeEvent>; + /// } + /// } + /// ``` + /// + /// I.e. an enum (with named or unnamed fields variant), named `Event`, with generic: none + /// or `T` or `T: Config`, and optional w here clause. + /// + /// `RuntimeEvent` must be defined in the `Config`, as shown in the example. + /// + /// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], [`codec::Encode`], + /// [`codec::Decode`], and [`Debug`] (on std only). For ease of use, bound by the trait + /// `Member`, available in [`frame_support::pallet_prelude`]. + pub use frame_support_procedural::event; + + /// 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 + /// pallet. /// /// > The exact definition of **extrinsic** can be found in /// > [`sp_runtime::generic::UncheckedExtrinsic`]. @@ -2374,14 +1987,24 @@ pub mod pallet_macros { /// If no `#[pallet::call]` exists, then a default implementation corresponding to the /// following code is automatically generated: /// - /// ```ignore - /// #[pallet::call] - /// impl Pallet {} + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// mod pallet { + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::call] // <- automatically generated + /// impl Pallet {} // <- automatically generated + /// + /// #[pallet::config] + /// pub trait Config: frame_system::Config {} + /// } /// ``` pub use frame_support_procedural::call; - /// Enforce the index of a variant in the generated `enum Call`. See [`call`] for more - /// information. + /// Enforce the index of a variant in the generated `enum Call`. + /// + /// See [`call`] for more information. /// /// All call indexes start from 0, until it encounters a dispatchable function with a /// defined call index. The dispatchable function that lexically follows the function with @@ -2391,7 +2014,9 @@ pub mod pallet_macros { pub use frame_support_procedural::call_index; /// Declares the arguments of a [`call`] function to be encoded using - /// [`codec::Compact`]. This will results in smaller extrinsic encoding. + /// [`codec::Compact`]. + /// + /// This will results in smaller extrinsic encoding. /// /// A common example of `compact` is for numeric values that are often times far far away /// from their theoretical maximum. For example, in the context of a crypto-currency, the @@ -2487,8 +2112,8 @@ pub mod pallet_macros { /// ``` pub use frame_support_procedural::genesis_build; - /// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded - /// by [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`) + /// Allows adding an associated type trait bounded by + /// [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`) /// into metadata. /// /// ## Example @@ -2509,9 +2134,10 @@ pub mod pallet_macros { /// ``` pub use frame_support_procedural::constant; - /// Declares a type alias as a storage item. Storage items are pointers to data stored - /// on-chain (the *blockchain state*), under a specific key. The exact key is dependent on - /// the type of the storage. + /// Declares a type alias as a storage item. + /// + /// Storage items are pointers to data stored on-chain (the *blockchain state*), under a + /// specific key. The exact key is dependent on the type of the storage. /// /// > From the perspective of this pallet, the entire blockchain state is abstracted behind /// > a key-value api, namely [`sp_io::storage`]. @@ -2691,6 +2317,8 @@ pub mod pallet_macros { /// * [`macro@getter`]: Creates a custom getter function. /// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item. /// * [`macro@unbounded`]: Declares the storage item as unbounded. + /// * [`macro@disable_try_decode_storage`]: Declares that try-runtime checks should not + /// attempt to decode the storage item. /// /// #### Example /// ``` @@ -2706,10 +2334,14 @@ pub mod pallet_macros { /// #[pallet::getter(fn foo)] /// #[pallet::storage_prefix = "OtherFoo"] /// #[pallet::unbounded] + /// #[pallet::disable_try_decode_storage] /// pub type Foo = StorageValue<_, u32, ValueQuery>; /// } /// ``` pub use frame_support_procedural::storage; + + /// Allows defining conditions for a task to run. + /// /// This attribute is attached to a function inside an `impl` block annoated with /// [`pallet::tasks_experimental`](`tasks_experimental`) to define the conditions for a /// given work item to be valid. @@ -2718,6 +2350,9 @@ pub mod pallet_macros { /// should have the same signature as the function it is attached to, except that it should /// return a `bool` instead. pub use frame_support_procedural::task_condition; + + /// Allows defining an index for a task. + /// /// This attribute is attached to a function inside an `impl` block annoated with /// [`pallet::tasks_experimental`](`tasks_experimental`) to define the index of a given /// work item. @@ -2725,22 +2360,29 @@ pub mod pallet_macros { /// It takes an integer literal as input, which is then used to define the index. This /// index should be unique for each function in the `impl` block. pub use frame_support_procedural::task_index; + + /// Allows defining an iterator over available work items for a task. + /// /// This attribute is attached to a function inside an `impl` block annoated with - /// [`pallet::tasks_experimental`](`tasks_experimental`) to define an iterator over the - /// available work items for a task. + /// [`pallet::tasks_experimental`](`tasks_experimental`). /// /// It takes an iterator as input that yields a tuple with same types as the function /// arguments. pub use frame_support_procedural::task_list; + + /// Allows defining the weight of a task. + /// /// This attribute is attached to a function inside an `impl` block annoated with /// [`pallet::tasks_experimental`](`tasks_experimental`) define the weight of a given work /// item. /// /// It takes a closure as input, which should return a `Weight` value. pub use frame_support_procedural::task_weight; + /// Allows you to define some service work that can be recognized by a script or an - /// off-chain worker. Such a script can then create and submit all such work items at any - /// given time. + /// off-chain worker. + /// + /// Such a script can then create and submit all such work items at any given time. /// /// These work items are defined as instances of the [`Task`](frame_support::traits::Task) /// trait. [`pallet:tasks_experimental`](`tasks_experimental`) when attached to an `impl` @@ -2765,6 +2407,64 @@ pub mod pallet_macros { /// Now, this can be executed as follows: #[doc = docify::embed!("src/tests/tasks.rs", tasks_work)] pub use frame_support_procedural::tasks_experimental; + + /// Allows a pallet to declare a type as an origin. + /// + /// If defined as such, this type will be amalgamated at the runtime level into + /// `RuntimeOrigin`, very similar to [`call`], [`error`] and [`event`]. See + /// [`composite_enum`] for similar cases. + /// + /// Origin is a complex FRAME topics and is further explained in `polkadot_sdk_docs`. + /// + /// ## Syntax Variants + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// /// On the spot declaration. + /// #[pallet::origin] + /// #[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] + /// pub enum Origin { + /// Foo, + /// Bar, + /// } + /// } + /// ``` + /// + /// Or, more commonly used: + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// #[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] + /// pub enum RawOrigin { + /// Foo, + /// Bar, + /// } + /// + /// #[pallet::origin] + /// pub type Origin = RawOrigin; + /// } + /// ``` + /// + /// ## Warning + /// + /// Modifying any pallet's origin type will cause the runtime level origin type to also + /// change in encoding. If stored anywhere on-chain, this will require a data migration. + /// + /// Read more about origins at the [Origin Reference + /// Docs](../../polkadot_sdk_docs/reference_docs/frame_origin/index.html). + pub use frame_support_procedural::origin; } #[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")] diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index d059a992a8664cd8c3583f7f6fd1bff6af102770..2ceab44cb16bd4bcf356caa07a3506aa76ba79db 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -16,13 +16,21 @@ // limitations under the License. use crate::{ - traits::{GetStorageVersion, NoStorageVersionSet, PalletInfoAccess, StorageVersion}, - weights::{RuntimeDbWeight, Weight}, + defensive, + storage::transactional::with_transaction_opaque_err, + traits::{ + Defensive, GetStorageVersion, NoStorageVersionSet, PalletInfoAccess, SafeMode, + StorageVersion, + }, + weights::{RuntimeDbWeight, Weight, WeightMeter}, }; +use codec::{Decode, Encode, MaxEncodedLen}; use impl_trait_for_tuples::impl_for_tuples; +use sp_arithmetic::traits::Bounded; use sp_core::Get; use sp_io::{hashing::twox_128, storage::clear_prefix, KillStorageResult}; -use sp_std::marker::PhantomData; +use sp_runtime::traits::Zero; +use sp_std::{marker::PhantomData, vec::Vec}; /// Handles storage migration pallet versioning. /// @@ -43,12 +51,30 @@ use sp_std::marker::PhantomData; /// Otherwise, a warning is logged notifying the developer that the upgrade was a noop and should /// probably be removed. /// +/// It is STRONGLY RECOMMENDED to write the unversioned migration logic in a private module and +/// only export the versioned migration logic to prevent accidentally using the unversioned +/// migration in any runtimes. +/// /// ### Examples /// ```ignore /// // In file defining migrations -/// pub struct VersionUncheckedMigrateV5ToV6(sp_std::marker::PhantomData); -/// impl OnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6 { -/// // OnRuntimeUpgrade implementation... +/// +/// /// Private module containing *version unchecked* migration logic. +/// /// +/// /// Should only be used by the [`VersionedMigration`] type in this module to create something to +/// /// export. +/// /// +/// /// We keep this private so the unversioned migration cannot accidentally be used in any runtimes. +/// /// +/// /// For more about this pattern of keeping items private, see +/// /// - https://github.com/rust-lang/rust/issues/30905 +/// /// - https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504/40 +/// mod version_unchecked { +/// use super::*; +/// pub struct MigrateV5ToV6(sp_std::marker::PhantomData); +/// impl OnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6 { +/// // OnRuntimeUpgrade implementation... +/// } /// } /// /// pub type MigrateV5ToV6 = @@ -73,7 +99,7 @@ pub struct VersionedMigration), @@ -91,7 +117,7 @@ impl< const FROM: u16, const TO: u16, Inner: crate::traits::OnRuntimeUpgrade, - Pallet: GetStorageVersion + PalletInfoAccess, + Pallet: GetStorageVersion + PalletInfoAccess, DbWeight: Get, > crate::traits::OnRuntimeUpgrade for VersionedMigration { @@ -100,7 +126,6 @@ impl< /// migration ran or not. #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - use codec::Encode; let on_chain_version = Pallet::on_chain_storage_version(); if on_chain_version == FROM { Ok(VersionedPostUpgradeData::MigrationExecuted(Inner::pre_upgrade()?).encode()) @@ -163,25 +188,25 @@ impl< } } -/// Can store the current pallet version in storage. -pub trait StoreCurrentStorageVersion { - /// Write the current storage version to the storage. - fn store_current_storage_version(); +/// Can store the in-code pallet version on-chain. +pub trait StoreInCodeStorageVersion { + /// Write the in-code storage version on-chain. + fn store_in_code_storage_version(); } -impl + PalletInfoAccess> - StoreCurrentStorageVersion for StorageVersion +impl + PalletInfoAccess> + StoreInCodeStorageVersion for StorageVersion { - fn store_current_storage_version() { - let version = ::current_storage_version(); + fn store_in_code_storage_version() { + let version = ::in_code_storage_version(); version.put::(); } } -impl + PalletInfoAccess> - StoreCurrentStorageVersion for NoStorageVersionSet +impl + PalletInfoAccess> + StoreInCodeStorageVersion for NoStorageVersionSet { - fn store_current_storage_version() { + fn store_in_code_storage_version() { StorageVersion::default().put::(); } } @@ -193,7 +218,7 @@ pub trait PalletVersionToStorageVersionHelper { impl PalletVersionToStorageVersionHelper for T where - T::CurrentStorageVersion: StoreCurrentStorageVersion, + T::InCodeStorageVersion: StoreInCodeStorageVersion, { fn migrate(db_weight: &RuntimeDbWeight) -> Weight { const PALLET_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__PALLET_VERSION__:"; @@ -204,8 +229,7 @@ where sp_io::storage::clear(&pallet_version_key(::name())); - >::store_current_storage_version( - ); + >::store_in_code_storage_version(); db_weight.writes(2) } @@ -226,7 +250,7 @@ impl PalletVersionToStorageVersionHelper for T { /// Migrate from the `PalletVersion` struct to the new [`StorageVersion`] struct. /// -/// This will remove all `PalletVersion's` from the state and insert the current storage version. +/// This will remove all `PalletVersion's` from the state and insert the in-code storage version. pub fn migrate_from_pallet_version_to_storage_version< Pallets: PalletVersionToStorageVersionHelper, >( @@ -344,3 +368,622 @@ impl, DbWeight: Get> frame_support::traits Ok(()) } } + +/// A migration that can proceed in multiple steps. +pub trait SteppedMigration { + /// The cursor type that stores the progress (aka. state) of this migration. + type Cursor: codec::FullCodec + codec::MaxEncodedLen; + + /// The unique identifier type of this migration. + type Identifier: codec::FullCodec + codec::MaxEncodedLen; + + /// The unique identifier of this migration. + /// + /// If two migrations have the same identifier, then they are assumed to be identical. + fn id() -> Self::Identifier; + + /// The maximum number of steps that this migration can take. + /// + /// This can be used to enforce progress and prevent migrations becoming stuck forever. A + /// migration that exceeds its max steps is treated as failed. `None` means that there is no + /// limit. + fn max_steps() -> Option { + None + } + + /// Try to migrate as much as possible with the given weight. + /// + /// **ANY STORAGE CHANGES MUST BE ROLLED-BACK BY THE CALLER UPON ERROR.** This is necessary + /// since the caller cannot return a cursor in the error case. [`Self::transactional_step`] is + /// provided as convenience for a caller. A cursor of `None` implies that the migration is at + /// its end. A migration that once returned `Nonce` is guaranteed to never be called again. + fn step( + cursor: Option, + meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError>; + + /// Same as [`Self::step`], but rolls back pending changes in the error case. + fn transactional_step( + mut cursor: Option, + meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + with_transaction_opaque_err(move || match Self::step(cursor, meter) { + Ok(new_cursor) => { + cursor = new_cursor; + sp_runtime::TransactionOutcome::Commit(Ok(cursor)) + }, + Err(err) => sp_runtime::TransactionOutcome::Rollback(Err(err)), + }) + .map_err(|()| SteppedMigrationError::Failed)? + } +} + +/// Error that can occur during a [`SteppedMigration`]. +#[derive(Debug, Encode, Decode, MaxEncodedLen, scale_info::TypeInfo)] +pub enum SteppedMigrationError { + // Transient errors: + /// The remaining weight is not enough to do anything. + /// + /// Can be resolved by calling with at least `required` weight. Note that calling it with + /// exactly `required` weight could cause it to not make any progress. + InsufficientWeight { + /// Amount of weight required to make progress. + required: Weight, + }, + // Permanent errors: + /// The migration cannot decode its cursor and therefore not proceed. + /// + /// This should not happen unless (1) the migration itself returned an invalid cursor in a + /// previous iteration, (2) the storage got corrupted or (3) there is a bug in the caller's + /// code. + InvalidCursor, + /// The migration encountered a permanent error and cannot continue. + Failed, +} + +/// Notification handler for status updates regarding Multi-Block-Migrations. +#[impl_trait_for_tuples::impl_for_tuples(8)] +pub trait MigrationStatusHandler { + /// Notifies of the start of a runtime migration. + fn started() {} + + /// Notifies of the completion of a runtime migration. + fn completed() {} +} + +/// Handles a failed runtime migration. +/// +/// This should never happen, but is here for completeness. +pub trait FailedMigrationHandler { + /// Infallibly handle a failed runtime migration. + /// + /// Gets passed in the optional index of the migration in the batch that caused the failure. + /// Returning `None` means that no automatic handling should take place and the callee decides + /// in the implementation what to do. + fn failed(migration: Option) -> FailedMigrationHandling; +} + +/// Do now allow any transactions to be processed after a runtime upgrade failed. +/// +/// This is **not a sane default**, since it prevents governance intervention. +pub struct FreezeChainOnFailedMigration; + +impl FailedMigrationHandler for FreezeChainOnFailedMigration { + fn failed(_migration: Option) -> FailedMigrationHandling { + FailedMigrationHandling::KeepStuck + } +} + +/// Enter safe mode on a failed runtime upgrade. +/// +/// This can be very useful to manually intervene and fix the chain state. `Else` is used in case +/// that the safe mode could not be entered. +pub struct EnterSafeModeOnFailedMigration( + PhantomData<(SM, Else)>, +); + +impl FailedMigrationHandler + for EnterSafeModeOnFailedMigration +where + ::BlockNumber: Bounded, +{ + fn failed(migration: Option) -> FailedMigrationHandling { + let entered = if SM::is_entered() { + SM::extend(Bounded::max_value()) + } else { + SM::enter(Bounded::max_value()) + }; + + // If we could not enter or extend safe mode (for whatever reason), then we try the next. + if entered.is_err() { + Else::failed(migration) + } else { + FailedMigrationHandling::KeepStuck + } + } +} + +/// How to proceed after a runtime upgrade failed. +/// +/// There is NO SANE DEFAULT HERE. All options are very dangerous and should be used with care. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FailedMigrationHandling { + /// Resume extrinsic processing of the chain. This will not resume the upgrade. + /// + /// This should be supplemented with additional measures to ensure that the broken chain state + /// does not get further messed up by user extrinsics. + ForceUnstuck, + /// Set the cursor to `Stuck` and keep blocking extrinsics. + KeepStuck, + /// Don't do anything with the cursor and let the handler decide. + /// + /// This can be useful in cases where the other two options would overwrite any changes that + /// were done by the handler to the cursor. + Ignore, +} + +/// Something that can do multi step migrations. +pub trait MultiStepMigrator { + /// Hint for whether [`Self::step`] should be called. + fn ongoing() -> bool; + + /// Do the next step in the MBM process. + /// + /// Must gracefully handle the case that it is currently not upgrading. + fn step() -> Weight; +} + +impl MultiStepMigrator for () { + fn ongoing() -> bool { + false + } + + fn step() -> Weight { + Weight::zero() + } +} + +/// Multiple [`SteppedMigration`]. +pub trait SteppedMigrations { + /// The number of migrations that `Self` aggregates. + fn len() -> u32; + + /// The `n`th [`SteppedMigration::id`]. + /// + /// Is guaranteed to return `Some` if `n < Self::len()`. + fn nth_id(n: u32) -> Option>; + + /// The [`SteppedMigration::max_steps`] of the `n`th migration. + /// + /// Is guaranteed to return `Some` if `n < Self::len()`. + fn nth_max_steps(n: u32) -> Option>; + + /// Do a [`SteppedMigration::step`] on the `n`th migration. + /// + /// Is guaranteed to return `Some` if `n < Self::len()`. + fn nth_step( + n: u32, + cursor: Option>, + meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>>; + + /// Do a [`SteppedMigration::transactional_step`] on the `n`th migration. + /// + /// Is guaranteed to return `Some` if `n < Self::len()`. + fn nth_transactional_step( + n: u32, + cursor: Option>, + meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>>; + + /// The maximal encoded length across all cursors. + fn cursor_max_encoded_len() -> usize; + + /// The maximal encoded length across all identifiers. + fn identifier_max_encoded_len() -> usize; + + /// Assert the integrity of the migrations. + /// + /// Should be executed as part of a test prior to runtime usage. May or may not need + /// externalities. + #[cfg(feature = "std")] + fn integrity_test() -> Result<(), &'static str> { + use crate::ensure; + let l = Self::len(); + + for n in 0..l { + ensure!(Self::nth_id(n).is_some(), "id is None"); + ensure!(Self::nth_max_steps(n).is_some(), "steps is None"); + + // The cursor that we use does not matter. Hence use empty. + ensure!( + Self::nth_step(n, Some(vec![]), &mut WeightMeter::new()).is_some(), + "steps is None" + ); + ensure!( + Self::nth_transactional_step(n, Some(vec![]), &mut WeightMeter::new()).is_some(), + "steps is None" + ); + } + + Ok(()) + } +} + +impl SteppedMigrations for () { + fn len() -> u32 { + 0 + } + + fn nth_id(_n: u32) -> Option> { + None + } + + fn nth_max_steps(_n: u32) -> Option> { + None + } + + fn nth_step( + _n: u32, + _cursor: Option>, + _meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + None + } + + fn nth_transactional_step( + _n: u32, + _cursor: Option>, + _meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + None + } + + fn cursor_max_encoded_len() -> usize { + 0 + } + + fn identifier_max_encoded_len() -> usize { + 0 + } +} + +// A collection consisting of only a single migration. +impl SteppedMigrations for T { + fn len() -> u32 { + 1 + } + + fn nth_id(_n: u32) -> Option> { + Some(T::id().encode()) + } + + 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()) + .defensive_proof("nth_max_steps should only be called with n==0") + } + + fn nth_step( + _n: u32, + cursor: Option>, + meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + if !_n.is_zero() { + defensive!("nth_step should only be called with n==0"); + return None + } + + let cursor = match cursor { + Some(cursor) => match T::Cursor::decode(&mut &cursor[..]) { + Ok(cursor) => Some(cursor), + Err(_) => return Some(Err(SteppedMigrationError::InvalidCursor)), + }, + None => None, + }; + + Some(T::step(cursor, meter).map(|cursor| cursor.map(|cursor| cursor.encode()))) + } + + fn nth_transactional_step( + n: u32, + cursor: Option>, + meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + if n != 0 { + defensive!("nth_transactional_step should only be called with n==0"); + return None + } + + let cursor = match cursor { + Some(cursor) => match T::Cursor::decode(&mut &cursor[..]) { + Ok(cursor) => Some(cursor), + Err(_) => return Some(Err(SteppedMigrationError::InvalidCursor)), + }, + None => None, + }; + + Some( + T::transactional_step(cursor, meter).map(|cursor| cursor.map(|cursor| cursor.encode())), + ) + } + + fn cursor_max_encoded_len() -> usize { + T::Cursor::max_encoded_len() + } + + fn identifier_max_encoded_len() -> usize { + T::Identifier::max_encoded_len() + } +} + +#[impl_trait_for_tuples::impl_for_tuples(1, 30)] +impl SteppedMigrations for Tuple { + fn len() -> u32 { + for_tuples!( #( Tuple::len() )+* ) + } + + fn nth_id(n: u32) -> Option> { + let mut i = 0; + + for_tuples!( #( + if (i + Tuple::len()) > n { + return Tuple::nth_id(n - i) + } + + i += Tuple::len(); + )* ); + + None + } + + fn nth_step( + n: u32, + cursor: Option>, + meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + let mut i = 0; + + for_tuples!( #( + if (i + Tuple::len()) > n { + return Tuple::nth_step(n - i, cursor, meter) + } + + i += Tuple::len(); + )* ); + + None + } + + fn nth_transactional_step( + n: u32, + cursor: Option>, + meter: &mut WeightMeter, + ) -> Option>, SteppedMigrationError>> { + let mut i = 0; + + for_tuples! ( #( + if (i + Tuple::len()) > n { + return Tuple::nth_transactional_step(n - i, cursor, meter) + } + + i += Tuple::len(); + )* ); + + None + } + + fn nth_max_steps(n: u32) -> Option> { + let mut i = 0; + + for_tuples!( #( + if (i + Tuple::len()) > n { + return Tuple::nth_max_steps(n - i) + } + + i += Tuple::len(); + )* ); + + None + } + + fn cursor_max_encoded_len() -> usize { + let mut max_len = 0; + + for_tuples!( #( + max_len = max_len.max(Tuple::cursor_max_encoded_len()); + )* ); + + max_len + } + + fn identifier_max_encoded_len() -> usize { + let mut max_len = 0; + + for_tuples!( #( + max_len = max_len.max(Tuple::identifier_max_encoded_len()); + )* ); + + max_len + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{assert_ok, storage::unhashed}; + + #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] + pub enum Either { + Left(L), + Right(R), + } + + pub struct M0; + impl SteppedMigration for M0 { + type Cursor = (); + type Identifier = u8; + + fn id() -> Self::Identifier { + 0 + } + + fn step( + _cursor: Option, + _meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + log::info!("M0"); + unhashed::put(&[0], &()); + Ok(None) + } + } + + pub struct M1; + impl SteppedMigration for M1 { + type Cursor = (); + type Identifier = u8; + + fn id() -> Self::Identifier { + 1 + } + + fn step( + _cursor: Option, + _meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + log::info!("M1"); + unhashed::put(&[1], &()); + Ok(None) + } + + fn max_steps() -> Option { + Some(1) + } + } + + pub struct M2; + impl SteppedMigration for M2 { + type Cursor = (); + type Identifier = u8; + + fn id() -> Self::Identifier { + 2 + } + + fn step( + _cursor: Option, + _meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + log::info!("M2"); + unhashed::put(&[2], &()); + Ok(None) + } + + fn max_steps() -> Option { + Some(2) + } + } + + pub struct F0; + impl SteppedMigration for F0 { + type Cursor = (); + type Identifier = u8; + + fn id() -> Self::Identifier { + 3 + } + + fn step( + _cursor: Option, + _meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + log::info!("F0"); + unhashed::put(&[3], &()); + Err(SteppedMigrationError::Failed) + } + } + + // Three migrations combined to execute in order: + type Triple = (M0, (M1, M2)); + // Six migrations, just concatenating the ones from before: + type Hextuple = (Triple, Triple); + + #[test] + fn singular_migrations_work() { + assert_eq!(M0::max_steps(), None); + assert_eq!(M1::max_steps(), Some(1)); + assert_eq!(M2::max_steps(), Some(2)); + + assert_eq!(<(M0, M1)>::nth_max_steps(0), Some(None)); + assert_eq!(<(M0, M1)>::nth_max_steps(1), Some(Some(1))); + assert_eq!(<(M0, M1, M2)>::nth_max_steps(2), Some(Some(2))); + + assert_eq!(<(M0, M1)>::nth_max_steps(2), None); + } + + #[test] + fn tuple_migrations_work() { + assert_eq!(<() as SteppedMigrations>::len(), 0); + assert_eq!(<((), ((), ())) as SteppedMigrations>::len(), 0); + assert_eq!(::len(), 3); + assert_eq!(::len(), 6); + + // Check the IDs. The index specific functions all return an Option, + // to account for the out-of-range case. + assert_eq!(::nth_id(0), Some(0u8.encode())); + assert_eq!(::nth_id(1), Some(1u8.encode())); + assert_eq!(::nth_id(2), Some(2u8.encode())); + + sp_io::TestExternalities::default().execute_with(|| { + for n in 0..3 { + ::nth_step( + n, + Default::default(), + &mut WeightMeter::new(), + ); + } + }); + } + + #[test] + fn integrity_test_works() { + sp_io::TestExternalities::default().execute_with(|| { + assert_ok!(<() as SteppedMigrations>::integrity_test()); + assert_ok!(::integrity_test()); + assert_ok!(::integrity_test()); + assert_ok!(::integrity_test()); + assert_ok!(::integrity_test()); + assert_ok!(::integrity_test()); + }); + } + + #[test] + fn transactional_rollback_works() { + sp_io::TestExternalities::default().execute_with(|| { + assert_ok!(<(M0, F0) as SteppedMigrations>::nth_transactional_step( + 0, + Default::default(), + &mut WeightMeter::new() + ) + .unwrap()); + assert!(unhashed::exists(&[0])); + + let _g = crate::StorageNoopGuard::new(); + assert!(<(M0, F0) as SteppedMigrations>::nth_transactional_step( + 1, + Default::default(), + &mut WeightMeter::new() + ) + .unwrap() + .is_err()); + assert!(<(F0, M1) as SteppedMigrations>::nth_transactional_step( + 0, + Default::default(), + &mut WeightMeter::new() + ) + .unwrap() + .is_err()); + }); + } +} diff --git a/substrate/frame/support/src/storage/transactional.rs b/substrate/frame/support/src/storage/transactional.rs index d42e1809e91292a8e0ad367af4e203b8b1b17f87..0671db4a3a86bc76f7706df6eefe28a8c34c0701 100644 --- a/substrate/frame/support/src/storage/transactional.rs +++ b/substrate/frame/support/src/storage/transactional.rs @@ -127,6 +127,22 @@ where } } +/// Same as [`with_transaction`] but casts any internal error to `()`. +/// +/// This rids `E` of the `From` bound that is required by `with_transaction`. +pub fn with_transaction_opaque_err(f: F) -> Result, ()> +where + F: FnOnce() -> TransactionOutcome>, +{ + with_transaction(move || -> TransactionOutcome, DispatchError>> { + match f() { + TransactionOutcome::Commit(res) => TransactionOutcome::Commit(Ok(res)), + TransactionOutcome::Rollback(res) => TransactionOutcome::Rollback(Ok(res)), + } + }) + .map_err(|_| ()) +} + /// Same as [`with_transaction`] but without a limit check on nested transactional layers. /// /// This is mostly for backwards compatibility before there was a transactional layer limit. diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 2a42fca76b3c57623c74e3724b342eadf57737cd..1997d8fc223efe7ff1d1be17e2bc10fb973d2cb9 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -59,10 +59,10 @@ pub use misc::{ 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, IsSubType, IsType, - Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, - TryCollect, TryDrop, TypedGet, UnixTime, VariantCount, VariantCountOf, WrapperKeepOpaque, - WrapperOpaque, + ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsInherent, + IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, + SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, VariantCount, VariantCountOf, + WrapperKeepOpaque, WrapperOpaque, }; #[allow(deprecated)] pub use misc::{PreimageProvider, PreimageRecipient}; @@ -86,7 +86,8 @@ mod hooks; pub use hooks::GenesisBuild; pub use hooks::{ BeforeAllRuntimeMigrations, BuildGenesisConfig, Hooks, IntegrityTest, OnFinalize, OnGenesis, - OnIdle, OnInitialize, OnRuntimeUpgrade, OnTimestampSet, + OnIdle, OnInitialize, OnPoll, OnRuntimeUpgrade, OnTimestampSet, PostInherents, + PostTransactions, PreInherents, }; pub mod schedule; @@ -124,6 +125,8 @@ pub use safe_mode::{SafeMode, SafeModeError, SafeModeNotify}; mod tx_pause; pub use tx_pause::{TransactionPause, TransactionPauseError}; +pub mod dynamic_params; + pub mod tasks; pub use tasks::Task; diff --git a/substrate/frame/support/src/traits/dispatch.rs b/substrate/frame/support/src/traits/dispatch.rs index de50ce7a26c211190ddcb81976d39b9779540756..212c3080352d7a4350a2638ae9204cc0020e4e22 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 sytsem signer, if that's what the caller is. + fn as_system_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/dynamic_params.rs b/substrate/frame/support/src/traits/dynamic_params.rs new file mode 100644 index 0000000000000000000000000000000000000000..8881df04141cc13a97f79bc6df3ed41b8db0323d --- /dev/null +++ b/substrate/frame/support/src/traits/dynamic_params.rs @@ -0,0 +1,153 @@ +// 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 for dynamic parameters. +//! +//! Can be used by 3rd party macros to define dynamic parameters that are compatible with the the +//! `parameters` pallet. + +use codec::MaxEncodedLen; +use frame_support::Parameter; + +/// A dynamic parameter store across an aggregated KV type. +pub trait RuntimeParameterStore { + type AggregratedKeyValue: AggregratedKeyValue; + + /// Get the value of a parametrized key. + /// + /// Should return `None` if no explicit value was set instead of a default. + fn get(key: K) -> Option + where + KV: AggregratedKeyValue, + K: Key + Into<::Key>, + ::Key: IntoKey< + <::AggregratedKeyValue as AggregratedKeyValue>::Key, + >, + <::AggregratedKeyValue as AggregratedKeyValue>::Value: + TryIntoKey<::Value>, + ::Value: TryInto; +} + +/// A dynamic parameter store across a concrete KV type. +pub trait ParameterStore { + /// Get the value of a parametrized key. + fn get(key: K) -> Option + where + K: Key + Into<::Key>, + ::Value: TryInto; +} + +/// Key of a dynamic parameter. +pub trait Key { + /// The value that the key is parametrized with. + type Value; + + /// An opaque representation of `Self::Value`. + type WrappedValue: Into; +} + +/// The aggregated key-value type of a dynamic parameter store. +pub trait AggregratedKeyValue: Parameter { + /// The aggregated key type. + type Key: Parameter + MaxEncodedLen; + + /// The aggregated value type. + type Value: Parameter + MaxEncodedLen; + + /// Split the aggregated key-value type into its parts. + fn into_parts(self) -> (Self::Key, Option); +} + +impl AggregratedKeyValue for () { + type Key = (); + type Value = (); + + fn into_parts(self) -> (Self::Key, Option) { + ((), None) + } +} + +/// Allows to create a `ParameterStore` from a `RuntimeParameterStore`. +/// +/// This concretization is useful when configuring pallets, since a pallet will require a parameter +/// store for its own KV type and not the aggregated runtime-wide KV type. +pub struct ParameterStoreAdapter(sp_std::marker::PhantomData<(PS, KV)>); + +impl ParameterStore for ParameterStoreAdapter +where + PS: RuntimeParameterStore, + KV: AggregratedKeyValue, + ::Key: + IntoKey<<::AggregratedKeyValue as AggregratedKeyValue>::Key>, + ::Value: TryFromKey< + <::AggregratedKeyValue as AggregratedKeyValue>::Value, + >, +{ + fn get(key: K) -> Option + where + K: Key + Into<::Key>, + ::Value: TryInto, + { + PS::get::(key) + } +} + +// workaround for rust bug https://github.com/rust-lang/rust/issues/51445 +mod workaround { + pub trait FromKey: Sized { + #[must_use] + fn from_key(value: T) -> Self; + } + + pub trait IntoKey: Sized { + #[must_use] + fn into_key(self) -> T; + } + + impl IntoKey for T + where + U: FromKey, + { + fn into_key(self) -> U { + U::from_key(self) + } + } + + pub trait TryIntoKey: Sized { + type Error; + + fn try_into_key(self) -> Result; + } + + pub trait TryFromKey: Sized { + type Error; + + fn try_from_key(value: T) -> Result; + } + + impl TryIntoKey for T + where + U: TryFromKey, + { + type Error = U::Error; + + fn try_into_key(self) -> Result { + U::try_from_key(self) + } + } +} +pub use workaround::*; diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index 20788ce932d8b397990767c6ae8a0d82016cccbd..7d0e5aa1e89ca1d76e81d526881041c09c6e6cf3 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -25,10 +25,74 @@ use crate::weights::Weight; use impl_trait_for_tuples::impl_for_tuples; use sp_runtime::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; +use sp_weights::WeightMeter; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; +/// Provides a callback to execute logic before the all inherents. +pub trait PreInherents { + /// Called before all inherents were applied but after `on_initialize`. + fn pre_inherents() {} +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl PreInherents for Tuple { + fn pre_inherents() { + for_tuples!( #( Tuple::pre_inherents(); )* ); + } +} + +/// Provides a callback to execute logic after the all inherents. +pub trait PostInherents { + /// Called after all inherents were applied. + fn post_inherents() {} +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl PostInherents for Tuple { + fn post_inherents() { + for_tuples!( #( Tuple::post_inherents(); )* ); + } +} + +/// Provides a callback to execute logic before the all transactions. +pub trait PostTransactions { + /// Called after all transactions were applied but before `on_finalize`. + fn post_transactions() {} +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl PostTransactions for Tuple { + fn post_transactions() { + for_tuples!( #( Tuple::post_transactions(); )* ); + } +} + +/// Periodically executes logic. Is not guaranteed to run within a specific timeframe and should +/// only be used on logic that has no deadline. +pub trait OnPoll { + /// Code to execute every now and then at the beginning of the block after inherent application. + /// + /// The remaining weight limit must be respected. + fn on_poll(_n: BlockNumber, _weight: &mut WeightMeter) {} +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl OnPoll for Tuple { + fn on_poll(n: BlockNumber, weight: &mut WeightMeter) { + for_tuples!( #( Tuple::on_poll(n.clone(), weight); )* ); + } +} + /// See [`Hooks::on_initialize`]. pub trait OnInitialize { /// See [`Hooks::on_initialize`]. @@ -90,7 +154,7 @@ impl OnIdle for Tuple { /// /// Implementing this trait for a pallet let's you express operations that should /// happen at genesis. It will be called in an externalities provided environment and -/// will see the genesis state after all pallets have written their genesis state. +/// will set the genesis state after all pallets have written their genesis state. #[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] @@ -306,19 +370,23 @@ pub trait IntegrityTest { /// end /// ``` /// -/// * `OnRuntimeUpgrade` is only executed before everything else if a code -/// * `OnRuntimeUpgrade` is mandatorily at the beginning of the block body (extrinsics) being -/// processed. change is detected. -/// * Extrinsics start with inherents, and continue with other signed or unsigned extrinsics. -/// * `OnIdle` optionally comes after extrinsics. -/// `OnFinalize` mandatorily comes after `OnIdle`. +/// * [`OnRuntimeUpgrade`](Hooks::OnRuntimeUpgrade) hooks are only executed when a code change is +/// detected. +/// * [`OnRuntimeUpgrade`](Hooks::OnRuntimeUpgrade) hooks are mandatorily executed at the very +/// beginning of the block body, before any extrinsics are processed. +/// * [`Inherents`](sp_inherents) are always executed before any other other signed or unsigned +/// extrinsics. +/// * [`OnIdle`](Hooks::OnIdle) hooks are executed after extrinsics if there is weight remaining in +/// the block. +/// * [`OnFinalize`](Hooks::OnFinalize) hooks are mandatorily executed after +/// [`OnIdle`](Hooks::OnIdle). /// -/// > `OffchainWorker` is not part of this flow, as it is not really part of the consensus/main -/// > block import path, and is called optionally, and in other circumstances. See -/// > [`crate::traits::misc::OffchainWorker`] for more information. +/// > [`OffchainWorker`](crate::traits::misc::OffchainWorker) hooks are not part of this flow, +/// > because they are not part of the consensus/main block building logic. See +/// > [`OffchainWorker`](crate::traits::misc::OffchainWorker) for more information. /// -/// To learn more about the execution of hooks see `frame-executive` as this component is is charge -/// of dispatching extrinsics and placing the hooks in the correct order. +/// To learn more about the execution of hooks see the FRAME `Executive` pallet which is in charge +/// of dispatching extrinsics and calling hooks in the correct order. pub trait Hooks { /// Block initialization hook. This is called at the very beginning of block execution. /// @@ -370,30 +438,44 @@ pub trait Hooks { Weight::zero() } - /// Hook executed when a code change (aka. a "runtime upgrade") is detected by FRAME. + /// A hook to run logic after inherent application. + /// + /// Is not guaranteed to execute in a block and should therefore only be used in no-deadline + /// scenarios. + fn on_poll(_n: BlockNumber, _weight: &mut WeightMeter) {} + + /// Hook executed when a code change (aka. a "runtime upgrade") is detected by the FRAME + /// `Executive` pallet. /// /// Be aware that this is called before [`Hooks::on_initialize`] of any pallet; therefore, a lot /// of the critical storage items such as `block_number` in system pallet might have not been - /// set. + /// set yet. /// - /// Vert similar to [`Hooks::on_initialize`], any code in this block is mandatory and MUST - /// execute. Use with care. + /// Similar to [`Hooks::on_initialize`], any code in this block is mandatory and MUST execute. + /// It is strongly recommended to dry-run the execution of these hooks using + /// [try-runtime-cli](https://github.com/paritytech/try-runtime-cli) to ensure they will not + /// produce and overweight block which can brick your chain. Use with care! /// - /// ## Implementation Note: Versioning + /// ## Implementation Note: Standalone Migrations /// - /// 1. An implementation of this should typically follow a pattern where the version of the - /// pallet is checked against the onchain version, and a decision is made about what needs to be - /// done. This is helpful to prevent accidental repetitive execution of this hook, which can be - /// catastrophic. + /// Additional migrations can be created by directly implementing [`OnRuntimeUpgrade`] on + /// structs and passing them to `Executive`. /// - /// Alternatively, [`frame_support::migrations::VersionedMigration`] can be used to assist with - /// this. + /// ## Implementation Note: Pallet Versioning /// - /// ## Implementation Note: Runtime Level Migration + /// Implementations of this hook are typically wrapped in + /// [`crate::migrations::VersionedMigration`] to ensure the migration is executed exactly + /// once and only when it is supposed to. /// - /// Additional "upgrade hooks" can be created by pallets by a manual implementation of - /// [`Hooks::on_runtime_upgrade`] which can be passed on to `Executive` at the top level - /// runtime. + /// Alternatively, developers can manually implement version checks. + /// + /// Failure to adequately check storage versions can result in accidental repetitive execution + /// of the hook, which can be catastrophic. + /// + /// ## Implementation Note: Weight + /// + /// Typically, implementations of this method are simple enough that weights can be calculated + /// manually. However, if required, a benchmark can also be used. fn on_runtime_upgrade() -> Weight { Weight::zero() } @@ -403,7 +485,7 @@ pub trait Hooks { /// It should focus on certain checks to ensure that the state is sensible. This is never /// executed in a consensus code-path, therefore it can consume as much weight as it needs. /// - /// This hook should not alter any storage. + /// This hook must not alter any storage. #[cfg(feature = "try-runtime")] fn try_state(_n: BlockNumber) -> Result<(), TryRuntimeError> { Ok(()) @@ -415,7 +497,7 @@ pub trait Hooks { /// which will be passed to `post_upgrade` after upgrading for post-check. An empty vector /// should be returned if there is no such need. /// - /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. + /// This hook is never executed on-chain but instead used by testing tools. #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { Ok(Vec::new()) @@ -434,7 +516,7 @@ pub trait Hooks { } /// Implementing this function on a pallet allows you to perform long-running tasks that are - /// dispatched as separate threads, and entirely independent of the main wasm runtime. + /// dispatched as separate threads, and entirely independent of the main blockchain execution. /// /// This function can freely read from the state, but any change it makes to the state is /// meaningless. Writes can be pushed back to the chain by submitting extrinsics from the diff --git a/substrate/frame/support/src/traits/messages.rs b/substrate/frame/support/src/traits/messages.rs index 995ac4f717911195e4dba202d350c6cbc09ae340..f3d893bcc1d899fce06ef00a38d687bfb3ea0181 100644 --- a/substrate/frame/support/src/traits/messages.rs +++ b/substrate/frame/support/src/traits/messages.rs @@ -123,6 +123,8 @@ impl ServiceQueues for NoopServiceQueues { pub struct QueueFootprint { /// The number of pages in the queue (including overweight pages). pub pages: u32, + /// The number of pages that are ready (not yet processed and also not overweight). + pub ready_pages: u32, /// The storage footprint of the queue (including overweight messages). pub storage: Footprint, } diff --git a/substrate/frame/support/src/traits/metadata.rs b/substrate/frame/support/src/traits/metadata.rs index 586af20511a89f82caf33297177a12f6d0988bf4..8bda4186bc967b29a6342ea96dd0a1cdc5072438 100644 --- a/substrate/frame/support/src/traits/metadata.rs +++ b/substrate/frame/support/src/traits/metadata.rs @@ -261,41 +261,64 @@ impl Add for StorageVersion { } } -/// Special marker struct if no storage version is set for a pallet. +/// Special marker struct used when [`storage_version`](crate::pallet_macros::storage_version) is +/// not defined for a pallet. /// /// If you (the reader) end up here, it probably means that you tried to compare /// [`GetStorageVersion::on_chain_storage_version`] against -/// [`GetStorageVersion::current_storage_version`]. This basically means that the -/// [`storage_version`](crate::pallet_macros::storage_version) is missing in the pallet where the -/// mentioned functions are being called. +/// [`GetStorageVersion::in_code_storage_version`]. This basically means that the +/// [`storage_version`](crate::pallet_macros::storage_version) is missing from the pallet where the +/// mentioned functions are being called, and needs to be defined. #[derive(Debug, Default)] pub struct NoStorageVersionSet; -/// Provides information about the storage version of a pallet. +/// Provides information about a pallet's storage versions. /// -/// It differentiates between current and on-chain storage version. Both should be only out of sync -/// when a new runtime upgrade was applied and the runtime migrations did not yet executed. -/// Otherwise it means that the pallet works with an unsupported storage version and unforeseen -/// stuff can happen. +/// Every pallet has two storage versions: +/// 1. An in-code storage version +/// 2. An on-chain storage version /// -/// The current storage version is the version of the pallet as supported at runtime. The active -/// storage version is the version of the pallet in the storage. +/// The in-code storage version is the version of the pallet as defined in the runtime blob, and the +/// on-chain storage version is the version of the pallet stored on-chain. /// -/// It is required to update the on-chain storage version manually when a migration was applied. +/// Storage versions should be only ever be out of sync when a pallet has been updated to a new +/// version and the in-code version is incremented, but the migration has not yet been executed +/// on-chain as part of a runtime upgrade. +/// +/// It is the responsibility of the developer to ensure that the on-chain storage version is set +/// correctly during a migration so that it matches the in-code storage version. pub trait GetStorageVersion { - /// This will be filled out by the [`pallet`](crate::pallet) macro. + /// This type is generated by the [`pallet`](crate::pallet) macro. + /// + /// If the [`storage_version`](crate::pallet_macros::storage_version) attribute isn't specified, + /// this is set to [`NoStorageVersionSet`] to signify that it is missing. + /// + /// If the [`storage_version`](crate::pallet_macros::storage_version) attribute is specified, + /// this is be set to a [`StorageVersion`] corresponding to the attribute. /// - /// If the [`storage_version`](crate::pallet_macros::storage_version) attribute isn't given - /// this is set to [`NoStorageVersionSet`] to inform the user that the attribute is missing. - /// This should prevent that the user forgets to set a storage version when required. However, - /// this will only work when the user actually tries to call [`Self::current_storage_version`] - /// to compare it against the [`Self::on_chain_storage_version`]. If the attribute is given, - /// this will be set to [`StorageVersion`]. - type CurrentStorageVersion; - - /// Returns the current storage version as supported by the pallet. - fn current_storage_version() -> Self::CurrentStorageVersion; - /// Returns the on-chain storage version of the pallet as stored in the storage. + /// The intention of using [`NoStorageVersionSet`] instead of defaulting to a [`StorageVersion`] + /// of zero is to prevent developers from forgetting to set + /// [`storage_version`](crate::pallet_macros::storage_version) when it is required, like in the + /// case that they wish to compare the in-code storage version to the on-chain storage version. + type InCodeStorageVersion; + + #[deprecated( + note = "This method has been renamed to `in_code_storage_version` and will be removed after March 2024." + )] + /// DEPRECATED: Use [`Self::current_storage_version`] instead. + /// + /// Returns the in-code storage version as specified in the + /// [`storage_version`](crate::pallet_macros::storage_version) attribute, or + /// [`NoStorageVersionSet`] if the attribute is missing. + fn current_storage_version() -> Self::InCodeStorageVersion { + Self::in_code_storage_version() + } + + /// Returns the in-code storage version as specified in the + /// [`storage_version`](crate::pallet_macros::storage_version) attribute, or + /// [`NoStorageVersionSet`] if the attribute is missing. + fn in_code_storage_version() -> Self::InCodeStorageVersion; + /// Returns the storage version of the pallet as last set in the actual on-chain storage. fn on_chain_storage_version() -> StorageVersion; } diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index eafd9c8abdd2dfc4b4174723678d94aa963ad738..fba546ce21b5414aab43a406922bfd7197c12ca2 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -23,6 +23,7 @@ use impl_trait_for_tuples::impl_for_tuples; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_arithmetic::traits::{CheckedAdd, CheckedMul, CheckedSub, One, Saturating}; use sp_core::bounded::bounded_vec::TruncateFrom; + #[doc(hidden)] pub use sp_runtime::traits::{ ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, @@ -895,11 +896,21 @@ pub trait GetBacking { /// A trait to ensure the inherent are before non-inherent in a block. /// /// This is typically implemented on runtime, through `construct_runtime!`. -pub trait EnsureInherentsAreFirst { +pub trait EnsureInherentsAreFirst: + IsInherent<::Extrinsic> +{ /// Ensure the position of inherent is correct, i.e. they are before non-inherents. /// - /// On error return the index of the inherent with invalid position (counting from 0). - fn ensure_inherents_are_first(block: &Block) -> Result<(), u32>; + /// On error return the index of the inherent with invalid position (counting from 0). On + /// success it returns the index of the last inherent. `0` therefore means that there are no + /// inherents. + fn ensure_inherents_are_first(block: &Block) -> Result; +} + +/// A trait to check if an extrinsic is an inherent. +pub trait IsInherent { + /// Whether this extrinsic is an inherent. + fn is_inherent(ext: &Extrinsic) -> bool; } /// An extrinsic on which we can get access to call. @@ -908,24 +919,13 @@ pub trait ExtrinsicCall: sp_runtime::traits::Extrinsic { fn call(&self) -> &Self::Call; } -#[cfg(feature = "std")] -impl ExtrinsicCall for sp_runtime::testing::TestXt -where - Call: codec::Codec + Sync + Send + TypeInfo, - Extra: TypeInfo, -{ - fn call(&self) -> &Self::Call { - &self.call - } -} - impl ExtrinsicCall 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 diff --git a/substrate/frame/support/src/transaction_extensions.rs b/substrate/frame/support/src/transaction_extensions.rs new file mode 100644 index 0000000000000000000000000000000000000000..98d78b9b4e4777e4e379975c63a2757f06b47553 --- /dev/null +++ b/substrate/frame/support/src/transaction_extensions.rs @@ -0,0 +1,89 @@ +// 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 extensions. + +use crate::{CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_io::hashing::blake2_256; +use sp_runtime::{ + impl_tx_ext_default, + traits::{ + transaction_extension::{TransactionExtensionBase, TransactionExtensionInterior}, + DispatchInfoOf, Dispatchable, IdentifyAccount, TransactionExtension, Verify, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, +}; + +#[derive( + CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, RuntimeDebugNoBound, TypeInfo, +)] +#[codec(encode_bound())] +#[codec(decode_bound())] +pub struct VerifyMultiSignature +where + V: TransactionExtensionInterior, + ::AccountId: TransactionExtensionInterior, +{ + signature: V, + account: ::AccountId, +} + +impl TransactionExtensionBase for VerifyMultiSignature +where + V: TransactionExtensionInterior, + ::AccountId: TransactionExtensionInterior, +{ + const IDENTIFIER: &'static str = "VerifyMultiSignature"; + type Implicit = (); +} + +impl TransactionExtension + for VerifyMultiSignature +where + V: TransactionExtensionInterior, + ::AccountId: TransactionExtensionInterior, + ::RuntimeOrigin: From::AccountId>>, +{ + type Val = (); + type Pre = (); + impl_tx_ext_default!(Call; Context; prepare); + + fn validate( + &self, + _origin: ::RuntimeOrigin, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + _: &mut Context, + _: (), + inherited_implication: &impl Encode, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + let msg = inherited_implication.using_encoded(blake2_256); + + if !self.signature.verify(&msg[..], &self.account) { + Err(InvalidTransaction::BadProof)? + } + // We clobber the original origin. Maybe we shuld check that it's none? + let origin = Some(self.account.clone()).into(); + Ok((ValidTransaction::default(), (), origin)) + } +} diff --git a/substrate/frame/support/src/weights/block_weights.rs b/substrate/frame/support/src/weights/block_weights.rs index 57a68554755abb007165e751df687d097cd48f17..647b619835757a380d37acd6c8003f758137ba93 100644 --- a/substrate/frame/support/src/weights/block_weights.rs +++ b/substrate/frame/support/src/weights/block_weights.rs @@ -15,24 +15,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16 (Y/M/D) -//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-01 (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: `./frame/support/src/weights/` +//! WEIGHT-PATH: `./substrate/frame/support/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: -// ./target/production/substrate +// ./target/production/substrate-node // benchmark // overhead // --chain=dev -// --execution=wasm // --wasm-execution=compiled -// --weight-path=./frame/support/src/weights/ -// --header=./HEADER-APACHE2 +// --weight-path=./substrate/frame/support/src/weights/ +// --header=./substrate/HEADER-APACHE2 // --warmup=10 // --repeat=100 @@ -44,17 +43,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 376_949, 622_462 - /// Average: 390_584 - /// Median: 386_322 - /// Std-Dev: 24792.0 + /// Min, Max: 424_332, 493_017 + /// Average: 437_118 + /// Median: 434_920 + /// Std-Dev: 8798.01 /// /// Percentiles nanoseconds: - /// 99th: 433_299 - /// 95th: 402_688 - /// 75th: 391_645 + /// 99th: 460_074 + /// 95th: 451_580 + /// 75th: 440_307 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(390_584), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(437_118), 0); } #[cfg(test)] diff --git a/substrate/frame/support/src/weights/extrinsic_weights.rs b/substrate/frame/support/src/weights/extrinsic_weights.rs index a304f089ff782c34ab9941705503c5e766bb08b0..99b392c4369a523ef2ce08bfdd9f9dfed86a9f94 100644 --- a/substrate/frame/support/src/weights/extrinsic_weights.rs +++ b/substrate/frame/support/src/weights/extrinsic_weights.rs @@ -15,24 +15,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16 (Y/M/D) -//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-01 (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: `./frame/support/src/weights/` +//! WEIGHT-PATH: `./substrate/frame/support/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: -// ./target/production/substrate +// ./target/production/substrate-node // benchmark // overhead // --chain=dev -// --execution=wasm // --wasm-execution=compiled -// --weight-path=./frame/support/src/weights/ -// --header=./HEADER-APACHE2 +// --weight-path=./substrate/frame/support/src/weights/ +// --header=./substrate/HEADER-APACHE2 // --warmup=10 // --repeat=100 @@ -44,17 +43,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 123_875, 128_419 - /// Average: 124_414 - /// Median: 124_332 - /// Std-Dev: 497.74 + /// Min, Max: 106_053, 107_403 + /// Average: 106_446 + /// Median: 106_415 + /// Std-Dev: 216.17 /// /// Percentiles nanoseconds: - /// 99th: 125_245 - /// 95th: 124_989 - /// 75th: 124_498 + /// 99th: 107_042 + /// 95th: 106_841 + /// 75th: 106_544 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(124_414), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(106_446), 0); } #[cfg(test)] diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 8b61f25f569aa51d3ac221f15d7f3ffc156b6739..2f12cc00ed9e08560870e6f62b1d1930bad90832 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] static_assertions = "1.1.0" -serde = { version = "1.0.195", default-features = false, features = ["derive"] } +serde = { features = ["derive"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } @@ -24,7 +24,7 @@ sp-api = { path = "../../../primitives/api", default-features = false } sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } sp-state-machine = { path = "../../../primitives/state-machine", optional = true } -frame-support = { path = "..", default-features = false } +frame-support = { path = "..", default-features = false, features = ["experimental"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } sp-runtime = { path = "../../../primitives/runtime", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index 48adbcab5826157ea3edfb4eb931f77b9b9794a1..ca889faef876b197cb15a338e0a65b30536b79ec 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["derive"] } +serde = { features = ["derive"], workspace = true } frame-support = { path = "../..", default-features = false } frame-system = { path = "../../../system", default-features = false } sp-runtime = { path = "../../../../primitives/runtime", default-features = false } 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 61cfc07caedc37e1a8427e8fadc61406813c52e6..c677ddcd672bc048b96e0c7274c36ffccf31e5ef 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 @@ -347,7 +347,7 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied 26 | System: frame_system::{Pallet, Call, Storage, Config, Event}, | ^^^^^^ the trait `Config` is not implemented for `Runtime` | -note: required by a bound in `frame_system::GenesisConfig` +note: required by a bound in `GenesisConfig` --> $WORKSPACE/substrate/frame/system/src/lib.rs | | pub struct GenesisConfig { @@ -477,7 +477,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `frame_support::sp_runtime::traits::Dispatchable::Config` - --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs + --> $WORKSPACE/substrate/primitives/runtime/src/traits/mod.rs | | type Config; | ^^^^^^^^^^^^ required by this bound in `Dispatchable::Config` @@ -510,7 +510,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `frame_support::pallet_prelude::ValidateUnsigned::Call` - --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs + --> $WORKSPACE/substrate/primitives/runtime/src/traits/mod.rs | | type Call; | ^^^^^^^^^^ required by this bound in `ValidateUnsigned::Call` diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr index 3b6329c650fa65208e01c7d991e321f256b7eecf..6160f8234a350cc3ee0a0761cab0eed6ea022525 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr @@ -4,88 +4,24 @@ error: The number of pallets exceeds the maximum number of tuple elements. To in 67 | pub struct Runtime | ^^^ -error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:35:64 - | -35 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | ^^^^^^^^^^^ not found in this scope - | -help: you might be missing a type parameter - | -35 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | +++++++++++++ - -error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:37:25 - | -37 | impl pallet::Config for Runtime {} - | ^^^^^^^ not found in this scope - -error[E0412]: cannot find type `Runtime` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:40:31 - | -40 | impl frame_system::Config for Runtime { - | ^^^^^^^ not found in this scope - -error[E0412]: cannot find type `RuntimeOrigin` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:42:23 - | -42 | type RuntimeOrigin = RuntimeOrigin; - | ^^^^^^^^^^^^^ - | -help: you might have meant to use the associated type - | -42 | type RuntimeOrigin = Self::RuntimeOrigin; - | ++++++ - -error[E0412]: cannot find type `RuntimeCall` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:44:21 - | -44 | type RuntimeCall = RuntimeCall; - | ^^^^^^^^^^^ - | -help: you might have meant to use the associated type - | -44 | type RuntimeCall = Self::RuntimeCall; - | ++++++ - -error[E0412]: cannot find type `RuntimeEvent` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:50:22 - | -50 | type RuntimeEvent = RuntimeEvent; - | ^^^^^^^^^^^^ - | -help: you might have meant to use the associated type - | -50 | type RuntimeEvent = Self::RuntimeEvent; - | ++++++ - -error[E0412]: cannot find type `PalletInfo` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:56:20 - | -56 | type PalletInfo = PalletInfo; - | ^^^^^^^^^^ - | -help: you might have meant to use the associated type - | -56 | type PalletInfo = Self::PalletInfo; - | ++++++ -help: consider importing one of these items - | -18 + use frame_benchmarking::__private::traits::PalletInfo; - | -18 + use frame_support::traits::PalletInfo; - | - -error[E0412]: cannot find type `RuntimeTask` in this scope - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:39:1 - | -39 | #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `frame_system::config_preludes::TestDefaultConfig` which comes from the expansion of the macro `frame_support::macro_magic::forward_tokens_verbatim` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might have meant to use the associated type - --> $WORKSPACE/substrate/frame/system/src/lib.rs - | - | type Self::RuntimeTask = (); - | ++++++ +error: recursion limit reached while expanding `frame_support::__private::tt_return!` + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:22:1 + | +22 | / #[frame_support::pallet] +23 | | mod pallet { +24 | | #[pallet::config] +25 | | pub trait Config: frame_system::Config {} +... | +66 | |/ construct_runtime! { +67 | || pub struct Runtime +68 | || { +69 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, +... || +180 | || } +181 | || } + | ||_^ + | |_| + | in this macro invocation + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`$CRATE`) + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) 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 a4c7ecf786588a782f96b3ae890c67973c2841fc..30005c07cb631dd48425117507006faa870866cd 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 @@ -53,8 +53,9 @@ error[E0599]: no function or associated item named `is_inherent` found for struc | |_^ 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 `is_inherent`, perhaps you need to implement it: + = note: the following traits define an item `is_inherent`, perhaps you need to implement one of them: candidate #1: `ProvideInherent` + candidate #2: `IsInherent` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `check_inherent` found for struct `pallet::Pallet` in the current scope @@ -119,3 +120,23 @@ error[E0599]: no function or associated item named `is_inherent_required` found = note: the following trait defines an item `is_inherent_required`, perhaps you need to implement it: candidate #1: `ProvideInherent` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `pallet::Pallet: ProvideInherent` is not satisfied + --> tests/construct_runtime_ui/undefined_inherent_part.rs:70:3 + | +70 | Pallet: pallet expanded::{}::{Pallet, Inherent}, + | ^^^^^^ the trait `ProvideInherent` is not implemented for `pallet::Pallet` + +error[E0277]: the trait bound `pallet::Pallet: ProvideInherent` is not satisfied + --> tests/construct_runtime_ui/undefined_inherent_part.rs:66:1 + | +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Inherent}, +71 | | } +72 | | } + | |_^ the trait `ProvideInherent` is not implemented for `pallet::Pallet` + | + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr index cda20288984ae535c0755fd1e6814384d124c515..c7159b34afb3d22737fb5d8ed6662027f04a3bd6 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr @@ -1,4 +1,4 @@ -error: `#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeTask`, `RuntimeOrigin` or `PalletInfo` +error: `#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeTask`, `RuntimeOrigin`, `RuntimeParameters` or `PalletInfo` --> tests/derive_impl_ui/inject_runtime_type_invalid.rs:32:5 | 32 | type RuntimeInfo = (); diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 9b4381c2f82bd4baa78fc8d175079a0e90480da3..4d2737d411ee8238124571d5c64260ac3dd79c03 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -209,7 +209,7 @@ pub mod pallet { where T::AccountId: From + From + SomeAssociation1, { - /// Doc comment put in metadata + /// call foo doc comment put in metadata #[pallet::call_index(0)] #[pallet::weight(Weight::from_parts(*foo as u64, 0))] pub fn foo( @@ -225,7 +225,7 @@ pub mod pallet { Ok(().into()) } - /// Doc comment put in metadata + /// call foo_storage_layer doc comment put in metadata #[pallet::call_index(1)] #[pallet::weight({1})] pub fn foo_storage_layer( @@ -270,7 +270,7 @@ pub mod pallet { #[pallet::error] #[derive(PartialEq, Eq)] pub enum Error { - /// doc comment put into metadata + /// error doc comment put in metadata InsufficientProposersBalance, NonExistentStorageValue, Code(u8), @@ -287,9 +287,8 @@ pub mod pallet { where T::AccountId: SomeAssociation1 + From, { - /// doc comment put in metadata + /// event doc comment put in metadata Proposed(::AccountId), - /// doc Spending(BalanceOf), Something(u32), SomethingElse(::_1), @@ -590,7 +589,7 @@ pub mod pallet2 { Self::deposit_event(Event::Something(31)); if UpdateStorageVersion::get() { - Self::current_storage_version().put::(); + Self::in_code_storage_version().put::(); } Weight::zero() @@ -744,14 +743,43 @@ impl pallet5::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; } +#[derive(Clone, Debug, codec::Encode, codec::Decode, PartialEq, Eq, scale_info::TypeInfo)] +pub struct AccountU64(u64); +impl sp_runtime::traits::IdentifyAccount for AccountU64 { + type AccountId = u64; + fn into_account(self) -> u64 { + self.0 + } +} + +impl sp_runtime::traits::Verify for AccountU64 { + type Signer = AccountU64; + fn verify>( + &self, + _msg: L, + _signer: &::AccountId, + ) -> bool { + true + } +} + +impl From for AccountU64 { + fn from(value: u64) -> Self { + Self(value) + } +} + 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, + AccountU64, + frame_system::CheckNonZeroSender, +>; frame_support::construct_runtime!( - pub struct Runtime - { + pub struct Runtime { // Exclude part `Storage` in order not to check its metadata in tests. System: frame_system exclude_parts { Pallet, Storage }, Example: pallet, @@ -772,6 +800,14 @@ fn _ensure_call_is_correctly_excluded_and_included(call: RuntimeCall) { } } +fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + doc + } +} + #[test] fn transactional_works() { TestExternalities::default().execute_with(|| { @@ -890,10 +926,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( @@ -905,14 +939,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, + })), ], ); @@ -927,14 +958,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, + })), ], ); @@ -948,10 +976,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(); @@ -966,10 +993,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(); @@ -985,14 +1014,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, + })), ], ); @@ -1007,18 +1035,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 {})), ], ); @@ -1033,18 +1057,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 {})), ], ); @@ -1310,7 +1333,7 @@ fn pallet_on_genesis() { assert_eq!(pallet::Pallet::::on_chain_storage_version(), StorageVersion::new(0)); pallet::Pallet::::on_genesis(); assert_eq!( - pallet::Pallet::::current_storage_version(), + pallet::Pallet::::in_code_storage_version(), pallet::Pallet::::on_chain_storage_version(), ); }) @@ -1362,19 +1385,47 @@ fn migrate_from_pallet_version_to_storage_version() { }); } +#[test] +fn pallet_item_docs_in_metadata() { + // call + let call_variants = match meta_type::>().type_info().type_def { + scale_info::TypeDef::Variant(variants) => variants.variants, + _ => unreachable!(), + }; + + assert_eq!(call_variants[0].docs, maybe_docs(vec!["call foo doc comment put in metadata"])); + assert_eq!( + call_variants[1].docs, + maybe_docs(vec!["call foo_storage_layer doc comment put in metadata"]) + ); + assert!(call_variants[2].docs.is_empty()); + + // event + let event_variants = match meta_type::>().type_info().type_def { + scale_info::TypeDef::Variant(variants) => variants.variants, + _ => unreachable!(), + }; + + assert_eq!(event_variants[0].docs, maybe_docs(vec!["event doc comment put in metadata"])); + assert!(event_variants[1].docs.is_empty()); + + // error + let error_variants = match meta_type::>().type_info().type_def { + scale_info::TypeDef::Variant(variants) => variants.variants, + _ => unreachable!(), + }; + + assert_eq!(error_variants[0].docs, maybe_docs(vec!["error doc comment put in metadata"])); + assert!(error_variants[1].docs.is_empty()); + + // storage is already covered in the main `fn metadata` test. +} + #[test] fn metadata() { use codec::Decode; use frame_metadata::{v15::*, *}; - fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { - if cfg!(feature = "no-metadata-docs") { - vec![] - } else { - doc - } - } - let readme = "Support code for the runtime.\n\nLicense: Apache-2.0\n"; let expected_pallet_doc = vec![" Pallet documentation", readme, readme]; @@ -1899,7 +1950,7 @@ fn extrinsic_metadata_ir_types() { >(), 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::>(), ir.extra_ty); @@ -2257,10 +2308,10 @@ fn pallet_on_chain_storage_version_initializes_correctly() { AllPalletsWithSystem, >; - // Simple example of a pallet with current version 10 being added to the runtime for the first + // Simple example of a pallet with in-code version 10 being added to the runtime for the first // time. TestExternalities::default().execute_with(|| { - let current_version = Example::current_storage_version(); + let in_code_version = Example::in_code_storage_version(); // Check the pallet has no storage items set. let pallet_hashed_prefix = twox_128(Example::name().as_bytes()); @@ -2271,14 +2322,14 @@ fn pallet_on_chain_storage_version_initializes_correctly() { // version. Executive::execute_on_runtime_upgrade(); - // Check that the storage version was initialized to the current version + // Check that the storage version was initialized to the in-code version let on_chain_version_after = StorageVersion::get::(); - assert_eq!(on_chain_version_after, current_version); + assert_eq!(on_chain_version_after, in_code_version); }); - // Pallet with no current storage version should have the on-chain version initialized to 0. + // Pallet with no in-code storage version should have the on-chain version initialized to 0. TestExternalities::default().execute_with(|| { - // Example4 current_storage_version is NoStorageVersionSet. + // Example4 in_code_storage_version is NoStorageVersionSet. // Check the pallet has no storage items set. let pallet_hashed_prefix = twox_128(Example4::name().as_bytes()); @@ -2308,7 +2359,7 @@ fn post_runtime_upgrade_detects_storage_version_issues() { impl OnRuntimeUpgrade for CustomUpgrade { fn on_runtime_upgrade() -> Weight { - Example2::current_storage_version().put::(); + Example2::in_code_storage_version().put::(); Default::default() } @@ -2351,14 +2402,14 @@ fn post_runtime_upgrade_detects_storage_version_issues() { >; TestExternalities::default().execute_with(|| { - // Set the on-chain version to one less than the current version for `Example`, simulating a + // Set the on-chain version to one less than the in-code version for `Example`, simulating a // forgotten migration StorageVersion::new(9).put::(); // The version isn't changed, we should detect it. assert!( Executive::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost).unwrap_err() == - "On chain and current storage version do not match. Missing runtime upgrade?" + "On chain and in-code storage version do not match. Missing runtime upgrade?" .into() ); }); diff --git a/substrate/frame/support/test/tests/pallet_instance.rs b/substrate/frame/support/test/tests/pallet_instance.rs index f8cc97623b8de219900e5d436a2b00d8f3c6fa91..505400a7c217df1321c2a5f5a3746b6b4bc1d671 100644 --- a/substrate/frame/support/test/tests/pallet_instance.rs +++ b/substrate/frame/support/test/tests/pallet_instance.rs @@ -943,7 +943,7 @@ fn metadata() { ty: scale_info::meta_type::(), version: 4, 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_outer_enums_explicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs index 79e9d6786717a5a27717cda754575c2ecd478aa3..33b96dea9486396629e19274de8437f0ca3c3162 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs @@ -90,6 +90,7 @@ fn module_error_outer_enum_expand_explicit() { frame_system::Error::NonDefaultComposite => (), frame_system::Error::NonZeroRefCount => (), frame_system::Error::CallFiltered => (), + frame_system::Error::MultiBlockMigrationsOngoing => (), #[cfg(feature = "experimental")] frame_system::Error::InvalidTask => (), #[cfg(feature = "experimental")] diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs index 4bd8ee0bb39a574b2ff3f59b571c1209fc675da4..db006fe79359aa9f096963ce9333933329c23508 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs @@ -90,6 +90,7 @@ fn module_error_outer_enum_expand_implicit() { frame_system::Error::NonDefaultComposite => (), frame_system::Error::NonZeroRefCount => (), frame_system::Error::CallFiltered => (), + frame_system::Error::MultiBlockMigrationsOngoing => (), #[cfg(feature = "experimental")] frame_system::Error::InvalidTask => (), #[cfg(feature = "experimental")] diff --git a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs index 840a6dee20ccc7a836619a1ef334cca6e22e7887..d2ca9fc80991a87dbb6f20323f07d8adcd29449d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs +++ b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.rs @@ -29,7 +29,7 @@ mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_runtime_upgrade() -> Weight { - if Self::current_storage_version() != Self::on_chain_storage_version() { + if Self::in_code_storage_version() != Self::on_chain_storage_version() { } diff --git a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr index 1b48197cc9ed1049ea0f52bb011fbc95654c59c0..3256e69528a2d28527ccfe1fa4d77dadfc77baa1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr @@ -1,7 +1,7 @@ error[E0369]: binary operation `!=` cannot be applied to type `NoStorageVersionSet` --> tests/pallet_ui/compare_unset_storage_version.rs:32:39 | -32 | if Self::current_storage_version() != Self::on_chain_storage_version() { +32 | if Self::in_code_storage_version() != Self::on_chain_storage_version() { | ------------------------------- ^^ -------------------------------- StorageVersion | | | NoStorageVersionSet diff --git a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr deleted file mode 100644 index e227033d3646bac74b23267531730e0a59ce06fb..0000000000000000000000000000000000000000 --- a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: use of deprecated struct `pallet::_::Store`: - Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. - Check https://github.com/paritytech/substrate/pull/13535 for more details. - --> tests/pallet_ui/deprecated_store_attr.rs:24:3 - | -24 | #[pallet::generate_store(trait Store)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D deprecated` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(deprecated)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs deleted file mode 100644 index 334fd8a46af2e14ef175acfbbdbc6a895b890595..0000000000000000000000000000000000000000 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs +++ /dev/null @@ -1,42 +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. - -#[frame_support::pallet] -mod pallet { - use frame_support::pallet_prelude::Hooks; - use frame_system::pallet_prelude::BlockNumberFor; - use frame_support::pallet_prelude::StorageValue; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - #[pallet::generate_store(trait Store)] - #[pallet::generate_store(trait Store)] - pub struct Pallet(core::marker::PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} - - #[pallet::storage] - type Foo = StorageValue<_, u8>; -} - -fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr deleted file mode 100644 index 864b399326e19ea96afa8d76ccf9815b057ceef6..0000000000000000000000000000000000000000 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Unexpected duplicated attribute - --> tests/pallet_ui/duplicate_store_attr.rs:29:3 - | -29 | #[pallet::generate_store(trait Store)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr index 33a2d1da78608c7d97e433d03c403cf4559a79b9..6f7f5617f7e5a8b40dc5e14f8684ccc256be1994 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr @@ -1,4 +1,4 @@ -error: expected one of: `generate_store`, `without_storage_info`, `storage_version` +error: expected `without_storage_info` or `storage_version` --> tests/pallet_ui/pallet_struct_invalid_attr.rs:24:12 | 24 | #[pallet::generate_storage_info] // invalid diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr index 7f125526edf26abddf82f2228da9a510200f0735..519fadaa6049cb26430719379d3f9847b81efb62 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr @@ -1,4 +1,4 @@ -error: expected one of: `getter`, `storage_prefix`, `unbounded`, `whitelist_storage` +error: expected one of: `getter`, `storage_prefix`, `unbounded`, `whitelist_storage`, `disable_try_decode_storage` --> tests/pallet_ui/storage_invalid_attribute.rs:33:12 | 33 | #[pallet::generate_store(pub trait Store)] diff --git a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr deleted file mode 100644 index ccb55122e8169e84f776dd41504738ab0f1772f5..0000000000000000000000000000000000000000 --- a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: use of deprecated struct `pallet::_::Store`: - Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. - Check https://github.com/paritytech/substrate/pull/13535 for more details. - --> tests/pallet_ui/store_trait_leak_private.rs:28:3 - | -28 | #[pallet::generate_store(pub trait Store)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D deprecated` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(deprecated)]` - -error[E0446]: private type `_GeneratedPrefixForStorageFoo` in public interface - --> tests/pallet_ui/store_trait_leak_private.rs:28:37 - | -28 | #[pallet::generate_store(pub trait Store)] - | ^^^^^ can't leak private type -... -37 | #[pallet::storage] - | ------- `_GeneratedPrefixForStorageFoo` declared as private diff --git a/substrate/frame/support/test/tests/runtime.rs b/substrate/frame/support/test/tests/runtime.rs new file mode 100644 index 0000000000000000000000000000000000000000..7e33ee4645833f66ea4ef4f173734f28538fcdc2 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime.rs @@ -0,0 +1,993 @@ +// 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. + +//! General tests for construct_runtime macro, test for: +//! * error declared with decl_error works +//! * integrity test is generated + +#![recursion_limit = "128"] + +use codec::MaxEncodedLen; +use frame_support::{ + derive_impl, parameter_types, traits::PalletInfo as _, weights::RuntimeDbWeight, +}; +use frame_system::limits::{BlockLength, BlockWeights}; +use scale_info::TypeInfo; +use sp_core::{sr25519, ConstU64}; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, ValidateUnsigned, Verify}, + DispatchError, ModuleError, +}; +use sp_version::RuntimeVersion; + +parameter_types! { + pub static IntegrityTestExec: u32 = 0; +} + +#[frame_support::pallet(dev_mode)] +mod module1 { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl, I: 'static> Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + #[scale_info(skip_type_params(I))] + pub struct Origin(pub PhantomData<(T, I)>); + + #[pallet::event] + pub enum Event, I: 'static = ()> { + A(::AccountId), + } + + #[pallet::error] + pub enum Error { + Something, + } +} + +#[frame_support::pallet(dev_mode)] +mod module2 { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + IntegrityTestExec::mutate(|i| *i += 1); + } + } + + #[pallet::call] + impl Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct Origin; + + #[pallet::event] + pub enum Event { + A, + } + + #[pallet::error] + pub enum Error { + Something, + } +} + +mod nested { + use super::*; + + #[frame_support::pallet(dev_mode)] + pub mod module3 { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + IntegrityTestExec::mutate(|i| *i += 1); + } + } + + #[pallet::call] + impl Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct Origin; + + #[pallet::event] + pub enum Event { + A, + } + + #[pallet::error] + pub enum Error { + Something, + } + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + #[serde(skip)] + pub _config: sp_std::marker::PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) {} + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } + } +} + +#[frame_support::pallet(dev_mode)] +pub mod module3 { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + pub fn aux_1(_origin: OriginFor, #[pallet::compact] _data: u32) -> DispatchResult { + unreachable!() + } + pub fn aux_2( + _origin: OriginFor, + _data: i32, + #[pallet::compact] _data2: u32, + ) -> DispatchResult { + unreachable!() + } + #[pallet::weight(0)] + pub fn aux_3(_origin: OriginFor, _data: i32, _data2: String) -> DispatchResult { + unreachable!() + } + #[pallet::weight(3)] + pub fn aux_4(_origin: OriginFor) -> DispatchResult { + unreachable!() + } + #[pallet::weight((5, DispatchClass::Operational))] + pub fn operational(_origin: OriginFor) -> DispatchResult { + unreachable!() + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct Origin(pub PhantomData); + + #[pallet::event] + pub enum Event { + A, + } + + #[pallet::error] + pub enum Error { + Something, + } + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + #[serde(skip)] + pub _config: sp_std::marker::PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) {} + } + + #[pallet::storage] + pub type Storage = StorageValue<_, u32>; + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } +} + +pub type BlockNumber = u64; +pub type Signature = sr25519::Signature; +pub type AccountId = ::Signer; +pub type Header = generic::Header; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type Block = generic::Block; + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(30)] + pub type System = frame_system + Pallet + Call + Event + Origin; + + #[runtime::pallet_index(31)] + pub type Module1_1 = module1; + + #[runtime::pallet_index(32)] + pub type Module2 = module2; + + #[runtime::pallet_index(33)] + pub type Module1_2 = module1; + + #[runtime::pallet_index(34)] + pub type NestedModule3 = nested::module3; + + #[runtime::pallet_index(35)] + #[runtime::disable_unsigned] + pub type Module3 = self::module3; + + #[runtime::pallet_index(6)] + #[runtime::disable_call] + pub type Module1_3 = module1; + + #[runtime::pallet_index(3)] + pub type Module1_4 = module1; + + #[runtime::pallet_index(4)] + #[runtime::disable_call] + pub type Module1_5 = module1; + + #[runtime::pallet_index(1)] + pub type Module1_6 = module1; + + #[runtime::pallet_index(2)] + pub type Module1_7 = module1; + + #[runtime::pallet_index(12)] + pub type Module1_8 = module1; + + #[runtime::pallet_index(13)] + pub type Module1_9 = module1; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; + type OnSetCode = (); + type Block = Block; + type BlockHashCount = ConstU64<10>; +} + +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl nested::module3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +fn test_pub() -> AccountId { + AccountId::from_raw([0; 32]) +} + +#[test] +fn check_modules_error_type() { + sp_io::TestExternalities::default().execute_with(|| { + assert_eq!( + Module1_1::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 31, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module2::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 32, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_2::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 33, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + NestedModule3::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 34, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_3::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 6, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_4::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 3, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_5::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 4, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_6::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 1, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_7::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 2, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_8::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 12, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_9::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 13, + error: [0; 4], + message: Some("Something") + })), + ); + }) +} + +#[test] +fn integrity_test_works() { + __construct_runtime_integrity_test::runtime_integrity_tests(); + assert_eq!(IntegrityTestExec::get(), 2); +} + +#[test] +fn origin_codec() { + use codec::Encode; + + let origin = OriginCaller::system(frame_system::RawOrigin::None); + assert_eq!(origin.encode()[0], 30); + + let origin = OriginCaller::Module1_1(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 31); + + let origin = OriginCaller::Module2(module2::Origin); + assert_eq!(origin.encode()[0], 32); + + let origin = OriginCaller::Module1_2(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 33); + + let origin = OriginCaller::NestedModule3(nested::module3::Origin); + assert_eq!(origin.encode()[0], 34); + + let origin = OriginCaller::Module3(module3::Origin(Default::default())); + assert_eq!(origin.encode()[0], 35); + + let origin = OriginCaller::Module1_6(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 1); + + let origin = OriginCaller::Module1_7(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 2); + + let origin = OriginCaller::Module1_8(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 12); + + let origin = OriginCaller::Module1_9(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 13); +} + +#[test] +fn event_codec() { + use codec::Encode; + + let event = + frame_system::Event::::ExtrinsicSuccess { dispatch_info: Default::default() }; + assert_eq!(RuntimeEvent::from(event).encode()[0], 30); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 31); + + let event = module2::Event::A; + assert_eq!(RuntimeEvent::from(event).encode()[0], 32); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 33); + + let event = nested::module3::Event::A; + assert_eq!(RuntimeEvent::from(event).encode()[0], 34); + + let event = module3::Event::A; + assert_eq!(RuntimeEvent::from(event).encode()[0], 35); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 4); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 1); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 2); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 12); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 13); +} + +#[test] +fn call_codec() { + use codec::Encode; + assert_eq!(RuntimeCall::System(frame_system::Call::remark { remark: vec![1] }).encode()[0], 30); + assert_eq!(RuntimeCall::Module1_1(module1::Call::fail {}).encode()[0], 31); + assert_eq!(RuntimeCall::Module2(module2::Call::fail {}).encode()[0], 32); + assert_eq!(RuntimeCall::Module1_2(module1::Call::fail {}).encode()[0], 33); + assert_eq!(RuntimeCall::NestedModule3(nested::module3::Call::fail {}).encode()[0], 34); + assert_eq!(RuntimeCall::Module3(module3::Call::fail {}).encode()[0], 35); + assert_eq!(RuntimeCall::Module1_4(module1::Call::fail {}).encode()[0], 3); + assert_eq!(RuntimeCall::Module1_6(module1::Call::fail {}).encode()[0], 1); + assert_eq!(RuntimeCall::Module1_7(module1::Call::fail {}).encode()[0], 2); + assert_eq!(RuntimeCall::Module1_8(module1::Call::fail {}).encode()[0], 12); + assert_eq!(RuntimeCall::Module1_9(module1::Call::fail {}).encode()[0], 13); +} + +#[test] +fn call_compact_attr() { + use codec::Encode; + let call: module3::Call = module3::Call::aux_1 { data: 1 }; + let encoded = call.encode(); + assert_eq!(2, encoded.len()); + assert_eq!(vec![1, 4], encoded); + + let call: module3::Call = module3::Call::aux_2 { data: 1, data2: 2 }; + let encoded = call.encode(); + assert_eq!(6, encoded.len()); + assert_eq!(vec![2, 1, 0, 0, 0, 8], encoded); +} + +#[test] +fn call_encode_is_correct_and_decode_works() { + use codec::{Decode, Encode}; + let call: module3::Call = module3::Call::fail {}; + let encoded = call.encode(); + assert_eq!(vec![0], encoded); + let decoded = module3::Call::::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded, call); + + let call: module3::Call = module3::Call::aux_3 { data: 32, data2: "hello".into() }; + let encoded = call.encode(); + assert_eq!(vec![3, 32, 0, 0, 0, 20, 104, 101, 108, 108, 111], encoded); + let decoded = module3::Call::::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded, call); +} + +#[test] +fn call_weight_should_attach_to_call_enum() { + use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, + weights::Weight, + }; + // operational. + assert_eq!( + module3::Call::::operational {}.get_dispatch_info(), + DispatchInfo { + weight: Weight::from_parts(5, 0), + class: DispatchClass::Operational, + pays_fee: Pays::Yes + }, + ); + // custom basic + assert_eq!( + module3::Call::::aux_4 {}.get_dispatch_info(), + DispatchInfo { + weight: Weight::from_parts(3, 0), + class: DispatchClass::Normal, + pays_fee: Pays::Yes + }, + ); +} + +#[test] +fn call_name() { + use frame_support::traits::GetCallName; + let name = module3::Call::::aux_4 {}.get_call_name(); + assert_eq!("aux_4", name); +} + +#[test] +fn call_metadata() { + use frame_support::traits::{CallMetadata, GetCallMetadata}; + let call = RuntimeCall::Module3(module3::Call::::aux_4 {}); + let metadata = call.get_call_metadata(); + let expected = CallMetadata { function_name: "aux_4".into(), pallet_name: "Module3".into() }; + assert_eq!(metadata, expected); +} + +#[test] +fn get_call_names() { + use frame_support::traits::GetCallName; + let call_names = module3::Call::::get_call_names(); + assert_eq!(["fail", "aux_1", "aux_2", "aux_3", "aux_4", "operational"], call_names); +} + +#[test] +fn get_module_names() { + use frame_support::traits::GetCallMetadata; + let module_names = RuntimeCall::get_module_names(); + assert_eq!( + [ + "Module1_6", + "Module1_7", + "Module1_4", + "Module1_8", + "Module1_9", + "System", + "Module1_1", + "Module2", + "Module1_2", + "NestedModule3", + "Module3", + ], + module_names + ); +} + +#[test] +fn call_subtype_conversion() { + use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; + let call = RuntimeCall::Module3(module3::Call::::fail {}); + let subcall: Option<&CallableCallFor> = call.is_sub_type(); + let subcall_none: Option<&CallableCallFor> = call.is_sub_type(); + assert_eq!(Some(&module3::Call::::fail {}), subcall); + assert_eq!(None, subcall_none); + + let from = RuntimeCall::from(subcall.unwrap().clone()); + assert_eq!(from, call); +} + +#[test] +fn test_metadata() { + use frame_metadata::{ + v14::{StorageEntryType::Plain, *}, + *, + }; + use scale_info::meta_type; + use sp_core::Encode; + use sp_metadata_ir::StorageEntryModifierIR::Optional; + + fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + doc + } + } + + let pallets = vec![ + PalletMetadata { + name: "Module1_6", + storage:None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 1, + }, + PalletMetadata { + name: "Module1_7", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 2, + }, + PalletMetadata { + name: "Module1_4", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 3, + }, + PalletMetadata { + name: "Module1_5", + storage: None, + calls: None, + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 4, + }, + PalletMetadata { + name: "Module1_3", + storage: None, + calls: None, + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 6, + }, + PalletMetadata { + name: "Module1_8", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 12, + }, + PalletMetadata { + name: "Module1_9", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 13, + }, + PalletMetadata { + name: "System", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![ + PalletConstantMetadata { + name: "BlockWeights", + ty: meta_type::(), + value: BlockWeights::default().encode(), + docs: maybe_docs(vec![" Block & extrinsics weights: base values and limits."]), + }, + PalletConstantMetadata { + name: "BlockLength", + ty: meta_type::(), + value: BlockLength::default().encode(), + docs: maybe_docs(vec![" The maximum length of a block (in bytes)."]), + }, + PalletConstantMetadata { + name: "BlockHashCount", + ty: meta_type::(), + value: 10u64.encode(), + docs: maybe_docs(vec![" Maximum number of block number to block hash mappings to keep (oldest pruned first)."]), + }, + PalletConstantMetadata { + name: "DbWeight", + ty: meta_type::(), + value: RuntimeDbWeight::default().encode(), + docs: maybe_docs(vec![" The weight of runtime database operations the runtime can invoke.",]), + }, + PalletConstantMetadata { + name: "Version", + ty: meta_type::(), + value: RuntimeVersion::default().encode(), + docs: maybe_docs(vec![ " Get the chain's in-code version."]), + }, + PalletConstantMetadata { + name: "SS58Prefix", + ty: meta_type::(), + value: 0u16.encode(), + docs: maybe_docs(vec![ + " The designated SS58 prefix of this chain.", + "", + " This replaces the \"ss58Format\" property declared in the chain spec. Reason is", + " that the runtime should know about the prefix in order to make use of it as", + " an identifier of the chain.", + ]), + }, + ], + error: Some(meta_type::>().into()), + index: 30, + }, + PalletMetadata { + name: "Module1_1", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 31, + }, + PalletMetadata { + name: "Module2", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 32, + }, + PalletMetadata { + name: "Module1_2", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 33, + }, + PalletMetadata { + name: "NestedModule3", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 34, + }, + PalletMetadata { + name: "Module3", + storage: Some(PalletStorageMetadata { + prefix: "Module3", + entries: vec![ + StorageEntryMetadata { + name: "Storage", + modifier: Optional.into(), + ty: Plain(meta_type::().into()), + default: vec![0], + docs: vec![], + }, + ] + }), + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 35, + }, + ]; + + let extrinsic = ExtrinsicMetadata { + ty: meta_type::(), + version: 4, + signed_extensions: vec![SignedExtensionMetadata { + identifier: "UnitTransactionExtension", + ty: meta_type::<()>(), + additional_signed: meta_type::<()>(), + }], + }; + + let expected_metadata: RuntimeMetadataPrefixed = + RuntimeMetadataLastVersion::new(pallets, extrinsic, meta_type::()).into(); + let actual_metadata = Runtime::metadata(); + + pretty_assertions::assert_eq!(actual_metadata, expected_metadata); +} + +#[test] +fn pallet_in_runtime_is_correct() { + assert_eq!(PalletInfo::index::().unwrap(), 30); + assert_eq!(PalletInfo::name::().unwrap(), "System"); + assert_eq!(PalletInfo::module_name::().unwrap(), "frame_system"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 31); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_1"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 32); + assert_eq!(PalletInfo::name::().unwrap(), "Module2"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module2"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 33); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_2"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 34); + assert_eq!(PalletInfo::name::().unwrap(), "NestedModule3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "nested::module3"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 35); + assert_eq!(PalletInfo::name::().unwrap(), "Module3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "self::module3"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 6); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 3); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_4"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 4); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_5"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 1); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_6"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 2); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_7"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 12); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_8"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 13); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_9"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); +} + +#[test] +fn test_validate_unsigned() { + use frame_support::pallet_prelude::*; + + let call = RuntimeCall::NestedModule3(nested::module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!(validity, TransactionValidityError::Invalid(InvalidTransaction::Call)); + + let call = RuntimeCall::Module3(module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!( + validity, + TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator) + ); +} diff --git a/substrate/frame/support/test/tests/construct_runtime.rs b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs similarity index 89% rename from substrate/frame/support/test/tests/construct_runtime.rs rename to substrate/frame/support/test/tests/runtime_legacy_ordering.rs index b8341b25cb0985915706ccb68b870474118d33cb..38875517018cdc8cd6cd05016ce776155bc93e7d 100644 --- a/substrate/frame/support/test/tests/construct_runtime.rs +++ b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs @@ -30,7 +30,7 @@ use scale_info::TypeInfo; use sp_core::{sr25519, ConstU64}; use sp_runtime::{ generic, - traits::{BlakeTwo256, Verify}, + traits::{BlakeTwo256, ValidateUnsigned, Verify}, DispatchError, ModuleError, }; use sp_version::RuntimeVersion; @@ -176,6 +176,17 @@ mod nested { impl BuildGenesisConfig for GenesisConfig { fn build(&self) {} } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } } } @@ -247,6 +258,20 @@ pub mod module3 { impl BuildGenesisConfig for GenesisConfig { fn build(&self) {} } + + #[pallet::storage] + pub type Storage = StorageValue<_, u32>; + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } } pub type BlockNumber = u64; @@ -256,24 +281,64 @@ pub type Header = generic::Header; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type Block = generic::Block; -frame_support::construct_runtime!( - pub struct Runtime - { - System: frame_system::{Pallet, Call, Event, Origin} = 30, - Module1_1: module1::::{Pallet, Call, Storage, Event, Origin}, - Module2: module2::{Pallet, Call, Storage, Event, Origin}, - Module1_2: module1::::{Pallet, Call, Storage, Event, Origin}, - NestedModule3: nested::module3::{Pallet, Call, Config, Storage, Event, Origin}, - Module3: self::module3::{Pallet, Call, Config, Storage, Event, Origin}, - Module1_3: module1::::{Pallet, Storage, Event } = 6, - Module1_4: module1::::{Pallet, Call, Event } = 3, - Module1_5: module1::::{Pallet, Event}, - Module1_6: module1::::{Pallet, Call, Storage, Event, Origin} = 1, - Module1_7: module1::::{Pallet, Call, Storage, Event, Origin}, - Module1_8: module1::::{Pallet, Call, Storage, Event, Origin} = 12, - Module1_9: module1::::{Pallet, Call, Storage, Event, Origin}, - } -); +#[frame_support::runtime(legacy_ordering)] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(30)] + pub type System = frame_system + Pallet + Call + Event + Origin; + + #[runtime::pallet_index(31)] + pub type Module1_1 = module1; + + #[runtime::pallet_index(32)] + pub type Module2 = module2; + + #[runtime::pallet_index(33)] + pub type Module1_2 = module1; + + #[runtime::pallet_index(34)] + pub type NestedModule3 = nested::module3; + + #[runtime::pallet_index(35)] + #[runtime::disable_unsigned] + pub type Module3 = self::module3; + + #[runtime::pallet_index(6)] + #[runtime::disable_call] + pub type Module1_3 = module1; + + #[runtime::pallet_index(3)] + pub type Module1_4 = module1; + + #[runtime::pallet_index(4)] + #[runtime::disable_call] + pub type Module1_5 = module1; + + #[runtime::pallet_index(1)] + pub type Module1_6 = module1; + + #[runtime::pallet_index(2)] + pub type Module1_7 = module1; + + #[runtime::pallet_index(12)] + pub type Module1_8 = module1; + + #[runtime::pallet_index(13)] + pub type Module1_9 = module1; +} #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { @@ -636,9 +701,13 @@ fn call_subtype_conversion() { #[test] fn test_metadata() { - use frame_metadata::{v14::*, *}; + use frame_metadata::{ + v14::{StorageEntryType::Plain, *}, + *, + }; use scale_info::meta_type; use sp_core::Encode; + use sp_metadata_ir::StorageEntryModifierIR::Optional; fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { if cfg!(feature = "no-metadata-docs") { @@ -703,7 +772,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_1", - storage: Some(PalletStorageMetadata { prefix: "Module1_1", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -712,7 +781,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module2", - storage: Some(PalletStorageMetadata { prefix: "Module2", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -721,7 +790,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_2", - storage: Some(PalletStorageMetadata { prefix: "Module1_2", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -730,7 +799,7 @@ fn test_metadata() { }, PalletMetadata { name: "NestedModule3", - storage: Some(PalletStorageMetadata { prefix: "NestedModule3", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -739,7 +808,18 @@ fn test_metadata() { }, PalletMetadata { name: "Module3", - storage: Some(PalletStorageMetadata { prefix: "Module3", entries: vec![] }), + storage: Some(PalletStorageMetadata { + prefix: "Module3", + entries: vec![ + StorageEntryMetadata { + name: "Storage", + modifier: Optional.into(), + ty: Plain(meta_type::().into()), + default: vec![0], + docs: vec![], + }, + ] + }), calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -748,7 +828,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_3", - storage: Some(PalletStorageMetadata { prefix: "Module1_3", entries: vec![] }), + storage: None, calls: None, event: Some(meta_type::>().into()), constants: vec![], @@ -775,7 +855,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_6", - storage: Some(PalletStorageMetadata { prefix: "Module1_6", entries: vec![] }), + storage:None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -784,7 +864,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_7", - storage: Some(PalletStorageMetadata { prefix: "Module1_7", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -793,7 +873,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_8", - storage: Some(PalletStorageMetadata { prefix: "Module1_8", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -802,7 +882,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_9", - storage: Some(PalletStorageMetadata { prefix: "Module1_9", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -815,7 +895,7 @@ fn test_metadata() { ty: meta_type::(), version: 4, signed_extensions: vec![SignedExtensionMetadata { - identifier: "UnitSignedExtension", + identifier: "UnitTransactionExtension", ty: meta_type::<()>(), additional_signed: meta_type::<()>(), }], @@ -895,3 +975,19 @@ fn pallet_in_runtime_is_correct() { assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); assert!(PalletInfo::crate_version::().is_some()); } + +#[test] +fn test_validate_unsigned() { + use frame_support::pallet_prelude::*; + + let call = RuntimeCall::NestedModule3(nested::module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!(validity, TransactionValidityError::Invalid(InvalidTransaction::Call)); + + let call = RuntimeCall::Module3(module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!( + validity, + TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator) + ); +} diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index bb7f7d2822e7cf1a15c41de1ca47686dd8440bfc..40e70b219ba94062af2bb75391628c73bc3a3233 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -101,7 +101,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } @@ -200,8 +200,8 @@ fn runtime_metadata() { name: "header", ty: meta_type::<&::Header>(), }], - output: meta_type::<()>(), - docs: maybe_docs(vec![" Initialize a block with the given header."]), + output: meta_type::(), + docs: maybe_docs(vec![" Initialize a block with the given header and return the runtime executive mode."]), }, ], docs: maybe_docs(vec![ diff --git a/substrate/frame/support/test/tests/runtime_ui.rs b/substrate/frame/support/test/tests/runtime_ui.rs new file mode 100644 index 0000000000000000000000000000000000000000..dbe150f38ed6a3b6a45ac58e288b65c397c671f9 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui.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. + +#[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] +#[test] +fn ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("SKIP_WASM_BUILD", "1"); + + // Deny all warnings since we emit warnings as part of a Runtime's UI. + std::env::set_var("RUSTFLAGS", "--deny warnings"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/runtime_ui/*.rs"); + t.pass("tests/runtime_ui/pass/*.rs"); +} diff --git a/substrate/frame/contracts/fixtures/contracts/invalid_contract_no_call.rs b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.rs similarity index 80% rename from substrate/frame/contracts/fixtures/contracts/invalid_contract_no_call.rs rename to substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.rs index 13af3eb22b1f5fd10c3e2b60061d3f7a6cc37c94..eb5868090418a3e10320cc4394c565d054926710 100644 --- a/substrate/frame/contracts/fixtures/contracts/invalid_contract_no_call.rs +++ b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.rs @@ -14,12 +14,8 @@ // 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. -//! Valid module but missing the call function -#![no_std] -#![no_main] -extern crate common; +#[frame_support::runtime] +fn construct_runtime() {} -#[no_mangle] -#[polkavm_derive::polkavm_export] -pub extern "C" fn deploy() {} +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.stderr b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.stderr new file mode 100644 index 0000000000000000000000000000000000000000..7c2f0d1f1699502c8847f308e7978d988552cc47 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.stderr @@ -0,0 +1,5 @@ +error: expected `mod` + --> tests/runtime_ui/can_only_be_attached_to_mod.rs:19:1 + | +19 | fn construct_runtime() {} + | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.rs similarity index 58% rename from substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs rename to substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.rs index 55dd315fb297cdf55802e25f48b53364b394dd3d..648812b52c4fe8b307b93a4e702b1ff98547e613 100644 --- a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.rs @@ -17,26 +17,27 @@ #[frame_support::pallet] mod pallet { - use frame_support::pallet_prelude::Hooks; - use frame_system::pallet_prelude::BlockNumberFor; - use frame_support::pallet_prelude::StorageValue; + #[pallet::config] + pub trait Config: frame_system::Config {} - #[pallet::config] - pub trait Config: frame_system::Config {} + #[pallet::pallet] + pub struct Pallet(_); - #[pallet::pallet] - #[pallet::generate_store(pub trait Store)] - pub struct Pallet(core::marker::PhantomData); + #[pallet::call] + impl Pallet {} +} - #[pallet::hooks] - impl Hooks> for Pallet {} +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; - #[pallet::call] - impl Pallet {} + #[runtime::pallet_index(0)] + pub type System = frame_system; - #[pallet::storage] - type Foo = StorageValue<_, u8>; + #[runtime::pallet_index(0)] + pub type Pallet = pallet; } -fn main() { -} +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.stderr b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.stderr new file mode 100644 index 0000000000000000000000000000000000000000..8963c5d3f265d1efb6be5fb1b820285f86d4245b --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.stderr @@ -0,0 +1,11 @@ +error: Pallet indices are conflicting: Both pallets System and Pallet are at index 0 + --> tests/runtime_ui/conflicting_pallet_index.rs:37:14 + | +37 | pub type System = frame_system; + | ^^^^^^ + +error: Pallet indices are conflicting: Both pallets System and Pallet are at index 0 + --> tests/runtime_ui/conflicting_pallet_index.rs:40:14 + | +40 | pub type Pallet = pallet; + | ^^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.rs b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.rs new file mode 100644 index 0000000000000000000000000000000000000000..c68f9a8082b47fcd3bf306187c8f511392baf95b --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.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 { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet {} +} + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + + #[runtime::pallet_index(1)] + pub type System = pallet; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.stderr b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.stderr new file mode 100644 index 0000000000000000000000000000000000000000..c250c24e3e704136e380f91b0e74eb3c4fd4d7b7 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.stderr @@ -0,0 +1,11 @@ +error: Two pallets with the same name! + --> tests/runtime_ui/conflicting_pallet_name.rs:37:14 + | +37 | pub type System = frame_system; + | ^^^^^^ + +error: Two pallets with the same name! + --> tests/runtime_ui/conflicting_pallet_name.rs:40:14 + | +40 | pub type System = pallet; + | ^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.rs similarity index 76% rename from substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs rename to substrate/frame/support/test/tests/runtime_ui/invalid_attribute.rs index 72ad7896dfec572014cb6b10dcc39bc417a275b6..5df2491cb24ba15000324efdb853e7e38af1b774 100644 --- a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.rs @@ -15,14 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[frame_support::pallet] -mod pallet { - #[pallet::config] - pub trait Config: frame_system::Config {} +#[frame_support::runtime(dummy)] +mod runtime { - #[pallet::pallet] - #[pallet::generate_store(trait Store)] - pub struct Pallet(core::marker::PhantomData); } fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.stderr b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e13552413c00a094bf37cb54f0f21db4e0030231 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.stderr @@ -0,0 +1,5 @@ +error: Invalid runtime macro call: unexpected attribute. Macro call must be bare, such as `#[frame_support::runtime]` or `#[runtime]`, or must specify the `legacy_ordering` attribute, such as `#[frame_support::runtime(legacy_ordering)]` or #[runtime(legacy_ordering)]. + --> tests/runtime_ui/invalid_attribute.rs:18:26 + | +18 | #[frame_support::runtime(dummy)] + | ^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.rs b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.rs new file mode 100644 index 0000000000000000000000000000000000000000..de89bb60224fd8fd77ac7c68f62353c6e51aafe6 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.rs @@ -0,0 +1,28 @@ +// 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::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; + + #[runtime::pallet_index("0")] + pub type System = frame_system; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.stderr b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.stderr new file mode 100644 index 0000000000000000000000000000000000000000..1fbd086ddbe7e243dff03df1a7e91dc9d911964d --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.stderr @@ -0,0 +1,5 @@ +error: expected integer literal + --> tests/runtime_ui/invalid_pallet_index.rs:24:29 + | +24 | #[runtime::pallet_index("0")] + | ^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.rs b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.rs new file mode 100644 index 0000000000000000000000000000000000000000..89ba2f23bb1afbde0ff2936acd7910b2b761fff7 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.rs @@ -0,0 +1,25 @@ +// 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::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeInfo)] + pub struct Runtime; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.stderr b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.stderr new file mode 100644 index 0000000000000000000000000000000000000000..0b128c3dd4579ba93f7950f42f0ff97440eadd38 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.stderr @@ -0,0 +1,5 @@ +error: expected one of: `RuntimeCall`, `RuntimeEvent`, `RuntimeError`, `RuntimeOrigin`, `RuntimeFreezeReason`, `RuntimeHoldReason`, `RuntimeSlashReason`, `RuntimeLockId`, `RuntimeTask` + --> tests/runtime_ui/invalid_runtime_type_derive.rs:21:23 + | +21 | #[runtime::derive(RuntimeInfo)] + | ^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime.rs b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.rs new file mode 100644 index 0000000000000000000000000000000000000000..c5febbe52876008e8a0537fece2b85806d6b323d --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.rs @@ -0,0 +1,21 @@ +// 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::runtime] +mod runtime {} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime.stderr b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.stderr new file mode 100644 index 0000000000000000000000000000000000000000..9790c5dbc1a9a3f16269c4adea0b2c558bf13c08 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.stderr @@ -0,0 +1,5 @@ +error: Missing Runtime. Please add a struct inside the module and annotate it with `#[runtime::runtime]` + --> tests/runtime_ui/missing_runtime.rs:19:1 + | +19 | mod runtime {} + | ^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.rs b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.rs new file mode 100644 index 0000000000000000000000000000000000000000..c3fb0fd454f023fda6b442a5411087caea172c17 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.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. + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + pub struct Runtime; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.stderr b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.stderr new file mode 100644 index 0000000000000000000000000000000000000000..1a8deebe5497c9c463f52140b8893b9c12529e52 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.stderr @@ -0,0 +1,5 @@ +error: Missing Runtime Types. Please annotate the runtime struct with `#[runtime::derive]` + --> tests/runtime_ui/missing_runtime_types_derive.rs:19:1 + | +19 | mod runtime { + | ^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.rs b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.rs new file mode 100644 index 0000000000000000000000000000000000000000..f9a15fcf992a459313495562316cfa7c0ff01fde --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.rs @@ -0,0 +1,25 @@ +// 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::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.stderr b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.stderr new file mode 100644 index 0000000000000000000000000000000000000000..dc3ac4cd5d560d208da05556f256498fd838da37 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.stderr @@ -0,0 +1,5 @@ +error: `System` pallet declaration is missing. Please add this line: `pub type System = frame_system;` + --> tests/runtime_ui/missing_system_pallet.rs:19:5 + | +19 | mod runtime { + | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs b/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs new file mode 100644 index 0000000000000000000000000000000000000000..514f150180153692caf55ba9b3ecb171ca4e1a2a --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/pass/basic.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. + +use frame_support::derive_impl; + +pub type Block = frame_system::mocking::MockBlock; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; +} + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall, RuntimeEvent, RuntimeOrigin, RuntimeError, RuntimeTask)] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/runtime_struct.rs b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.rs new file mode 100644 index 0000000000000000000000000000000000000000..bfa2fb75f04b8ce04d5aabdc83e36414f2dd3c00 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.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. + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + pub enum Runtime {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/runtime_struct.stderr b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.stderr new file mode 100644 index 0000000000000000000000000000000000000000..04192bcf7f192c833893f8a57536961fcd9b32ca --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.stderr @@ -0,0 +1,5 @@ +error: Invalid runtime::runtime, expected struct definition + --> tests/runtime_ui/runtime_struct.rs:21:5 + | +21 | pub enum Runtime {} + | ^^^ diff --git a/substrate/frame/support/test/tests/storage_transaction.rs b/substrate/frame/support/test/tests/storage_transaction.rs index c47743308609850ae480f3194773a76c36bbba58..f1489a8b0a6b3d9696249bc006d5fd10c13e36c9 100644 --- a/substrate/frame/support/test/tests/storage_transaction.rs +++ b/substrate/frame/support/test/tests/storage_transaction.rs @@ -41,7 +41,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub (super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index d4094601314873671a1c749c72b91a27452b5702..416969e9c4776aa161dde65281b7847156bdbf56 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -18,9 +18,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"] } +serde = { features = ["alloc", "derive"], workspace = true } frame-support = { path = "../support", default-features = false } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/system/benchmarking/src/extensions.rs b/substrate/frame/system/benchmarking/src/extensions.rs new file mode 100644 index 0000000000000000000000000000000000000000..bfc3b4343a6ca162cbbe65b79856e4b8a5a6f4f7 --- /dev/null +++ b/substrate/frame/system/benchmarking/src/extensions.rs @@ -0,0 +1,213 @@ +// 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 frame_benchmarking::{account, v2::*, BenchmarkError}; +use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, + weights::Weight, +}; +use frame_system::{ + pallet_prelude::*, CheckGenesis, CheckMortality, CheckNonZeroSender, CheckNonce, + CheckSpecVersion, CheckTxVersion, CheckWeight, Config, Pallet as System, RawOrigin, +}; +use sp_runtime::{ + generic::Era, + traits::{AsSystemOriginSigner, DispatchTransaction, Dispatchable, Get}, +}; +use sp_std::prelude::*; + +pub struct Pallet(System); + +#[benchmarks(where + T: Send + Sync, + T::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + Clone) +] +mod benchmarks { + use super::*; + + #[benchmark] + fn check_genesis() -> Result<(), BenchmarkError> { + let len = 0_usize; + let caller = account("caller", 0, 0); + let info = DispatchInfo { weight: Weight::zero(), ..Default::default() }; + let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + + #[block] + { + CheckGenesis::::new() + .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) + .unwrap() + .unwrap(); + } + + Ok(()) + } + + #[benchmark] + fn check_mortality() -> 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 { + weight: Weight::from_parts(100, 0), + class: DispatchClass::Normal, + ..Default::default() + }; + let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + + #[block] + { + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| 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 { 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, |_| 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 { 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, |_| { + 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 { 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, |_| 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 { 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, |_| 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 info = DispatchInfo { + weight: Weight::from_parts(base_extrinsic.ref_time() * 5, 0), + 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, |_| Ok(post_info)) + .unwrap() + .unwrap(); + } + + assert_eq!( + System::::block_weight().total(), + initial_block_weight + base_extrinsic + post_info.actual_weight.unwrap(), + ); + 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 18bfb85f52dfd4c2b6a5c8a57e78494d97fbdeeb..c9f0869d3bc8945e9af1be6bf38bd5eb8447e4ea 100644 --- a/substrate/frame/system/benchmarking/src/lib.rs +++ b/substrate/frame/system/benchmarking/src/lib.rs @@ -21,13 +21,14 @@ #![cfg(feature = "runtime-benchmarks")] use codec::Encode; -use frame_benchmarking::{impl_benchmark_test_suite, v2::*}; +use frame_benchmarking::v2::*; use frame_support::{dispatch::DispatchClass, storage, traits::Get}; use frame_system::{Call, Pallet as System, RawOrigin}; use sp_core::storage::well_known_keys; use sp_runtime::traits::Hash; use sp_std::{prelude::*, vec}; +pub mod extensions; mod mock; pub struct Pallet(System); diff --git a/substrate/frame/system/benchmarking/src/mock.rs b/substrate/frame/system/benchmarking/src/mock.rs index edbf74a9a51ac9bd90ee65f208c7d96be08430e3..1f84dd530040619f4b902242edf29002f383c073 100644 --- a/substrate/frame/system/benchmarking/src/mock.rs +++ b/substrate/frame/system/benchmarking/src/mock.rs @@ -57,6 +57,7 @@ impl frame_system::Config for Test { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); + type ExtensionsWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; diff --git a/substrate/frame/system/src/extensions/check_genesis.rs b/substrate/frame/system/src/extensions/check_genesis.rs index 76a711a823e7d7a4b1092d9220b846584b21603f..3f11f745cd9b7c509a6827100acae66413c80e5d 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, TransactionExtensionBase, Zero}, transaction_validity::TransactionValidityError, }; @@ -46,30 +47,26 @@ impl sp_std::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(sp_std::marker::PhantomData) } } -impl SignedExtension for CheckGenesis { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = T::Hash; - type Pre = (); +impl TransactionExtensionBase 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(|_| ()) + fn weight(&self) -> sp_weights::Weight { + ::check_genesis() } } +impl TransactionExtension + for CheckGenesis +{ + type Val = (); + type Pre = (); + impl_tx_ext_default!(T::RuntimeCall; Context; validate prepare); +} diff --git a/substrate/frame/system/src/extensions/check_mortality.rs b/substrate/frame/system/src/extensions/check_mortality.rs index 148dfd4aad471b8a51aa3106581531b17090c20a..deb44880d6441429cdd1513bdc4ac0fbfc6c0421 100644 --- a/substrate/frame/system/src/extensions/check_mortality.rs +++ b/substrate/frame/system/src/extensions/check_mortality.rs @@ -20,10 +20,12 @@ use codec::{Decode, Encode}; 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, TransactionExtensionBase, + ValidateResult, }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; /// Check for transaction mortality. @@ -54,29 +56,11 @@ impl sp_std::fmt::Debug for CheckMortality { } } -impl SignedExtension for CheckMortality { - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = T::Hash; - type Pre = (); +impl TransactionExtensionBase 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) { @@ -85,16 +69,38 @@ impl SignedExtension for CheckMortality { Ok(>::block_hash(n)) } } + fn weight(&self) -> sp_weights::Weight { + ::check_mortality() + } +} +impl TransactionExtension + for CheckMortality +{ + type Pre = (); + type Val = (); - 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, + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> 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; Context; prepare); } #[cfg(test)] @@ -106,23 +112,21 @@ mod tests { weights::Weight, }; use sp_core::H256; + use sp_runtime::traits::DispatchTransaction; #[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()); }) } @@ -142,7 +146,10 @@ 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).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 92eed60fc66b53dec19a86c1fac20f1af8ff4d7b..115ffac9b038a722c404cb714442306dc704a75d 100644 --- a/substrate/frame/system/src/extensions/check_non_zero_sender.rs +++ b/substrate/frame/system/src/extensions/check_non_zero_sender.rs @@ -17,13 +17,14 @@ use crate::Config; use codec::{Decode, Encode}; -use frame_support::{dispatch::DispatchInfo, DefaultNoBound}; +use frame_support::{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::{ + transaction_extension::TransactionExtensionBase, DispatchInfoOf, TransactionExtension, }, + transaction_validity::InvalidTransaction, }; use sp_std::{marker::PhantomData, prelude::*}; @@ -45,66 +46,82 @@ impl sp_std::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(sp_std::marker::PhantomData) } } -impl SignedExtension for CheckNonZeroSender -where - T::RuntimeCall: Dispatchable, -{ - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); +impl TransactionExtensionBase for CheckNonZeroSender { const IDENTIFIER: &'static str = "CheckNonZeroSender"; - - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) + type Implicit = (); + fn weight(&self) -> sp_weights::Weight { + ::check_non_zero_sender() } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) - } - +} +impl TransactionExtension + for CheckNonZeroSender +{ + type Val = (); + type Pre = (); 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)) + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> sp_runtime::traits::ValidateResult { + if let Some(who) = origin.as_system_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; Context; 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::DispatchTransaction, 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) + .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 + )); + }) + } + + #[test] + fn unsigned_origin_works() { + new_test_ext().execute_with(|| { + let info = DispatchInfo::default(); + let len = 0_usize; + assert_ok!(CheckNonZeroSender::::new().validate_only( + None.into(), + CALL, + &info, + len + )); }) } } diff --git a/substrate/frame/system/src/extensions/check_nonce.rs b/substrate/frame/system/src/extensions/check_nonce.rs index 7504a814aef13b0230e1067c0d95e0104ad74275..ead9d9f7c8177ca1392b092b9418b3b2ae0b93ea 100644 --- a/substrate/frame/system/src/extensions/check_nonce.rs +++ b/substrate/frame/system/src/extensions/check_nonce.rs @@ -15,16 +15,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::Config; +use crate::{AccountInfo, Config}; use codec::{Decode, Encode}; use frame_support::dispatch::DispatchInfo; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero}, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, One, TransactionExtension, + TransactionExtensionBase, ValidateResult, Zero, + }, transaction_validity::{ - InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError, - ValidTransaction, + InvalidTransaction, TransactionLongevity, TransactionValidityError, ValidTransaction, }, + Saturating, }; use sp_std::vec; @@ -58,75 +61,78 @@ impl sp_std::fmt::Debug for CheckNonce { } } -impl SignedExtension for CheckNonce +impl TransactionExtensionBase for CheckNonce { + const IDENTIFIER: &'static str = "CheckNonce"; + type Implicit = (); + fn weight(&self) -> sp_weights::Weight { + ::check_nonce() + } +} +impl TransactionExtension for CheckNonce where T::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, { - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); + type Val = Option<(T::AccountId, AccountInfo)>; type Pre = (); - const IDENTIFIER: &'static str = "CheckNonce"; - - fn additional_signed(&self) -> sp_std::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 validate( &self, - who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> ValidateResult { + let Some(who) = origin.as_system_origin_signer() else { + return Ok((Default::default(), None, 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.clone(), self.0))]; let requires = if account.nonce < self.0 { - vec![Encode::encode(&(who, self.0 - One::one()))] + vec![Encode::encode(&(who.clone(), 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, Some((who.clone(), account)), origin)) + } + + fn prepare( + self, + val: Self::Val, + _origin: &T::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + _context: &Context, + ) -> Result { + let Some((who, mut account)) = val else { return Ok(()) }; + // `self.0 < account.nonce` already checked in `validate`. + if self.0 > account.nonce { + return Err(InvalidTransaction::Future.into()) + } + account.nonce.saturating_inc(); + crate::Account::::insert(who, account); + Ok(()) } } @@ -134,7 +140,8 @@ where mod tests { use super::*; use crate::mock::{new_test_ext, Test, CALL}; - use frame_support::{assert_noop, assert_ok}; + use frame_support::assert_ok; + use sp_runtime::traits::DispatchTransaction; #[test] fn signed_ext_check_nonce_works() { @@ -152,22 +159,33 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; // stale - assert_noop!( - CheckNonce::(0).validate(&1, CALL, &info, len), - InvalidTransaction::Stale + assert_eq!( + CheckNonce::(0) + .validate_only(Some(1).into(), CALL, &info, len,) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Stale) ); - assert_noop!( - CheckNonce::(0).pre_dispatch(&1, CALL, &info, len), - InvalidTransaction::Stale + assert_eq!( + CheckNonce::(0) + .validate_and_prepare(Some(1).into(), CALL, &info, len) + .unwrap_err(), + InvalidTransaction::Stale.into() ); // correct - assert_ok!(CheckNonce::(1).validate(&1, CALL, &info, len)); - assert_ok!(CheckNonce::(1).pre_dispatch(&1, CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate_only(Some(1).into(), CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate_and_prepare( + Some(1).into(), + CALL, + &info, + len + )); // future - assert_ok!(CheckNonce::(5).validate(&1, CALL, &info, len)); - assert_noop!( - CheckNonce::(5).pre_dispatch(&1, CALL, &info, len), - InvalidTransaction::Future + assert_ok!(CheckNonce::(5).validate_only(Some(1).into(), CALL, &info, len)); + assert_eq!( + CheckNonce::(5) + .validate_and_prepare(Some(1).into(), CALL, &info, len) + .unwrap_err(), + InvalidTransaction::Future.into() ); }) } @@ -198,20 +216,44 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; // Both providers and sufficients zero - assert_noop!( - CheckNonce::(1).validate(&1, CALL, &info, len), - InvalidTransaction::Payment + assert_eq!( + CheckNonce::(1) + .validate_only(Some(1).into(), CALL, &info, len) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Payment) ); - assert_noop!( - CheckNonce::(1).pre_dispatch(&1, CALL, &info, len), - InvalidTransaction::Payment + assert_eq!( + CheckNonce::(1) + .validate_and_prepare(Some(1).into(), CALL, &info, len) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Payment) ); // Non-zero providers - assert_ok!(CheckNonce::(1).validate(&2, CALL, &info, len)); - assert_ok!(CheckNonce::(1).pre_dispatch(&2, CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate_only(Some(2).into(), CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate_and_prepare( + Some(2).into(), + CALL, + &info, + len + )); // Non-zero sufficients - assert_ok!(CheckNonce::(1).validate(&3, CALL, &info, len)); - assert_ok!(CheckNonce::(1).pre_dispatch(&3, CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate_only(Some(3).into(), CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate_and_prepare( + Some(3).into(), + CALL, + &info, + len + )); + }) + } + + #[test] + fn unsigned_check_nonce_works() { + new_test_ext().execute_with(|| { + let info = DispatchInfo::default(); + let len = 0_usize; + assert_ok!(CheckNonce::(1).validate_only(None.into(), CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate_and_prepare(None.into(), CALL, &info, len)); }) } } diff --git a/substrate/frame/system/src/extensions/check_spec_version.rs b/substrate/frame/system/src/extensions/check_spec_version.rs index 24d5ef9cafb17b0dd8c1ac02fc127f7068cf6cca..3109708f48efe467b6c727c6813db2275b70c548 100644 --- a/substrate/frame/system/src/extensions/check_spec_version.rs +++ b/substrate/frame/system/src/extensions/check_spec_version.rs @@ -19,7 +19,8 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension}, + impl_tx_ext_default, + traits::{transaction_extension::TransactionExtensionBase, TransactionExtension}, transaction_validity::TransactionValidityError, }; @@ -46,30 +47,26 @@ impl sp_std::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(sp_std::marker::PhantomData) } } -impl SignedExtension for CheckSpecVersion { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = u32; - type Pre = (); +impl TransactionExtensionBase 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(|_| ()) + fn weight(&self) -> sp_weights::Weight { + ::check_spec_version() } } +impl TransactionExtension<::RuntimeCall, Context> + for CheckSpecVersion +{ + type Val = (); + type Pre = (); + impl_tx_ext_default!(::RuntimeCall; Context; 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 3f9d6a1903fe1d08d05266a46625aeacba3c273c..ee1d507e7bc83d8bd90f08d1fb04f7b67842a011 100644 --- a/substrate/frame/system/src/extensions/check_tx_version.rs +++ b/substrate/frame/system/src/extensions/check_tx_version.rs @@ -19,7 +19,8 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension}, + impl_tx_ext_default, + traits::{transaction_extension::TransactionExtensionBase, TransactionExtension}, transaction_validity::TransactionValidityError, }; @@ -46,29 +47,26 @@ impl sp_std::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(sp_std::marker::PhantomData) } } -impl SignedExtension for CheckTxVersion { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = u32; - type Pre = (); +impl TransactionExtensionBase 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(|_| ()) + fn weight(&self) -> sp_weights::Weight { + ::check_tx_version() } } +impl TransactionExtension<::RuntimeCall, Context> + for CheckTxVersion +{ + type Val = (); + type Pre = (); + impl_tx_ext_default!(::RuntimeCall; Context; validate prepare); +} diff --git a/substrate/frame/system/src/extensions/check_weight.rs b/substrate/frame/system/src/extensions/check_weight.rs index 70d1e75633278c665f4c06ca22f02a96668ef964..5c35acfb3f355c6784b4f6f9e2ca1269463346f0 100644 --- a/substrate/frame/system/src/extensions/check_weight.rs +++ b/substrate/frame/system/src/extensions/check_weight.rs @@ -23,9 +23,12 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, - transaction_validity::{InvalidTransaction, TransactionValidity, TransactionValidityError}, - DispatchResult, + traits::{ + DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension, + TransactionExtensionBase, ValidateResult, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError}, + DispatchResult, ValidTransaction, }; use sp_weights::Weight; @@ -100,39 +103,43 @@ 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 pre-dispatch checks. This can be applied to both signed and unsigned. + /// Do the validate checks. This can be applied to both signed and unsigned. /// - /// It checks and notes the new weight and length. - pub fn do_pre_dispatch( + /// 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<(), TransactionValidityError> { + ) -> Result<(ValidTransaction, u32), TransactionValidityError> { + // ignore the next length. If they return `Ok`, then it is below the limit. let next_len = Self::check_block_length(info, len)?; - let next_weight = Self::check_block_weight(info)?; + // 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)?; - crate::AllExtrinsicsLen::::put(next_len); - crate::BlockWeight::::put(next_weight); - Ok(()) + Ok((Default::default(), next_len)) } - /// Do the validate checks. This can be applied to both signed and unsigned. + /// Do the pre-dispatch 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)?; + /// It checks and notes the new weight and length. + pub fn do_prepare( + info: &DispatchInfoOf, + next_len: u32, + ) -> Result<(), TransactionValidityError> { + let next_weight = Self::check_block_weight(info)?; + // Extrinsic weight already checked in `validate`. - Ok(Default::default()) + crate::AllExtrinsicsLen::::put(next_len); + crate::BlockWeight::::put(next_weight); + Ok(()) } } @@ -201,62 +208,55 @@ where Ok(all_weight) } -impl SignedExtension for CheckWeight +impl TransactionExtensionBase for CheckWeight { + const IDENTIFIER: &'static str = "CheckWeight"; + type Implicit = (); + + fn weight(&self) -> Weight { + ::check_weight() + } +} +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"; - - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result<(), TransactionValidityError> { - Self::do_pre_dispatch(info, len) - } + type Val = u32; /* next block length */ fn validate( &self, - _who: &Self::AccountId, - _call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - Self::do_validate(info, len) - } - - fn pre_dispatch_unsigned( - _call: &Self::Call, - info: &DispatchInfoOf, + origin: T::RuntimeOrigin, + _call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> Result<(), TransactionValidityError> { - Self::do_pre_dispatch(info, len) + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> ValidateResult { + let (validity, next_len) = Self::do_validate(info, len)?; + Ok((validity, next_len, origin)) } - fn validate_unsigned( - _call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - Self::do_validate(info, len) + fn prepare( + self, + val: Self::Val, + _origin: &T::RuntimeOrigin, + _call: &T::RuntimeCall, + info: &DispatchInfoOf, + _len: usize, + _context: &Context, + ) -> Result { + Self::do_prepare(info, val) } fn post_dispatch( - _pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + _pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, _len: usize, _result: &DispatchResult, + _context: &Context, ) -> Result<(), TransactionValidityError> { let unspent = post_info.calc_unspent(info); if unspent.any_gt(Weight::zero()) { @@ -301,6 +301,7 @@ mod tests { AllExtrinsicsLen, BlockWeight, DispatchClass, }; use frame_support::{assert_err, assert_ok, dispatch::Pays, weights::Weight}; + use sp_runtime::traits::DispatchTransaction; use sp_std::marker::PhantomData; fn block_weights() -> crate::limits::BlockWeights { @@ -338,7 +339,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, next_len)); assert_eq!(System::block_weight().total(), Weight::MAX); assert!(System::block_weight().total().ref_time() > block_weight_limit().ref_time()); }); @@ -419,9 +421,11 @@ mod tests { 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, 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, 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. @@ -443,10 +447,12 @@ mod tests { 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, 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, 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)); }); @@ -469,16 +475,19 @@ mod tests { }; 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, 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, next_len)); // Not too much though assert_err!( - CheckWeight::::do_pre_dispatch(&dispatch_operational, len), + CheckWeight::::do_prepare(&dispatch_operational, next_len), InvalidTransaction::ExhaustsResources ); // Even with full block, validity of single transaction should be correct. @@ -503,21 +512,35 @@ 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) + .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 + )); // 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) + .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 + )); }) } @@ -528,7 +551,12 @@ 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, + ); if f { assert!(r.is_err()) } else { @@ -571,7 +599,12 @@ 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, + ); if f { assert!(r.is_err()) } else { @@ -604,18 +637,22 @@ 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) + .unwrap() + .0; assert_eq!( BlockWeight::::get().total(), info.weight + Weight::from_parts(256, 0) ); assert_ok!(CheckWeight::::post_dispatch( - Some(pre), + pre, &info, &post_info, len, - &Ok(()) + &Ok(()), + &() )); assert_eq!( BlockWeight::::get().total(), @@ -639,7 +676,10 @@ 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) + .unwrap() + .0; assert_eq!( BlockWeight::::get().total(), info.weight + @@ -648,11 +688,12 @@ mod tests { ); assert_ok!(CheckWeight::::post_dispatch( - Some(pre), + pre, &info, &post_info, len, - &Ok(()) + &Ok(()), + &() )); assert_eq!( BlockWeight::::get().total(), @@ -672,7 +713,12 @@ mod tests { // 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 + )); assert_eq!( System::block_weight().total(), weights.get(DispatchClass::Normal).base_extrinsic + weights.base_block @@ -696,9 +742,11 @@ mod tests { 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, 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, 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(())); diff --git a/substrate/frame/system/src/extensions/mod.rs b/substrate/frame/system/src/extensions/mod.rs index a88c9fbf96ebdac86d9c45a8e5b07020c3325bb0..d79104d224035450f9ca69ba7d4b502b9ff0289d 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 0000000000000000000000000000000000000000..0d2fcb15ee66e927bb21c159f5b5b7a3dcbb22f5 --- /dev/null +++ b/substrate/frame/system/src/extensions/weights.rs @@ -0,0 +1,196 @@ +// 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-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=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() -> 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: `54` + // Estimated: `3509` + // Minimum execution time: 3_876_000 picoseconds. + Weight::from_parts(4_160_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() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 6_296_000 picoseconds. + Weight::from_parts(6_523_000, 3509) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 449_000 picoseconds. + Weight::from_parts(527_000, 0) + } + /// 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: 5_689_000 picoseconds. + Weight::from_parts(6_000_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: 399_000 picoseconds. + Weight::from_parts(461_000, 0) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 390_000 picoseconds. + Weight::from_parts(439_000, 0) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1489` + // Minimum execution time: 4_375_000 picoseconds. + Weight::from_parts(4_747_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// 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: `54` + // Estimated: `3509` + // Minimum execution time: 3_876_000 picoseconds. + Weight::from_parts(4_160_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() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 6_296_000 picoseconds. + Weight::from_parts(6_523_000, 3509) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 449_000 picoseconds. + Weight::from_parts(527_000, 0) + } + /// 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: 5_689_000 picoseconds. + Weight::from_parts(6_000_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: 399_000 picoseconds. + Weight::from_parts(461_000, 0) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 390_000 picoseconds. + Weight::from_parts(439_000, 0) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1489` + // Minimum execution time: 4_375_000 picoseconds. + Weight::from_parts(4_747_000, 1489) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 069217bcee46b4663c836a750bfd90a568c1a4d2..0318f77342e00380bc6b663e3973e01eb629efa7 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -130,11 +130,13 @@ use frame_support::{ DispatchResult, DispatchResultWithPostInfo, PerDispatchClass, PostDispatchInfo, }, ensure, impl_ensure_origin_with_arg_ignoring_arg, + migrations::MultiStepMigrator, pallet_prelude::Pays, storage::{self, StorageStreamIter}, traits::{ ConstU32, Contains, EnsureOrigin, EnsureOriginWithArg, Get, HandleLifetime, - OnKilledAccount, OnNewAccount, OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, + OnKilledAccount, OnNewAccount, OnRuntimeUpgrade, OriginTrait, PalletInfo, SortedMembers, + StoredMap, TypedGet, }, Parameter, }; @@ -148,6 +150,7 @@ use sp_io::TestExternalities; pub mod limits; #[cfg(test)] pub(crate) mod mock; + pub mod offchain; mod extensions; @@ -163,11 +166,12 @@ 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; pub use frame_support::dispatch::RawOrigin; +use frame_support::traits::{PostInherents, PostTransactions, PreInherents}; pub use weights::WeightInfo; const LOG_TARGET: &str = "runtime::system"; @@ -280,6 +284,7 @@ pub mod pallet { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); + type ExtensionsWeightInfo = (); type SS58Prefix = (); type Version = (); type BlockWeights = (); @@ -298,9 +303,14 @@ pub mod pallet { type BaseCallFilter = frame_support::traits::Everything; type BlockHashCount = frame_support::traits::ConstU64<10>; type OnSetCode = (); + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); } - /// Default configurations of this pallet in a solo-chain environment. + /// Default configurations of this pallet in a solochain environment. /// /// ## Considerations: /// @@ -347,6 +357,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 = (); @@ -392,6 +405,11 @@ pub mod pallet { /// The set code logic, just the default since we're not a parachain. type OnSetCode = (); + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); } /// Default configurations of this pallet in a relay-chain environment. @@ -451,6 +469,7 @@ pub mod pallet { + Clone + OriginTrait; + #[docify::export(system_runtime_call)] /// The aggregated `RuntimeCall` type. #[pallet::no_default_bounds] type RuntimeCall: Parameter @@ -523,7 +542,7 @@ pub mod pallet { #[pallet::constant] type DbWeight: Get; - /// Get the chain's current version. + /// Get the chain's in-code version. #[pallet::constant] type Version: Get; @@ -548,8 +567,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 @@ -570,6 +593,35 @@ pub mod pallet { /// The maximum number of consumers allowed on a single account. type MaxConsumers: ConsumerLimits; + + /// All migrations that should run in the next runtime upgrade. + /// + /// These used to be formerly configured in `Executive`. Parachains need to ensure that + /// running all these migrations in one block will not overflow the weight limit of a block. + /// The migrations are run *before* the pallet `on_runtime_upgrade` hooks, just like the + /// `OnRuntimeUpgrade` migrations. + type SingleBlockMigrations: OnRuntimeUpgrade; + + /// The migrator that is used to run Multi-Block-Migrations. + /// + /// Can be set to [`pallet-migrations`] or an alternative implementation of the interface. + /// The diagram in `frame_executive::block_flowchart` explains when it runs. + type MultiBlockMigrator: MultiStepMigrator; + + /// A callback that executes in *every block* directly before all inherents were applied. + /// + /// See `frame_executive::block_flowchart` for a in-depth explanation when it runs. + type PreInherents: PreInherents; + + /// A callback that executes in *every block* directly after all inherents were applied. + /// + /// See `frame_executive::block_flowchart` for a in-depth explanation when it runs. + type PostInherents: PostInherents; + + /// A callback that executes in *every block* directly after all transactions were applied. + /// + /// See `frame_executive::block_flowchart` for a in-depth explanation when it runs. + type PostTransactions: PostTransactions; } #[pallet::pallet] @@ -617,6 +669,9 @@ pub mod pallet { } /// Set the new runtime code without doing any checks of the given `code`. + /// + /// Note that runtime upgrades will not run if this is called with a not-increasing spec + /// version! #[pallet::call_index(3)] #[pallet::weight((T::SystemWeightInfo::set_code(), DispatchClass::Operational))] pub fn set_code_without_checks( @@ -812,6 +867,8 @@ pub mod pallet { NonZeroRefCount, /// The origin filter prevent the call to be dispatched. CallFiltered, + /// A multi-block migration is ongoing and prevents the current code from being replaced. + MultiBlockMigrationsOngoing, #[cfg(feature = "experimental")] /// The specified [`Task`] is not valid. InvalidTask, @@ -843,11 +900,15 @@ pub mod pallet { #[pallet::storage] pub(super) type ExtrinsicCount = StorageValue<_, u32>; + /// Whether all inherents have been applied. + #[pallet::storage] + pub type InherentsApplied = StorageValue<_, bool, ValueQuery>; + /// The current weight for the block. #[pallet::storage] #[pallet::whitelist_storage] #[pallet::getter(fn block_weight)] - pub(super) type BlockWeight = StorageValue<_, ConsumedWeight, ValueQuery>; + pub type BlockWeight = StorageValue<_, ConsumedWeight, ValueQuery>; /// Total length (in bytes) for all extrinsics put together, for the current block. #[pallet::storage] @@ -892,6 +953,7 @@ pub mod pallet { /// just in case someone still reads them from within the runtime. #[pallet::storage] #[pallet::whitelist_storage] + #[pallet::disable_try_decode_storage] #[pallet::unbounded] pub(super) type Events = StorageValue<_, Vec>>, ValueQuery>; @@ -1370,6 +1432,19 @@ impl Pallet { Self::deposit_event(Event::CodeUpdated); } + /// Whether all inherents have been applied. + pub fn inherents_applied() -> bool { + InherentsApplied::::get() + } + + /// Note that all inherents have been applied. + /// + /// Should be called immediately after all inherents have been applied. Must be called at least + /// once per block. + pub fn note_inherents_applied() { + InherentsApplied::::put(true); + } + /// Increment the reference counter on an account. #[deprecated = "Use `inc_consumers` instead"] pub fn inc_ref(who: &T::AccountId) { @@ -1689,6 +1764,7 @@ impl Pallet { >::put(digest); >::put(parent_hash); >::insert(*number - One::one(), parent_hash); + >::kill(); // Remove previous block data from storage BlockWeight::::kill(); @@ -1735,6 +1811,7 @@ impl Pallet { ExecutionPhase::::kill(); AllExtrinsicsLen::::kill(); storage::unhashed::kill(well_known_keys::INTRABLOCK_ENTROPY); + InherentsApplied::::kill(); // The following fields // @@ -1978,10 +2055,14 @@ impl Pallet { /// Determine whether or not it is possible to update the code. /// - /// Checks the given code if it is a valid runtime wasm blob by instantianting + /// Checks the given code if it is a valid runtime wasm blob by instantiating /// it and extracting the runtime version of it. It checks that the runtime version /// of the old and new runtime has the same spec name and that the spec version is increasing. pub fn can_set_code(code: &[u8]) -> Result<(), sp_runtime::DispatchError> { + if T::MultiBlockMigrator::ongoing() { + return Err(Error::::MultiBlockMigrationsOngoing.into()) + } + let current_version = T::Version::get(); let new_version = sp_io::misc::runtime_version(code) .and_then(|v| RuntimeVersion::decode(&mut &v[..]).ok()) diff --git a/substrate/frame/system/src/mock.rs b/substrate/frame/system/src/mock.rs index 06527a9bb2912b4253186307456ad0885cf2c17e..7059845a7df33104a66348803fee6396bf2f93d2 100644 --- a/substrate/frame/system/src/mock.rs +++ b/substrate/frame/system/src/mock.rs @@ -16,15 +16,8 @@ // limitations under the License. use crate::{self as frame_system, *}; -use frame_support::{ - derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, -}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, Perbill, -}; +use frame_support::{derive_impl, parameter_types}; +use sp_runtime::{BuildStorage, Perbill}; type Block = mocking::MockBlock; @@ -87,29 +80,28 @@ impl OnKilledAccount for RecordKilled { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl Config for Test { - type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<10>; - type DbWeight = DbWeight; type Version = Version; - type PalletInfo = PalletInfo; type AccountData = u32; - type OnNewAccount = (); type OnKilledAccount = RecordKilled; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MockedMigrator; +} + +parameter_types! { + pub static Ongoing: bool = false; +} + +pub struct MockedMigrator; +impl frame_support::migrations::MultiStepMigrator for MockedMigrator { + fn ongoing() -> bool { + Ongoing::get() + } + + fn step() -> Weight { + Weight::zero() + } } pub type SysEvent = frame_system::Event; diff --git a/substrate/frame/system/src/offchain.rs b/substrate/frame/system/src/offchain.rs index a019cfd666e8cb3ddccc02aa706692cbe6cee2e3..ee73e33fe31302ea1fb864b7e88164f3feb02e39 100644 --- a/substrate/frame/system/src/offchain.rs +++ b/substrate/frame/system/src/offchain.rs @@ -79,6 +79,9 @@ pub struct SubmitTransaction, Overarchi _phantom: sp_std::marker::PhantomData<(T, OverarchingCall)>, } +// TODO [#2415]: Avoid splitting call and the totally opaque `signature`; `CreateTransaction` trait +// should provide something which impls `Encode`, which can be sent onwards to +// `sp_io::offchain::submit_transaction`. There's no great need to split things up as in here. impl SubmitTransaction where T: SendTransactionTypes, @@ -88,6 +91,8 @@ where call: >::OverarchingCall, signature: Option<::SignaturePayload>, ) -> Result<(), ()> { + // TODO: Use regular transaction API instead. + #[allow(deprecated)] let xt = T::Extrinsic::new(call, signature).ok_or(())?; sp_io::offchain::submit_transaction(xt.encode()) } @@ -471,7 +476,7 @@ pub trait SendTransactionTypes { /// /// 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`). +/// This will most likely include creation of `TxExtension` (a tuple of `TransactionExtension`s). /// Note that the result can be altered by inspecting the `Call` (for instance adjusting /// fees, or mortality depending on the `pallet` being called). pub trait CreateSignedTransaction: @@ -621,14 +626,17 @@ mod tests { use crate::mock::{RuntimeCall, Test as TestRuntime, CALL}; use codec::Decode; use sp_core::offchain::{testing, TransactionPoolExt}; - use sp_runtime::testing::{TestSignature, TestXt, UintAuthorityId}; + use sp_runtime::{ + generic::UncheckedExtrinsic, + testing::{TestSignature, UintAuthorityId}, + }; impl SigningTypes for TestRuntime { type Public = UintAuthorityId; type Signature = TestSignature; } - type Extrinsic = TestXt; + type Extrinsic = UncheckedExtrinsic; impl SendTransactionTypes for TestRuntime { type Extrinsic = Extrinsic; @@ -693,7 +701,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 +732,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 +766,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 +798,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 e437e7f9f39b0845d9f7eef33e3c90546c8dbbd2..b889b5ca046efe557e7706870c11febce8a358b2 100644 --- a/substrate/frame/system/src/tests.rs +++ b/substrate/frame/system/src/tests.rs @@ -675,6 +675,28 @@ fn set_code_with_real_wasm_blob() { }); } +#[test] +fn set_code_rejects_during_mbm() { + Ongoing::set(true); + + let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); + let mut ext = new_test_ext(); + ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); + ext.execute_with(|| { + System::set_block_number(1); + let res = System::set_code( + RawOrigin::Root.into(), + substrate_test_runtime_client::runtime::wasm_binary_unwrap().to_vec(), + ); + assert_eq!( + res, + Err(DispatchErrorWithPostInfo::from(Error::::MultiBlockMigrationsOngoing)) + ); + + assert!(System::events().is_empty()); + }); +} + #[test] fn set_code_via_authorization_works() { let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); diff --git a/substrate/frame/system/src/weights.rs b/substrate/frame/system/src/weights.rs index 41807dea1c55f9cd246db231fc9102d4b9eb5c4f..bd64bbf37639f4b257b0e2d3b75e812131b16e72 100644 --- a/substrate/frame/system/src/weights.rs +++ b/substrate/frame/system/src/weights.rs @@ -15,30 +15,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for frame_system +//! Autogenerated weights for `frame_system` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-22, STEPS: `50`, REPEAT: `20`, 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: `runner-s7kdgajz-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=frame_system +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=frame-system -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/system/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/system/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for frame_system. +/// Weight functions needed for `frame_system`. pub trait WeightInfo { fn remark(b: u32, ) -> Weight; fn remark_with_event(b: u32, ) -> Weight; @@ -61,7 +62,7 @@ pub trait WeightInfo { fn apply_authorized_upgrade() -> Weight; } -/// Weights for frame_system using the Substrate node and recommended hardware. +/// Weights for `frame_system` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 3932160]`. @@ -69,84 +70,86 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_004_000 picoseconds. - Weight::from_parts(2_119_000, 0) + // Minimum execution time: 2_130_000 picoseconds. + Weight::from_parts(2_976_430, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(390, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(386, 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: 8_032_000 picoseconds. - Weight::from_parts(8_097_000, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_455, 0).saturating_mul(b.into())) + // Minimum execution time: 5_690_000 picoseconds. + Weight::from_parts(15_071_416, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_387, 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_446_000 picoseconds. - Weight::from_parts(4_782_000, 1485) + // Minimum execution time: 3_822_000 picoseconds. + Weight::from_parts(4_099_000, 1485) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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: `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: `0` - // Estimated: `1485` - // Minimum execution time: 84_000_503_000 picoseconds. - Weight::from_parts(87_586_619_000, 1485) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 81_512_045_000 picoseconds. + Weight::from_parts(82_321_281_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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_086_000 picoseconds. - Weight::from_parts(2_175_000, 0) - // Standard Error: 1_056 - .saturating_add(Weight::from_parts(841_511, 0).saturating_mul(i.into())) + // Minimum execution time: 2_074_000 picoseconds. + Weight::from_parts(2_137_000, 0) + // Standard Error: 879 + .saturating_add(Weight::from_parts(797_224, 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_000_000 picoseconds. - Weight::from_parts(2_255_000, 0) - // Standard Error: 1_425 - .saturating_add(Weight::from_parts(662_473, 0).saturating_mul(i.into())) + // Minimum execution time: 2_122_000 picoseconds. + Weight::from_parts(2_208_000, 0) + // Standard Error: 855 + .saturating_add(Weight::from_parts(594_034, 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: `115 + p * (69 ±0)` - // Estimated: `128 + p * (70 ±0)` - // Minimum execution time: 4_189_000 picoseconds. - Weight::from_parts(4_270_000, 128) - // Standard Error: 2_296 - .saturating_add(Weight::from_parts(1_389_650, 0).saturating_mul(p.into())) + // Measured: `129 + p * (69 ±0)` + // Estimated: `135 + p * (70 ±0)` + // Minimum execution time: 3_992_000 picoseconds. + Weight::from_parts(4_170_000, 135) + // Standard Error: 1_377 + .saturating_add(Weight::from_parts(1_267_892, 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())) @@ -157,114 +160,116 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 33_027_000 picoseconds. - Weight::from_parts(33_027_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) + // Minimum execution time: 8_872_000 picoseconds. + Weight::from_parts(9_513_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: `22` - // Estimated: `1518` - // Minimum execution time: 118_101_992_000 picoseconds. - Weight::from_parts(118_101_992_000, 0) - .saturating_add(Weight::from_parts(0, 1518)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `164` + // Estimated: `67035` + // Minimum execution time: 85_037_546_000 picoseconds. + Weight::from_parts(85_819_414_000, 67035) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { /// The range of component `b` is `[0, 3932160]`. fn remark(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_004_000 picoseconds. - Weight::from_parts(2_119_000, 0) + // Minimum execution time: 2_130_000 picoseconds. + Weight::from_parts(2_976_430, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(390, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(386, 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: 8_032_000 picoseconds. - Weight::from_parts(8_097_000, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_455, 0).saturating_mul(b.into())) + // Minimum execution time: 5_690_000 picoseconds. + Weight::from_parts(15_071_416, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_387, 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_446_000 picoseconds. - Weight::from_parts(4_782_000, 1485) + // Minimum execution time: 3_822_000 picoseconds. + Weight::from_parts(4_099_000, 1485) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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: `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: `0` - // Estimated: `1485` - // Minimum execution time: 84_000_503_000 picoseconds. - Weight::from_parts(87_586_619_000, 1485) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 81_512_045_000 picoseconds. + Weight::from_parts(82_321_281_000, 67035) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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_086_000 picoseconds. - Weight::from_parts(2_175_000, 0) - // Standard Error: 1_056 - .saturating_add(Weight::from_parts(841_511, 0).saturating_mul(i.into())) + // Minimum execution time: 2_074_000 picoseconds. + Weight::from_parts(2_137_000, 0) + // Standard Error: 879 + .saturating_add(Weight::from_parts(797_224, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::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_000_000 picoseconds. - Weight::from_parts(2_255_000, 0) - // Standard Error: 1_425 - .saturating_add(Weight::from_parts(662_473, 0).saturating_mul(i.into())) + // Minimum execution time: 2_122_000 picoseconds. + Weight::from_parts(2_208_000, 0) + // Standard Error: 855 + .saturating_add(Weight::from_parts(594_034, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::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: `115 + p * (69 ±0)` - // Estimated: `128 + p * (70 ±0)` - // Minimum execution time: 4_189_000 picoseconds. - Weight::from_parts(4_270_000, 128) - // Standard Error: 2_296 - .saturating_add(Weight::from_parts(1_389_650, 0).saturating_mul(p.into())) + // Measured: `129 + p * (69 ±0)` + // Estimated: `135 + p * (70 ±0)` + // Minimum execution time: 3_992_000 picoseconds. + Weight::from_parts(4_170_000, 135) + // Standard Error: 1_377 + .saturating_add(Weight::from_parts(1_267_892, 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())) @@ -275,25 +280,25 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 33_027_000 picoseconds. - Weight::from_parts(33_027_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Minimum execution time: 8_872_000 picoseconds. + Weight::from_parts(9_513_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: `22` - // Estimated: `1518` - // Minimum execution time: 118_101_992_000 picoseconds. - Weight::from_parts(118_101_992_000, 0) - .saturating_add(Weight::from_parts(0, 1518)) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Measured: `164` + // Estimated: `67035` + // Minimum execution time: 85_037_546_000 picoseconds. + Weight::from_parts(85_819_414_000, 67035) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } } diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index cd0737c6bb8fea31471e7e9ba14637588b33c4de..28e57fcab0a79d18ea8d8a1b2b8be90cb05198db 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/timestamp/src/mock.rs b/substrate/frame/timestamp/src/mock.rs index 5cbc5211368d4e6ed8027b56a06a49f02f1d3f86..244b66a4bb2c64428011b1e90fea0ec76d5ba6f2 100644 --- a/substrate/frame/timestamp/src/mock.rs +++ b/substrate/frame/timestamp/src/mock.rs @@ -20,16 +20,9 @@ use super::*; use crate as pallet_timestamp; -use frame_support::{ - derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, -}; -use sp_core::H256; +use frame_support::{derive_impl, parameter_types, traits::ConstU64}; use sp_io::TestExternalities; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; type Moment = u64; @@ -44,29 +37,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } parameter_types! { diff --git a/substrate/frame/timestamp/src/weights.rs b/substrate/frame/timestamp/src/weights.rs index 46c544734869442c17d2be8b354bed916e197b83..2df68ba0f1e716ed5c390f7a173ff449c35e88d2 100644 --- a/substrate/frame/timestamp/src/weights.rs +++ b/substrate/frame/timestamp/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_timestamp +//! Autogenerated weights for `pallet_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/timestamp/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/timestamp/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,57 +49,57 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_timestamp. +/// Weight functions needed for `pallet_timestamp`. pub trait WeightInfo { fn set() -> Weight; fn on_finalize() -> Weight; } -/// Weights for pallet_timestamp using the Substrate node and recommended hardware. +/// Weights for `pallet_timestamp` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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: `312` + // Measured: `345` // Estimated: `1493` - // Minimum execution time: 9_857_000 picoseconds. - Weight::from_parts(10_492_000, 1493) + // Minimum execution time: 8_417_000 picoseconds. + Weight::from_parts(8_932_000, 1493) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `161` + // Measured: `194` // Estimated: `0` - // Minimum execution time: 4_175_000 picoseconds. - Weight::from_parts(4_334_000, 0) + // Minimum execution time: 3_911_000 picoseconds. + Weight::from_parts(4_092_000, 0) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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: `312` + // Measured: `345` // Estimated: `1493` - // Minimum execution time: 9_857_000 picoseconds. - Weight::from_parts(10_492_000, 1493) + // Minimum execution time: 8_417_000 picoseconds. + Weight::from_parts(8_932_000, 1493) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `161` + // Measured: `194` // Estimated: `0` - // Minimum execution time: 4_175_000 picoseconds. - Weight::from_parts(4_334_000, 0) + // Minimum execution time: 3_911_000 picoseconds. + Weight::from_parts(4_092_000, 0) } } diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 900cd47e0dc02afaad237b1de8c1e98c6941e672..7339cf0a8cce86ec15aebe6a55115f10360b1a7f 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", features = ["derive"], optional = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/tips/src/lib.rs b/substrate/frame/tips/src/lib.rs index 4c7cfc3028a9f04c87022ffc89892b59ce3c5610..8c360fb57d72488553529ab4264eb7f8b444c064 100644 --- a/substrate/frame/tips/src/lib.rs +++ b/substrate/frame/tips/src/lib.rs @@ -122,7 +122,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - /// The current storage version. + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index 9d4047cd80eabb3c7c2b36382c8ec1020fc2bd6b..0e7ea1f47817c5ae14dace2dce7ce7e555a68a03 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -59,29 +59,10 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/tips/src/weights.rs b/substrate/frame/tips/src/weights.rs index ec6228667159ddbdbfecd12ccb5ff6250390829a..dbe1ed246ff015567e94e2396141d583b2a17a6c 100644 --- a/substrate/frame/tips/src/weights.rs +++ b/substrate/frame/tips/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_tips +//! Autogenerated weights for `pallet_tips` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/tips/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/tips/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_tips. +/// Weight functions needed for `pallet_tips`. pub trait WeightInfo { fn report_awesome(r: u32, ) -> Weight; fn retract_tip() -> Weight; @@ -60,220 +59,220 @@ pub trait WeightInfo { fn slash_tip(t: u32, ) -> Weight; } -/// Weights for pallet_tips using the Substrate node and recommended hardware. +/// Weights for `pallet_tips` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: `Tips::Reasons` (r:1 w:1) + /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Tips` (r:1 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `3469` - // Minimum execution time: 29_576_000 picoseconds. - Weight::from_parts(30_722_650, 3469) - // Standard Error: 192 - .saturating_add(Weight::from_parts(2_601, 0).saturating_mul(r.into())) + // Minimum execution time: 25_145_000 picoseconds. + Weight::from_parts(26_085_800, 3469) + // Standard Error: 216 + .saturating_add(Weight::from_parts(5_121, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// 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`) fn retract_tip() -> Weight { // Proof Size summary in bytes: // Measured: `221` // Estimated: `3686` - // Minimum execution time: 28_522_000 picoseconds. - Weight::from_parts(29_323_000, 3686) + // Minimum execution time: 25_302_000 picoseconds. + Weight::from_parts(26_229_000, 3686) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:0 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Reasons` (r:1 w:1) + /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Tips` (r:0 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 300]`. /// 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: 19_650_000 picoseconds. - Weight::from_parts(19_837_982, 3991) - // Standard Error: 151 - .saturating_add(Weight::from_parts(1_746, 0).saturating_mul(r.into())) - // Standard Error: 3_588 - .saturating_add(Weight::from_parts(102_359, 0).saturating_mul(t.into())) + // Minimum execution time: 16_600_000 picoseconds. + Weight::from_parts(17_071_638, 3991) + // Standard Error: 131 + .saturating_add(Weight::from_parts(1_138, 0).saturating_mul(r.into())) + // Standard Error: 3_125 + .saturating_add(Weight::from_parts(82_996, 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())) } - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Tips` (r:1 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// 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: 15_641_000 picoseconds. - Weight::from_parts(15_745_460, 4212) - // Standard Error: 5_106 - .saturating_add(Weight::from_parts(229_475, 0).saturating_mul(t.into())) + // Minimum execution time: 13_972_000 picoseconds. + Weight::from_parts(14_269_356, 4212) + // Standard Error: 4_695 + .saturating_add(Weight::from_parts(205_433, 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())) } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: `Tips::Tips` (r:1 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `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 close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `786 + t * (112 ±0)` // Estimated: `4242 + t * (112 ±0)` - // Minimum execution time: 62_059_000 picoseconds. - Weight::from_parts(64_604_554, 4242) - // Standard Error: 11_818 - .saturating_add(Weight::from_parts(116_297, 0).saturating_mul(t.into())) + // Minimum execution time: 51_878_000 picoseconds. + Weight::from_parts(54_513_477, 4242) + // Standard Error: 12_281 + .saturating_add(Weight::from_parts(126_605, 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())) } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// 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 { // Proof Size summary in bytes: // Measured: `269` // Estimated: `3734` - // Minimum execution time: 14_133_000 picoseconds. - Weight::from_parts(14_957_547, 3734) - // Standard Error: 2_765 - .saturating_add(Weight::from_parts(22_138, 0).saturating_mul(t.into())) + // Minimum execution time: 11_800_000 picoseconds. + Weight::from_parts(12_520_984, 3734) + // Standard Error: 2_360 + .saturating_add(Weight::from_parts(28_777, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: `Tips::Reasons` (r:1 w:1) + /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Tips` (r:1 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `3469` - // Minimum execution time: 29_576_000 picoseconds. - Weight::from_parts(30_722_650, 3469) - // Standard Error: 192 - .saturating_add(Weight::from_parts(2_601, 0).saturating_mul(r.into())) + // Minimum execution time: 25_145_000 picoseconds. + Weight::from_parts(26_085_800, 3469) + // Standard Error: 216 + .saturating_add(Weight::from_parts(5_121, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// 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`) fn retract_tip() -> Weight { // Proof Size summary in bytes: // Measured: `221` // Estimated: `3686` - // Minimum execution time: 28_522_000 picoseconds. - Weight::from_parts(29_323_000, 3686) + // Minimum execution time: 25_302_000 picoseconds. + Weight::from_parts(26_229_000, 3686) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:0 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Reasons` (r:1 w:1) + /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Tips` (r:0 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[0, 300]`. /// 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: 19_650_000 picoseconds. - Weight::from_parts(19_837_982, 3991) - // Standard Error: 151 - .saturating_add(Weight::from_parts(1_746, 0).saturating_mul(r.into())) - // Standard Error: 3_588 - .saturating_add(Weight::from_parts(102_359, 0).saturating_mul(t.into())) + // Minimum execution time: 16_600_000 picoseconds. + Weight::from_parts(17_071_638, 3991) + // Standard Error: 131 + .saturating_add(Weight::from_parts(1_138, 0).saturating_mul(r.into())) + // Standard Error: 3_125 + .saturating_add(Weight::from_parts(82_996, 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())) } - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Tips::Tips` (r:1 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// 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: 15_641_000 picoseconds. - Weight::from_parts(15_745_460, 4212) - // Standard Error: 5_106 - .saturating_add(Weight::from_parts(229_475, 0).saturating_mul(t.into())) + // Minimum execution time: 13_972_000 picoseconds. + Weight::from_parts(14_269_356, 4212) + // Standard Error: 4_695 + .saturating_add(Weight::from_parts(205_433, 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())) } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: `Tips::Tips` (r:1 w:1) + /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Elections::Members` (r:1 w:0) + /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `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 close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `786 + t * (112 ±0)` // Estimated: `4242 + t * (112 ±0)` - // Minimum execution time: 62_059_000 picoseconds. - Weight::from_parts(64_604_554, 4242) - // Standard Error: 11_818 - .saturating_add(Weight::from_parts(116_297, 0).saturating_mul(t.into())) + // Minimum execution time: 51_878_000 picoseconds. + Weight::from_parts(54_513_477, 4242) + // Standard Error: 12_281 + .saturating_add(Weight::from_parts(126_605, 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())) } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// 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 { // Proof Size summary in bytes: // Measured: `269` // Estimated: `3734` - // Minimum execution time: 14_133_000 picoseconds. - Weight::from_parts(14_957_547, 3734) - // Standard Error: 2_765 - .saturating_add(Weight::from_parts(22_138, 0).saturating_mul(t.into())) + // Minimum execution time: 11_800_000 picoseconds. + Weight::from_parts(12_520_984, 3734) + // Standard Error: 2_360 + .saturating_add(Weight::from_parts(28_777, 0).saturating_mul(t.into())) .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 4b30f8e755f5926f1cae65d73a022426bcccded9..66e0bef1436f1a197a5d450680c88a72ddd885e0 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -20,7 +20,8 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } +frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } @@ -29,13 +30,14 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } pallet-balances = { path = "../balances" } [features] default = ["std"] std = [ "codec/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "pallet-balances/std", @@ -46,6 +48,13 @@ std = [ "sp-runtime/std", "sp-std/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 7640cc815e56c7fcecbb7d09c61c81635ca22491..528f29e8e4ae7738ea9d72ed8dcd54a9c6f659b0 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -19,6 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] # Substrate dependencies sp-runtime = { path = "../../../primitives/runtime", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } pallet-asset-conversion = { path = "../../asset-conversion", default-features = false } @@ -37,6 +38,7 @@ pallet-balances = { path = "../../balances" } default = ["std"] std = [ "codec/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "pallet-asset-conversion/std", @@ -50,6 +52,16 @@ std = [ "sp-std/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 eccba773673e690a6d415a4c61d267ba75a1c12e..fcd1527526e98ecf45c7979bb40a2d59aad93452 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 0000000000000000000000000000000000000000..0bffb991e4a3b53eac2c385f6e901eeef0c6800c --- /dev/null +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.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. + +//! Benchmarks for Asset Conversion Tx Payment Pallet's transaction extension + +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, DispatchTransaction, Dispatchable}; + +#[benchmarks(where + T::RuntimeCall: Dispatchable, + AssetBalanceOf: Send + Sync, + BalanceOf: Send + + Sync + + From + + Into> + + Into> + + From>, + ChargeAssetIdOf: Send + Sync + Default, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn charge_asset_tx_payment_zero() { + let caller: T::AccountId = whitelisted_caller(); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(0u64.into(), None); + let inner = frame_system::Call::remark { remark: vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + 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, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_native() { + let caller: T::AccountId = whitelisted_caller(); + 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: vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + weight: Weight::from_parts(10, 0), + 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, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_asset() { + let caller: T::AccountId = whitelisted_caller(); + 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: vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + weight: Weight::from_parts(10, 0), + 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, |_| 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 ed0ed56e6e074b49db7abf6d43ddb9305d7fb616..8ef7c2ba38e27f8b50c3489504db8ba195b88cf0 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 [`AssetConversionAdapter`] (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 @@ -53,23 +53,29 @@ use frame_support::{ }, 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::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, + TransactionExtension, TransactionExtensionBase, 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; /// Type aliases used for interaction with `OnChargeTransaction`. pub(crate) type OnChargeTransactionOf = @@ -125,11 +131,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; + #[cfg(feature = "runtime-benchmarks")] + /// Benchmark helper + 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 { @@ -179,9 +204,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)) @@ -225,9 +249,8 @@ impl sp_std::fmt::Debug for ChargeAssetTxPayment { } } -impl SignedExtension for ChargeAssetTxPayment +impl TransactionExtensionBase for ChargeAssetTxPayment where - T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync, BalanceOf: Send + Sync @@ -238,109 +261,145 @@ where ChargeAssetIdOf: Send + Sync, { const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); + + fn weight(&self) -> Weight { + if self.asset_id.is_some() { + ::WeightInfo::charge_asset_tx_payment_asset() + } else { + ::WeightInfo::charge_asset_tx_payment_native() + } + } +} + +impl TransactionExtension for ChargeAssetTxPayment +where + T::RuntimeCall: Dispatchable, + AssetBalanceOf: Send + Sync, + BalanceOf: Send + + Sync + + From + + Into> + + Into> + + From>, + ChargeAssetIdOf: Send + Sync, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, +{ + type Val = ( + // tip + BalanceOf, + // who paid the fee + T::AccountId, + // transaction fee + BalanceOf, + ); type Pre = ( // tip BalanceOf, // who paid the fee - Self::AccountId, + T::AccountId, // imbalance resulting from withdrawing the fee InitialPayment, // asset_id for the transaction payment Option>, ); - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } - 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)?; + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> ValidateResult { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + // 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); let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - Ok(ValidTransaction { priority, ..Default::default() }) + let validity = ValidTransaction { priority, ..Default::default() }; + let val = (self.tip, 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, + _context: &Context, ) -> Result { - let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; - Ok((self.tip, who.clone(), initial_payment, self.asset_id)) + let (tip, who, fee) = val; + // Mutating call of `withdraw_fee` to actually charge for the transaction. + let (_fee, initial_payment) = self.withdraw_fee(&who, call, info, fee)?; + Ok((tip, who, initial_payment, self.asset_id.clone())) } fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, + _context: &Context, ) -> Result<(), TransactionValidityError> { - if let Some((tip, who, initial_payment, asset_id)) = pre { - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - debug_assert!( - asset_id.is_none(), - "For that payment type the `asset_id` should be None" - ); - pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( - Some((tip, who, already_withdrawn)), + let (tip, who, initial_payment, asset_id) = pre; + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + debug_assert!( + asset_id.is_none(), + "For that payment type the `asset_id` should be None" + ); + pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( + (tip, who, already_withdrawn), + info, + post_info, + len, + result, + &(), + )?; + }, + InitialPayment::Asset(already_withdrawn) => { + debug_assert!( + asset_id.is_some(), + "For that payment type the `asset_id` should be set" + ); + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, info, post_info, tip, + ); + + if let Some(asset_id) = asset_id { + let (used_for_fee, received_exchanged, asset_consumed) = already_withdrawn; + let converted_fee = T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, info, post_info, - len, - result, + actual_fee.into(), + tip.into(), + used_for_fee.into(), + received_exchanged.into(), + asset_id.clone(), + asset_consumed.into(), )?; - }, - InitialPayment::Asset(already_withdrawn) => { - debug_assert!( - asset_id.is_some(), - "For that payment type the `asset_id` should be set" - ); - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - - if let Some(asset_id) = asset_id { - let (used_for_fee, received_exchanged, asset_consumed) = already_withdrawn; - let converted_fee = T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee.into(), - tip.into(), - used_for_fee.into(), - received_exchanged.into(), - asset_id.clone(), - asset_consumed.into(), - )?; - 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."); - }, - } + 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."); + }, } Ok(()) 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 c8bf2eb8f440fd1203796fd89d9265403b3fdad0..853753d41cfb16b4b84d8ff4317a89ca32fbf309 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 @@ -168,12 +168,12 @@ impl OnUnbalanced> for DealWithFees } } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; } @@ -269,4 +269,72 @@ impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = AssetConversionAdapter; + type WeightInfo = (); + #[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, id) + } + + fn setup_balances_and_pool(asset_id: u32, account: u64) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + use sp_runtime::traits::StaticLookup; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_id.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_id.into(), &lp_provider_account, u64::MAX / 2)); + + let token_1 = Box::new(NativeOrWithId::Native); + let token_2 = Box::new(NativeOrWithId::WithId(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_id.into(), &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, account), balance); + } } 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 62faed269d377cc1dc2b75091d79210401cd0a26..619077c0a5ef42e47e4f445ce1cd1623172a2580 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 @@ -28,7 +28,10 @@ use frame_support::{ 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 }); @@ -160,33 +163,35 @@ 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) + let (pre, _) = ChargeAssetTxPayment::::from(0, None) + .validate_and_prepare(Some(1).into(), CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); let initial_balance = 10 * balance_factor; assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + pre, &info_from_weight(WEIGHT_5), &default_post_info(), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .pre_dispatch(&2, CALL, &info_from_weight(WEIGHT_100), len) + let (pre, _) = ChargeAssetTxPayment::::from(5 /* tipped */, None) + .validate_and_prepare(Some(2).into(), CALL, &info_from_weight(WEIGHT_100), len) .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), + pre, &info_from_weight(WEIGHT_100), &post_info_from_weight(WEIGHT_50), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); }); @@ -237,8 +242,8 @@ 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)) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -247,11 +252,12 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + 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); @@ -289,12 +295,8 @@ 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)).pre_dispatch( - &caller, - CALL, - &info_from_weight(WEIGHT_5), - len, - ); + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len); // As there is no pool in the dex set up for this asset, conversion should fail. assert!(pre.is_err()); @@ -344,8 +346,8 @@ 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)) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); // assert that native balance is not used @@ -363,11 +365,12 @@ fn transaction_payment_without_fee() { assert_eq!(refund, 199); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + pre, &info_from_weight(WEIGHT_5), &post_info_from_pays(Pays::No), len, - &Ok(()) + &Ok(()), + &() )); // caller should get refunded @@ -419,8 +422,8 @@ fn asset_transaction_payment_with_tip_and_refund() { assert_eq!(input_quote, Some(1206)); let fee_in_asset = input_quote.unwrap(); - let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_100), len) + let (pre, _) = ChargeAssetTxPayment::::from(tip, Some(asset_id)) + .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_100), len) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); @@ -435,11 +438,12 @@ fn asset_transaction_payment_with_tip_and_refund() { .unwrap(); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + pre, &info_from_weight(WEIGHT_100), &post_info_from_weight(WEIGHT_50), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(TipUnbalancedAmount::get(), tip); @@ -500,8 +504,8 @@ fn payment_from_account_with_only_assets() { .unwrap(); assert_eq!(fee_in_asset, 301); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); assert_eq!(Balances::free_balance(caller), ed); // check that fee was charged in the given asset @@ -516,11 +520,12 @@ fn payment_from_account_with_only_assets() { .unwrap(); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + pre, &info_from_weight(WEIGHT_5), &default_post_info(), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset + refund); assert_eq!(Balances::free_balance(caller), 0); @@ -565,18 +570,19 @@ 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)) - .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) .unwrap(); // `Pays::No` implies there are no fees assert_eq!(Assets::balance(asset_id, caller), balance); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + pre, &info_from_pays(Pays::No), &post_info_from_pays(Pays::No), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(Assets::balance(asset_id, caller), balance); } @@ -591,17 +597,23 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { ) .unwrap(); - 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, + ) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + 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); }); @@ -641,8 +653,8 @@ 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)) - .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) .unwrap(); // `Pays::No` implies no pre-dispatch fees @@ -658,62 +670,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), + 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); }); 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 0000000000000000000000000000000000000000..f95e49f80730318d4957538ded3812c661009be0 --- /dev/null +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.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. + +//! Autogenerated weights for `pallet_asset_conversion_tx_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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_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: 628_000 picoseconds. + Weight::from_parts(694_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: 34_410_000 picoseconds. + Weight::from_parts(35_263_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:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Authorship::Author` (r:1 w:0) + /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `888` + // Estimated: `6208` + // Minimum execution time: 112_432_000 picoseconds. + Weight::from_parts(113_992_000, 6208) + .saturating_add(T::DbWeight::get().reads(7_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: 628_000 picoseconds. + Weight::from_parts(694_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: 34_410_000 picoseconds. + Weight::from_parts(35_263_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:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Authorship::Author` (r:1 w:0) + /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `888` + // Estimated: `6208` + // Minimum execution time: 112_432_000 picoseconds. + Weight::from_parts(113_992_000, 6208) + .saturating_add(RocksDbWeight::get().reads(7_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 f7114e8f24b6ffc8c2654895104b682457c5c45e..06d9c30792e6f8a93d43ce48a06a9c0d34f5cc55 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -30,10 +30,10 @@ frame-benchmarking = { path = "../../benchmarking", default-features = false, op # Other dependencies codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } sp-storage = { path = "../../../primitives/storage", default-features = false } @@ -66,6 +66,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 fc860347d85fa37fc98890b5d4b2f56722040a8e..933ce13b0ee6f7a23110772a82b51ab15fc7dd2a 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 0000000000000000000000000000000000000000..17e96e2b02562d226a50800ffbb2109bd66c276e --- /dev/null +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs @@ -0,0 +1,123 @@ +// 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 + +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, DispatchTransaction, Dispatchable}; + +#[benchmarks(where + 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 = whitelisted_caller(); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(0u32.into(), None); + let inner = frame_system::Call::remark { remark: vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + 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, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_native() { + let caller: T::AccountId = whitelisted_caller(); + 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: vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + weight: Weight::from_parts(10, 0), + 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, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_asset() { + let caller: T::AccountId = whitelisted_caller(); + 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: vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + weight: Weight::from_parts(10, 0), + 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, |_| 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 753fae747a37ec914abb439fc3829c4caca9a448..991b5f314061639665ecd825ea1ace2ff38745ce 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -31,7 +31,7 @@ //! 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)] @@ -40,6 +40,7 @@ use sp_std::prelude::*; use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, + pallet_prelude::Weight, traits::{ tokens::{ fungibles::{Balanced, Credit, Inspect}, @@ -52,10 +53,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, + TransactionExtension, TransactionExtensionBase, Zero, }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; #[cfg(test)] @@ -63,8 +65,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 = @@ -120,11 +128,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; + #[cfg(feature = "runtime-benchmarks")] + /// Benchmark helper + 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 { @@ -172,9 +199,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)) @@ -209,104 +235,139 @@ impl sp_std::fmt::Debug for ChargeAssetTxPayment { } } -impl SignedExtension for ChargeAssetTxPayment +impl TransactionExtensionBase for ChargeAssetTxPayment where - T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync, BalanceOf: Send + Sync + From + IsType>, ChargeAssetIdOf: Send + Sync, Credit: IsType>, { const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); + + fn weight(&self) -> Weight { + if self.asset_id.is_some() { + ::WeightInfo::charge_asset_tx_payment_asset() + } else { + ::WeightInfo::charge_asset_tx_payment_native() + } + } +} + +impl TransactionExtension for ChargeAssetTxPayment +where + T::RuntimeCall: Dispatchable, + AssetBalanceOf: Send + Sync, + BalanceOf: Send + Sync + From + IsType>, + ChargeAssetIdOf: Send + Sync, + Credit: IsType>, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, +{ + type Val = ( + // tip + BalanceOf, + // who paid the fee + T::AccountId, + // transaction fee + BalanceOf, + ); type Pre = ( // tip BalanceOf, // who paid the fee - Self::AccountId, + T::AccountId, // imbalance resulting from withdrawing the fee InitialPayment, // asset_id for the transaction payment Option>, ); - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } - fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + _call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> TransactionValidity { + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { use pallet_transaction_payment::ChargeTransactionPayment; - let (fee, _) = self.withdraw_fee(who, call, info, len)?; + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + // 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); let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - Ok(ValidTransaction { priority, ..Default::default() }) + let val = (self.tip, 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, + _context: &Context, ) -> Result { - let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; - Ok((self.tip, who.clone(), initial_payment, self.asset_id)) + let (tip, who, fee) = val; + // Mutating call of `withdraw_fee` to actually charge for the transaction. + let (_fee, initial_payment) = self.withdraw_fee(&who, call, info, fee)?; + Ok((tip, who, initial_payment, self.asset_id)) } fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, + _context: &Context, ) -> 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)), + let (tip, who, initial_payment, asset_id) = pre; + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( + (tip, who, already_withdrawn), + info, + post_info, + len, + result, + &(), + )?; + }, + 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, - len, - result, + 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, + }); + }, + 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(()) 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 1f335b4f6c4ab5cc59a4815a2160328aa7f584df..bb484795e82598f52f518edb15dcf26443d9f118 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -136,12 +136,12 @@ impl WeightToFeeT for TransactionByteFee { } } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; } @@ -205,4 +205,56 @@ impl Config for Runtime { pallet_assets::BalanceToAssetBalance, CreditToBlockAuthor, >; + type WeightInfo = (); + #[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/tests.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs index 8df98ceda9971565788576ee839792f6d58da2b0..42b8f2cf5fabb8b74aa0a99ac2b67fefa656728a 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -25,7 +25,10 @@ use frame_support::{ 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 }); @@ -116,33 +119,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::from_parts(5, 0)), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, None) + .validate_and_prepare( + Some(1).into(), + CALL, + &info_from_weight(Weight::from_parts(5, 0)), + len, + ) .unwrap(); let initial_balance = 10 * balance_factor; assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + pre, &info_from_weight(Weight::from_parts(5, 0)), &default_post_info(), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) + let (pre, _) = ChargeAssetTxPayment::::from(5 /* tipped */, None) + .validate_and_prepare( + Some(2).into(), + CALL, + &info_from_weight(Weight::from_parts(100, 0)), + len, + ) .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), + pre, &info_from_weight(Weight::from_parts(100, 0)), &post_info_from_weight(Weight::from_parts(50, 0)), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); }); @@ -179,8 +194,13 @@ 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, + ) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -189,11 +209,12 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + 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 @@ -232,8 +253,13 @@ 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, + ) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -242,11 +268,12 @@ fn transaction_payment_without_fee() { assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + 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); @@ -287,18 +314,24 @@ fn asset_transaction_payment_with_tip_and_refund() { // 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) + let (pre, _) = ChargeAssetTxPayment::::from(tip, Some(asset_id)) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + ) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); let final_weight = 50; assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + pre, &info_from_weight(Weight::from_parts(weight, 0)), &post_info_from_weight(Weight::from_parts(final_weight, 0)), len, - &Ok(()) + &Ok(()), + &() )); let final_fee = fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get(); @@ -339,19 +372,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, + ) .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), + 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); @@ -372,7 +411,12 @@ 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 + ) .is_err()); // create the non-sufficient asset @@ -386,7 +430,12 @@ 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 + ) .is_err()); }); } @@ -424,33 +473,40 @@ 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) .unwrap(); // `Pays::No` still implies no fees assert_eq!(Assets::balance(asset_id, caller), balance); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + 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, + ) .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), + pre, &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()) + &Ok(()), + &() )); assert_eq!(Assets::balance(asset_id, caller), balance - 1); }); @@ -488,8 +544,8 @@ 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) .unwrap(); // `Pays::No` implies no pre-dispatch fees assert_eq!(Assets::balance(asset_id, caller), balance); @@ -503,60 +559,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), + 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 = 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(); - - 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); }); 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 0000000000000000000000000000000000000000..1af1c94177d26b3316d506d1419a3d6cb052d4c2 --- /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/rpc/Cargo.toml b/substrate/frame/transaction-payment/rpc/Cargo.toml index e7edf8a4b87920702d9669e62d611c2349bd20e4..6d7f632af82813050d4c0523dcd61dc27ea512f1 100644 --- a/substrate/frame/transaction-payment/rpc/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } pallet-transaction-payment-rpc-runtime-api = { path = "runtime-api" } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } 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 6c34c26ce9236dd76ff90224d3ce2d59dbd3157a..9810ea08c790d2ad964d5bf98906d12b76fe8f91 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,8 @@ //! //! This pallet wraps an existing transaction payment pallet. This means you should both pallets //! in your `construct_runtime` macro and include this pallet's -//! [`SignedExtension`] ([`SkipCheckIfFeeless`]) that would accept the existing one as an argument. +//! [`TransactionExtension`] ([`SkipCheckIfFeeless`]) that would accept the existing one as an +//! argument. #![cfg_attr(not(feature = "std"), no_std)] @@ -42,7 +43,10 @@ use frame_support::{ }; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ - traits::{DispatchInfoOf, PostDispatchInfoOf, SignedExtension}, + traits::{ + DispatchInfoOf, OriginOf, PostDispatchInfoOf, TransactionExtension, + TransactionExtensionBase, ValidateResult, + }, transaction_validity::TransactionValidityError, }; @@ -70,11 +74,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, sp_std::marker::PhantomData); @@ -103,53 +107,96 @@ impl From for SkipCheckIfFeeless { } } -impl> SignedExtension +pub enum Intermediate { + /// The wrapped extension should be applied. + Apply(T), + /// The wrapped extension should be skipped. + Skip(O), +} +use Intermediate::*; + +impl TransactionExtensionBase for SkipCheckIfFeeless -where - S::Call: 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() + } - fn additional_signed(&self) -> Result { - self.0.additional_signed() + fn weight(&self) -> frame_support::weights::Weight { + self.0.weight() } +} - fn pre_dispatch( +impl> + TransactionExtension for SkipCheckIfFeeless +where + T::RuntimeCall: CheckIfFeeless>, +{ + type Val = Intermediate as OriginTrait>::PalletsOrigin>; + type Pre = Intermediate as OriginTrait>::PalletsOrigin>; + + fn validate( + &self, + origin: OriginOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, + len: usize, + context: &mut Context, + self_implicit: S::Implicit, + inherited_implication: &impl Encode, + ) -> ValidateResult { + if call.is_feeless(&origin) { + Ok((Default::default(), Skip(origin.caller().clone()), origin)) + } else { + let (x, y, z) = self.0.validate( + origin, + call, + info, + len, + context, + self_implicit, + inherited_implication, + )?; + Ok((x, Apply(y), z)) + } + } + + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, + val: Self::Val, + origin: &OriginOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, + context: &Context, ) -> 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, context).map(Apply), + Skip(origin) => Ok(Skip(origin)), } } fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, + context: &Context, ) -> 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 }); - } + match pre { + Apply(pre) => S::post_dispatch(pre, info, post_info, len, result, context), + Skip(origin) => { + Pallet::::deposit_event(Event::::FeeSkipped { origin }); + Ok(()) + }, } - 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 17c4c773997eb591c1f8aac06a607c3e35df8db0..06948de4c3ce972ba0e38eddac6ae3ab23804bbd 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::{ + impl_tx_ext_default, + traits::{OriginOf, TransactionExtension}, +}; type Block = frame_system::mocking::MockBlock; -type AccountId = u64; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { @@ -38,21 +41,22 @@ parameter_types! { #[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 TransactionExtensionBase for DummyExtension { const IDENTIFIER: &'static str = "DummyExtension"; - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } - fn pre_dispatch( + type Implicit = (); +} +impl TransactionExtension for DummyExtension { + type Val = (); + type Pre = (); + impl_tx_ext_default!(RuntimeCall; C; validate); + fn prepare( self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, + _val: Self::Val, + _origin: &OriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, _len: usize, + _context: &C, ) -> Result { PreDispatchCount::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 4b4dd6997418f9c9e39ebe0ab294051a688f2f87..96b4af7e203e0bcbd1773969f2baefdfe24150d6 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs @@ -16,18 +16,19 @@ use super::*; use crate::mock::{pallet_dummy::Call, DummyExtension, PreDispatchCount, Runtime, RuntimeCall}; use frame_support::dispatch::DispatchInfo; +use sp_runtime::traits::DispatchTransaction; #[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) .unwrap(); assert_eq!(PreDispatchCount::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) .unwrap(); assert_eq!(PreDispatchCount::get(), 1); } diff --git a/substrate/frame/transaction-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..d63c5a7d746e4cb5030438a2c9c82b1a307f965e --- /dev/null +++ b/substrate/frame/transaction-payment/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 Transaction Payment Pallet's transaction extension + +use super::*; +use crate::Pallet; +use frame_benchmarking::v2::*; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use frame_system::{EventRecord, RawOrigin}; +use sp_runtime::traits::{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::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + From, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn charge_transaction_payment() { + let caller: T::AccountId = whitelisted_caller(); + >::endow_account( + &caller, + >::minimum_balance() * 1000.into(), + ); + let tip = >::minimum_balance(); + let ext: ChargeTransactionPayment = ChargeTransactionPayment::from(tip); + let inner = frame_system::Call::remark { remark: vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + weight: Weight::from_parts(100, 0), + 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, 10, |_| Ok( + post_info + )) + .unwrap() + .is_ok()); + } + + 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 efadfd60bdd30126f8627fccea7c02f4c42c68a3..6b17616bdc7eb1ba22dddb135926b0ab83b5592e 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -62,23 +62,28 @@ pub use payment::*; use sp_runtime::{ traits::{ Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion, - Saturating, SignedExtension, Zero, + Saturating, TransactionExtension, TransactionExtensionBase, Zero, }, transaction_validity::{ - TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, + InvalidTransaction, TransactionPriority, TransactionValidityError, ValidTransaction, }, FixedPointNumber, FixedU128, Perbill, Perquintill, RuntimeDebug, }; use sp_std::prelude::*; 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; @@ -335,6 +340,7 @@ pub mod pallet { type RuntimeEvent = (); type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = (); + type WeightInfo = (); } } @@ -387,6 +393,9 @@ pub mod pallet { /// transactions. #[pallet::constant] type OperationalFeeMultiplier: Get; + + /// The weight information of this pallet. + type WeightInfo: WeightInfo; } #[pallet::type_value] @@ -507,11 +516,11 @@ 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; @@ -531,11 +540,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) } } @@ -714,7 +723,7 @@ where who: &T::AccountId, call: &T::RuntimeCall, info: &DispatchInfoOf, - len: usize, + fee: BalanceOf, ) -> Result< ( BalanceOf, @@ -723,7 +732,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, @@ -731,6 +739,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. /// @@ -817,67 +841,93 @@ impl sp_std::fmt::Debug for ChargeTransactionPayment { } } -impl SignedExtension for ChargeTransactionPayment +impl TransactionExtensionBase for ChargeTransactionPayment { + const IDENTIFIER: &'static str = "ChargeTransactionPayment"; + type Implicit = (); + + fn weight(&self) -> Weight { + T::WeightInfo::charge_transaction_payment() + } +} + +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 Val = ( + // tip + BalanceOf, + // who paid the fee + T::AccountId, + // computed fee + BalanceOf, + ); type Pre = ( // tip BalanceOf, - // who paid the fee - this is an option to allow for a Default impl. - Self::AccountId, + // who paid the fee + T::AccountId, // imbalance resulting from withdrawing the fee <::OnChargeTransaction as OnChargeTransaction>::LiquidityInfo, ); - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } 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)?; + _context: &mut Context, + _: (), + _implication: &impl Encode, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + let who = frame_system::ensure_signed(origin.clone()) + .map_err(|_| InvalidTransaction::BadSigner)?; + 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() + }, + (self.0, who, 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, + _context: &Context, ) -> Result { - let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?; - Ok((self.0, who.clone(), imbalance)) + let (tip, who, fee) = val; + // Mutating call to `withdraw_fee` to actually charge for the transaction. + let (_final_fee, imbalance) = self.withdraw_fee(&who, call, info, fee)?; + Ok((tip, who, imbalance)) } fn post_dispatch( - maybe_pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + (tip, who, imbalance): Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, _result: &DispatchResult, + _context: &Context, ) -> 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 }); - } + 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(()) } } diff --git a/substrate/frame/transaction-payment/src/mock.rs b/substrate/frame/transaction-payment/src/mock.rs index 1ca2e3d734720455f8a2fdc9453c712d1f199796..eda234ffcae577f9794b4b310eb2492ff32843b4 100644 --- a/substrate/frame/transaction-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/src/mock.rs @@ -157,4 +157,14 @@ impl Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; type FeeMultiplierUpdate = (); + type WeightInfo = (); +} + +#[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 886683f2e0b883aea0ccd4e769c902ee45bdf99a..a13e73b50b0e931579a21995ca466ca6b3de4621 100644 --- a/substrate/frame/transaction-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/src/payment.rs @@ -20,7 +20,7 @@ use crate::Config; use core::marker::PhantomData; use sp_runtime::{ - traits::{DispatchInfoOf, PostDispatchInfoOf, Saturating, Zero}, + traits::{CheckedSub, DispatchInfoOf, PostDispatchInfoOf, Saturating, Zero}, transaction_validity::InvalidTransaction, }; @@ -51,6 +51,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. @@ -64,6 +75,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 the transaction payment for a pallet implementing the `Currency` @@ -121,6 +138,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. @@ -153,4 +197,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 d3a1721ccb9909b2f2a705d9bb9ddc9ebc7cb5ee..7a49f8111e2315de5784101fa7de86d7010b4c32 100644 --- a/substrate/frame/transaction-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/src/tests.rs @@ -21,11 +21,14 @@ 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, + BuildStorage, }; use frame_support::{ - assert_noop, assert_ok, + assert_ok, dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, traits::Currency, weights::Weight, @@ -128,44 +131,37 @@ 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) + let info = info_from_weight(Weight::from_parts(5, 0)); + Ext::from(0) + .test_run(Some(1).into(), CALL, &info, 10, |_| { + assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); + Ok(default_post_info()) + }) + .unwrap() .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); 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 info = info_from_weight(Weight::from_parts(100, 0)); + Ext::from(5 /* tipped */) + .test_run(Some(2).into(), CALL, &info, 10, |_| { + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 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!(TipUnbalancedAmount::get(), 5); @@ -173,43 +169,37 @@ fn signed_extension_transaction_payment_work() { } #[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; >::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) + let len = 10; + let origin = Some(2).into(); + let info = info_from_weight(Weight::from_parts(100, 0)); + Ext::from(5 /* tipped */) + .test_run(origin, CALL, &info, len, |_| { + // 5 base fee, 10 byte fee, 3/2 * 100 weight fee, 5 tip + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 150 - 5); + Ok(post_info_from_weight(Weight::from_parts(50, 0))) + }) + .unwrap() .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); }); } #[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)); // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), @@ -220,7 +210,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 +222,28 @@ 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 { + let op_tx = DispatchInfo { weight: Weight::from_parts(0, 0), 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)); // like a InsecureFreeNormal - let free_transaction = DispatchInfo { + let free_tx = DispatchInfo { weight: Weight::from_parts(0, 0), 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).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,16 +252,15 @@ fn signed_ext_length_fee_is_also_updated_per_congestion() { // all fees should be x1.5 >::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)); 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 ); }) } @@ -291,62 +270,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 - >::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 + >::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 }, + ); + }); } #[test] @@ -357,39 +336,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 - >::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 * multipler */ - }), - tip: 0, - }, - ); - }); + .base_weight(Weight::from_parts(5, 0)) + .weight_fee(2) + .build() + .execute_with(|| { + // all fees should be x1.5 + >::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 * multipler */ + }), + tip: 0, + }, + ); + }); } #[test] @@ -526,27 +505,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, |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 { @@ -568,20 +543,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, |_| { + 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); }); } @@ -594,25 +564,20 @@ fn zero_transfer_on_free_transaction() { .execute_with(|| { // So events are emitted System::set_block_number(10); - let len = 10; - let dispatch_info = DispatchInfo { + let info = DispatchInfo { weight: Weight::from_parts(100, 0), 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, |_| { + 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 { @@ -639,19 +604,11 @@ fn refund_consistent_with_actual_weight() { >::put(Multiplier::saturating_from_rational(5, 4)); - let pre = ChargeTransactionPayment::::from(tip) - .pre_dispatch(&2, CALL, &info, len) + Ext::from(tip) + .test_run(Some(2).into(), CALL, &info, len, |_| 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); @@ -673,18 +630,13 @@ fn should_alter_operational_priority() { class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; + let ext = Ext::from(tip); + let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; assert_eq!(priority, 60); - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; - + let ext = Ext::from(2 * tip); + let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; assert_eq!(priority, 110); }); @@ -694,16 +646,13 @@ fn should_alter_operational_priority() { class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; + + let ext = Ext::from(tip); + let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; assert_eq!(priority, 5810); - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; + let ext = Ext::from(2 * tip); + let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; assert_eq!(priority, 6110); }); } @@ -719,11 +668,8 @@ fn no_tip_has_some_priority() { class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; - + let ext = Ext::from(tip); + let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; assert_eq!(priority, 10); }); @@ -733,10 +679,8 @@ fn no_tip_has_some_priority() { class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; + let ext = Ext::from(tip); + let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; assert_eq!(priority, 5510); }); } @@ -744,8 +688,8 @@ 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 { @@ -753,10 +697,8 @@ fn higher_tip_have_higher_priority() { class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - priority1 = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; + let ext = Ext::from(tip); + pri1 = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; }); ExtBuilder::default().balance_factor(100).build().execute_with(|| { @@ -765,13 +707,11 @@ fn higher_tip_have_higher_priority() { class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - priority2 = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; + let ext = Ext::from(tip); + pri2 = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; }); - (priority1, priority2) + (pri1, pri2) }; let mut prev_priorities = get_priorities(0); @@ -799,19 +739,11 @@ fn post_info_can_change_pays_fee() { >::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, |_| 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); diff --git a/substrate/frame/transaction-payment/src/types.rs b/substrate/frame/transaction-payment/src/types.rs index 25cecc58a63ab092822d61bb32259a7a846b230a..bfb3012fef06033f9419708251865b8eadb619be 100644 --- a/substrate/frame/transaction-payment/src/types.rs +++ b/substrate/frame/transaction-payment/src/types.rs @@ -112,7 +112,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 0000000000000000000000000000000000000000..bcffb2eb331acf77f694f74510f61d8653db0f95 --- /dev/null +++ b/substrate/frame/transaction-payment/src/weights.rs @@ -0,0 +1,92 @@ +// 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-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_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: `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: `248` + // Estimated: `1733` + // Minimum execution time: 40_506_000 picoseconds. + Weight::from_parts(41_647_000, 1733) + .saturating_add(T::DbWeight::get().reads(3_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Authorship::Author` (r:1 w:0) + /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `248` + // Estimated: `1733` + // Minimum execution time: 40_506_000 picoseconds. + Weight::from_parts(41_647_000, 1733) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + } +} diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index c96aa91d54a8287f66ebccaa4493f8d69ab496d5..1386d9b5a5691475bdc06a198a86cb944b7e8305 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", optional = true } +serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } @@ -29,7 +29,7 @@ sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-transaction-storage-proof = { path = "../../primitives/transaction-storage-proof", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/transaction-storage/src/weights.rs b/substrate/frame/transaction-storage/src/weights.rs index 519317177c492f4e1179b9ee12f17da7d442b0e4..bfbed62c5a37202bb4b93ac9e07cedc0891251cc 100644 --- a/substrate/frame/transaction-storage/src/weights.rs +++ b/substrate/frame/transaction-storage/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_transaction_storage +//! Autogenerated weights for `pallet_transaction_storage` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/transaction-storage/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/transaction-storage/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,125 +49,133 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_transaction_storage. +/// Weight functions needed for `pallet_transaction_storage`. pub trait WeightInfo { fn store(l: u32, ) -> Weight; fn renew() -> Weight; fn check_proof_max() -> Weight; } -/// Weights for pallet_transaction_storage using the Substrate node and recommended hardware. +/// Weights for `pallet_transaction_storage` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: TransactionStorage ByteFee (r:1 w:0) - /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage EntryFee (r:1 w:0) - /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage BlockTransactions (r:1 w:1) - /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) + /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) + /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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`) + /// 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]`. fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `176` + // Measured: `242` // Estimated: `38351` - // Minimum execution time: 34_844_000 picoseconds. - Weight::from_parts(35_489_000, 38351) + // Minimum execution time: 57_912_000 picoseconds. + Weight::from_parts(58_642_000, 38351) // Standard Error: 11 - .saturating_add(Weight::from_parts(6_912, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(6_778, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: TransactionStorage Transactions (r:1 w:0) - /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) - /// Storage: TransactionStorage ByteFee (r:1 w:0) - /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage EntryFee (r:1 w:0) - /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage BlockTransactions (r:1 w:1) - /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) + /// Storage: `TransactionStorage::Transactions` (r:1 w:0) + /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) + /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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`) + /// 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: `326` + // Measured: `430` // Estimated: `40351` - // Minimum execution time: 48_244_000 picoseconds. - Weight::from_parts(50_939_000, 40351) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 72_571_000 picoseconds. + Weight::from_parts(74_832_000, 40351) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: TransactionStorage ProofChecked (r:1 w:1) - /// Proof: TransactionStorage ProofChecked (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: TransactionStorage StoragePeriod (r:1 w:0) - /// Proof: TransactionStorage StoragePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: TransactionStorage ChunkCount (r:1 w:0) - /// Proof: TransactionStorage ChunkCount (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TransactionStorage Transactions (r:1 w:0) - /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) + /// Storage: `TransactionStorage::ProofChecked` (r:1 w:1) + /// Proof: `TransactionStorage::ProofChecked` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::StoragePeriod` (r:1 w:0) + /// Proof: `TransactionStorage::StoragePeriod` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::ChunkCount` (r:1 w:0) + /// Proof: `TransactionStorage::ChunkCount` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::Transactions` (r:1 w:0) + /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) fn check_proof_max() -> Weight { // Proof Size summary in bytes: - // Measured: `37145` + // Measured: `37211` // Estimated: `40351` - // Minimum execution time: 80_913_000 picoseconds. - Weight::from_parts(84_812_000, 40351) + // Minimum execution time: 65_985_000 picoseconds. + Weight::from_parts(72_960_000, 40351) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: TransactionStorage ByteFee (r:1 w:0) - /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage EntryFee (r:1 w:0) - /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage BlockTransactions (r:1 w:1) - /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) + /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) + /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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`) + /// 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]`. fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `176` + // Measured: `242` // Estimated: `38351` - // Minimum execution time: 34_844_000 picoseconds. - Weight::from_parts(35_489_000, 38351) + // Minimum execution time: 57_912_000 picoseconds. + Weight::from_parts(58_642_000, 38351) // Standard Error: 11 - .saturating_add(Weight::from_parts(6_912, 0).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(6_778, 0).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: TransactionStorage Transactions (r:1 w:0) - /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) - /// Storage: TransactionStorage ByteFee (r:1 w:0) - /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage EntryFee (r:1 w:0) - /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: TransactionStorage BlockTransactions (r:1 w:1) - /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) + /// Storage: `TransactionStorage::Transactions` (r:1 w:0) + /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) + /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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`) + /// 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: `326` + // Measured: `430` // Estimated: `40351` - // Minimum execution time: 48_244_000 picoseconds. - Weight::from_parts(50_939_000, 40351) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 72_571_000 picoseconds. + Weight::from_parts(74_832_000, 40351) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: TransactionStorage ProofChecked (r:1 w:1) - /// Proof: TransactionStorage ProofChecked (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: TransactionStorage StoragePeriod (r:1 w:0) - /// Proof: TransactionStorage StoragePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: TransactionStorage ChunkCount (r:1 w:0) - /// Proof: TransactionStorage ChunkCount (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TransactionStorage Transactions (r:1 w:0) - /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) + /// Storage: `TransactionStorage::ProofChecked` (r:1 w:1) + /// Proof: `TransactionStorage::ProofChecked` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::StoragePeriod` (r:1 w:0) + /// Proof: `TransactionStorage::StoragePeriod` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::ChunkCount` (r:1 w:0) + /// Proof: `TransactionStorage::ChunkCount` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TransactionStorage::Transactions` (r:1 w:0) + /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) fn check_proof_max() -> Weight { // Proof Size summary in bytes: - // Measured: `37145` + // Measured: `37211` // Estimated: `40351` - // Minimum execution time: 80_913_000 picoseconds. - Weight::from_parts(84_812_000, 40351) + // Minimum execution time: 65_985_000 picoseconds. + Weight::from_parts(72_960_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 2dc603e9f9b5bc7e4f82795dd9aedcc5f21d5393..5f90904123d9341425ff707ae7682e2f20f28ecf 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = docify = "0.2.7" impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", features = ["derive"], optional = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index e35d50e23a3424ddb17c03acc89d42baf7429bb4..b488300de99d5d0c77d8496b597f71c03935b61e 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -20,9 +20,8 @@ #![cfg(test)] use core::{cell::RefCell, marker::PhantomData}; -use sp_core::H256; use sp_runtime::{ - traits::{BadOrigin, BlakeTwo256, Dispatchable, IdentityLookup}, + traits::{BadOrigin, Dispatchable, IdentityLookup}, BuildStorage, }; @@ -56,29 +55,10 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { type MaxLocks = (); diff --git a/substrate/frame/treasury/src/weights.rs b/substrate/frame/treasury/src/weights.rs index 030e18980eb54f8b16452691b884e6046878aaa2..8ef4f89fd6519037d811666e0792cd13bcc2661a 100644 --- a/substrate/frame/treasury/src/weights.rs +++ b/substrate/frame/treasury/src/weights.rs @@ -15,27 +15,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_treasury +//! 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: `20`, REPEAT: `2`, 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: `cob`, 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/debug/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev -// --steps=20 -// --repeat=2 -// --pallet=pallet-treasury +// --steps=50 +// --repeat=20 +// --pallet=pallet_treasury +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/treasury/src/._weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/treasury/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_treasury. +/// Weight functions needed for `pallet_treasury`. pub trait WeightInfo { fn spend_local() -> Weight; fn propose_spend() -> Weight; @@ -59,304 +63,304 @@ pub trait WeightInfo { fn void_spend() -> Weight; } -/// Weights for pallet_treasury using the Substrate node and recommended hardware. +/// Weights for `pallet_treasury` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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: `76` // Estimated: `1887` - // Minimum execution time: 179_000_000 picoseconds. - Weight::from_parts(190_000_000, 1887) + // Minimum execution time: 11_686_000 picoseconds. + Weight::from_parts(12_138_000, 1887) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, 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::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn propose_spend() -> Weight { // Proof Size summary in bytes: // Measured: `177` // Estimated: `1489` - // Minimum execution time: 349_000_000 picoseconds. - Weight::from_parts(398_000_000, 1489) + // Minimum execution time: 23_773_000 picoseconds. + Weight::from_parts(24_801_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Treasury Proposals (r:1 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Treasury::Proposals` (r:1 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn reject_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3593` - // Minimum execution time: 367_000_000 picoseconds. - Weight::from_parts(388_000_000, 3593) + // Minimum execution time: 24_533_000 picoseconds. + Weight::from_parts(25_731_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: Treasury Proposals (r:1 w:0) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, 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:1 w:0) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `483 + p * (9 ±0)` + // Measured: `504 + p * (8 ±0)` // Estimated: `3573` - // Minimum execution time: 111_000_000 picoseconds. - Weight::from_parts(108_813_243, 3573) - // Standard Error: 147_887 - .saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into())) + // Minimum execution time: 8_245_000 picoseconds. + Weight::from_parts(11_300_222, 3573) + // Standard Error: 1_080 + .saturating_add(Weight::from_parts(71_375, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_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: 71_000_000 picoseconds. - Weight::from_parts(78_000_000, 1887) + // Minimum execution time: 6_231_000 picoseconds. + Weight::from_parts(6_517_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::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`) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `427 + p * (251 ±0)` + // Measured: `451 + p * (251 ±0)` // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 614_000_000 picoseconds. - Weight::from_parts(498_501_558, 1887) - // Standard Error: 1_070_260 - .saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into())) + // Minimum execution time: 30_729_000 picoseconds. + Weight::from_parts(37_861_389, 1887) + // Standard Error: 18_741 + .saturating_add(Weight::from_parts(31_377_118, 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())) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:0) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, 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(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, 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`) fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3501` - // Minimum execution time: 214_000_000 picoseconds. - Weight::from_parts(216_000_000, 3501) + // Minimum execution time: 13_700_000 picoseconds. + Weight::from_parts(14_519_000, 3501) .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(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `705` + // Measured: `709` // Estimated: `6208` - // Minimum execution time: 760_000_000 picoseconds. - Weight::from_parts(822_000_000, 6208) + // Minimum execution time: 54_888_000 picoseconds. + Weight::from_parts(55_966_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(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `194` - // Estimated: `3534` - // Minimum execution time: 153_000_000 picoseconds. - Weight::from_parts(160_000_000, 3534) + // Measured: `198` + // Estimated: `3538` + // Minimum execution time: 11_802_000 picoseconds. + Weight::from_parts(12_421_000, 3538) .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(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `194` - // Estimated: `3534` - // Minimum execution time: 147_000_000 picoseconds. - Weight::from_parts(181_000_000, 3534) + // Measured: `198` + // Estimated: `3538` + // Minimum execution time: 10_571_000 picoseconds. + Weight::from_parts(11_052_000, 3538) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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: `76` // Estimated: `1887` - // Minimum execution time: 179_000_000 picoseconds. - Weight::from_parts(190_000_000, 1887) + // Minimum execution time: 11_686_000 picoseconds. + Weight::from_parts(12_138_000, 1887) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, 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::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn propose_spend() -> Weight { // Proof Size summary in bytes: // Measured: `177` // Estimated: `1489` - // Minimum execution time: 349_000_000 picoseconds. - Weight::from_parts(398_000_000, 1489) + // Minimum execution time: 23_773_000 picoseconds. + Weight::from_parts(24_801_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Treasury Proposals (r:1 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Treasury::Proposals` (r:1 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn reject_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3593` - // Minimum execution time: 367_000_000 picoseconds. - Weight::from_parts(388_000_000, 3593) + // Minimum execution time: 24_533_000 picoseconds. + Weight::from_parts(25_731_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: Treasury Proposals (r:1 w:0) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, 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:1 w:0) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `483 + p * (9 ±0)` + // Measured: `504 + p * (8 ±0)` // Estimated: `3573` - // Minimum execution time: 111_000_000 picoseconds. - Weight::from_parts(108_813_243, 3573) - // Standard Error: 147_887 - .saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into())) + // Minimum execution time: 8_245_000 picoseconds. + Weight::from_parts(11_300_222, 3573) + // Standard Error: 1_080 + .saturating_add(Weight::from_parts(71_375, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_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: 71_000_000 picoseconds. - Weight::from_parts(78_000_000, 1887) + // Minimum execution time: 6_231_000 picoseconds. + Weight::from_parts(6_517_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::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`) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `427 + p * (251 ±0)` + // Measured: `451 + p * (251 ±0)` // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 614_000_000 picoseconds. - Weight::from_parts(498_501_558, 1887) - // Standard Error: 1_070_260 - .saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into())) + // Minimum execution time: 30_729_000 picoseconds. + Weight::from_parts(37_861_389, 1887) + // Standard Error: 18_741 + .saturating_add(Weight::from_parts(31_377_118, 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())) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:0) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, 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(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, 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`) fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3501` - // Minimum execution time: 214_000_000 picoseconds. - Weight::from_parts(216_000_000, 3501) + // Minimum execution time: 13_700_000 picoseconds. + Weight::from_parts(14_519_000, 3501) .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(69), added: 2544, mode: MaxEncodedLen) - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `705` + // Measured: `709` // Estimated: `6208` - // Minimum execution time: 760_000_000 picoseconds. - Weight::from_parts(822_000_000, 6208) + // Minimum execution time: 54_888_000 picoseconds. + Weight::from_parts(55_966_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(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `194` - // Estimated: `3534` - // Minimum execution time: 153_000_000 picoseconds. - Weight::from_parts(160_000_000, 3534) + // Measured: `198` + // Estimated: `3538` + // Minimum execution time: 11_802_000 picoseconds. + Weight::from_parts(12_421_000, 3538) .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(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `194` - // Estimated: `3534` - // Minimum execution time: 147_000_000 picoseconds. - Weight::from_parts(181_000_000, 3534) + // Measured: `198` + // Estimated: `3538` + // Minimum execution time: 10_571_000 picoseconds. + Weight::from_parts(11_052_000, 3538) .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 b733e64b159dc40872e27dd540ed40820e5cc78d..14fead12a8e11647c15714b2937f06da7c8b2f99 100644 --- a/substrate/frame/tx-pause/src/weights.rs +++ b/substrate/frame/tx-pause/src/weights.rs @@ -17,27 +17,29 @@ //! Autogenerated weights for `pallet_tx_pause` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-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-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-aahe6cbd-project-145-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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_tx_pause +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_tx_pause -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/tx-pause/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/tx-pause/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,8 +64,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3997` - // Minimum execution time: 15_096_000 picoseconds. - Weight::from_parts(15_437_000, 3997) + // Minimum execution time: 12_014_000 picoseconds. + Weight::from_parts(12_980_000, 3997) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -73,8 +75,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `565` // Estimated: `3997` - // Minimum execution time: 21_546_000 picoseconds. - Weight::from_parts(22_178_000, 3997) + // Minimum execution time: 17_955_000 picoseconds. + Weight::from_parts(18_348_000, 3997) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -88,8 +90,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3997` - // Minimum execution time: 15_096_000 picoseconds. - Weight::from_parts(15_437_000, 3997) + // Minimum execution time: 12_014_000 picoseconds. + Weight::from_parts(12_980_000, 3997) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -99,8 +101,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `565` // Estimated: `3997` - // Minimum execution time: 21_546_000 picoseconds. - Weight::from_parts(22_178_000, 3997) + // Minimum execution time: 17_955_000 picoseconds. + Weight::from_parts(18_348_000, 3997) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index 8a5a180d75f3ab03bb0ecce8c7a337dc9f3e0c17..4e5f21b3d8df8fa45da0735cdd0ebe1afac6d181 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/uniques/src/mock.rs b/substrate/frame/uniques/src/mock.rs index 16da2b2a2e285af87d1fb392f5b17b1022ad4ef2..eae125971635ec7d3b6ed7a8559e0a5e018592f7 100644 --- a/substrate/frame/uniques/src/mock.rs +++ b/substrate/frame/uniques/src/mock.rs @@ -24,11 +24,7 @@ use frame_support::{ construct_runtime, derive_impl, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -43,29 +39,8 @@ construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/uniques/src/weights.rs b/substrate/frame/uniques/src/weights.rs index eb80ee550a1db2d97aaed001f5041e49fdbca864..6c7b60b82e52e2caa9ac4536a33dda4df687c122 100644 --- a/substrate/frame/uniques/src/weights.rs +++ b/substrate/frame/uniques/src/weights.rs @@ -17,27 +17,29 @@ //! Autogenerated weights for `pallet_uniques` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-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-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-gghbxkbs-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_uniques +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_uniques -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/uniques/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/uniques/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -88,8 +90,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `249` // Estimated: `3643` - // Minimum execution time: 31_393_000 picoseconds. - Weight::from_parts(32_933_000, 3643) + // Minimum execution time: 27_960_000 picoseconds. + Weight::from_parts(28_781_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -101,8 +103,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3643` - // Minimum execution time: 14_827_000 picoseconds. - Weight::from_parts(15_273_000, 3643) + // Minimum execution time: 11_970_000 picoseconds. + Weight::from_parts(12_512_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -111,13 +113,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Uniques::Asset` (r:1001 w:1000) /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1000 w:1000) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1000 w:1000) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:1) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:0 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) /// Storage: `Uniques::Account` (r:0 w:1000) /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Uniques::CollectionMaxSupply` (r:0 w:1) @@ -128,15 +130,15 @@ impl WeightInfo for SubstrateWeight { 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)` - // Estimated: `3643 + a * (2839 ±0) + m * (2583 ±0) + n * (2597 ±0)` - // Minimum execution time: 3_281_673_000 picoseconds. - Weight::from_parts(3_443_387_000, 3643) - // Standard Error: 41_937 - .saturating_add(Weight::from_parts(7_914_842, 0).saturating_mul(n.into())) - // Standard Error: 41_937 - .saturating_add(Weight::from_parts(519_960, 0).saturating_mul(m.into())) - // Standard Error: 41_937 - .saturating_add(Weight::from_parts(462_690, 0).saturating_mul(a.into())) + // Estimated: `3643 + a * (2647 ±0) + m * (2662 ±0) + n * (2597 ±0)` + // Minimum execution time: 2_979_858_000 picoseconds. + Weight::from_parts(3_007_268_000, 3643) + // Standard Error: 29_899 + .saturating_add(Weight::from_parts(6_943_612, 0).saturating_mul(n.into())) + // Standard Error: 29_899 + .saturating_add(Weight::from_parts(398_114, 0).saturating_mul(m.into())) + // Standard Error: 29_899 + .saturating_add(Weight::from_parts(369_941, 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()))) @@ -145,8 +147,8 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2647).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: `Uniques::Asset` (r:1 w:1) @@ -161,8 +163,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 38_122_000 picoseconds. - Weight::from_parts(38_924_000, 3643) + // Minimum execution time: 32_733_000 picoseconds. + Weight::from_parts(33_487_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -178,8 +180,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 38_835_000 picoseconds. - Weight::from_parts(39_754_000, 3643) + // Minimum execution time: 34_202_000 picoseconds. + Weight::from_parts(35_146_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -195,8 +197,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 27_032_000 picoseconds. - Weight::from_parts(27_793_000, 3643) + // Minimum execution time: 24_285_000 picoseconds. + Weight::from_parts(25_300_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -209,10 +211,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `805 + i * (76 ±0)` // Estimated: `3643 + i * (2597 ±0)` - // Minimum execution time: 14_737_000 picoseconds. - Weight::from_parts(15_070_000, 3643) - // Standard Error: 22_500 - .saturating_add(Weight::from_parts(18_855_468, 0).saturating_mul(i.into())) + // Minimum execution time: 11_641_000 picoseconds. + Weight::from_parts(12_261_000, 3643) + // Standard Error: 18_897 + .saturating_add(Weight::from_parts(15_263_570, 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,8 +229,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 18_664_000 picoseconds. - Weight::from_parts(19_455_000, 3643) + // Minimum execution time: 16_122_000 picoseconds. + Weight::from_parts(16_627_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,8 +242,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 18_247_000 picoseconds. - Weight::from_parts(18_763_000, 3643) + // Minimum execution time: 15_824_000 picoseconds. + Weight::from_parts(16_522_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -251,8 +253,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 13_219_000 picoseconds. - Weight::from_parts(13_923_000, 3643) + // Minimum execution time: 10_802_000 picoseconds. + Weight::from_parts(11_206_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -262,8 +264,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 13_376_000 picoseconds. - Weight::from_parts(13_904_000, 3643) + // Minimum execution time: 10_805_000 picoseconds. + Weight::from_parts(11_340_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -271,16 +273,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:2) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `423` + // Measured: `597` // Estimated: `3643` - // Minimum execution time: 22_353_000 picoseconds. - Weight::from_parts(23_222_000, 3643) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 24_213_000 picoseconds. + Weight::from_parts(25_547_000, 3643) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) @@ -288,8 +292,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 14_072_000 picoseconds. - Weight::from_parts(14_619_000, 3643) + // Minimum execution time: 11_256_000 picoseconds. + Weight::from_parts(11_585_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -301,90 +305,90 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 17_081_000 picoseconds. - Weight::from_parts(17_698_000, 3643) + // Minimum execution time: 14_616_000 picoseconds. + Weight::from_parts(15_064_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `547` - // Estimated: `3829` - // Minimum execution time: 41_501_000 picoseconds. - Weight::from_parts(43_101_000, 3829) + // Measured: `626` + // Estimated: `3652` + // Minimum execution time: 35_640_000 picoseconds. + Weight::from_parts(37_007_000, 3652) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `936` - // Estimated: `3829` - // Minimum execution time: 39_722_000 picoseconds. - Weight::from_parts(40_390_000, 3829) + // Measured: `823` + // Estimated: `3652` + // Minimum execution time: 34_410_000 picoseconds. + Weight::from_parts(35_431_000, 3652) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// 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` - // Estimated: `3643` - // Minimum execution time: 30_726_000 picoseconds. - Weight::from_parts(31_557_000, 3643) + // Estimated: `3652` + // Minimum execution time: 26_187_000 picoseconds. + Weight::from_parts(27_837_000, 3652) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `547` - // Estimated: `3643` - // Minimum execution time: 31_303_000 picoseconds. - Weight::from_parts(32_389_000, 3643) + // Measured: `626` + // Estimated: `3652` + // Minimum execution time: 26_640_000 picoseconds. + Weight::from_parts(27_688_000, 3652) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// 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` // Estimated: `3643` - // Minimum execution time: 32_155_000 picoseconds. - Weight::from_parts(32_885_000, 3643) + // Minimum execution time: 26_781_000 picoseconds. + Weight::from_parts(27_628_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:0) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// 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: `461` + // Measured: `540` // Estimated: `3643` - // Minimum execution time: 30_044_000 picoseconds. - Weight::from_parts(31_405_000, 3643) + // Minimum execution time: 26_295_000 picoseconds. + Weight::from_parts(26_903_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -396,8 +400,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 18_904_000 picoseconds. - Weight::from_parts(19_687_000, 3643) + // Minimum execution time: 16_678_000 picoseconds. + Weight::from_parts(17_548_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -409,8 +413,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `528` // Estimated: `3643` - // Minimum execution time: 19_144_000 picoseconds. - Weight::from_parts(19_706_000, 3643) + // Minimum execution time: 16_408_000 picoseconds. + Weight::from_parts(16_957_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -420,8 +424,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3517` - // Minimum execution time: 15_339_000 picoseconds. - Weight::from_parts(15_918_000, 3517) + // Minimum execution time: 12_568_000 picoseconds. + Weight::from_parts(12_960_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -433,8 +437,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_387_000 picoseconds. - Weight::from_parts(15_726_000, 3643) + // Minimum execution time: 13_110_000 picoseconds. + Weight::from_parts(13_620_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -446,8 +450,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `326` // Estimated: `3587` - // Minimum execution time: 15_873_000 picoseconds. - Weight::from_parts(16_860_000, 3587) + // Minimum execution time: 13_568_000 picoseconds. + Weight::from_parts(14_211_000, 3587) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -463,8 +467,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `607` // Estimated: `3643` - // Minimum execution time: 37_245_000 picoseconds. - Weight::from_parts(38_383_000, 3643) + // Minimum execution time: 32_660_000 picoseconds. + Weight::from_parts(33_734_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -480,8 +484,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `249` // Estimated: `3643` - // Minimum execution time: 31_393_000 picoseconds. - Weight::from_parts(32_933_000, 3643) + // Minimum execution time: 27_960_000 picoseconds. + Weight::from_parts(28_781_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -493,8 +497,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3643` - // Minimum execution time: 14_827_000 picoseconds. - Weight::from_parts(15_273_000, 3643) + // Minimum execution time: 11_970_000 picoseconds. + Weight::from_parts(12_512_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -503,13 +507,13 @@ impl WeightInfo for () { /// Storage: `Uniques::Asset` (r:1001 w:1000) /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1000 w:1000) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1000 w:1000) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:1) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:0 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) /// Storage: `Uniques::Account` (r:0 w:1000) /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Uniques::CollectionMaxSupply` (r:0 w:1) @@ -520,15 +524,15 @@ impl WeightInfo for () { 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)` - // Estimated: `3643 + a * (2839 ±0) + m * (2583 ±0) + n * (2597 ±0)` - // Minimum execution time: 3_281_673_000 picoseconds. - Weight::from_parts(3_443_387_000, 3643) - // Standard Error: 41_937 - .saturating_add(Weight::from_parts(7_914_842, 0).saturating_mul(n.into())) - // Standard Error: 41_937 - .saturating_add(Weight::from_parts(519_960, 0).saturating_mul(m.into())) - // Standard Error: 41_937 - .saturating_add(Weight::from_parts(462_690, 0).saturating_mul(a.into())) + // Estimated: `3643 + a * (2647 ±0) + m * (2662 ±0) + n * (2597 ±0)` + // Minimum execution time: 2_979_858_000 picoseconds. + Weight::from_parts(3_007_268_000, 3643) + // Standard Error: 29_899 + .saturating_add(Weight::from_parts(6_943_612, 0).saturating_mul(n.into())) + // Standard Error: 29_899 + .saturating_add(Weight::from_parts(398_114, 0).saturating_mul(m.into())) + // Standard Error: 29_899 + .saturating_add(Weight::from_parts(369_941, 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()))) @@ -537,8 +541,8 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2647).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: `Uniques::Asset` (r:1 w:1) @@ -553,8 +557,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 38_122_000 picoseconds. - Weight::from_parts(38_924_000, 3643) + // Minimum execution time: 32_733_000 picoseconds. + Weight::from_parts(33_487_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -570,8 +574,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 38_835_000 picoseconds. - Weight::from_parts(39_754_000, 3643) + // Minimum execution time: 34_202_000 picoseconds. + Weight::from_parts(35_146_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -587,8 +591,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 27_032_000 picoseconds. - Weight::from_parts(27_793_000, 3643) + // Minimum execution time: 24_285_000 picoseconds. + Weight::from_parts(25_300_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -601,10 +605,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `805 + i * (76 ±0)` // Estimated: `3643 + i * (2597 ±0)` - // Minimum execution time: 14_737_000 picoseconds. - Weight::from_parts(15_070_000, 3643) - // Standard Error: 22_500 - .saturating_add(Weight::from_parts(18_855_468, 0).saturating_mul(i.into())) + // Minimum execution time: 11_641_000 picoseconds. + Weight::from_parts(12_261_000, 3643) + // Standard Error: 18_897 + .saturating_add(Weight::from_parts(15_263_570, 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)) @@ -619,8 +623,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 18_664_000 picoseconds. - Weight::from_parts(19_455_000, 3643) + // Minimum execution time: 16_122_000 picoseconds. + Weight::from_parts(16_627_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -632,8 +636,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 18_247_000 picoseconds. - Weight::from_parts(18_763_000, 3643) + // Minimum execution time: 15_824_000 picoseconds. + Weight::from_parts(16_522_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -643,8 +647,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 13_219_000 picoseconds. - Weight::from_parts(13_923_000, 3643) + // Minimum execution time: 10_802_000 picoseconds. + Weight::from_parts(11_206_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -654,8 +658,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 13_376_000 picoseconds. - Weight::from_parts(13_904_000, 3643) + // Minimum execution time: 10_805_000 picoseconds. + Weight::from_parts(11_340_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -663,16 +667,18 @@ impl WeightInfo for () { /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:2) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `423` + // Measured: `597` // Estimated: `3643` - // Minimum execution time: 22_353_000 picoseconds. - Weight::from_parts(23_222_000, 3643) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 24_213_000 picoseconds. + Weight::from_parts(25_547_000, 3643) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) @@ -680,8 +686,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 14_072_000 picoseconds. - Weight::from_parts(14_619_000, 3643) + // Minimum execution time: 11_256_000 picoseconds. + Weight::from_parts(11_585_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -693,90 +699,90 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 17_081_000 picoseconds. - Weight::from_parts(17_698_000, 3643) + // Minimum execution time: 14_616_000 picoseconds. + Weight::from_parts(15_064_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `547` - // Estimated: `3829` - // Minimum execution time: 41_501_000 picoseconds. - Weight::from_parts(43_101_000, 3829) + // Measured: `626` + // Estimated: `3652` + // Minimum execution time: 35_640_000 picoseconds. + Weight::from_parts(37_007_000, 3652) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `936` - // Estimated: `3829` - // Minimum execution time: 39_722_000 picoseconds. - Weight::from_parts(40_390_000, 3829) + // Measured: `823` + // Estimated: `3652` + // Minimum execution time: 34_410_000 picoseconds. + Weight::from_parts(35_431_000, 3652) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// 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` - // Estimated: `3643` - // Minimum execution time: 30_726_000 picoseconds. - Weight::from_parts(31_557_000, 3643) + // Estimated: `3652` + // Minimum execution time: 26_187_000 picoseconds. + Weight::from_parts(27_837_000, 3652) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `547` - // Estimated: `3643` - // Minimum execution time: 31_303_000 picoseconds. - Weight::from_parts(32_389_000, 3643) + // Measured: `626` + // Estimated: `3652` + // Minimum execution time: 26_640_000 picoseconds. + Weight::from_parts(27_688_000, 3652) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// 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` // Estimated: `3643` - // Minimum execution time: 32_155_000 picoseconds. - Weight::from_parts(32_885_000, 3643) + // Minimum execution time: 26_781_000 picoseconds. + Weight::from_parts(27_628_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:0) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// 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: `461` + // Measured: `540` // Estimated: `3643` - // Minimum execution time: 30_044_000 picoseconds. - Weight::from_parts(31_405_000, 3643) + // Minimum execution time: 26_295_000 picoseconds. + Weight::from_parts(26_903_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -788,8 +794,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 18_904_000 picoseconds. - Weight::from_parts(19_687_000, 3643) + // Minimum execution time: 16_678_000 picoseconds. + Weight::from_parts(17_548_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -801,8 +807,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `528` // Estimated: `3643` - // Minimum execution time: 19_144_000 picoseconds. - Weight::from_parts(19_706_000, 3643) + // Minimum execution time: 16_408_000 picoseconds. + Weight::from_parts(16_957_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -812,8 +818,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3517` - // Minimum execution time: 15_339_000 picoseconds. - Weight::from_parts(15_918_000, 3517) + // Minimum execution time: 12_568_000 picoseconds. + Weight::from_parts(12_960_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -825,8 +831,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_387_000 picoseconds. - Weight::from_parts(15_726_000, 3643) + // Minimum execution time: 13_110_000 picoseconds. + Weight::from_parts(13_620_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -838,8 +844,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `326` // Estimated: `3587` - // Minimum execution time: 15_873_000 picoseconds. - Weight::from_parts(16_860_000, 3587) + // Minimum execution time: 13_568_000 picoseconds. + Weight::from_parts(14_211_000, 3587) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -855,8 +861,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `607` // Estimated: `3643` - // Minimum execution time: 37_245_000 picoseconds. - Weight::from_parts(38_383_000, 3643) + // Minimum execution time: 32_660_000 picoseconds. + Weight::from_parts(33_734_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index 1a1196cb4c0669c279b47c48e309101e9d27e3d9..8742513be95043186dbe840540247fe7160fdfaa 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -27,13 +27,12 @@ use frame_support::{ dispatch::{DispatchErrorWithPostInfo, Pays}, error::BadOrigin, parameter_types, storage, - traits::{ConstU32, ConstU64, Contains}, + traits::{ConstU64, Contains}, weights::Weight, }; use pallet_collective::{EnsureProportionAtLeast, Instance1}; -use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, Dispatchable, Hash, IdentityLookup}, + traits::{BlakeTwo256, Dispatchable, Hash}, BuildStorage, DispatchError, TokenError, }; @@ -148,27 +147,8 @@ parameter_types! { impl frame_system::Config for Test { type BaseCallFilter = TestBaseCallFilter; type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = frame_system::weights::SubstrateWeight; - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/utility/src/weights.rs b/substrate/frame/utility/src/weights.rs index 1a3ea6c1f7fc85df4e90a6e8552fc211a51f5405..60b1c48f0868febb7d62cf8865e2bc9a2a79f0b2 100644 --- a/substrate/frame/utility/src/weights.rs +++ b/substrate/frame/utility/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_utility +//! Autogenerated weights for `pallet_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/utility/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/utility/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_utility. +/// Weight functions needed for `pallet_utility`. pub trait WeightInfo { fn batch(c: u32, ) -> Weight; fn as_derivative() -> Weight; @@ -59,99 +58,139 @@ pub trait WeightInfo { fn force_batch(c: u32, ) -> Weight; } -/// Weights for pallet_utility using the Substrate node and recommended hardware. +/// Weights for `pallet_utility` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); 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: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_763_000 picoseconds. - Weight::from_parts(16_943_157, 0) - // Standard Error: 1_904 - .saturating_add(Weight::from_parts(4_653_855, 0).saturating_mul(c.into())) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 5_143_000 picoseconds. + Weight::from_parts(11_552_299, 3997) + // Standard Error: 2_325 + .saturating_add(Weight::from_parts(4_708_951, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_derivative() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_149_000 picoseconds. - Weight::from_parts(5_268_000, 0) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 9_103_000 picoseconds. + Weight::from_parts(9_549_000, 3997) + .saturating_add(T::DbWeight::get().reads(2_u64)) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_976_000 picoseconds. - Weight::from_parts(16_448_433, 0) - // Standard Error: 1_834 - .saturating_add(Weight::from_parts(4_796_983, 0).saturating_mul(c.into())) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 5_147_000 picoseconds. + Weight::from_parts(15_698_086, 3997) + // Standard Error: 3_066 + .saturating_add(Weight::from_parts(4_809_412, 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: 9_102_000 picoseconds. - Weight::from_parts(9_353_000, 0) + // Minimum execution time: 6_683_000 picoseconds. + Weight::from_parts(7_047_000, 0) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_840_000 picoseconds. - Weight::from_parts(17_748_474, 0) - // Standard Error: 2_059 - .saturating_add(Weight::from_parts(4_630_079, 0).saturating_mul(c.into())) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 4_982_000 picoseconds. + Weight::from_parts(14_474_780, 3997) + // Standard Error: 2_291 + .saturating_add(Weight::from_parts(4_632_643, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. 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: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_763_000 picoseconds. - Weight::from_parts(16_943_157, 0) - // Standard Error: 1_904 - .saturating_add(Weight::from_parts(4_653_855, 0).saturating_mul(c.into())) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 5_143_000 picoseconds. + Weight::from_parts(11_552_299, 3997) + // Standard Error: 2_325 + .saturating_add(Weight::from_parts(4_708_951, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_derivative() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_149_000 picoseconds. - Weight::from_parts(5_268_000, 0) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 9_103_000 picoseconds. + Weight::from_parts(9_549_000, 3997) + .saturating_add(RocksDbWeight::get().reads(2_u64)) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_976_000 picoseconds. - Weight::from_parts(16_448_433, 0) - // Standard Error: 1_834 - .saturating_add(Weight::from_parts(4_796_983, 0).saturating_mul(c.into())) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 5_147_000 picoseconds. + Weight::from_parts(15_698_086, 3997) + // Standard Error: 3_066 + .saturating_add(Weight::from_parts(4_809_412, 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: 9_102_000 picoseconds. - Weight::from_parts(9_353_000, 0) + // Minimum execution time: 6_683_000 picoseconds. + Weight::from_parts(7_047_000, 0) } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_840_000 picoseconds. - Weight::from_parts(17_748_474, 0) - // Standard Error: 2_059 - .saturating_add(Weight::from_parts(4_630_079, 0).saturating_mul(c.into())) + // Measured: `145` + // Estimated: `3997` + // Minimum execution time: 4_982_000 picoseconds. + Weight::from_parts(14_474_780, 3997) + // Standard Error: 2_291 + .saturating_add(Weight::from_parts(4_632_643, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) } } diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index f81b7a122c57b82c8a8b841ca72e56d5fb275f48..96938b95a2ad4c09f3ec821ecc14c5cc3bc68270 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/vesting/src/mock.rs b/substrate/frame/vesting/src/mock.rs index befe8cd3b760eddce92f7de73893df753b71546b..8a0cd1351253663983774a7a79d17dd60583b3f5 100644 --- a/substrate/frame/vesting/src/mock.rs +++ b/substrate/frame/vesting/src/mock.rs @@ -17,13 +17,9 @@ use frame_support::{ derive_impl, parameter_types, - traits::{ConstU32, ConstU64, WithdrawReasons}, -}; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, Identity, IdentityLookup}, - BuildStorage, + traits::{ConstU32, WithdrawReasons}, }; +use sp_runtime::{traits::Identity, BuildStorage}; use super::*; use crate as pallet_vesting; @@ -42,28 +38,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; - type AccountId = u64; - type BaseCallFilter = frame_support::traits::Everything; - type BlockHashCount = ConstU64<250>; - type BlockLength = (); - type BlockWeights = (); - type RuntimeCall = RuntimeCall; - type DbWeight = (); - type RuntimeEvent = RuntimeEvent; - type Hash = H256; - type Hashing = BlakeTwo256; type Block = Block; - type Nonce = u64; - type Lookup = IdentityLookup; - type OnKilledAccount = (); - type OnNewAccount = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - type RuntimeOrigin = RuntimeOrigin; - type PalletInfo = PalletInfo; - type SS58Prefix = (); - type SystemWeightInfo = (); - type Version = (); } impl pallet_balances::Config for Test { diff --git a/substrate/frame/vesting/src/weights.rs b/substrate/frame/vesting/src/weights.rs index ddc7db8fa61fbedef4c2629117459dc37c5f8bcd..d91c47ae195ab380b2fc18e560877e499d0093aa 100644 --- a/substrate/frame/vesting/src/weights.rs +++ b/substrate/frame/vesting/src/weights.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_vesting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-29, STEPS: `50`, REPEAT: `20`, 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: `runner-vmdtonbz-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("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_vesting +// --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_vesting -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/vesting/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -75,12 +77,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 32_846_000 picoseconds. - Weight::from_parts(30_974_459, 4764) - // Standard Error: 1_755 - .saturating_add(Weight::from_parts(73_138, 0).saturating_mul(l.into())) - // Standard Error: 3_123 - .saturating_add(Weight::from_parts(82_417, 0).saturating_mul(s.into())) + // Minimum execution time: 31_890_000 picoseconds. + Weight::from_parts(31_128_476, 4764) + // Standard Error: 1_193 + .saturating_add(Weight::from_parts(63_760, 0).saturating_mul(l.into())) + // Standard Error: 2_124 + .saturating_add(Weight::from_parts(57_247, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -96,12 +98,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_360_000 picoseconds. - Weight::from_parts(34_964_080, 4764) - // Standard Error: 1_996 - .saturating_add(Weight::from_parts(48_024, 0).saturating_mul(l.into())) - // Standard Error: 3_552 - .saturating_add(Weight::from_parts(34_411, 0).saturating_mul(s.into())) + // Minimum execution time: 33_958_000 picoseconds. + Weight::from_parts(33_537_005, 4764) + // Standard Error: 1_354 + .saturating_add(Weight::from_parts(60_604, 0).saturating_mul(l.into())) + // Standard Error: 2_410 + .saturating_add(Weight::from_parts(51_378, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -119,12 +121,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_859_000 picoseconds. - Weight::from_parts(32_950_681, 4764) - // Standard Error: 1_745 - .saturating_add(Weight::from_parts(69_323, 0).saturating_mul(l.into())) - // Standard Error: 3_105 - .saturating_add(Weight::from_parts(86_370, 0).saturating_mul(s.into())) + // Minimum execution time: 33_243_000 picoseconds. + Weight::from_parts(32_552_805, 4764) + // Standard Error: 1_413 + .saturating_add(Weight::from_parts(67_137, 0).saturating_mul(l.into())) + // Standard Error: 2_515 + .saturating_add(Weight::from_parts(70_000, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -142,12 +144,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_239_000 picoseconds. - Weight::from_parts(36_459_756, 4764) - // Standard Error: 2_051 - .saturating_add(Weight::from_parts(56_670, 0).saturating_mul(l.into())) - // Standard Error: 3_650 - .saturating_add(Weight::from_parts(49_663, 0).saturating_mul(s.into())) + // Minimum execution time: 35_396_000 picoseconds. + Weight::from_parts(35_774_949, 4764) + // Standard Error: 1_404 + .saturating_add(Weight::from_parts(55_349, 0).saturating_mul(l.into())) + // Standard Error: 2_497 + .saturating_add(Weight::from_parts(39_228, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -165,12 +167,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 70_330_000 picoseconds. - Weight::from_parts(71_196_328, 4764) - // Standard Error: 2_923 - .saturating_add(Weight::from_parts(67_238, 0).saturating_mul(l.into())) - // Standard Error: 5_201 - .saturating_add(Weight::from_parts(89_102, 0).saturating_mul(s.into())) + // Minimum execution time: 68_441_000 picoseconds. + Weight::from_parts(68_961_970, 4764) + // Standard Error: 2_509 + .saturating_add(Weight::from_parts(83_345, 0).saturating_mul(l.into())) + // Standard Error: 4_464 + .saturating_add(Weight::from_parts(124_158, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -188,12 +190,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `658 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 70_235_000 picoseconds. - Weight::from_parts(71_960_020, 6196) - // Standard Error: 2_493 - .saturating_add(Weight::from_parts(64_835, 0).saturating_mul(l.into())) - // Standard Error: 4_436 - .saturating_add(Weight::from_parts(102_159, 0).saturating_mul(s.into())) + // Minimum execution time: 70_190_000 picoseconds. + Weight::from_parts(72_355_984, 6196) + // Standard Error: 2_295 + .saturating_add(Weight::from_parts(59_968, 0).saturating_mul(l.into())) + // Standard Error: 4_084 + .saturating_add(Weight::from_parts(87_090, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -211,12 +213,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_352_000 picoseconds. - Weight::from_parts(33_697_027, 4764) - // Standard Error: 2_008 - .saturating_add(Weight::from_parts(79_270, 0).saturating_mul(l.into())) - // Standard Error: 3_710 - .saturating_add(Weight::from_parts(60_691, 0).saturating_mul(s.into())) + // Minimum execution time: 33_911_000 picoseconds. + Weight::from_parts(33_243_006, 4764) + // Standard Error: 1_199 + .saturating_add(Weight::from_parts(70_586, 0).saturating_mul(l.into())) + // Standard Error: 2_214 + .saturating_add(Weight::from_parts(60_985, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -234,12 +236,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 37_467_000 picoseconds. - Weight::from_parts(36_866_847, 4764) - // Standard Error: 1_692 - .saturating_add(Weight::from_parts(57_882, 0).saturating_mul(l.into())) - // Standard Error: 3_124 - .saturating_add(Weight::from_parts(80_266, 0).saturating_mul(s.into())) + // Minimum execution time: 36_242_000 picoseconds. + Weight::from_parts(35_812_994, 4764) + // Standard Error: 1_351 + .saturating_add(Weight::from_parts(68_256, 0).saturating_mul(l.into())) + // Standard Error: 2_496 + .saturating_add(Weight::from_parts(66_171, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -257,12 +259,12 @@ impl WeightInfo for SubstrateWeight { // 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())) + // Minimum execution time: 37_817_000 picoseconds. + Weight::from_parts(37_397_127, 4764) + // Standard Error: 1_665 + .saturating_add(Weight::from_parts(72_049, 0).saturating_mul(l.into())) + // Standard Error: 3_075 + .saturating_add(Weight::from_parts(60_973, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -282,12 +284,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 32_846_000 picoseconds. - Weight::from_parts(30_974_459, 4764) - // Standard Error: 1_755 - .saturating_add(Weight::from_parts(73_138, 0).saturating_mul(l.into())) - // Standard Error: 3_123 - .saturating_add(Weight::from_parts(82_417, 0).saturating_mul(s.into())) + // Minimum execution time: 31_890_000 picoseconds. + Weight::from_parts(31_128_476, 4764) + // Standard Error: 1_193 + .saturating_add(Weight::from_parts(63_760, 0).saturating_mul(l.into())) + // Standard Error: 2_124 + .saturating_add(Weight::from_parts(57_247, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -303,12 +305,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_360_000 picoseconds. - Weight::from_parts(34_964_080, 4764) - // Standard Error: 1_996 - .saturating_add(Weight::from_parts(48_024, 0).saturating_mul(l.into())) - // Standard Error: 3_552 - .saturating_add(Weight::from_parts(34_411, 0).saturating_mul(s.into())) + // Minimum execution time: 33_958_000 picoseconds. + Weight::from_parts(33_537_005, 4764) + // Standard Error: 1_354 + .saturating_add(Weight::from_parts(60_604, 0).saturating_mul(l.into())) + // Standard Error: 2_410 + .saturating_add(Weight::from_parts(51_378, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -326,12 +328,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_859_000 picoseconds. - Weight::from_parts(32_950_681, 4764) - // Standard Error: 1_745 - .saturating_add(Weight::from_parts(69_323, 0).saturating_mul(l.into())) - // Standard Error: 3_105 - .saturating_add(Weight::from_parts(86_370, 0).saturating_mul(s.into())) + // Minimum execution time: 33_243_000 picoseconds. + Weight::from_parts(32_552_805, 4764) + // Standard Error: 1_413 + .saturating_add(Weight::from_parts(67_137, 0).saturating_mul(l.into())) + // Standard Error: 2_515 + .saturating_add(Weight::from_parts(70_000, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -349,12 +351,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_239_000 picoseconds. - Weight::from_parts(36_459_756, 4764) - // Standard Error: 2_051 - .saturating_add(Weight::from_parts(56_670, 0).saturating_mul(l.into())) - // Standard Error: 3_650 - .saturating_add(Weight::from_parts(49_663, 0).saturating_mul(s.into())) + // Minimum execution time: 35_396_000 picoseconds. + Weight::from_parts(35_774_949, 4764) + // Standard Error: 1_404 + .saturating_add(Weight::from_parts(55_349, 0).saturating_mul(l.into())) + // Standard Error: 2_497 + .saturating_add(Weight::from_parts(39_228, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -372,12 +374,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 70_330_000 picoseconds. - Weight::from_parts(71_196_328, 4764) - // Standard Error: 2_923 - .saturating_add(Weight::from_parts(67_238, 0).saturating_mul(l.into())) - // Standard Error: 5_201 - .saturating_add(Weight::from_parts(89_102, 0).saturating_mul(s.into())) + // Minimum execution time: 68_441_000 picoseconds. + Weight::from_parts(68_961_970, 4764) + // Standard Error: 2_509 + .saturating_add(Weight::from_parts(83_345, 0).saturating_mul(l.into())) + // Standard Error: 4_464 + .saturating_add(Weight::from_parts(124_158, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -395,12 +397,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `658 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 70_235_000 picoseconds. - Weight::from_parts(71_960_020, 6196) - // Standard Error: 2_493 - .saturating_add(Weight::from_parts(64_835, 0).saturating_mul(l.into())) - // Standard Error: 4_436 - .saturating_add(Weight::from_parts(102_159, 0).saturating_mul(s.into())) + // Minimum execution time: 70_190_000 picoseconds. + Weight::from_parts(72_355_984, 6196) + // Standard Error: 2_295 + .saturating_add(Weight::from_parts(59_968, 0).saturating_mul(l.into())) + // Standard Error: 4_084 + .saturating_add(Weight::from_parts(87_090, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -418,12 +420,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_352_000 picoseconds. - Weight::from_parts(33_697_027, 4764) - // Standard Error: 2_008 - .saturating_add(Weight::from_parts(79_270, 0).saturating_mul(l.into())) - // Standard Error: 3_710 - .saturating_add(Weight::from_parts(60_691, 0).saturating_mul(s.into())) + // Minimum execution time: 33_911_000 picoseconds. + Weight::from_parts(33_243_006, 4764) + // Standard Error: 1_199 + .saturating_add(Weight::from_parts(70_586, 0).saturating_mul(l.into())) + // Standard Error: 2_214 + .saturating_add(Weight::from_parts(60_985, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -441,12 +443,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 37_467_000 picoseconds. - Weight::from_parts(36_866_847, 4764) - // Standard Error: 1_692 - .saturating_add(Weight::from_parts(57_882, 0).saturating_mul(l.into())) - // Standard Error: 3_124 - .saturating_add(Weight::from_parts(80_266, 0).saturating_mul(s.into())) + // Minimum execution time: 36_242_000 picoseconds. + Weight::from_parts(35_812_994, 4764) + // Standard Error: 1_351 + .saturating_add(Weight::from_parts(68_256, 0).saturating_mul(l.into())) + // Standard Error: 2_496 + .saturating_add(Weight::from_parts(66_171, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -464,12 +466,12 @@ impl WeightInfo for () { // 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())) + // Minimum execution time: 37_817_000 picoseconds. + Weight::from_parts(37_397_127, 4764) + // Standard Error: 1_665 + .saturating_add(Weight::from_parts(72_049, 0).saturating_mul(l.into())) + // Standard Error: 3_075 + .saturating_add(Weight::from_parts(60_973, 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/mock.rs b/substrate/frame/whitelist/src/mock.rs index c0c38075f298909e7f918de1d74514ee0f86e16d..e323e806b8152b3765f60af46a59ec151f147154 100644 --- a/substrate/frame/whitelist/src/mock.rs +++ b/substrate/frame/whitelist/src/mock.rs @@ -21,16 +21,9 @@ use crate as pallet_whitelist; -use frame_support::{ - construct_runtime, derive_impl, - traits::{ConstU32, ConstU64, Nothing}, -}; +use frame_support::{construct_runtime, derive_impl, traits::ConstU64}; use frame_system::EnsureRoot; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -46,29 +39,8 @@ construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = Nothing; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/substrate/frame/whitelist/src/weights.rs b/substrate/frame/whitelist/src/weights.rs index de42c5a5841cf8c2d3aea1227dafd35ec461b234..13b653f6ca7d367b83d5771f4805a61d8a7e40fd 100644 --- a/substrate/frame/whitelist/src/weights.rs +++ b/substrate/frame/whitelist/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_whitelist +//! Autogenerated weights for `pallet_whitelist` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, 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: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), 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/production/substrate +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -35,12 +35,11 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/whitelist/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/whitelist/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_whitelist. +/// Weight functions needed for `pallet_whitelist`. pub trait WeightInfo { fn whitelist_call() -> Weight; fn remove_whitelisted_call() -> Weight; @@ -58,133 +57,149 @@ pub trait WeightInfo { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight; } -/// Weights for pallet_whitelist using the Substrate node and recommended hardware. +/// Weights for `pallet_whitelist` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `217` + // Measured: `317` // Estimated: `3556` - // Minimum execution time: 19_914_000 picoseconds. - Weight::from_parts(20_892_000, 3556) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 18_503_000 picoseconds. + Weight::from_parts(19_497_000, 3556) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `346` + // Measured: `446` // Estimated: `3556` - // Minimum execution time: 18_142_000 picoseconds. - Weight::from_parts(18_529_000, 3556) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 17_633_000 picoseconds. + Weight::from_parts(18_196_000, 3556) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `422 + n * (1 ±0)` - // Estimated: `3886 + n * (1 ±0)` - // Minimum execution time: 30_671_000 picoseconds. - Weight::from_parts(31_197_000, 3886) + // Measured: `522 + n * (1 ±0)` + // Estimated: `3986 + n * (1 ±0)` + // Minimum execution time: 28_020_000 picoseconds. + Weight::from_parts(28_991_000, 3986) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(Weight::from_parts(1_171, 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())) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `346` + // Measured: `446` // Estimated: `3556` - // Minimum execution time: 22_099_000 picoseconds. - Weight::from_parts(23_145_477, 3556) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_422, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 21_916_000 picoseconds. + Weight::from_parts(23_082_065, 3556) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_388, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `217` + // Measured: `317` // Estimated: `3556` - // Minimum execution time: 19_914_000 picoseconds. - Weight::from_parts(20_892_000, 3556) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 18_503_000 picoseconds. + Weight::from_parts(19_497_000, 3556) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `346` + // Measured: `446` // Estimated: `3556` - // Minimum execution time: 18_142_000 picoseconds. - Weight::from_parts(18_529_000, 3556) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 17_633_000 picoseconds. + Weight::from_parts(18_196_000, 3556) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `422 + n * (1 ±0)` - // Estimated: `3886 + n * (1 ±0)` - // Minimum execution time: 30_671_000 picoseconds. - Weight::from_parts(31_197_000, 3886) + // Measured: `522 + n * (1 ±0)` + // Estimated: `3986 + n * (1 ±0)` + // Minimum execution time: 28_020_000 picoseconds. + Weight::from_parts(28_991_000, 3986) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(Weight::from_parts(1_171, 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())) } - /// 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) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// 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: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: `346` + // Measured: `446` // Estimated: `3556` - // Minimum execution time: 22_099_000 picoseconds. - Weight::from_parts(23_145_477, 3556) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_422, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 21_916_000 picoseconds. + Weight::from_parts(23_082_065, 3556) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_388, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index cd882c7a050fee1a32cba0183adec7b1a4d323a7..f4b1d13c520399a9d5960bf90958fdd5b154d10a 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -27,12 +27,12 @@ sp-version = { path = "../version", default-features = false } sp-state-machine = { path = "../state-machine", default-features = false, optional = true } sp-trie = { path = "../trie", default-features = false, optional = true } hash-db = { version = "0.16.0", optional = true } -thiserror = { version = "1.0.48", optional = true } +thiserror = { optional = true, workspace = true } scale-info = { version = "2.10.0", default-features = false, features = [ "derive", ] } sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] sp-test-primitives = { path = "../test-primitives" } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 166ce55e5151c48267b799e18a403a7d0b5337b6..f5406758687ae20e9ce13a2cf02959c5cccbd576 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -19,8 +19,8 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.28" -syn = { version = "2.0.48", features = ["extra-traits", "fold", "full", "visit"] } +quote = { workspace = true } +syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } proc-macro2 = "1.0.56" blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "3.0.0" 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 2b1e65ec88524a0236a464005fb2d1215c1157fe..e34e4c0e7672164afb41702ab3bae87082df9062 100644 --- a/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -456,6 +456,7 @@ impl<'a> ToClientSideDecl<'a> { |err| #crate_::ApiError::FailedToDecodeReturnValue { function: #function_name, error: err, + raw: r.clone(), } ) ) diff --git a/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index c1339ff6621b389e32c2f9ca2a7f19079c2d269e..1761e0ac9dbf450c15adae2659119c918f300334 100644 --- a/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -158,7 +158,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result::Hash, _: &<#block_type as #crate_::BlockT>::Header, - ) -> std::result::Result<(), #crate_::ApiError> { + ) -> std::result::Result<#crate_::__private::ExtrinsicInclusionMode, #crate_::ApiError> { unimplemented!("`Core::initialize_block` not implemented for runtime api mocks") } } diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index 190de1ab3fdee0611f27071b9c769a164c3aca9d..a945b9f21f3cff60d6a9d5e24aa07704a1dc8d31 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -101,7 +101,7 @@ pub mod __private { generic::BlockId, traits::{Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, NumberFor}, transaction_validity::TransactionValidity, - RuntimeString, TransactionOutcome, + ExtrinsicInclusionMode, RuntimeString, TransactionOutcome, }; pub use sp_std::{mem, slice, vec}; pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion}; @@ -115,11 +115,11 @@ pub use sp_core::traits::CallContext; use sp_core::OpaqueMetadata; #[cfg(feature = "std")] use sp_externalities::{Extension, Extensions}; -use sp_runtime::traits::Block as BlockT; #[cfg(feature = "std")] use sp_runtime::traits::HashingFor; #[cfg(feature = "std")] pub use sp_runtime::TransactionOutcome; +use sp_runtime::{traits::Block as BlockT, ExtrinsicInclusionMode}; #[cfg(feature = "std")] pub use sp_state_machine::StorageProof; #[cfg(feature = "std")] @@ -280,7 +280,7 @@ pub use sp_api_proc_macro::decl_runtime_apis; /// ```rust /// use sp_version::create_runtime_str; /// # -/// # use sp_runtime::traits::Block as BlockT; +/// # use sp_runtime::{ExtrinsicInclusionMode, traits::Block as BlockT}; /// # use sp_test_primitives::Block; /// # /// # /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro @@ -307,7 +307,9 @@ pub use sp_api_proc_macro::decl_runtime_apis; /// # unimplemented!() /// # } /// # fn execute_block(_block: Block) {} -/// # fn initialize_block(_header: &::Header) {} +/// # fn initialize_block(_header: &::Header) -> ExtrinsicInclusionMode { +/// # unimplemented!() +/// # } /// # } /// /// impl self::Balance for Runtime { @@ -540,11 +542,12 @@ pub fn init_runtime_logger() { #[cfg(feature = "std")] #[derive(Debug, thiserror::Error)] pub enum ApiError { - #[error("Failed to decode return value of {function}")] + #[error("Failed to decode return value of {function}: {error} raw data: {raw:?}")] FailedToDecodeReturnValue { function: &'static str, #[source] error: codec::Error, + raw: Vec, }, #[error("Failed to convert return value from runtime to node of {function}")] FailedToConvertReturnValue { @@ -800,15 +803,18 @@ pub fn deserialize_runtime_api_info(bytes: [u8; RUNTIME_API_INFO_SIZE]) -> ([u8; decl_runtime_apis! { /// The `Core` runtime api that every Substrate runtime needs to implement. #[core_trait] - #[api_version(4)] + #[api_version(5)] pub trait Core { /// Returns the version of the runtime. fn version() -> RuntimeVersion; /// Execute the given block. fn execute_block(block: Block); /// Initialize a block with the given header. + #[changed_in(5)] #[renamed("initialise_block", 2)] fn initialize_block(header: &::Header); + /// Initialize a block with the given header and return the runtime executive mode. + fn initialize_block(header: &::Header) -> ExtrinsicInclusionMode; } /// The `Metadata` api trait that returns metadata for the runtime. diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index b0975082c44ecde816cfc332c940dfbd1783b04b..3a90553bbf000c1b1ea70ae11e7532a456f1c2f2 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -31,7 +31,7 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive [dev-dependencies] criterion = "0.4.0" futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } sp-core = { path = "../../core" } static_assertions = "1.1.0" diff --git a/substrate/primitives/api/test/tests/decl_and_impl.rs b/substrate/primitives/api/test/tests/decl_and_impl.rs index d68470551d20061aa09d277a9999db81654ff47d..211a08561fd4bcf601d9508d96447fc07f82657f 100644 --- a/substrate/primitives/api/test/tests/decl_and_impl.rs +++ b/substrate/primitives/api/test/tests/decl_and_impl.rs @@ -139,7 +139,7 @@ impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs index 43718e4cd04a3f25fcc805edec3c14283f1f5f56..262a874213a5662c0c87a79989b620c661e707c7 100644 --- a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs +++ b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.rs @@ -40,7 +40,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/test/tests/ui/impl_missing_version.rs b/substrate/primitives/api/test/tests/ui/impl_missing_version.rs index 560257b5168c921ce112a56fcbd7e9c303363c77..58850ab343fbb7bcc2c04b01c7aec9cb881023d0 100644 --- a/substrate/primitives/api/test/tests/ui/impl_missing_version.rs +++ b/substrate/primitives/api/test/tests/ui/impl_missing_version.rs @@ -45,7 +45,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs b/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs index 6ead545f85a11e8f0382331e77145acb4a053d5e..70f75d065154afcb807e1712c95fc24eca5267b1 100644 --- a/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs +++ b/substrate/primitives/api/test/tests/ui/missing_versioned_method.rs @@ -44,7 +44,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs b/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs index 8eebc1d79babcbd6fb95876a530a920397c035a6..63032000040b7d19f8e31fc4ac3221369aef9e7e 100644 --- a/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs +++ b/substrate/primitives/api/test/tests/ui/missing_versioned_method_multiple_vers.rs @@ -47,7 +47,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs b/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs index 594556d57be50dbd151de486dc22a63a733b933b..0858813bc99941be005e0c0141b2defc3a96a3d3 100644 --- a/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs +++ b/substrate/primitives/api/test/tests/ui/positive_cases/custom_where_bound.rs @@ -51,7 +51,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs b/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs index ae573238ffe144d26b7e5dd4528e8a9e5ab88a9e..3e0cb79156c8bf5c218e29e3024d181a69fc4da6 100644 --- a/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs +++ b/substrate/primitives/api/test/tests/ui/positive_cases/default_impls.rs @@ -46,7 +46,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs index 921bf0d04351dac4ddcdd18030619f1ebcf15008..b2caea7ab7e44d910628d0ac834017e66e7e5d2e 100644 --- a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs +++ b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.rs @@ -42,7 +42,7 @@ sp_api::impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) { + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 2b38b59b4dad5b9d2b0633b772fe7aa80cc97cdf..6f90a2b6262e50d7edd23e415924a8259f0a0d96 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -21,7 +21,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-core = { path = "../core", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, optional = true, features = ["alloc", "derive"] } +serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-std = { path = "../std", default-features = false } sp-io = { path = "../io", default-features = false } diff --git a/substrate/primitives/application-crypto/check-features-variants.sh b/substrate/primitives/application-crypto/check-features-variants.sh new file mode 100755 index 0000000000000000000000000000000000000000..dd45a212bae097beb40171295e254a601674ff00 --- /dev/null +++ b/substrate/primitives/application-crypto/check-features-variants.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env -S bash -eux + +export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +T=wasm32-unknown-unknown +cargo check --release +cargo check --release --target=$T --no-default-features +cargo check --release --target=$T --no-default-features --features="full_crypto" +cargo check --release --target=$T --no-default-features --features="serde" +cargo check --release --target=$T --no-default-features --features="serde,full_crypto" +cargo check --release --target=$T --no-default-features --features="bandersnatch-experimental" +cargo check --release --target=$T --no-default-features --features="bls-experimental" +cargo check --release --target=$T --no-default-features --features="bls-experimental,full_crypto" diff --git a/substrate/primitives/application-crypto/src/bls377.rs b/substrate/primitives/application-crypto/src/bls377.rs index ee17060564fa8bec54888c1123b7c86af13863d3..3bd01de139c9496d35b143ddeb07de1285154946 100644 --- a/substrate/primitives/application-crypto/src/bls377.rs +++ b/substrate/primitives/application-crypto/src/bls377.rs @@ -19,14 +19,13 @@ use crate::{KeyTypeId, RuntimePublic}; pub use sp_core::bls::bls377::*; +use sp_std::vec::Vec; mod app { crate::app_crypto!(super, sp_core::testing::BLS377); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/ecdsa.rs b/substrate/primitives/application-crypto/src/ecdsa.rs index 27ffe12579f5591cf71a0f22cd5bb2702ce83afb..439b51dc604509788bd16b25aea2dbf6201471bd 100644 --- a/substrate/primitives/application-crypto/src/ecdsa.rs +++ b/substrate/primitives/application-crypto/src/ecdsa.rs @@ -27,9 +27,7 @@ mod app { crate::app_crypto!(super, sp_core::testing::ECDSA); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs index 70940587cedaf6312dbc75834d2180131ca157b4..8dee73095fb2e2fcbeb968edef2aad667112767a 100644 --- a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs +++ b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs @@ -18,6 +18,7 @@ //! ECDSA and BLS12-377 paired crypto applications. use crate::{KeyTypeId, RuntimePublic}; +use sp_std::vec::Vec; pub use sp_core::paired_crypto::ecdsa_bls377::*; diff --git a/substrate/primitives/application-crypto/src/ed25519.rs b/substrate/primitives/application-crypto/src/ed25519.rs index bc05018370edb16c41ed1dddef2dafd7d785cc32..addefe7daf6431415f1c06727b88edd1b3bd9158 100644 --- a/substrate/primitives/application-crypto/src/ed25519.rs +++ b/substrate/primitives/application-crypto/src/ed25519.rs @@ -27,9 +27,7 @@ mod app { crate::app_crypto!(super, sp_core::testing::ED25519); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 686b486f335301e8750253cb2e306a0f5cb222d4..ea2e5a83127bb50a8060e22d81660c80e9e18ee2 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -20,12 +20,9 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -pub use sp_core::crypto::{key_types, CryptoTypeId, KeyTypeId}; +pub use sp_core::crypto::{key_types, CryptoTypeId, DeriveJunction, KeyTypeId, Ss58Codec}; #[doc(hidden)] -#[cfg(feature = "full_crypto")] pub use sp_core::crypto::{DeriveError, Pair, SecretStringError}; -#[cfg(any(feature = "full_crypto", feature = "serde"))] -pub use sp_core::crypto::{DeriveJunction, Ss58Codec}; #[doc(hidden)] pub use sp_core::{ self, @@ -85,7 +82,7 @@ macro_rules! app_crypto { $module::CRYPTO_ID ); $crate::app_crypto_signature_common!($module::Signature, $key_type); - $crate::app_crypto_pair!($module::Pair, $key_type, $module::CRYPTO_ID); + $crate::app_crypto_pair_common!($module::Pair, $key_type, $module::CRYPTO_ID); }; } @@ -116,13 +113,15 @@ macro_rules! app_crypto { $module::CRYPTO_ID ); $crate::app_crypto_signature_common!($module::Signature, $key_type); + $crate::app_crypto_pair_common!($module::Pair, $key_type, $module::CRYPTO_ID); }; } /// Declares `Pair` type which is functionally equivalent to `$pair`, but is /// new application-specific type whose identifier is `$key_type`. +/// It is a common part shared between full_crypto and non full_crypto environments. #[macro_export] -macro_rules! app_crypto_pair { +macro_rules! app_crypto_pair_common { ($pair:ty, $key_type:expr, $crypto_type:expr) => { $crate::wrap! { /// A generic `AppPublic` wrapper type over $pair crypto; this has no specific App. @@ -140,7 +139,14 @@ macro_rules! app_crypto_pair { type Signature = Signature; $crate::app_crypto_pair_functions_if_std!($pair); + $crate::app_crypto_pair_functions_if_full_crypto!($pair); + fn from_phrase( + phrase: &str, + password: Option<&str>, + ) -> Result<(Self, Self::Seed), $crate::SecretStringError> { + <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) + } fn derive>( &self, path: Iter, @@ -154,9 +160,6 @@ macro_rules! app_crypto_pair { fn from_seed_slice(seed: &[u8]) -> Result { <$pair>::from_seed_slice(seed).map(Self) } - fn sign(&self, msg: &[u8]) -> Self::Signature { - Signature(self.0.sign(msg)) - } fn verify>( sig: &Self::Signature, message: M, @@ -203,13 +206,6 @@ macro_rules! app_crypto_pair_functions_if_std { let r = <$pair>::generate_with_phrase(password); (Self(r.0), r.1, r.2) } - - fn from_phrase( - phrase: &str, - password: Option<&str>, - ) -> Result<(Self, Self::Seed), $crate::SecretStringError> { - <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) - } }; } @@ -220,6 +216,25 @@ macro_rules! app_crypto_pair_functions_if_std { ($pair:ty) => {}; } +/// Implements functions for the `Pair` trait when `feature = "full_crypto"` is enabled. +#[doc(hidden)] +#[cfg(feature = "full_crypto")] +#[macro_export] +macro_rules! app_crypto_pair_functions_if_full_crypto { + ($pair:ty) => { + fn sign(&self, msg: &[u8]) -> Self::Signature { + Signature(self.0.sign(msg)) + } + }; +} + +#[doc(hidden)] +#[cfg(not(feature = "full_crypto"))] +#[macro_export] +macro_rules! app_crypto_pair_functions_if_full_crypto { + ($pair:ty) => {}; +} + /// Declares `Public` type which is functionally equivalent to `$public` but is /// new application-specific type whose identifier is `$key_type`. /// For full functionality, `app_crypto_public_common!` must be called too. @@ -267,7 +282,7 @@ macro_rules! app_crypto_public_not_full_crypto { $crate::wrap! { /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive( - Clone, Eq, PartialEq, Ord, PartialOrd, + Clone, Eq, Hash, PartialEq, Ord, PartialOrd, $crate::codec::Encode, $crate::codec::Decode, $crate::RuntimeDebug, @@ -277,10 +292,13 @@ macro_rules! app_crypto_public_not_full_crypto { pub struct Public($public); } - impl $crate::CryptoType for Public {} + impl $crate::CryptoType for Public { + type Pair = Pair; + } impl $crate::AppCrypto for Public { type Public = Public; + type Pair = Pair; type Signature = Signature; const ID: $crate::KeyTypeId = $key_type; const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type; @@ -452,10 +470,13 @@ macro_rules! app_crypto_signature_not_full_crypto { pub struct Signature($sig); } - impl $crate::CryptoType for Signature {} + impl $crate::CryptoType for Signature { + type Pair = Pair; + } impl $crate::AppCrypto for Signature { type Public = Public; + type Pair = Pair; type Signature = Signature; const ID: $crate::KeyTypeId = $key_type; const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type; diff --git a/substrate/primitives/application-crypto/src/sr25519.rs b/substrate/primitives/application-crypto/src/sr25519.rs index 7c91bfa7bb5ffe221a618769f2cb3de3e054d042..d411cc253c0d84fd0bd7f366a7dec86f4c9acc91 100644 --- a/substrate/primitives/application-crypto/src/sr25519.rs +++ b/substrate/primitives/application-crypto/src/sr25519.rs @@ -27,9 +27,7 @@ mod app { crate::app_crypto!(super, sp_core::testing::SR25519); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/traits.rs b/substrate/primitives/application-crypto/src/traits.rs index e9b1080f63d9ce96ced35989cfba56887f03feb9..0b59abf272dc7761f08c8604db33762b07e31584 100644 --- a/substrate/primitives/application-crypto/src/traits.rs +++ b/substrate/primitives/application-crypto/src/traits.rs @@ -18,9 +18,7 @@ use codec::Codec; use scale_info::TypeInfo; -#[cfg(feature = "full_crypto")] -use sp_core::crypto::Pair; -use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Public}; +use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Pair, Public}; use sp_std::{fmt::Debug, vec::Vec}; /// Application-specific cryptographic object. @@ -45,24 +43,14 @@ pub trait AppCrypto: 'static + Sized + CryptoType { type Signature: AppSignature; /// The corresponding key pair type in this application scheme. - #[cfg(feature = "full_crypto")] type Pair: AppPair; } /// Type which implements Hash in std, not when no-std (std variant). -#[cfg(any(feature = "std", feature = "full_crypto"))] pub trait MaybeHash: sp_std::hash::Hash {} -#[cfg(any(feature = "std", feature = "full_crypto"))] impl MaybeHash for T {} -/// Type which implements Hash in std, not when no-std (no-std variant). -#[cfg(all(not(feature = "std"), not(feature = "full_crypto")))] -pub trait MaybeHash {} -#[cfg(all(not(feature = "std"), not(feature = "full_crypto")))] -impl MaybeHash for T {} - /// Application-specific key pair. -#[cfg(feature = "full_crypto")] pub trait AppPair: AppCrypto + Pair::Public, Signature = ::Signature> { diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 332646710eab1511cd3980086ac833a123418608..301821ad6893117661e439921f23d4d5d48f16b5 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = integer-sqrt = "0.1.2" num-traits = { version = "0.2.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"], optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index 176e9ed6dd28f1fc55b7b237746325071d8a9e64..9d13d627eebc36dcc5bdce3efd073a7dc29012a0 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -19,10 +19,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } parking_lot = "0.12.1" schnellru = "0.2.1" -thiserror = "1.0.48" +thiserror = { workspace = true } sp-api = { path = "../api" } sp-consensus = { path = "../consensus/common" } sp-database = { path = "../database" } diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index 9409b44ef62d38b322fca70f9abc95d72e020e58..8b3006f79a7ffc87a69a7eb2921f4b4f0533d1a1 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { version = "0.1.74", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"], optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } sp-consensus-slots = { path = "../slots", default-features = false } diff --git a/substrate/primitives/consensus/babe/src/inherents.rs b/substrate/primitives/consensus/babe/src/inherents.rs index 909769f3031be658e758087c4323ed7ec80fdcce..54b7b64401673927602a3e816cc9d5dcb9ede14a 100644 --- a/substrate/primitives/consensus/babe/src/inherents.rs +++ b/substrate/primitives/consensus/babe/src/inherents.rs @@ -17,7 +17,6 @@ //! Inherents for BABE -use core::result::Result; use sp_inherents::{Error, InherentData, InherentIdentifier}; /// The BABE inherent identifier. diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs index d6b2cdd55e0daddf7e49a132d48bbc8c1741736a..ff0b4568226ef129305d6ab516d6b7032c54c2a0 100644 --- a/substrate/primitives/consensus/babe/src/lib.rs +++ b/substrate/primitives/consensus/babe/src/lib.rs @@ -256,6 +256,12 @@ pub struct BabeEpochConfiguration { pub allowed_slots: AllowedSlots, } +impl Default for BabeEpochConfiguration { + fn default() -> Self { + Self { c: (1, 4), allowed_slots: AllowedSlots::PrimaryAndSecondaryVRFSlots } + } +} + /// Verifies the equivocation proof by making sure that: both headers have /// different hashes, are targetting the same slot, and have valid signatures by /// the same authority. diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 6232eca5ff89b5e979d1a098206607bf2a55ef0d..8ab817d52ef93469959c4de17a459a319b07b4e0 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, optional = true, features = ["alloc", "derive"] } +serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } sp-core = { path = "../../core", default-features = false } @@ -25,6 +25,7 @@ sp-crypto-hashing = { path = "../../crypto/hashing", default-features = false } sp-io = { path = "../../io", default-features = false } sp-mmr-primitives = { path = "../../merkle-mountain-range", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } +sp-keystore = { path = "../../keystore", default-features = false } sp-std = { path = "../../std", default-features = false } strum = { version = "0.24.1", features = ["derive"], default-features = false } lazy_static = { version = "1.4.0", optional = true } @@ -45,6 +46,7 @@ std = [ "sp-core/std", "sp-crypto-hashing/std", "sp-io/std", + "sp-keystore/std", "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 37be1a4f6fc3e20977e6ee1beb90cf2cf8e67874..335c6b604f044872ca5dc20319d0e2de94313606 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -97,6 +97,19 @@ pub struct SignedCommitment { pub signatures: Vec>, } +impl sp_std::fmt::Display + for SignedCommitment +{ + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + let signatures_count = self.signatures.iter().filter(|s| s.is_some()).count(); + write!( + f, + "SignedCommitment(commitment: {:?}, signatures_count: {})", + self.commitment, signatures_count + ) + } +} + impl SignedCommitment { /// Return the number of collected signatures. pub fn no_of_signatures(&self) -> usize { @@ -241,6 +254,14 @@ pub enum VersionedFinalityProof { V1(SignedCommitment), } +impl sp_std::fmt::Display for VersionedFinalityProof { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + match self { + VersionedFinalityProof::V1(sc) => write!(f, "VersionedFinalityProof::V1({})", sc), + } + } +} + impl From> for VersionedFinalityProof { fn from(commitment: SignedCommitment) -> Self { VersionedFinalityProof::V1(commitment) @@ -398,7 +419,7 @@ mod tests { assert_eq!( encoded, array_bytes::hex2bytes_unchecked( - "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01667603fc041cf9d7147d22bf54b15e5778893d6986b71a929747befd3b4d233fbe668bc480e8865116b94db46ca25a01e03c71955f2582604e415da68f2c3c406b9d5f4ad416230ec5453f05ac16a50d8d0923dfb0413cc956ae3fa6334465bd1f2cacec8e9cd606438390fe2a29dc052d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00df61d3b2be0963eb6caa243cc505d327aec73e1bb7ffe9a14b1354b0c406792ac6d6f47c06987c15dec9993f43eefa001d866fe0850d986702c414840f0d9ec0fdc04832ef91ae37c8d49e2f573ca50cb37f152801d489a19395cb04e5fc8f2ab6954b58a3bcc40ef9b6409d2ff7ef07" + "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba015dd1c9b2237e54baa93d232cdf83a430b58a5efbc2f86ca1bab173a315ff6f15bef161425750c028055e9a23947b73002889a8b22168628438875a8ef25d76db998a80187b50719471286f054f3b3809b77a0cd87d7fe9c1a9d5d562683e25a70610f0804e92340549a43a7159b77b0c2d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a001074884b6998c82331bd57ffa0a02cbfd02483c765b9216eab6a1fc119206236bf7971be68acaebff7400edee943240006a6096c9cfa65e9eb4e67f025c27112d14b4574fb208c439500f45cf3a8060f6cf009044f3141cce0364a7c2710a19b1bdf4abf27f86e5e3db08bddd35a7d12" ) ); } diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 68eeeb3c680071dff08aa0aac9de3bf6e62c140e..1c3801e3a506bc9c04976713e1fae9cf02511a3d 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -32,20 +32,22 @@ //! while GRANDPA uses `ed25519`. mod commitment; -pub mod mmr; mod payload; -#[cfg(feature = "std")] -mod test_utils; + +pub mod mmr; pub mod witness; +/// Test utilities +#[cfg(feature = "std")] +pub mod test_utils; + pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; -#[cfg(feature = "std")] -pub use test_utils::*; use codec::{Codec, Decode, Encode}; +use core::fmt::{Debug, Display}; use scale_info::TypeInfo; -use sp_application_crypto::RuntimeAppPublic; +use sp_application_crypto::{AppCrypto, AppPublic, ByteArray, RuntimeAppPublic}; use sp_core::H256; use sp_runtime::traits::{Hash, Keccak256, NumberFor}; use sp_std::prelude::*; @@ -63,6 +65,25 @@ pub trait BeefyAuthorityId: RuntimeAppPublic { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool; } +/// Hasher used for BEEFY signatures. +pub type BeefySignatureHasher = sp_runtime::traits::Keccak256; + +/// A trait bound which lists all traits which are required to be implemented by +/// a BEEFY AuthorityId type in order to be able to be used in BEEFY Keystore +pub trait AuthorityIdBound: + Codec + + Debug + + Clone + + AsRef<[u8]> + + ByteArray + + AppPublic + + AppCrypto + + RuntimeAppPublic + + Display + + BeefyAuthorityId +{ +} + /// BEEFY cryptographic types for ECDSA crypto /// /// This module basically introduces four crypto types: @@ -74,7 +95,7 @@ pub trait BeefyAuthorityId: RuntimeAppPublic { /// Your code should use the above types as concrete types for all crypto related /// functionality. pub mod ecdsa_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; + use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa}; use sp_core::crypto::Wraps; @@ -101,6 +122,7 @@ pub mod ecdsa_crypto { } } } + impl AuthorityIdBound for AuthorityId {} } /// BEEFY cryptographic types for BLS crypto @@ -116,7 +138,7 @@ pub mod ecdsa_crypto { #[cfg(feature = "bls-experimental")] pub mod bls_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; + use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, bls377}; use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _}; @@ -134,13 +156,14 @@ pub mod bls_crypto { { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { // `w3f-bls` library uses IETF hashing standard and as such does not expose - // a choice of hash to field function. + // a choice of hash-to-field function. // We are directly calling into the library to avoid introducing new host call. // and because BeefyAuthorityId::verify is being called in the runtime so we don't have BlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) } } + impl AuthorityIdBound for AuthorityId {} } /// BEEFY cryptographic types for (ECDSA,BLS) crypto pair @@ -155,7 +178,7 @@ pub mod bls_crypto { /// functionality. #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; + use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair}; @@ -187,6 +210,8 @@ pub mod ecdsa_bls_crypto { ) } } + + impl AuthorityIdBound for AuthorityId {} } /// The `ConsensusEngineId` of BEEFY. diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index a6e65e5bff0b0d6bc75d93ea3d5fc7b49741287f..ec13c9c690046ae795fe50af3bfc775721dfb6ee 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -15,18 +15,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![cfg(feature = "std")] +#[cfg(feature = "bls-experimental")] +use crate::ecdsa_bls_crypto; +use crate::{ + ecdsa_crypto, AuthorityIdBound, BeefySignatureHasher, Commitment, EquivocationProof, Payload, + ValidatorSetId, VoteMessage, +}; +use sp_application_crypto::{AppCrypto, AppPair, RuntimeAppPublic, Wraps}; +use sp_core::{ecdsa, Pair}; +use sp_runtime::traits::Hash; -use crate::{ecdsa_crypto, Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage}; use codec::Encode; -use sp_core::{ecdsa, Pair}; -use std::collections::HashMap; +use std::{collections::HashMap, marker::PhantomData}; use strum::IntoEnumIterator; /// Set of test accounts using [`crate::ecdsa_crypto`] types. #[allow(missing_docs)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] -pub enum Keyring { +pub enum Keyring { Alice, Bob, Charlie, @@ -35,71 +41,110 @@ pub enum Keyring { Ferdie, One, Two, + _Marker(PhantomData), +} + +/// Trait representing BEEFY specific generation and signing behavior of authority id +/// +/// Accepts custom hashing fn for the message and custom convertor fn for the signer. +pub trait BeefySignerAuthority: AppPair { + /// Generate and return signature for `message` using custom hashing `MsgHash` + fn sign_with_hasher(&self, message: &[u8]) -> ::Signature; +} + +impl BeefySignerAuthority for ::Pair +where + MsgHash: Hash, + ::Output: Into<[u8; 32]>, +{ + fn sign_with_hasher(&self, message: &[u8]) -> ::Signature { + let hashed_message = ::hash(message).into(); + self.as_inner_ref().sign_prehashed(&hashed_message).into() + } +} + +#[cfg(feature = "bls-experimental")] +impl BeefySignerAuthority for ::Pair +where + MsgHash: Hash, + ::Output: Into<[u8; 32]>, +{ + fn sign_with_hasher(&self, message: &[u8]) -> ::Signature { + self.as_inner_ref().sign_with_hasher::(&message).into() + } } -impl Keyring { +/// Implement Keyring functionalities generically over AuthorityId +impl Keyring +where + AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, + ::Pair: BeefySignerAuthority, + ::Signature: + Send + Sync + From<<::Pair as AppCrypto>::Signature>, +{ /// Sign `msg`. - pub fn sign(self, msg: &[u8]) -> ecdsa_crypto::Signature { - // todo: use custom signature hashing type - let msg = sp_crypto_hashing::keccak_256(msg); - ecdsa::Pair::from(self).sign_prehashed(&msg).into() + pub fn sign(&self, msg: &[u8]) -> ::Signature { + let key_pair: ::Pair = self.pair(); + key_pair.sign_with_hasher(&msg).into() } /// Return key pair. - pub fn pair(self) -> ecdsa_crypto::Pair { - ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into() + pub fn pair(&self) -> ::Pair { + ::Pair::from_string(self.to_seed().as_str(), None) + .unwrap() + .into() } /// Return public key. - pub fn public(self) -> ecdsa_crypto::Public { - self.pair().public() + pub fn public(&self) -> AuthorityId { + self.pair().public().into() } /// Return seed string. - pub fn to_seed(self) -> String { + pub fn to_seed(&self) -> String { format!("//{}", self) } /// Get Keyring from public key. - pub fn from_public(who: &ecdsa_crypto::Public) -> Option { - Self::iter().find(|&k| &ecdsa_crypto::Public::from(k) == who) + pub fn from_public(who: &AuthorityId) -> Option> { + Self::iter().find(|k| k.public() == *who) } } lazy_static::lazy_static! { - static ref PRIVATE_KEYS: HashMap = - Keyring::iter().map(|i| (i, i.pair())).collect(); - static ref PUBLIC_KEYS: HashMap = - PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); + static ref PRIVATE_KEYS: HashMap, ecdsa_crypto::Pair> = + Keyring::iter().map(|i| (i.clone(), i.pair())).collect(); + static ref PUBLIC_KEYS: HashMap, ecdsa_crypto::Public> = + PRIVATE_KEYS.iter().map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair))).collect(); } -impl From for ecdsa_crypto::Pair { - fn from(k: Keyring) -> Self { +impl From> for ecdsa_crypto::Pair { + fn from(k: Keyring) -> Self { k.pair() } } -impl From for ecdsa::Pair { - fn from(k: Keyring) -> Self { +impl From> for ecdsa::Pair { + fn from(k: Keyring) -> Self { k.pair().into() } } -impl From for ecdsa_crypto::Public { - fn from(k: Keyring) -> Self { +impl From> for ecdsa_crypto::Public { + fn from(k: Keyring) -> Self { (*PUBLIC_KEYS).get(&k).cloned().unwrap() } } /// Create a new `EquivocationProof` based on given arguments. pub fn generate_equivocation_proof( - vote1: (u64, Payload, ValidatorSetId, &Keyring), - vote2: (u64, Payload, ValidatorSetId, &Keyring), + vote1: (u64, Payload, ValidatorSetId, &Keyring), + vote2: (u64, Payload, ValidatorSetId, &Keyring), ) -> EquivocationProof { let signed_vote = |block_number: u64, payload: Payload, validator_set_id: ValidatorSetId, - keyring: &Keyring| { + keyring: &Keyring| { let commitment = Commitment { validator_set_id, block_number, payload }; let signature = keyring.sign(&commitment.encode()); VoteMessage { commitment, id: keyring.public(), signature } diff --git a/substrate/primitives/consensus/common/Cargo.toml b/substrate/primitives/consensus/common/Cargo.toml index 00c2fca5e22f05cb5fd0f00880ca346ba012dd24..048e31b0265f57f0404b3777897a27f42fe3de68 100644 --- a/substrate/primitives/consensus/common/Cargo.toml +++ b/substrate/primitives/consensus/common/Cargo.toml @@ -19,8 +19,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.74" futures = { version = "0.3.21", features = ["thread-pool"] } -log = "0.4.17" -thiserror = "1.0.48" +log = { workspace = true, default-features = true } +thiserror = { workspace = true } sp-core = { path = "../../core" } sp-inherents = { path = "../../inherents" } sp-runtime = { path = "../../runtime" } diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index de02b1890703c22265c8f2e71a43a473d926b02a..b06208a4308b355031adde70de72e0e136debda5 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -19,9 +19,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", features = ["alloc", "derive"], default-features = false, optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } sp-core = { path = "../../core", default-features = false } diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 6d44bc6c5a8fe9b879962e1ddb102b5638d9dc1b..b707ad18b5b9c6d4649a31a0c8f6a4dd4eeaf1f8 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["derive"], optional = true } +serde = { features = ["derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false, features = ["bandersnatch-experimental"] } sp-consensus-slots = { path = "../slots", default-features = false } diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index fadcd1215eee8f4780457ec50052413512812af0..8372b2b04a6b662cd76a07b6d7245ba9ba46b251 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0", default-features = false, features = ["alloc", "derive"], optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-std = { path = "../../std", default-features = false } sp-timestamp = { path = "../../timestamp", default-features = false } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index f5914049f41a6c5eefe0b4ebd362d7d762c2e101..908f2498de5330c307e164f35c6f9ccfc1aa7b76 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -18,8 +18,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } -serde = { version = "1.0.195", optional = true, default-features = false, features = ["alloc", "derive"] } +log = { workspace = true } +serde = { optional = true, features = ["alloc", "derive"], workspace = true } bounded-collections = { version = "0.2.0", default-features = false } primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } @@ -27,10 +27,11 @@ hash-db = { version = "0.16.0", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } bs58 = { version = "0.5.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } -substrate-bip39 = { version = "0.4.5", optional = true } -bip39 = { version = "2.0.0", default-features = false } +substrate-bip39 = { path = "../../utils/substrate-bip39", default-features = false } +# personal fork here as workaround for: https://github.com/rust-bitcoin/rust-bip39/pull/64 +bip39 = { package = "parity-bip39", version = "2.0.1", default-features = false, features = ["alloc"] } zeroize = { version = "1.4.3", default-features = false } -secrecy = { version = "0.8.0", default-features = false } +secrecy = { version = "0.8.0", default-features = false, features = ["alloc"] } parking_lot = { version = "0.12.1", optional = true } ss58-registry = { version = "1.34.0", default-features = false } sp-std = { path = "../std", default-features = false } @@ -39,22 +40,25 @@ sp-storage = { path = "../storage", default-features = false } sp-externalities = { path = "../externalities", optional = true } futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } -thiserror = { version = "1.0.48", optional = true } +thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } bitflags = "1.3" paste = "1.0.7" itertools = { version = "0.10.3", optional = true } # full crypto -array-bytes = { version = "6.1", optional = true } -ed25519-zebra = { version = "3.1.0", default-features = false, optional = true } +array-bytes = { version = "6.1" } +ed25519-zebra = { version = "3.1.0", default-features = false } blake2 = { version = "0.10.4", default-features = false, optional = true } -libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } +libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"] } schnorrkel = { version = "0.11.4", features = ["preaudit_deprecated"], default-features = false } merlin = { version = "3.0", default-features = false } -secp256k1 = { version = "0.28.0", default-features = false, features = ["alloc", "recovery"], optional = true } -sp-crypto-hashing = { path = "../crypto/hashing", default-features = false, optional = true } +sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } sp-runtime-interface = { path = "../runtime-interface", default-features = false } +# k256 crate, better portability, intended to be used in substrate-runtimes (no-std) +k256 = { version = "0.13.3", features = ["alloc", "ecdsa"], default-features = false } +# secp256k1 crate, better performance, intended to be used on host side (std) +secp256k1 = { version = "0.28.0", default-features = false, features = ["alloc", "recovery"], optional = true } # bls crypto w3f-bls = { version = "0.1.3", default-features = false, optional = true } @@ -63,7 +67,7 @@ bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "e9782f9", [dev-dependencies] criterion = "0.4.0" -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } lazy_static = "1.4.0" regex = "1.6.0" @@ -76,8 +80,8 @@ bench = false [features] default = ["std"] + std = [ - "array-bytes", "bandersnatch_vrfs?/std", "bip39/rand", "bip39/std", @@ -94,6 +98,7 @@ std = [ "hash256-std-hasher/std", "impl-serde/std", "itertools", + "k256/std", "libsecp256k1/std", "log/std", "merlin/std", @@ -107,7 +112,6 @@ std = [ "schnorrkel/std", "secp256k1/global-context", "secp256k1/std", - "secrecy/alloc", "serde/std", "sp-crypto-hashing/std", "sp-debug-derive/std", @@ -116,7 +120,7 @@ std = [ "sp-std/std", "sp-storage/std", "ss58-registry/std", - "substrate-bip39", + "substrate-bip39/std", "thiserror", "tracing", "w3f-bls?/std", @@ -126,16 +130,14 @@ std = [ # Serde support without relying on std features. serde = [ - "array-bytes", "blake2", "bounded-collections/serde", "bs58/alloc", "dep:serde", "impl-serde", + "k256/serde", "primitive-types/serde_no_std", "scale-info/serde", - "secrecy/alloc", - "sp-crypto-hashing", "sp-storage/serde", ] @@ -143,12 +145,7 @@ serde = [ # or Intel SGX. # For the regular wasm runtime builds this should not be used. full_crypto = [ - "array-bytes", "blake2", - "ed25519-zebra", - "libsecp256k1", - "secp256k1", - "sp-crypto-hashing", "sp-runtime-interface/disable_target_static_assertions", ] diff --git a/substrate/primitives/core/check-features-variants.sh b/substrate/primitives/core/check-features-variants.sh new file mode 100755 index 0000000000000000000000000000000000000000..6d28212065a623096202f9da483aead71806c513 --- /dev/null +++ b/substrate/primitives/core/check-features-variants.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env -S bash -eux + +export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +T=wasm32-unknown-unknown + +cargo check --target=$T --release --no-default-features --features="bls-experimental" +cargo check --target=$T --release --no-default-features --features="full_crypto,bls-experimental" +cargo check --target=$T --release --no-default-features --features="bandersnatch-experimental" +cargo check --target=$T --release --no-default-features --features="full_crypto,serde,bandersnatch-experimental" +cargo check --target=$T --release --no-default-features --features="full_crypto,serde" +cargo check --target=$T --release --no-default-features --features="full_crypto" +cargo check --target=$T --release --no-default-features --features="serde" +cargo check --target=$T --release --no-default-features diff --git a/substrate/primitives/core/src/address_uri.rs b/substrate/primitives/core/src/address_uri.rs index 211d47c0093d8800646c9a47273128af18edbad5..2e32d0cd86dffea77bb47a2b025d67502a72898b 100644 --- a/substrate/primitives/core/src/address_uri.rs +++ b/substrate/primitives/core/src/address_uri.rs @@ -17,7 +17,7 @@ //! Little util for parsing an address URI. Replaces regular expressions. -#[cfg(all(not(feature = "std"), any(feature = "serde", feature = "full_crypto")))] +#[cfg(not(feature = "std"))] use sp_std::{ alloc::string::{String, ToString}, vec::Vec, diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 96b0ff19e561a41a43584142e62f8bc6d8e886b1..5cae6047f164e9ae92896e6502a1082061db1a32 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -22,19 +22,18 @@ #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; +#[cfg(feature = "full_crypto")] +use crate::crypto::VrfSecret; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom, VrfPublic, + ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, VrfPublic, }; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError, VrfSecret}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -use bandersnatch_vrfs::CanonicalSerialize; -#[cfg(feature = "full_crypto")] -use bandersnatch_vrfs::SecretKey; +use bandersnatch_vrfs::{CanonicalSerialize, SecretKey}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; @@ -45,10 +44,8 @@ use sp_std::{vec, vec::Vec}; pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band"); /// Context used to produce a plain signature without any VRF input/output. -#[cfg(feature = "full_crypto")] pub const SIGNING_CTX: &[u8] = b"BandersnatchSigningContext"; -#[cfg(feature = "full_crypto")] const SEED_SERIALIZED_SIZE: usize = 32; const PUBLIC_SERIALIZED_SIZE: usize = 33; @@ -56,7 +53,6 @@ const SIGNATURE_SERIALIZED_SIZE: usize = 65; const PREOUT_SERIALIZED_SIZE: usize = 33; /// Bandersnatch public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( Clone, Copy, @@ -69,6 +65,7 @@ const PREOUT_SERIALIZED_SIZE: usize = 33; PassByInner, MaxEncodedLen, TypeInfo, + Hash, )] pub struct Public(pub [u8; PUBLIC_SERIALIZED_SIZE]); @@ -116,7 +113,6 @@ impl ByteArray for Public { impl TraitPublic for Public {} impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } @@ -154,8 +150,9 @@ impl<'de> Deserialize<'de> for Public { /// /// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript /// `label`. -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo)] +#[derive( + Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Hash, +)] pub struct Signature([u8; SIGNATURE_SERIALIZED_SIZE]); impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { @@ -194,7 +191,6 @@ impl ByteArray for Signature { } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } @@ -211,18 +207,15 @@ impl sp_std::fmt::Debug for Signature { } /// The raw secret seed, which can be used to reconstruct the secret [`Pair`]. -#[cfg(feature = "full_crypto")] type Seed = [u8; SEED_SERIALIZED_SIZE]; /// Bandersnatch secret key. -#[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair { secret: SecretKey, seed: Seed, } -#[cfg(feature = "full_crypto")] impl Pair { /// Get the key seed. pub fn seed(&self) -> Seed { @@ -230,7 +223,6 @@ impl Pair { } } -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Seed = Seed; type Public = Public; @@ -287,6 +279,7 @@ impl TraitPair for Pair { /// the constant label [`SIGNING_CTX`] and `data` without any additional data. /// /// See [`vrf::VrfSignData`] for additional details. + #[cfg(feature = "full_crypto")] fn sign(&self, data: &[u8]) -> Signature { let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data], None); self.vrf_sign(&data).signature @@ -305,7 +298,6 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } @@ -985,6 +977,19 @@ mod tests { assert!(res.is_err()); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + } + #[test] fn sign_verify() { let pair = Pair::from_seed(DEV_SEED); diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 452c6372d16b3b2dccf60ac0e7bdde01f24f8cc1..2256e4cd823dc3184f7fc86adb3ddc0f01e0dd7a 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -15,15 +15,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Simple BLS (Boneh–Lynn–Shacham) Signature API. +//! BLS (Boneh–Lynn–Shacham) Signature along with efficiently verifiable Chaum-Pedersen proof API. +//! Signatures are implemented according to +//! [Efficient Aggregatable BLS Signatures with Chaum-Pedersen Proofs](https://eprint.iacr.org/2022/1611) +//! Hash-to-BLS-curve is using Simplified SWU for AB == 0 +//! [RFC 9380](https://datatracker.ietf.org/doc/rfc9380/) Sect 6.6.3. +//! Chaum-Pedersen proof uses the same hash-to-field specified in RFC 9380 for the field of the BLS +//! curve. #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; -use crate::crypto::{ByteArray, CryptoType, Derive, Public as TraitPublic, UncheckedFrom}; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; +use crate::crypto::{ + ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, +}; -#[cfg(feature = "full_crypto")] use sp_std::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; @@ -34,9 +40,10 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -use w3f_bls::{DoublePublicKey, DoubleSignature, EngineBLS, SerializableToBytes, TinyBLS381}; -#[cfg(feature = "full_crypto")] -use w3f_bls::{DoublePublicKeyScheme, Keypair, Message, SecretKey}; +use w3f_bls::{ + DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message, + SecretKey, SerializableToBytes, TinyBLS381, +}; use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; @@ -51,7 +58,6 @@ pub mod bls377 { pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7"); /// BLS12-377 key pair. - #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; /// BLS12-377 public key. pub type Public = super::Public; @@ -73,7 +79,6 @@ pub mod bls381 { pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls8"); /// BLS12-381 key pair. - #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; /// BLS12-381 public key. pub type Public = super::Public; @@ -90,7 +95,6 @@ trait BlsBound: EngineBLS + HardJunctionId + Send + Sync + 'static {} impl BlsBound for T {} /// Secret key serialized size -#[cfg(feature = "full_crypto")] const SECRET_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; @@ -107,7 +111,6 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize = /// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). -#[cfg(feature = "full_crypto")] type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; /// A public key. @@ -144,7 +147,6 @@ impl Ord for Public { } } -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Public { fn hash(&self, state: &mut H) { self.inner.hash(state) @@ -220,7 +222,6 @@ impl From> for [u8; PUBLIC_KEY_SERIALIZED_SIZE] { } } -#[cfg(feature = "full_crypto")] impl From> for Public { fn from(x: Pair) -> Self { x.public() @@ -290,7 +291,6 @@ impl TraitPublic for Public {} impl Derive for Public {} impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } @@ -316,7 +316,6 @@ impl PartialEq for Signature { impl Eq for Signature {} -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Signature { fn hash(&self, state: &mut H) { self.inner.hash(state) @@ -406,15 +405,12 @@ impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } /// A key pair. -#[cfg(feature = "full_crypto")] pub struct Pair(Keypair); -#[cfg(feature = "full_crypto")] impl Clone for Pair { fn clone(&self) -> Self { Pair(self.0.clone()) @@ -426,15 +422,12 @@ trait HardJunctionId { } /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { (T::ID, secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } -#[cfg(feature = "full_crypto")] impl Pair {} -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Seed = Seed; type Public = Public; @@ -452,11 +445,12 @@ impl TraitPair for Pair { fn derive>( &self, path: Iter, - _seed: Option, + seed: Option, ) -> Result<(Self, Option), DeriveError> { - let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = self.0.secret.to_bytes().try_into().expect( - "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size; qed", - ); + let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = + seed.unwrap_or(self.0.secret.to_bytes().try_into().expect( + "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size; qed", + )); for j in path { match j { DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), @@ -473,6 +467,7 @@ impl TraitPair for Pair { Self::Public::unchecked_from(raw) } + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Self::Signature { let mut mutable_self = self.clone(); let r: [u8; SIGNATURE_SERIALIZED_SIZE] = @@ -516,7 +511,6 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } @@ -544,7 +538,7 @@ mod test { "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", ); let pair = Pair::from_seed(&seed); - // we are using hash to field so this is not going to work + // we are using hash-to-field so this is not going to work // assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; @@ -588,12 +582,12 @@ mod test { assert_eq!( public, Public::unchecked_from(array_bytes::hex2array_unchecked( - "6dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" )) ); let message = b""; let signature = - array_bytes::hex2array_unchecked("bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c" + array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" ); let expected_signature = Signature::unchecked_from(signature); println!("signature is {:?}", pair.sign(&message[..])); @@ -647,12 +641,30 @@ mod test { assert_eq!(pair1.public(), pair2.public()); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + } + #[test] fn password_does_something() { let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); assert_ne!(pair1.public(), pair2.public()); + assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec()); } #[test] diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index d8436d2a96cb1a380bc2534a94e50fa5940d4fc5..fab865d8c1f4215ccc3fbf38f19543117d5a52c2 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -18,7 +18,6 @@ //! Cryptographic utilities. use crate::{ed25519, sr25519}; -#[cfg(feature = "std")] use bip39::{Language, Mnemonic}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] @@ -26,7 +25,6 @@ use itertools::Itertools; #[cfg(feature = "std")] use rand::{rngs::OsRng, RngCore}; use scale_info::TypeInfo; -#[cfg(feature = "std")] pub use secrecy::{ExposeSecret, SecretString}; use sp_runtime_interface::pass_by::PassByInner; #[doc(hidden)] @@ -41,10 +39,7 @@ pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58Addres /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; -#[cfg(feature = "std")] -pub use crate::address_uri::AddressUri; -#[cfg(any(feature = "std", feature = "full_crypto"))] -pub use crate::address_uri::Error as AddressUriError; +pub use crate::address_uri::{AddressUri, Error as AddressUriError}; /// The root phrase for our publicly known keys. pub const DEV_PHRASE: &str = @@ -82,7 +77,6 @@ impl> UncheckedInto for S { /// An error with the interpretation of a secret. #[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg(feature = "full_crypto")] pub enum SecretStringError { /// The overall format was invalid (e.g. the seed phrase contained symbols). #[cfg_attr(feature = "std", error("Invalid format {0}"))] @@ -104,7 +98,6 @@ pub enum SecretStringError { InvalidPath, } -#[cfg(any(feature = "std", feature = "full_crypto"))] impl From for SecretStringError { fn from(e: AddressUriError) -> Self { Self::InvalidFormat(e) @@ -114,7 +107,6 @@ impl From for SecretStringError { /// An error when deriving a key. #[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg(feature = "full_crypto")] pub enum DeriveError { /// A soft key was found in the path (and is unsupported). #[cfg_attr(feature = "std", error("Soft key in path"))] @@ -125,7 +117,6 @@ pub enum DeriveError { /// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex` /// a new public key from an existing public key. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)] -#[cfg(any(feature = "full_crypto", feature = "serde"))] pub enum DeriveJunction { /// Soft (vanilla) derivation. Public keys have a correspondent derivation. Soft([u8; JUNCTION_ID_LEN]), @@ -133,7 +124,6 @@ pub enum DeriveJunction { Hard([u8; JUNCTION_ID_LEN]), } -#[cfg(any(feature = "full_crypto", feature = "serde"))] impl DeriveJunction { /// Consume self to return a soft derive junction with the same chain code. pub fn soften(self) -> Self { @@ -192,7 +182,6 @@ impl DeriveJunction { } } -#[cfg(any(feature = "full_crypto", feature = "serde"))] impl> From for DeriveJunction { fn from(j: T) -> DeriveJunction { let j = j.as_ref(); @@ -773,6 +762,8 @@ mod dummy { /// Similarly an empty password (ending the `SURI` with `///`) is perfectly valid and will /// generally be equivalent to no password at all. /// +/// The `password` is used as salt when generating the seed from the BIP-39 key phrase. +/// /// # Example /// /// Parse [`DEV_PHRASE`] secret uri with junction: @@ -810,7 +801,6 @@ mod dummy { /// assert_eq!("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", suri.phrase.expose_secret()); /// assert!(suri.password.is_none()); /// ``` -#[cfg(feature = "std")] pub struct SecretUri { /// The phrase to derive the private key. /// @@ -822,7 +812,6 @@ pub struct SecretUri { pub junctions: Vec, } -#[cfg(feature = "std")] impl sp_std::str::FromStr for SecretUri { type Err = SecretStringError; @@ -843,7 +832,6 @@ impl sp_std::str::FromStr for SecretUri { /// Trait suitable for typical cryptographic PKI key pair type. /// /// For now it just specifies how to create a key from a phrase and derivation path. -#[cfg(feature = "full_crypto")] pub trait Pair: CryptoType + Sized { /// The type which is used to encode a public key. type Public: Public + Hash; @@ -876,21 +864,19 @@ pub trait Pair: CryptoType + Sized { #[cfg(feature = "std")] fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { let mnemonic = Mnemonic::generate(12).expect("Mnemonic generation always works; qed"); - let phrase = mnemonic.word_iter().join(" "); + let phrase = mnemonic.words().join(" "); let (pair, seed) = Self::from_phrase(&phrase, password) .expect("All phrases generated by Mnemonic are valid; qed"); (pair, phrase.to_owned(), seed) } /// Returns the KeyPair from the English BIP39 seed `phrase`, or an error if it's invalid. - #[cfg(feature = "std")] fn from_phrase( phrase: &str, password: Option<&str>, ) -> Result<(Self, Self::Seed), SecretStringError> { let mnemonic = Mnemonic::parse_in(Language::English, phrase) .map_err(|_| SecretStringError::InvalidPhrase)?; - let (entropy, entropy_len) = mnemonic.to_entropy_array(); let big_seed = substrate_bip39::seed_from_entropy(&entropy[0..entropy_len], password.unwrap_or("")) @@ -926,6 +912,7 @@ pub trait Pair: CryptoType + Sized { fn from_seed_slice(seed: &[u8]) -> Result; /// Sign a message. + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Self::Signature; /// Verify a signature on a message. Returns true if the signature is good. @@ -960,7 +947,6 @@ pub trait Pair: CryptoType + Sized { /// Notably, integer junction indices may be legally prefixed with arbitrary number of zeros. /// Similarly an empty password (ending the SURI with `///`) is perfectly valid and will /// generally be equivalent to no password at all. - #[cfg(feature = "std")] fn from_string_with_seed( s: &str, password_override: Option<&str>, @@ -994,7 +980,6 @@ pub trait Pair: CryptoType + Sized { /// Interprets the string `s` in order to generate a key pair. /// /// See [`from_string_with_seed`](Pair::from_string_with_seed) for more extensive documentation. - #[cfg(feature = "std")] fn from_string(s: &str, password_override: Option<&str>) -> Result { Self::from_string_with_seed(s, password_override).map(|x| x.0) } @@ -1052,7 +1037,6 @@ where /// Type which has a particular kind of crypto associated with it. pub trait CryptoType { /// The pair key type of this crypto. - #[cfg(feature = "full_crypto")] type Pair: Pair; } diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 1b63db7af7f2b73f41766fc31061e7333af922a2..fa071e1b03ff8df61d79d0815c5979bb4fc95489 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -24,24 +24,22 @@ use sp_runtime_interface::pass_by::PassByInner; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom, + ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, }; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; -#[cfg(all(feature = "full_crypto", not(feature = "std")))] -use secp256k1::Secp256k1; + +#[cfg(not(feature = "std"))] +use k256::ecdsa::{SigningKey as SecretKey, VerifyingKey}; #[cfg(feature = "std")] -use secp256k1::SECP256K1; -#[cfg(feature = "full_crypto")] use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, - Message, PublicKey, SecretKey, + Message, PublicKey, SecretKey, SECP256K1, }; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -#[cfg(feature = "full_crypto")] +#[cfg(not(feature = "std"))] use sp_std::vec::Vec; /// An identifier used to match public keys against ecdsa keys @@ -53,14 +51,12 @@ pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33; /// The byte length of signature pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; -/// A secret seed (which is bytewise essentially equivalent to a SecretKey). +/// The secret seed. /// -/// We need it as a different type because `Seed` is expected to be AsRef<[u8]>. -#[cfg(feature = "full_crypto")] +/// The raw secret seed, which can be used to create the `Pair`. type Seed = [u8; 32]; /// The ECDSA compressed public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( Clone, Copy, @@ -73,6 +69,7 @@ type Seed = [u8; 32]; PartialEq, PartialOrd, Ord, + Hash, )] pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]); @@ -96,18 +93,21 @@ impl Public { /// Create a new instance from the given full public key. /// /// This will convert the full public key into the compressed format. - #[cfg(feature = "std")] pub fn from_full(full: &[u8]) -> Result { - let pubkey = if full.len() == 64 { + let mut tagged_full = [0u8; 65]; + let full = if full.len() == 64 { // Tag it as uncompressed public key. - let mut tagged_full = [0u8; 65]; tagged_full[0] = 0x04; tagged_full[1..].copy_from_slice(full); - secp256k1::PublicKey::from_slice(&tagged_full) + &tagged_full } else { - secp256k1::PublicKey::from_slice(full) + full }; - pubkey.map(|k| Self(k.serialize())).map_err(|_| ()) + #[cfg(feature = "std")] + let pubkey = PublicKey::from_slice(&full); + #[cfg(not(feature = "std"))] + let pubkey = VerifyingKey::from_sec1_bytes(&full); + pubkey.map(|k| k.into()).map_err(|_| ()) } } @@ -131,6 +131,24 @@ impl AsMut<[u8]> for Public { } } +#[cfg(feature = "std")] +impl From for Public { + fn from(pubkey: PublicKey) -> Self { + Self(pubkey.serialize()) + } +} + +#[cfg(not(feature = "std"))] +impl From for Public { + fn from(pubkey: VerifyingKey) -> Self { + Self::unchecked_from( + pubkey.to_sec1_bytes()[..] + .try_into() + .expect("valid key is serializable to [u8,33]. qed."), + ) + } +} + impl TryFrom<&[u8]> for Public { type Error = (); @@ -199,8 +217,7 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value, plus 8 bits for recovery ID). -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Hash, Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); impl ByteArray for Signature { @@ -323,31 +340,40 @@ impl Signature { } /// Recover the public key from this signature and a message. - #[cfg(feature = "full_crypto")] pub fn recover>(&self, message: M) -> Option { self.recover_prehashed(&sp_crypto_hashing::blake2_256(message.as_ref())) } /// Recover the public key from this signature and a pre-hashed message. - #[cfg(feature = "full_crypto")] pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option { - let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; - let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; - let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); - #[cfg(feature = "std")] - let context = SECP256K1; + { + let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; + let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; + let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); + SECP256K1.recover_ecdsa(&message, &sig).ok().map(Public::from) + } + #[cfg(not(feature = "std"))] - let context = Secp256k1::verification_only(); + { + let rid = k256::ecdsa::RecoveryId::from_byte(self.0[64])?; + let sig = k256::ecdsa::Signature::from_bytes((&self.0[..64]).into()).ok()?; + VerifyingKey::recover_from_prehash(message, &sig, rid).map(Public::from).ok() + } + } +} - context - .recover_ecdsa(&message, &sig) - .ok() - .map(|pubkey| Public(pubkey.serialize())) +#[cfg(not(feature = "std"))] +impl From<(k256::ecdsa::Signature, k256::ecdsa::RecoveryId)> for Signature { + fn from(recsig: (k256::ecdsa::Signature, k256::ecdsa::RecoveryId)) -> Signature { + let mut r = Self::default(); + r.0[..64].copy_from_slice(&recsig.0.to_bytes()); + r.0[64] = recsig.1.to_byte(); + r } } -#[cfg(feature = "full_crypto")] +#[cfg(feature = "std")] impl From for Signature { fn from(recsig: RecoverableSignature) -> Signature { let mut r = Self::default(); @@ -360,20 +386,17 @@ impl From for Signature { } /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { ("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } /// A key pair. -#[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair { public: Public, secret: SecretKey, } -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Public = Public; type Seed = Seed; @@ -384,17 +407,19 @@ impl TraitPair for Pair { /// /// You should never need to use this; generate(), generate_with_phrase fn from_seed_slice(seed_slice: &[u8]) -> Result { - let secret = - SecretKey::from_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?; - #[cfg(feature = "std")] - let context = SECP256K1; - #[cfg(not(feature = "std"))] - let context = Secp256k1::signing_only(); + { + let secret = SecretKey::from_slice(seed_slice) + .map_err(|_| SecretStringError::InvalidSeedLength)?; + Ok(Pair { public: PublicKey::from_secret_key(&SECP256K1, &secret).into(), secret }) + } - let public = PublicKey::from_secret_key(&context, &secret); - let public = Public(public.serialize()); - Ok(Pair { public, secret }) + #[cfg(not(feature = "std"))] + { + let secret = SecretKey::from_slice(seed_slice) + .map_err(|_| SecretStringError::InvalidSeedLength)?; + Ok(Pair { public: VerifyingKey::from(&secret).into(), secret }) + } } /// Derive a child key from a series of given junctions. @@ -419,6 +444,7 @@ impl TraitPair for Pair { } /// Sign a message. + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Signature { self.sign_prehashed(&sp_crypto_hashing::blake2_256(message)) } @@ -434,11 +460,17 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl Pair { /// Get the seed for this key. pub fn seed(&self) -> Seed { - self.secret.secret_bytes() + #[cfg(feature = "std")] + { + self.secret.secret_bytes() + } + #[cfg(not(feature = "std"))] + { + self.secret.to_bytes().into() + } } /// Exactly as `from_string` except that if no matches are found then, the the first 32 @@ -454,15 +486,21 @@ impl Pair { } /// Sign a pre-hashed message + #[cfg(feature = "full_crypto")] pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature { - let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); - #[cfg(feature = "std")] - let context = SECP256K1; - #[cfg(not(feature = "std"))] - let context = Secp256k1::signing_only(); + { + let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); + SECP256K1.sign_ecdsa_recoverable(&message, &self.secret).into() + } - context.sign_ecdsa_recoverable(&message, &self.secret).into() + #[cfg(not(feature = "std"))] + { + self.secret + .sign_prehash_recoverable(message) + .expect("signing may not fail (???). qed.") + .into() + } } /// Verify a signature on a pre-hashed message. Return `true` if the signature is valid @@ -503,7 +541,7 @@ impl Pair { // NOTE: this solution is not effective when `Pair` is moved around memory. // The very same problem affects other cryptographic backends that are just using // `zeroize`for their secrets. -#[cfg(feature = "full_crypto")] +#[cfg(feature = "std")] impl Drop for Pair { fn drop(&mut self) { self.secret.non_secure_erase() @@ -511,16 +549,13 @@ impl Drop for Pair { } impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } @@ -644,12 +679,29 @@ mod test { assert_eq!(pair1.public(), pair2.public()); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + assert_eq!(pair.secret, repair_seed.secret); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + assert_eq!(pair.secret, repair_phrase.secret); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + assert_eq!(pair.secret, repair_string.secret); + } + #[test] fn password_does_something() { let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); assert_ne!(pair1.public(), pair2.public()); + assert_ne!(pair1.secret, pair2.secret); } #[test] @@ -753,8 +805,18 @@ mod test { let msg = [0u8; 32]; let sig1 = pair.sign_prehashed(&msg); let sig2: Signature = { - let message = Message::from_digest_slice(&msg).unwrap(); - SECP256K1.sign_ecdsa_recoverable(&message, &pair.secret).into() + #[cfg(feature = "std")] + { + let message = Message::from_digest_slice(&msg).unwrap(); + SECP256K1.sign_ecdsa_recoverable(&message, &pair.secret).into() + } + #[cfg(not(feature = "std"))] + { + pair.secret + .sign_prehash_recoverable(&msg) + .expect("signing may not fail (???). qed.") + .into() + } }; assert_eq!(sig1, sig2); diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index aa0d77510bd81efdd9186e730842622f65620558..9f42b36dc8bd562022fa7443db0fcbbae3687c10 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -19,7 +19,6 @@ //! Simple Ed25519 API. // end::description[] -#[cfg(feature = "full_crypto")] use sp_std::vec::Vec; use crate::{ @@ -32,13 +31,11 @@ use scale_info::TypeInfo; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ - CryptoType, CryptoTypeId, Derive, FromEntropy, Public as TraitPublic, UncheckedFrom, + CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, FromEntropy, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, }; #[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; -#[cfg(feature = "full_crypto")] use core::convert::TryFrom; -#[cfg(feature = "full_crypto")] use ed25519_zebra::{SigningKey, VerificationKey}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -53,11 +50,9 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ed25"); /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). -#[cfg(feature = "full_crypto")] type Seed = [u8; 32]; /// A public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( PartialEq, Eq, @@ -70,11 +65,11 @@ type Seed = [u8; 32]; PassByInner, MaxEncodedLen, TypeInfo, + Hash, )] pub struct Public(pub [u8; 32]); /// A key pair. -#[cfg(feature = "full_crypto")] #[derive(Copy, Clone)] pub struct Pair { public: VerificationKey, @@ -210,8 +205,7 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value). -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] pub struct Signature(pub [u8; 64]); impl TryFrom<&[u8]> for Signature { @@ -370,12 +364,10 @@ impl TraitPublic for Public {} impl Derive for Public {} /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { ("Ed25519HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Public = Public; type Seed = Seed; @@ -414,6 +406,7 @@ impl TraitPair for Pair { } /// Sign a message. + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Signature { Signature::from_raw(self.secret.sign(message).into()) } @@ -433,7 +426,6 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl Pair { /// Get the seed for this key. pub fn seed(&self) -> Seed { @@ -454,16 +446,13 @@ impl Pair { } impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } @@ -501,6 +490,22 @@ mod test { ); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + } + #[test] fn test_vector_should_work() { let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( @@ -590,6 +595,7 @@ mod test { let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); assert_ne!(pair1.public(), pair2.public()); + assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec()); } #[test] diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 0d43eea99629915715f452da409d53522d199e53..c0b41234460dad301056ae542eaa2721522487fc 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -46,7 +46,6 @@ pub use sp_debug_derive::RuntimeDebug; #[cfg(feature = "serde")] pub use impl_serde::serialize as bytes; -#[cfg(feature = "full_crypto")] #[deprecated( since = "27.0.0", note = "`sp-crypto-hashing` re-exports will be removed after June 2024. Use `sp-crypto-hashing` instead." @@ -58,7 +57,6 @@ pub mod crypto; pub mod hexdisplay; pub use paste; -#[cfg(any(feature = "full_crypto", feature = "std"))] mod address_uri; #[cfg(feature = "bandersnatch-experimental")] pub mod bandersnatch; @@ -87,7 +85,6 @@ pub use self::{ hash::{convert_hash, H160, H256, H512}, uint::{U256, U512}, }; -#[cfg(feature = "full_crypto")] pub use crypto::{ByteArray, DeriveJunction, Pair, Public}; #[cfg(feature = "std")] diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 960b8469249e22b10352545f26d3940df3da2e77..6d2e6ddf3348bf34443e0fc7fa96f75e2ba55467 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -19,11 +19,11 @@ #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; -use crate::crypto::{ByteArray, CryptoType, Derive, Public as PublicT, UncheckedFrom}; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as PairT, SecretStringError}; +use crate::crypto::{ + ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT, + SecretStringError, UncheckedFrom, +}; -#[cfg(feature = "full_crypto")] use sp_std::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; @@ -39,12 +39,11 @@ use sp_std::convert::TryFrom; /// ECDSA and BLS12-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377 { + use crate::{bls377, crypto::CryptoTypeId, ecdsa}; #[cfg(feature = "full_crypto")] - use crate::Hasher; use crate::{ - bls377, - crypto::{CryptoTypeId, Pair as PairT, UncheckedFrom}, - ecdsa, + crypto::{Pair as PairT, UncheckedFrom}, + Hasher, }; /// An identifier used to match public keys against BLS12-377 keys @@ -56,7 +55,6 @@ pub mod ecdsa_bls377 { ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE; /// (ECDSA,BLS12-377) key-pair pair. - #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; /// (ECDSA,BLS12-377) public key pair. pub type Public = super::Public; @@ -64,16 +62,13 @@ pub mod ecdsa_bls377 { pub type Signature = super::Signature; impl super::CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl super::CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } - #[cfg(feature = "full_crypto")] impl super::CryptoType for Pair { type Pair = Pair; } @@ -136,7 +131,6 @@ pub mod ecdsa_bls377 { /// Secure seed length. /// /// Currently only supporting sub-schemes whose seed is a 32-bytes array. -#[cfg(feature = "full_crypto")] const SECURE_SEED_LEN: usize = 32; /// A secret seed. @@ -144,14 +138,12 @@ const SECURE_SEED_LEN: usize = 32; /// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). -#[cfg(feature = "full_crypto")] type Seed = [u8; SECURE_SEED_LEN]; /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] pub struct Public([u8; LEFT_PLUS_RIGHT_LEN]); -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Public { fn hash(&self, state: &mut H) { self.0.hash(state); @@ -215,7 +207,6 @@ impl PassBy for Public { type PassBy = pass_by::Inner; } -#[cfg(feature = "full_crypto")] impl< LeftPair: PairT, RightPair: PairT, @@ -311,7 +302,6 @@ impl SignatureBound for T {} #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] pub struct Signature([u8; LEFT_PLUS_RIGHT_LEN]); -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Signature { fn hash(&self, state: &mut H) { self.0.hash(state); @@ -411,7 +401,6 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> } /// A key pair. -#[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair< LeftPair: PairT, @@ -423,7 +412,6 @@ pub struct Pair< right: RightPair, } -#[cfg(feature = "full_crypto")] impl< LeftPair: PairT, RightPair: PairT, @@ -460,10 +448,11 @@ where path: Iter, seed: Option, ) -> Result<(Self, Option), DeriveError> { - let path: Vec<_> = path.collect(); + let left_path: Vec<_> = path.collect(); + let right_path: Vec<_> = left_path.clone(); - let left = self.left.derive(path.iter().cloned(), seed.map(|s| s.into()))?; - let right = self.right.derive(path.into_iter(), seed.map(|s| s.into()))?; + let left = self.left.derive(left_path.into_iter(), seed.map(|s| s.into()))?; + let right = self.right.derive(right_path.into_iter(), seed.map(|s| s.into()))?; let seed = match (left.1, right.1) { (Some(l), Some(r)) if l.as_ref() == r.as_ref() => Some(l.into()), @@ -482,6 +471,7 @@ where Self::Public::unchecked_from(raw) } + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Self::Signature { let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; raw[..LeftPair::Signature::LEN].copy_from_slice(self.left.sign(message).as_ref()); @@ -542,13 +532,30 @@ mod test { ); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + } + #[test] fn seed_and_derive_should_work() { let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", ); let pair = Pair::from_seed(&seed_for_right_and_left); - // we are using hash to field so this is not going to work + // we are using hash-to-field so this is not going to work // assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; @@ -599,13 +606,13 @@ mod test { assert_eq!( public, Public::unchecked_from( - array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" ), ), ); let message = b""; let signature = - array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c" + array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" ); let signature = Signature::unchecked_from(signature); assert!(pair.sign(&message[..]) == signature); @@ -664,6 +671,7 @@ mod test { let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); assert_ne!(pair1.public(), pair2.public()); + assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec()); } #[test] diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index b821055e2c56713067bf096899c2b10b6155c877..6c04eb8def1f4fdb2dd8ddc0773ab458b6ce1a8e 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -19,20 +19,14 @@ //! //! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN` //! for this to work. -#[cfg(any(feature = "full_crypto", feature = "serde"))] -use crate::crypto::DeriveJunction; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; +use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, Pair as TraitPair, SecretStringError}; -#[cfg(feature = "full_crypto")] -use schnorrkel::{ - derive::CHAIN_CODE_LENGTH, signing_context, ExpansionMode, Keypair, MiniSecretKey, SecretKey, -}; -#[cfg(any(feature = "full_crypto", feature = "serde"))] +use schnorrkel::signing_context; use schnorrkel::{ - derive::{ChainCode, Derivation}, - PublicKey, + derive::{ChainCode, Derivation, CHAIN_CODE_LENGTH}, + ExpansionMode, Keypair, MiniSecretKey, PublicKey, SecretKey, }; use sp_std::vec::Vec; @@ -47,7 +41,6 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_std::ops::Deref; -#[cfg(feature = "full_crypto")] use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -56,14 +49,12 @@ use sp_runtime_interface::pass_by::PassByInner; use sp_std::alloc::{format, string::String}; // signing context -#[cfg(feature = "full_crypto")] const SIGNING_CTX: &[u8] = b"substrate"; /// An identifier used to match public keys against sr25519 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); /// An Schnorrkel/Ristretto x25519 ("sr25519") public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( PartialEq, Eq, @@ -76,14 +67,13 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); PassByInner, MaxEncodedLen, TypeInfo, + Hash, )] pub struct Public(pub [u8; 32]); /// An Schnorrkel/Ristretto x25519 ("sr25519") key pair. -#[cfg(feature = "full_crypto")] pub struct Pair(Keypair); -#[cfg(feature = "full_crypto")] impl Clone for Pair { fn clone(&self) -> Self { Pair(schnorrkel::Keypair { @@ -216,8 +206,7 @@ impl<'de> Deserialize<'de> for Public { } /// An Schnorrkel/Ristretto x25519 ("sr25519") signature. -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] pub struct Signature(pub [u8; 64]); impl TryFrom<&[u8]> for Signature { @@ -435,16 +424,13 @@ impl AsRef for Pair { } /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> MiniSecretKey { secret.hard_derive_mini_secret_key(Some(ChainCode(*cc)), b"").0 } /// The raw secret seed, which can be used to recreate the `Pair`. -#[cfg(feature = "full_crypto")] type Seed = [u8; MINI_SECRET_KEY_LENGTH]; -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Public = Public; type Seed = Seed; @@ -499,6 +485,7 @@ impl TraitPair for Pair { Ok((Self(result.into()), seed.map(|s| MiniSecretKey::to_bytes(&s)))) } + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Signature { let context = signing_context(SIGNING_CTX); self.0.sign(context.bytes(message)).into() @@ -533,16 +520,13 @@ impl Pair { } impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } @@ -970,6 +954,22 @@ mod tests { assert!(Pair::verify(&signature, &message[..], &public)); } + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string() { + let (pair, phrase, seed) = Pair::generate_with_phrase(None); + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + } + #[test] fn generated_pair_should_work() { let (pair, _) = Pair::generate(); diff --git a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml index 179b70048a754799fd3b3693f934a0807cb872a6..f244b02ca101670df10f5aea1a1482cb86cfdaed 100644 --- a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml @@ -19,6 +19,6 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.28" -syn = { version = "2.0.48", features = ["full", "parsing"] } +quote = { workspace = true } +syn = { features = ["full", "parsing"], workspace = true } sp-crypto-hashing = { path = "..", default-features = false } diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 2a18f505fcbc8ad1f61449a20a58b1d8bc2aaa94..debf964aa3dfdf7cebd23e0f1d24e74b0d880ec0 100644 --- a/substrate/primitives/debug-derive/Cargo.toml +++ b/substrate/primitives/debug-derive/Cargo.toml @@ -19,8 +19,8 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.28" -syn = "2.0.48" +quote = { workspace = true } +syn = { workspace = true } proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/externalities/src/extensions.rs b/substrate/primitives/externalities/src/extensions.rs index 282e6ea914a84caae6a1c63af8d9ff0e125176fc..d99dfe6cf530ae29718a1cf0a24a5a6afa851894 100644 --- a/substrate/primitives/externalities/src/extensions.rs +++ b/substrate/primitives/externalities/src/extensions.rs @@ -78,16 +78,16 @@ macro_rules! decl_extension { $vis struct $ext_name (pub $inner); impl $crate::Extension for $ext_name { - fn as_mut_any(&mut self) -> &mut dyn std::any::Any { + fn as_mut_any(&mut self) -> &mut dyn core::any::Any { self } - fn type_id(&self) -> std::any::TypeId { - std::any::Any::type_id(self) + fn type_id(&self) -> core::any::TypeId { + core::any::Any::type_id(self) } } - impl std::ops::Deref for $ext_name { + impl core::ops::Deref for $ext_name { type Target = $inner; fn deref(&self) -> &Self::Target { @@ -95,7 +95,7 @@ macro_rules! decl_extension { } } - impl std::ops::DerefMut for $ext_name { + impl core::ops::DerefMut for $ext_name { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } @@ -115,12 +115,12 @@ macro_rules! decl_extension { $vis struct $ext_name; impl $crate::Extension for $ext_name { - fn as_mut_any(&mut self) -> &mut dyn std::any::Any { + fn as_mut_any(&mut self) -> &mut dyn core::any::Any { self } - fn type_id(&self) -> std::any::TypeId { - std::any::Any::type_id(self) + fn type_id(&self) -> core::any::TypeId { + core::any::Any::type_id(self) } } } diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index 1967e9ff8856eed3f930ef50b027dd68c41ca870..15440b4811ec4664725f8b0df5335748917b20fc 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true -description = "Substrate GenesisConfig builder API" +description = "Substrate RuntimeGenesisConfig builder API" readme = "README.md" [lints] @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { path = "../api", default-features = false } sp-runtime = { path = "../runtime", default-features = false } sp-std = { path = "../std", default-features = false } -serde_json = { version = "1.0.111", default-features = false, features = ["alloc", "arbitrary_precision"] } +serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/genesis-builder/src/lib.rs b/substrate/primitives/genesis-builder/src/lib.rs index e002cd3aa6f704d8889fd35d04fdd65b46a1b754..bb1a2a352488ac0c03cfcd35dac1b45444b1d9a1 100644 --- a/substrate/primitives/genesis-builder/src/lib.rs +++ b/substrate/primitives/genesis-builder/src/lib.rs @@ -19,36 +19,37 @@ //! Substrate genesis config builder //! -//! This Runtime API allows to construct `GenesisConfig`, in particular: -//! - serialize the runtime default `GenesisConfig` struct into json format, -//! - put the GenesisConfig struct into the storage. Internally this operation calls +//! This Runtime API allows to construct `RuntimeGenesisConfig`, in particular: +//! - serialize the runtime default `RuntimeGenesisConfig` struct into json format, +//! - put the RuntimeGenesisConfig struct into the storage. Internally this operation calls //! `GenesisBuild::build` function for all runtime pallets, which is typically provided by //! pallet's author. -//! - deserialize the `GenesisConfig` from given json blob and put `GenesisConfig` into the state -//! storage. Allows to build customized configuration. +//! - deserialize the `RuntimeGenesisConfig` from given json blob and put `RuntimeGenesisConfig` +//! into the state storage. Allows to build customized configuration. //! -//! Providing externalities with empty storage and putting `GenesisConfig` into storage allows to -//! catch and build the raw storage of `GenesisConfig` which is the foundation for genesis block. +//! Providing externalities with empty storage and putting `RuntimeGenesisConfig` into storage +//! allows to catch and build the raw storage of `RuntimeGenesisConfig` which is the foundation for +//! genesis block. /// The result type alias, used in build methods. `Err` contains formatted error message. pub type Result = core::result::Result<(), sp_runtime::RuntimeString>; sp_api::decl_runtime_apis! { - /// API to interact with GenesisConfig for the runtime + /// API to interact with RuntimeGenesisConfig for the runtime pub trait GenesisBuilder { - /// Creates the default `GenesisConfig` and returns it as a JSON blob. + /// Creates the default `RuntimeGenesisConfig` and returns it as a JSON blob. /// - /// This function instantiates the default `GenesisConfig` struct for the runtime and serializes it into a JSON - /// blob. It returns a `Vec` containing the JSON representation of the default `GenesisConfig`. + /// This function instantiates the default `RuntimeGenesisConfig` struct for the runtime and serializes it into a JSON + /// blob. It returns a `Vec` containing the JSON representation of the default `RuntimeGenesisConfig`. fn create_default_config() -> sp_std::vec::Vec; - /// Build `GenesisConfig` from a JSON blob not using any defaults and store it in the storage. + /// Build `RuntimeGenesisConfig` from a JSON blob not using any defaults and store it in the storage. /// - /// This function deserializes the full `GenesisConfig` from the given JSON blob and puts it into the storage. + /// 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. /// It is recommended to log any errors encountered during the process. /// - /// Please note that provided json blob must contain all `GenesisConfig` fields, no defaults will be used. + /// Please note that provided json blob must contain all `RuntimeGenesisConfig` fields, no defaults will be used. fn build_config(json: sp_std::vec::Vec) -> Result; } } diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index 2a9d205e16642d3565a941f0a2969fadc43895cb..bfb1d7733471fa7fd9f0a13c14d337e34188065d 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -21,7 +21,7 @@ async-trait = { version = "0.1.74", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" -thiserror = { version = "1.0.48", optional = true } +thiserror = { optional = true, workspace = true } sp-runtime = { path = "../runtime", default-features = false, optional = true } sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/inherents/src/lib.rs b/substrate/primitives/inherents/src/lib.rs index dd7c294f1e245126bd02ef14a470595dc13841bb..415319a6849c97f9a0c89b663bb4248a50d5b7dd 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::{generic::UncheckedExtrinsic, testing::MockCallU64}; //! # 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/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index d2d56b831532a4fdbf6e3ca70cf52820b2dc42fc..e47775d56d9e55780c6e18c2d33e132407c83786 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime-interface = { path = "../runtime-interface", default-features = false sp-trie = { path = "../trie", default-features = false, optional = true } sp-externalities = { path = "../externalities", default-features = false } sp-tracing = { path = "../tracing", default-features = false } -log = { version = "0.4.17", optional = true } +log = { optional = true, workspace = true, default-features = true } secp256k1 = { version = "0.28.0", features = ["global-context", "recovery"], optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.32", default-features = false } @@ -38,6 +38,9 @@ tracing-core = { version = "0.1.32", default-features = false } # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. ed25519-dalek = { version = "2.1", default-features = false, optional = true } +[target.'cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))'.dependencies] +polkavm-derive = { workspace = true } + [build-dependencies] rustversion = "1.0.6" diff --git a/substrate/primitives/io/src/global_alloc_riscv.rs b/substrate/primitives/io/src/global_alloc_riscv.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d7c69c20945946a352238dc8a94ecaba2f2a266 --- /dev/null +++ b/substrate/primitives/io/src/global_alloc_riscv.rs @@ -0,0 +1,19 @@ +// 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. + +#[global_allocator] +static ALLOCATOR: polkavm_derive::LeakingAllocator = polkavm_derive::LeakingAllocator; diff --git a/substrate/primitives/io/src/global_alloc_wasm.rs b/substrate/primitives/io/src/global_alloc_wasm.rs new file mode 100644 index 0000000000000000000000000000000000000000..cf19a6e21a2d26f20d7989a9b155709b2afa73ac --- /dev/null +++ b/substrate/primitives/io/src/global_alloc_wasm.rs @@ -0,0 +1,34 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::alloc::{GlobalAlloc, Layout}; + +/// Allocator used by Substrate from within the runtime. +struct RuntimeAllocator; + +#[global_allocator] +static ALLOCATOR: RuntimeAllocator = RuntimeAllocator; + +unsafe impl GlobalAlloc for RuntimeAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + crate::allocator::malloc(layout.size() as u32) + } + + unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) { + crate::allocator::free(ptr) + } +} diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 6d34199416a36deeb011003989f6e361d535a0e6..684854ea5c8d4568c60b8ede7b89cdf4c26a4c38 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -129,6 +129,16 @@ use sp_externalities::{Externalities, ExternalitiesExt}; pub use sp_externalities::MultiRemovalResults; +#[cfg(all(not(feature = "disable_allocator"), substrate_runtime, target_family = "wasm"))] +mod global_alloc_wasm; + +#[cfg(all( + not(feature = "disable_allocator"), + substrate_runtime, + any(target_arch = "riscv32", target_arch = "riscv64") +))] +mod global_alloc_riscv; + #[cfg(feature = "std")] const LOG_TARGET: &str = "runtime::io"; @@ -1737,30 +1747,6 @@ mod tracing_setup { pub use tracing_setup::init_tracing; -/// Allocator used by Substrate from within the runtime. -#[cfg(substrate_runtime)] -struct RuntimeAllocator; - -#[cfg(all(not(feature = "disable_allocator"), substrate_runtime))] -#[global_allocator] -static ALLOCATOR: RuntimeAllocator = RuntimeAllocator; - -#[cfg(substrate_runtime)] -mod allocator_impl { - use super::*; - use core::alloc::{GlobalAlloc, Layout}; - - unsafe impl GlobalAlloc for RuntimeAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - allocator::malloc(layout.size() as u32) - } - - unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) { - allocator::free(ptr) - } - } -} - /// Crashes the execution of the program. /// /// Equivalent to the WASM `unreachable` instruction, RISC-V `unimp` instruction, diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 1c936b6685be86c54a70824ab902f616c0639945..940fe90916d25aabef032437f0a6e0a05d270464 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -18,10 +18,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] strum = { version = "0.24.1", features = ["derive"], default-features = false } -sp-core = { path = "../core" } -sp-runtime = { path = "../runtime" } +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } [features] +default = ["std"] +std = ["sp-core/std", "sp-runtime/std", "strum/std"] + # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. diff --git a/substrate/primitives/keyring/check-features-variants.sh b/substrate/primitives/keyring/check-features-variants.sh new file mode 100755 index 0000000000000000000000000000000000000000..9c28d83589465483a290b6485f9c77fa7dbdb5a8 --- /dev/null +++ b/substrate/primitives/keyring/check-features-variants.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env -S bash -eux + +export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +T=wasm32-unknown-unknown + +cargo check --release +cargo check --release --features="bandersnatch-experimental" +cargo check --release --target=$T --no-default-features diff --git a/substrate/primitives/keyring/src/bandersnatch.rs b/substrate/primitives/keyring/src/bandersnatch.rs index eb60f85632725ca9efbac46c63222fc71609d74f..67fc5c47df643ee4b45b8ebbb99089abdb466d96 100644 --- a/substrate/primitives/keyring/src/bandersnatch.rs +++ b/substrate/primitives/keyring/src/bandersnatch.rs @@ -18,14 +18,21 @@ //! A set of well-known keys used for testing. pub use sp_core::bandersnatch; +#[cfg(feature = "std")] +use sp_core::bandersnatch::Signature; use sp_core::{ - bandersnatch::{Pair, Public, Signature}, + bandersnatch::{Pair, Public}, crypto::UncheckedFrom, hex2array, ByteArray, Pair as PairT, }; +extern crate alloc; +use alloc::{fmt, format, str::FromStr, string::String, vec::Vec}; + /// Set of test accounts. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter, Ord, PartialOrd, +)] pub enum Keyring { Alice, Bob, @@ -56,6 +63,7 @@ impl Keyring { Public::from(self).to_raw_vec() } + #[cfg(feature = "std")] pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } @@ -102,16 +110,16 @@ impl From for &'static str { #[derive(Debug)] pub struct ParseKeyringError; -impl std::fmt::Display for ParseKeyringError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for ParseKeyringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ParseKeyringError") } } -impl std::str::FromStr for Keyring { +impl FromStr for Keyring { type Err = ParseKeyringError; - fn from_str(s: &str) -> Result::Err> { + fn from_str(s: &str) -> Result::Err> { match s { "Alice" => Ok(Keyring::Alice), "Bob" => Ok(Keyring::Bob), diff --git a/substrate/primitives/keyring/src/ed25519.rs b/substrate/primitives/keyring/src/ed25519.rs index ade42b294940213664d0553a4e4ec537ce553f15..98ca368e53caac26ae690b76500475b1749a07b1 100644 --- a/substrate/primitives/keyring/src/ed25519.rs +++ b/substrate/primitives/keyring/src/ed25519.rs @@ -18,14 +18,21 @@ //! Support code for the runtime. A set of test accounts. pub use sp_core::ed25519; +#[cfg(feature = "std")] +use sp_core::ed25519::Signature; use sp_core::{ - ed25519::{Pair, Public, Signature}, + ed25519::{Pair, Public}, hex2array, ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; +extern crate alloc; +use alloc::{format, string::String, vec::Vec}; + /// Set of test accounts. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter, Ord, PartialOrd, +)] pub enum Keyring { Alice, Bob, @@ -76,6 +83,7 @@ impl Keyring { self.to_raw_public().into() } + #[cfg(feature = "std")] pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } diff --git a/substrate/primitives/keyring/src/lib.rs b/substrate/primitives/keyring/src/lib.rs index ee7fd56ba11bf5855d8ae648f073ea004bb257aa..f753bf4b0dd684d0aa292eeca1f97ad9f5cafdda 100644 --- a/substrate/primitives/keyring/src/lib.rs +++ b/substrate/primitives/keyring/src/lib.rs @@ -17,6 +17,8 @@ //! Support code for the runtime. A set of test accounts. +#![cfg_attr(not(feature = "std"), no_std)] + /// Test account crypto for sr25519. pub mod sr25519; diff --git a/substrate/primitives/keyring/src/sr25519.rs b/substrate/primitives/keyring/src/sr25519.rs index 1c2a2526efb1eccb16cb0696f89cb3fc7583357b..a3a506152d7d6f0b76b366a930860e39f3f8fae0 100644 --- a/substrate/primitives/keyring/src/sr25519.rs +++ b/substrate/primitives/keyring/src/sr25519.rs @@ -18,15 +18,22 @@ //! Support code for the runtime. A set of test accounts. pub use sp_core::sr25519; +#[cfg(feature = "std")] +use sp_core::sr25519::Signature; use sp_core::{ hex2array, - sr25519::{Pair, Public, Signature}, + sr25519::{Pair, Public}, ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; +extern crate alloc; +use alloc::{fmt, format, str::FromStr, string::String, vec::Vec}; + /// Set of test accounts. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter, Ord, PartialOrd, +)] pub enum Keyring { Alice, Bob, @@ -77,6 +84,7 @@ impl Keyring { self.to_raw_public().into() } + #[cfg(feature = "std")] pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } @@ -140,16 +148,16 @@ impl From for sp_runtime::MultiSigner { #[derive(Debug)] pub struct ParseKeyringError; -impl std::fmt::Display for ParseKeyringError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for ParseKeyringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ParseKeyringError") } } -impl std::str::FromStr for Keyring { +impl FromStr for Keyring { type Err = ParseKeyringError; - fn from_str(s: &str) -> Result::Err> { + fn from_str(s: &str) -> Result::Err> { match s { "alice" => Ok(Keyring::Alice), "bob" => Ok(Keyring::Bob), diff --git a/substrate/primitives/keystore/Cargo.toml b/substrate/primitives/keystore/Cargo.toml index 139f04beb205f5dd72c1549c680dedfe4685d63e..a34839358e18333154962f71e1957f9884a71a2f 100644 --- a/substrate/primitives/keystore/Cargo.toml +++ b/substrate/primitives/keystore/Cargo.toml @@ -17,8 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -parking_lot = { version = "0.12.1", default-features = false } -thiserror = "1.0" +parking_lot = { version = "0.12.1", default-features = false, optional = true } sp-core = { path = "../core", default-features = false } sp-externalities = { path = "../externalities", default-features = false } @@ -28,7 +27,7 @@ rand_chacha = "0.2.2" [features] default = ["std"] -std = ["codec/std", "sp-core/std", "sp-externalities/std"] +std = ["codec/std", "dep:parking_lot", "sp-core/std", "sp-externalities/std"] # This feature adds BLS crypto primitives. # It should not be used in production since the implementation and interface may still diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 07c4e2d5fd1dc4b8cc903d34154dbc51a050426c..64f0e3ea49e8bd3a7e682ad024cd7c28fbcd3abd 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -17,6 +17,10 @@ //! Keystore traits +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + #[cfg(feature = "std")] pub mod testing; @@ -29,25 +33,35 @@ use sp_core::{ ecdsa, ed25519, sr25519, }; -use std::sync::Arc; +use alloc::{string::String, sync::Arc, vec::Vec}; /// Keystore error -#[derive(Debug, thiserror::Error)] +#[derive(Debug)] pub enum Error { /// Public key type is not supported - #[error("Key not supported: {0:?}")] KeyNotSupported(KeyTypeId), /// Validation error - #[error("Validation error: {0}")] ValidationError(String), /// Keystore unavailable - #[error("Keystore unavailable")] Unavailable, /// Programming errors - #[error("An unknown keystore error occurred: {0}")] Other(String), } +impl core::fmt::Display for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Error::KeyNotSupported(key_type) => write!(fmt, "Key not supported: {key_type:?}"), + Error::ValidationError(error) => write!(fmt, "Validation error: {error}"), + Error::Unavailable => fmt.write_str("Keystore unavailable"), + Error::Other(error) => write!(fmt, "An unknown keystore error occurred: {error}"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + /// Something that generates, stores and provides access to secret keys. pub trait Keystore: Send + Sync { /// Returns all the sr25519 public keys for the given key type. @@ -355,6 +369,24 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result, Error>; + /// Hashes the `message` using keccak256 and then signs it using ECDSA + /// algorithm. It does not affect the behavior of BLS12-377 component. It generates + /// BLS12-377 Signature according to IETF standard. + /// + /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error>; + /// Insert a new secret key. fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; @@ -661,6 +693,16 @@ impl Keystore for Arc { (**self).ecdsa_bls377_sign(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + (**self).ecdsa_bls377_sign_with_keccak256(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index 2879c458b4f68c40338b544532bdf80b9bf1d32f..e10660b126a33f23e00f5774412f65d665cc6737 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -22,7 +22,7 @@ use crate::{Error, Keystore, KeystorePtr}; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381, ecdsa_bls377}; +use sp_core::{bls377, bls381, ecdsa_bls377, KeccakHasher}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, ecdsa, ed25519, sr25519, @@ -346,6 +346,19 @@ impl Keystore for MemoryKeystore { self.sign::(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result, Error> { + let sig = self + .pair::(key_type, public) + .map(|pair| pair.sign_with_hasher::(msg)); + Ok(sig) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() @@ -493,6 +506,38 @@ mod tests { assert!(res.is_some()); } + #[test] + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign_with_keccak_works() { + use sp_core::testing::ECDSA_BLS377; + + let store = MemoryKeystore::new(); + + let suri = "//Alice"; + let pair = ecdsa_bls377::Pair::from_string(suri, None).unwrap(); + + let msg = b"this should be a normal unhashed message not "; + + // insert key, sign again + store.insert(ECDSA_BLS377, suri, pair.public().as_ref()).unwrap(); + + let res = store + .ecdsa_bls377_sign_with_keccak256(ECDSA_BLS377, &pair.public(), &msg[..]) + .unwrap(); + + assert!(res.is_some()); + + // does not verify with default out-of-the-box verification + assert!(!ecdsa_bls377::Pair::verify(&res.clone().unwrap(), &msg[..], &pair.public())); + + // should verify using keccak256 as hasher + assert!(ecdsa_bls377::Pair::verify_with_hasher::( + &res.unwrap(), + msg, + &pair.public() + )); + } + #[test] #[cfg(feature = "bandersnatch-experimental")] fn bandersnatch_vrf_sign() { diff --git a/substrate/primitives/maybe-compressed-blob/Cargo.toml b/substrate/primitives/maybe-compressed-blob/Cargo.toml index 84a5592dcaf2702497cecf6e26d9878cf62a9c6b..fa5383d03b10d5c6560e50ff28be7b6e71ffe2b0 100644 --- a/substrate/primitives/maybe-compressed-blob/Cargo.toml +++ b/substrate/primitives/maybe-compressed-blob/Cargo.toml @@ -14,5 +14,5 @@ readme = "README.md" workspace = true [dependencies] -thiserror = "1.0" +thiserror = { workspace = true } zstd = { version = "0.12.4", default-features = false } diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 729f458dd8dfa3186b6646d7a2b37f1e68da3567..50d8477823948a4005a9cb0ccfabf73349f91222 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -17,15 +17,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } -serde = { version = "1.0.195", features = ["alloc", "derive"], default-features = false, optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../api", default-features = false } sp-core = { path = "../core", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-runtime = { path = "../runtime", default-features = false } sp-std = { path = "../std", default-features = false } -thiserror = { version = "1.0", optional = true } +thiserror = { optional = true, workspace = true } [dev-dependencies] array-bytes = "6.1" diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index edfa58f8618942e34b6937733cbd2a5f5c4dffbb..66aff2c599fc9438c2e42bcd3c409d8fbabe6dca 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -84,7 +84,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 b107d20a8e2bfbf55d0d558bb60346cb7a52dd70..e60881ed6b8d86df2bc0b92c744b569168e3f75d 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -166,10 +166,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: rename this to `extension_ty`. 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 { @@ -183,27 +184,27 @@ 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 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 + /// The type of the additional signed data, with the data to be included in the signed payload. pub additional_signed: 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), diff --git a/substrate/primitives/metadata-ir/src/v14.rs b/substrate/primitives/metadata-ir/src/v14.rs index e1b7a24f76577c09f7f8c8040ae06bf433f9126d..ec08de3478622421214bc40f7ea4a5b1dca6cadc 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,8 +137,8 @@ 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, @@ -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 a942eb73223b2c80e2d71ef1cb070c45a2ca588f..dc5ce1c88fdfa5b32d4304a0e164c98b450f5005 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,8 +87,8 @@ 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, @@ -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/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index 74423ea556c2c841c2415dd7af8776fac5e6891b..7373aa849cb8d8f47fe3cffefd5302eee28a7dfb 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"], optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-arithmetic = { path = "../arithmetic", default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 931773254365f82566b37c766046fcb2aacca653..bcd908b970508f19bd131d9eba08c18306b632c8 100644 --- a/substrate/primitives/npos-elections/fuzzer/Cargo.toml +++ b/substrate/primitives/npos-elections/fuzzer/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } sp-npos-elections = { path = ".." } diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index 735f8ed32da1ffa77a4a2ba693e1c20209478a76..dce0eeee9f99bd9cd544e584e07cd3c29ca20ae1 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -17,8 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] rustc-hash = "1.1.0" -serde = { version = "1.0.195", features = ["derive"] } +serde = { features = ["derive"], workspace = true, default-features = true } sp-core = { path = "../core" } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index c453f9079bbde85176463d130bbed9e22ce736dd..7dbd810fea932fd4bf284f80c1de976be7009b6d 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -22,6 +22,6 @@ proc-macro = true Inflector = "0.11.4" proc-macro-crate = "3.0.0" proc-macro2 = "1.0.56" -quote = "1.0.28" +quote = { workspace = true } expander = "2.0.0" -syn = { version = "2.0.48", features = ["extra-traits", "fold", "full", "visit"] } +syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index f4b1158242941286e539c9a87bbc16d57ab1b3af..758cd8944fdc1603f569e966f0dea2347c830635 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -17,15 +17,16 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +tuplex = { version = "0.1.2", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } either = { version = "1.5", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.17", default-features = false } +log = { workspace = true } paste = "1.0" rand = { version = "0.8.5", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"], optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-arithmetic = { path = "../arithmetic", default-features = false } sp-core = { path = "../core", default-features = false } @@ -34,11 +35,11 @@ sp-std = { path = "../std", default-features = false } sp-weights = { path = "../weights", default-features = false } docify = { version = "0.2.7" } -simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b", optional = true } +simple-mermaid = { version = "0.1.1", optional = true } [dev-dependencies] rand = "0.8.5" -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } zstd = { version = "0.12.4", default-features = false } sp-api = { path = "../api" } sp-state-machine = { path = "../state-machine" } @@ -67,6 +68,7 @@ std = [ "sp-std/std", "sp-tracing/std", "sp-weights/std", + "tuplex/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 44325920beee0c1026c4ec7dc68b6943652dfc92..e28c8fe424abc7a0d27d41a6751e1118f50d945d 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -18,81 +18,115 @@ //! Generic implementation of an extrinsic that has passed the verification //! stage. +use codec::Encode; + use crate::{ traits::{ - self, DispatchInfoOf, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, - SignedExtension, ValidateUnsigned, + self, transaction_extension::TransactionExtension, DispatchInfoOf, DispatchTransaction, + Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, }, transaction_validity::{TransactionSource, TransactionValidity}, }; +/// 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(Extension), +} + +// TODO: Rename ValidateUnsigned to ValidateInherent +// TODO: Consider changing ValidateInherent API to avoid need for duplicating validate +// code into pre_dispatch (rename that to `prepare`). +// TODO: New extrinsic type corresponding to `ExtrinsicFormat::General`, which is +// unsigned but includes extension data. +// TODO: Move usage of `signed` to `format`: +// - Inherent instead of None. +// - Signed(id, extension) instead of Some((id, extra)). +// - Introduce General(extension) for one without a signature. + /// 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, + Call: Member + Dispatchable + Encode, + Extension: TransactionExtension, RuntimeOrigin: From>, { 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::validate_bare_compat(&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).map(|x| x.0) + }, + ExtrinsicFormat::General(ref extension) => + extension.validate_only(None.into(), &self.function, info, len).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: Remove below once `pre_dispatch_unsigned` is removed from `LegacyExtension` + // or `LegacyExtension` is removed. + #[allow(deprecated)] + Extension::validate_bare_compat(&self.function, info, len)?; + #[allow(deprecated)] + Extension::pre_dispatch_bare_compat(&self.function, info, len)?; + let res = self.function.dispatch(None.into()); + let post_info = res.unwrap_or_else(|err| err.post_info); + let pd_res = res.map(|_| ()).map_err(|e| e.error); + // TODO: Remove below once `pre_dispatch_unsigned` is removed from `LegacyExtension` + // or `LegacyExtension` is removed. + #[allow(deprecated)] + Extension::post_dispatch_bare_compat(info, &post_info, len, &pd_res)?; + Ok(res) + }, + ExtrinsicFormat::Signed(signer, extension) => + extension.dispatch_transaction(Some(signer).into(), self.function, info, len), + ExtrinsicFormat::General(extension) => + extension.dispatch_transaction(None.into(), self.function, info, len), + } } } diff --git a/substrate/primitives/runtime/src/generic/mod.rs b/substrate/primitives/runtime/src/generic/mod.rs index 3687f7cdb3b2b24c087ac47c470b4d39721e2df5..5713c166b04c81045ccf458a538d4ca083178840 100644 --- a/substrate/primitives/runtime/src/generic/mod.rs +++ b/substrate/primitives/runtime/src/generic/mod.rs @@ -29,9 +29,9 @@ 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::{Preamble, SignedPayload, UncheckedExtrinsic}, }; diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 5b54caf597b7396dd5f32b0f695db2e011a9fca1..44dfda13d9441c2a2408628d58e57f673719ffcf 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -18,10 +18,11 @@ //! 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::TransactionExtensionBase, Checkable, Dispatchable, Extrinsic, + ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, SignaturePayload, + TransactionExtension, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -40,8 +41,60 @@ use sp_std::{fmt, prelude::*}; /// the decoding fails. const EXTRINSIC_FORMAT_VERSION: u8 = 4; -/// The `SingaturePayload` of `UncheckedExtrinsic`. -type UncheckedSignaturePayload = (Address, Signature, Extra); +/// The `SignaturePayload` of `UncheckedExtrinsic`. +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, Encode, Decode)] +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`. + #[codec(index = 0b00000100)] + Bare, + /// An old-school transaction extrinsic which includes a signature of some hard-coded crypto. + #[codec(index = 0b10000100)] + Signed(Address, Signature, Extension), + /// A new-school transaction extrinsic which does not include a signature. + #[codec(index = 0b01000100)] + General(Extension), +} + +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(tx_ext) => write!(f, "General({:?})", tx_ext), + } + } +} /// An extrinsic right from the external world. This is unchecked and so can contain a signature. /// @@ -65,41 +118,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() @@ -111,7 +151,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 @@ -121,66 +161,113 @@ 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) + } + + /// 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(..)) + } + + /// Create an `UncheckedExtrinsic` from a `Preamble` and the actual `Call`. + pub fn from_parts(function: Call, preamble: Preamble) -> Self { + Self { preamble, function } + } + + /// New instance of a bare (ne unsigned) extrinsic. + pub fn new_bare(function: Call) -> Self { + Self { preamble: Preamble::Bare, function } + } + + /// New instance of an old-school signed transaction. + 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(tx_ext), function } } } -impl - Extrinsic for UncheckedExtrinsic +// TODO: We can get rid of this trait and just use UncheckedExtrinsic directly. + +impl Extrinsic + for UncheckedExtrinsic { type Call = Call; - type SignaturePayload = UncheckedSignaturePayload; + type SignaturePayload = UncheckedSignaturePayload; + + fn is_bare(&self) -> bool { + matches!(self.preamble, Preamble::Bare) + } fn is_signed(&self) -> Option { - Some(self.signature.is_some()) + Some(matches!(self.preamble, Preamble::Signed(..))) } 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) + Self::new_bare(function) }) } + + fn new_inherent(function: Call) -> Self { + Self::new_bare(function) + } } -impl Checkable - for UncheckedExtrinsic +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)?; + // CHECK! Should this not contain implicit? + 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(tx_ext) => CheckedExtrinsic { + format: ExtrinsicFormat::General(tx_ext), + function: self.function, }, - None => CheckedExtrinsic { signed: None, function: self.function }, + Preamble::Bare => + CheckedExtrinsic { format: ExtrinsicFormat::Bare, function: self.function }, }) } @@ -189,91 +276,38 @@ where self, lookup: &Lookup, ) -> Result { - Ok(match self.signature { - Some((signed, _, extra)) => { + Ok(match self.preamble { + Preamble::Signed(signed, _, extra) => { 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, extra), + function: self.function, + } }, - None => CheckedExtrinsic { signed: None, function: self.function }, + Preamble::General(extra) => CheckedExtrinsic { + format: ExtrinsicFormat::General(extra), + 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; -} - -/// 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, -{ - /// 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 - } + type Extra = Extension; } -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) - } - }) - } -} - -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 @@ -282,15 +316,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)) = @@ -303,31 +329,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(sp_std::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); @@ -342,19 +357,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 @@ -365,45 +380,88 @@ 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: TransactionExtensionBase, { - 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`. + /// + /// 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 From> - for OpaqueExtrinsic +impl Encode for SignedPayload +where + Call: Encode + Dispatchable, + Extension: TransactionExtensionBase, +{ + /// 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) + } + }) + } +} + +impl EncodeLike for SignedPayload +where + Call: Encode + Dispatchable, + Extension: TransactionExtensionBase, +{ +} + +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", @@ -411,60 +469,198 @@ 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 OldUncheckedSignaturePayload = (Address, Signature, Extra); + + #[derive(PartialEq, Eq, Clone, Debug)] + pub struct OldUncheckedExtrinsic { + pub signature: Option>, + pub function: Call, + } + + impl TypeInfo + for OldUncheckedExtrinsic + where + Address: StaticTypeInfo, + Call: StaticTypeInfo, + Signature: StaticTypeInfo, + Extra: StaticTypeInfo, + { + type Identity = OldUncheckedExtrinsic; + + 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 OldUncheckedExtrinsic { + 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 OldUncheckedExtrinsic + 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 OldUncheckedExtrinsic + 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 OldUncheckedExtrinsic + where + Address: Encode, + Signature: Encode, + Call: Encode, + Extra: Encode, + { + } +} + #[cfg(test)] mod tests { - use super::*; + use super::{legacy::OldUncheckedExtrinsic, *}; 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 TransactionExtensionBase for DummyExtension { + const IDENTIFIER: &'static str = "DummyExtension"; + type Implicit = (); + } + impl TransactionExtension for DummyExtension { + type Val = (); type Pre = (); - - fn additional_signed(&self) -> sp_std::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; Context; 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_inherent(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_inherent(vec![0u8; 0].into()); let mut encoded = ux.encode(); let length = Compact::::decode(&mut &encoded[..]).unwrap(); @@ -473,13 +669,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)); @@ -488,13 +691,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)); @@ -502,44 +705,63 @@ 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_inherent(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(DummyExtension), + function: vec![0u8; 0].into() + }), + ); + } + #[test] fn signed_check_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, ); - 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_inherent(vec![0u8; 0].into()); let encoded = ex.encode(); let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); assert_eq!(decoded, ex); @@ -549,7 +771,7 @@ mod tests { #[test] fn conversion_to_opaque() { - let ux = Ex::new_unsigned(vec![0u8; 0]); + let ux = Ex::new_inherent(vec![0u8; 0].into()); let encoded = ux.encode(); let opaque: OpaqueExtrinsic = ux.into(); let opaque_encoded = opaque.encode(); @@ -558,10 +780,62 @@ mod tests { #[test] fn large_bad_prefix_should_work() { - let encoded = Compact::::from(u32::MAX).encode(); - assert_eq!( - Ex::decode(&mut &encoded[..]), - Err(Error::from("Not enough data to fill buffer")) - ); + let encoded = (Compact::::from(u32::MAX), Preamble::<(), (), ()>::Bare).encode(); + assert!(Ex::decode(&mut &encoded[..]).is_err()); + } + + #[test] + fn legacy_signed_encode_decode() { + let call: TestCall = vec![0u8; 0].into(); + let signed = TEST_ACCOUNT; + let signature = TestSig(TEST_ACCOUNT, (vec![0u8; 0], DummyExtension).encode()); + let extension = DummyExtension; + + let new_ux = Ex::new_signed(call.clone(), signed, signature.clone(), extension.clone()); + let old_ux = + OldUncheckedExtrinsic::::new_signed( + call, signed, signature, extension, + ); + + let encoded_new_ux = new_ux.encode(); + let encoded_old_ux = old_ux.encode(); + + assert_eq!(encoded_new_ux, encoded_old_ux); + + let decoded_new_ux = Ex::decode(&mut &encoded_new_ux[..]).unwrap(); + let decoded_old_ux = + OldUncheckedExtrinsic::::decode( + &mut &encoded_old_ux[..], + ) + .unwrap(); + + assert_eq!(new_ux, decoded_new_ux); + assert_eq!(old_ux, decoded_old_ux); + } + + #[test] + fn legacy_unsigned_encode_decode() { + let call: TestCall = vec![0u8; 0].into(); + + let new_ux = Ex::new_bare(call.clone()); + let old_ux = + OldUncheckedExtrinsic::::new_unsigned( + call, + ); + + let encoded_new_ux = new_ux.encode(); + let encoded_old_ux = old_ux.encode(); + + assert_eq!(encoded_new_ux, encoded_old_ux); + + let decoded_new_ux = Ex::decode(&mut &encoded_new_ux[..]).unwrap(); + let decoded_old_ux = + OldUncheckedExtrinsic::::decode( + &mut &encoded_old_ux[..], + ) + .unwrap(); + + assert_eq!(new_ux, decoded_new_ux); + assert_eq!(old_ux, decoded_old_ux); } } diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs index ddf92554c83056f192015a26285408b7fdf33695..70605970b4efa683deaef19fed7c2cfa920d3e51 100644 --- a/substrate/primitives/runtime/src/lib.rs +++ b/substrate/primitives/runtime/src/lib.rs @@ -125,6 +125,11 @@ pub use sp_arithmetic::{ Perquintill, Rational128, Rounding, UpperOf, }; +pub use transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidityError, UnknownTransaction, + ValidTransaction, +}; + pub use either::Either; /// The number of bytes of the module-specific `error` field defined in [`ModuleError`]. @@ -443,21 +448,21 @@ impl std::fmt::Display for MultiSigner { impl Verify for MultiSignature { type Signer = MultiSigner; fn verify>(&self, mut msg: L, signer: &AccountId32) -> bool { - match (self, signer) { - (Self::Ed25519(ref sig), who) => match ed25519::Public::from_slice(who.as_ref()) { + match self { + Self::Ed25519(ref sig) => match ed25519::Public::from_slice(signer.as_ref()) { Ok(signer) => sig.verify(msg, &signer), Err(()) => false, }, - (Self::Sr25519(ref sig), who) => match sr25519::Public::from_slice(who.as_ref()) { + Self::Sr25519(ref sig) => match sr25519::Public::from_slice(signer.as_ref()) { Ok(signer) => sig.verify(msg, &signer), Err(()) => false, }, - (Self::Ecdsa(ref sig), who) => { + Self::Ecdsa(ref sig) => { let m = sp_io::hashing::blake2_256(msg.get()); match sp_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) { Ok(pubkey) => &sp_io::hashing::blake2_256(pubkey.as_ref()) == - >::as_ref(who), + >::as_ref(signer), _ => false, } }, @@ -944,9 +949,13 @@ impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic { } } +// TODO: OpaqueExtrinsics cannot act like regular extrinsics, right?! impl traits::Extrinsic for OpaqueExtrinsic { type Call = (); type SignaturePayload = (); + fn is_bare(&self) -> bool { + false + } } /// Print something that implements `Printable` from the runtime. @@ -998,6 +1007,16 @@ impl TransactionOutcome { } } +/// Confines the kind of extrinsics that can be included in a block. +#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Encode, Decode, TypeInfo)] +pub enum ExtrinsicInclusionMode { + /// All extrinsics are allowed to be included in this block. + #[default] + AllExtrinsics, + /// Inherents are allowed to be included. + OnlyInherents, +} + #[cfg(test)] mod tests { use crate::traits::BlakeTwo256; diff --git a/substrate/primitives/runtime/src/testing.rs b/substrate/primitives/runtime/src/testing.rs index 5f94c834a8f295bee945e9d772019e12ed37c828..3d6e0b5ab8bc1c2836755f8622b1f0b7adb8d847 100644 --- a/substrate/primitives/runtime/src/testing.rs +++ b/substrate/primitives/runtime/src/testing.rs @@ -21,24 +21,16 @@ use crate::{ codec::{Codec, Decode, Encode, MaxEncodedLen}, generic, scale_info::TypeInfo, - traits::{ - self, Applyable, BlakeTwo256, Checkable, DispatchInfoOf, Dispatchable, OpaqueKeys, - PostDispatchInfoOf, SignaturePayload, SignedExtension, ValidateUnsigned, - }, - transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, - ApplyExtrinsicResultWithInfo, KeyTypeId, + traits::{self, BlakeTwo256, Dispatchable, OpaqueKeys}, + DispatchResultWithInfo, KeyTypeId, }; -use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize}; use sp_core::{ crypto::{key_types, ByteArray, CryptoType, Dummy}, U256, }; 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. /// @@ -198,42 +190,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 { @@ -283,139 +239,22 @@ where } } -/// The signature payload of a `TestXt`. -type TxSingaturePayload = (u64, Extra); - -impl SignaturePayload for TxSingaturePayload { - type SignatureAddress = u64; - type Signature = (); - type SignatureExtra = Extra; -} - -/// 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)) - } -} +/// Wrapper over a `u64` that can be used as a `RuntimeCall`. +#[derive(PartialEq, Eq, Debug, Clone, Encode, Decode, TypeInfo)] +pub struct MockCallU64(pub u64); -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 Dispatchable for MockCallU64 { + type RuntimeOrigin = u64; + type Config = (); + type Info = (); + type PostInfo = (); + fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithInfo { + Ok(()) } } -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 = TxSingaturePayload; - - fn is_signed(&self) -> Option { - Some(self.signature.is_some()) - } - - fn new(c: Call, sig: Option) -> Option { - Some(TestXt { signature: sig, call: c }) - } -} - -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 94% rename from substrate/primitives/runtime/src/traits.rs rename to substrate/primitives/runtime/src/traits/mod.rs index caede5e2b59a7e3843c1ec966a02f2bbd86f2a84..b217166d8de34e35b102aefd786e8e25e91b1bb8 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, @@ -52,6 +52,12 @@ use std::fmt::Display; #[cfg(feature = "std")] use std::str::FromStr; +pub mod transaction_extension; +pub use transaction_extension::{ + DispatchTransaction, TransactionExtension, TransactionExtensionBase, + TransactionExtensionInterior, TransactionExtensionMetadata, ValidateResult, +}; + /// A lazy value. pub trait Lazy { /// Get a reference to the underlying value. @@ -1253,7 +1259,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 @@ -1323,19 +1329,31 @@ pub trait Extrinsic: 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 } - /// 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 { + #[allow(deprecated)] + !self + .is_signed() + .expect("`is_signed` must return `Some` on production extrinsics; qed") + } + + /// Create a new old-school extrinsic, either a bare extrinsic if `_signed_data` is `None` or + /// a signed transaction is it is `Some`. + #[deprecated = "Use `new_inherent` or the `CreateTransaction` trait instead"] fn new(_call: Self::Call, _signed_data: Option) -> Option { None } + + /// Create a new inherent extrinsic. + fn new_inherent(function: Self::Call) -> Self { + #[allow(deprecated)] + Self::new(function, None).expect("Extrinsic must provide inherents; qed") + } } /// Something that acts like a [`SignaturePayload`](Extrinsic::SignaturePayload) of an @@ -1371,7 +1389,8 @@ pub trait ExtrinsicMetadata { const VERSION: u8; /// Signed extensions attached to this `Extrinsic`. - type SignedExtensions: SignedExtension; + // TODO: metadata-v16: rename to `Extension`. + type Extra; } /// Extract the hashing type for a block. @@ -1456,6 +1475,8 @@ pub trait Dispatchable { -> crate::DispatchResultWithInfo; } +/// Shortcut to reference the `Origin` type of a `Dispatchable`. +pub type OriginOf = ::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 +1495,49 @@ 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>; +} + /// 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 +1555,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 +1594,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,126 +1624,47 @@ 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 { - sp_std::vec![SignedExtensionMetadata { + /// [`TransactionExtensionMetadata`]. + fn metadata() -> Vec { + sp_std::vec![TransactionExtensionMetadata { identifier: Self::IDENTIFIER, ty: scale_info::meta_type::(), additional_signed: 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, + _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) -> sp_std::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(|_| ()) - } } /// An "executable" piece of information, used by the standard Substrate Executive in order to @@ -1762,6 +1713,7 @@ pub trait GetNodeBlockType { /// function is called right before dispatching the call wrapped by an unsigned extrinsic. The /// [`validate_unsigned`](Self::validate_unsigned) function is mainly being used in the context of /// the transaction pool to check the validity of the call wrapped by an unsigned extrinsic. +// TODO: Rename to ValidateBareTransaction (or just remove). pub trait ValidateUnsigned { /// The call to validate type Call; 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 0000000000000000000000000000000000000000..a834e88c0b4e6dae831b5eec3f138f9aae3764a8 --- /dev/null +++ b/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.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. + +//! 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}, + InvalidTransaction, +}; + +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 TransactionExtensionBase for AsTransactionExtension { + const IDENTIFIER: &'static str = SE::IDENTIFIER; + type Implicit = SE::AdditionalSigned; + + fn implicit(&self) -> Result { + self.0.additional_signed() + } + fn metadata() -> Vec { + SE::metadata() + } +} + +impl TransactionExtension + for AsTransactionExtension +where + ::RuntimeOrigin: AsSystemOriginSigner + Clone, +{ + type Val = (); + type Pre = SE::Pre; + + fn validate( + &self, + origin: ::RuntimeOrigin, + call: &SE::Call, + info: &DispatchInfoOf, + len: usize, + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> 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, + _context: &Context, + ) -> Result { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + self.0.pre_dispatch(who, call, info, len) + } + + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + _context: &Context, + ) -> Result<(), TransactionValidityError> { + SE::post_dispatch(Some(pre), info, post_info, len, result) + } + + fn validate_bare_compat( + call: &SE::Call, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + SE::validate_unsigned(call, info, len) + } + + fn pre_dispatch_bare_compat( + call: &SE::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + SE::pre_dispatch_unsigned(call, info, len) + } + + fn post_dispatch_bare_compat( + info: &DispatchInfoOf, + post_info: &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 0000000000000000000000000000000000000000..8efa586aa0e77f60b5671bb868438d7aa7bdaf3d --- /dev/null +++ b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.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. + +//! The [DispatchTransaction] trait. + +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, + ) -> Result<(ValidTransaction, Self::Val, Self::Origin), TransactionValidityError>; + /// Prepare and validate a transaction, ready for dispatch. + fn validate_and_prepare( + self, + origin: Self::Origin, + call: &Call, + info: &Self::Info, + len: usize, + ) -> 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, + ) -> 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, + substitute: impl FnOnce( + Self::Origin, + ) -> crate::DispatchResultWithInfo<::PostInfo>, + ) -> Self::Result; +} + +impl, Call: Dispatchable + Encode> DispatchTransaction + for T +{ + 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, + ) -> Result<(ValidTransaction, T::Val, Self::Origin), TransactionValidityError> { + self.validate(origin, call, info, len, &mut (), self.implicit()?, call) + } + fn validate_and_prepare( + self, + origin: Self::Origin, + call: &Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(T::Pre, Self::Origin), TransactionValidityError> { + let (_, val, origin) = self.validate_only(origin, call, info, len)?; + let pre = self.prepare(val, &origin, &call, info, len, &())?; + Ok((pre, origin)) + } + fn dispatch_transaction( + self, + origin: ::RuntimeOrigin, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> Self::Result { + let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?; + let res = call.dispatch(origin); + let post_info = res.unwrap_or_else(|err| err.post_info); + let pd_res = res.map(|_| ()).map_err(|e| e.error); + 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, + substitute: impl FnOnce( + Self::Origin, + ) -> crate::DispatchResultWithInfo<::PostInfo>, + ) -> Self::Result { + let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?; + let res = substitute(origin); + let post_info = match res { + Ok(info) => info, + Err(err) => err.post_info, + }; + let pd_res = res.map(|_| ()).map_err(|e| e.error); + 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 0000000000000000000000000000000000000000..69a0ba18adb72a67951d8548724182060916e0ee --- /dev/null +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -0,0 +1,526 @@ +// 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::{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, Dispatchable, OriginOf, PostDispatchInfoOf}; + +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, OriginOf), TransactionValidityError>; + +/// Simple blanket implementation trait to denote the bounds of a type which can be contained within +/// a [`TransactionExtension`]. +pub trait TransactionExtensionInterior: + Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo +{ +} +impl + TransactionExtensionInterior for T +{ +} + +/// Base for [TransactionExtension]s; this contains the associated types and does not require any +/// generic parameterization. +pub trait TransactionExtensionBase: TransactionExtensionInterior { + /// 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 transactiob validation. Also perform any + /// pre-signature-verification checks and return an error if needed. + fn implicit(&self) -> Result { + use crate::InvalidTransaction::IndeterminateImplicit; + Ok(Self::Implicit::decode(&mut &[][..]).map_err(|_| IndeterminateImplicit)?) + } + + /// The weight consumed by executing this extension instance fully during transaction dispatch. + fn weight(&self) -> Weight { + Weight::zero() + } + + /// 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::(), + // TODO: Metadata-v16: Rename to "implicit" + additional_signed: scale_info::meta_type::() + }] + } +} + +/// 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 transction 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 circumctances 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` 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 5 functions in this trait, 3 of them must return a value of an associated type on +/// success, and none of these types implement [Default] or anything like it. This means that +/// default implementations cannot be provided for these functions. However, a macro is provided +/// [impl_tx_ext_default](crate::impl_tx_ext_default) which is capable of generating default +/// implementations for each of these 3 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. +/// +/// ## 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 datatypes ([Val](TransactionExtension::Val), +/// [Pre](TransactionExtension::Pre) and [Implicit](TransactionExtensionBase::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](TransactionExtensionBase::implicit) function. This is only utilized by extensions +/// which preceed it in a pipeline or, if the transaction is an old-school signed trasnaction, 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. +pub trait TransactionExtension: TransactionExtensionBase { + /// 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; + + /// 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. + /// - `context`: Some opaque mutable context, as yet unused. + /// + /// 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: OriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + context: &mut Context, + self_implicit: Self::Implicit, + inherited_implication: &impl Encode, + ) -> 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. + /// - `context`: Some opaque mutable context, as yet unused. + /// + /// 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: &OriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + context: &Context, + ) -> 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. + /// + /// 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. + /// - `context`: Some opaque mutable context, as yet unused. + /// + /// 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( + _pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + _context: &Context, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + + /// Compatibility function for supporting the `SignedExtension::validate_unsigned` function. + /// + /// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME! + #[deprecated = "Only for compatibility. DO NOT USE."] + fn validate_bare_compat( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + Ok(ValidTransaction::default()) + } + + /// Compatibility function for supporting the `SignedExtension::pre_dispatch_unsigned` function. + /// + /// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME! + #[deprecated = "Only for compatibility. DO NOT USE."] + fn pre_dispatch_bare_compat( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + + /// Compatibility function for supporting the `SignedExtension::post_dispatch` function where + /// `pre` is `None`. + /// + /// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME! + #[deprecated = "Only for compatibility. DO NOT USE."] + fn post_dispatch_bare_compat( + _info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } +} + +/// Implict +#[macro_export] +macro_rules! impl_tx_ext_default { + ($call:ty ; $context:ty ; , $( $rest:tt )*) => { + impl_tx_ext_default!{$call ; $context ; $( $rest )*} + }; + ($call:ty ; $context:ty ; validate $( $rest:tt )*) => { + fn validate( + &self, + origin: $crate::traits::OriginOf<$call>, + _call: &$call, + _info: &$crate::traits::DispatchInfoOf<$call>, + _len: usize, + _context: &mut $context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl $crate::codec::Encode, + ) -> $crate::traits::ValidateResult { + Ok((Default::default(), Default::default(), origin)) + } + impl_tx_ext_default!{$call ; $context ; $( $rest )*} + }; + ($call:ty ; $context:ty ; prepare $( $rest:tt )*) => { + fn prepare( + self, + _val: Self::Val, + _origin: &$crate::traits::OriginOf<$call>, + _call: &$call, + _info: &$crate::traits::DispatchInfoOf<$call>, + _len: usize, + _context: & $context, + ) -> Result { + Ok(Default::default()) + } + impl_tx_ext_default!{$call ; $context ; $( $rest )*} + }; + ($call:ty ; $context: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. + // TODO: Rename "implicit" + pub additional_signed: MetaType, +} + +#[impl_for_tuples(1, 12)] +impl TransactionExtensionBase for Tuple { + for_tuples!( where #( Tuple: TransactionExtensionBase )* ); + const IDENTIFIER: &'static str = "Use `metadata()`!"; + for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); ); + fn implicit(&self) -> Result { + Ok(for_tuples!( ( #( Tuple.implicit()? ),* ) )) + } + fn weight(&self) -> Weight { + let mut weight = Weight::zero(); + for_tuples!( #( weight += Tuple.weight(); )* ); + weight + } + fn metadata() -> Vec { + let mut ids = Vec::new(); + for_tuples!( #( ids.extend(Tuple::metadata()); )* ); + ids + } +} + +#[impl_for_tuples(1, 12)] +impl TransactionExtension for Tuple { + for_tuples!( where #( Tuple: TransactionExtension )* ); + for_tuples!( type Val = ( #( Tuple::Val ),* ); ); + for_tuples!( type Pre = ( #( Tuple::Pre ),* ); ); + + fn validate( + &self, + origin: ::RuntimeOrigin, + call: &Call, + info: &DispatchInfoOf, + len: usize, + context: &mut Context, + self_implicit: Self::Implicit, + inherited_implication: &impl Encode, + ) -> 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, context, item_implicit, &implications)? + }; + 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, + context: &Context, + ) -> Result { + Ok(for_tuples!( ( #( + Tuple::prepare(self.Tuple, val.Tuple, origin, call, info, len, context)? + ),* ) )) + } + + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + context: &Context, + ) -> Result<(), TransactionValidityError> { + for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info, post_info, len, result, context)?; )* ); + Ok(()) + } +} + +impl TransactionExtensionBase for () { + const IDENTIFIER: &'static str = "UnitTransactionExtension"; + type Implicit = (); + fn implicit(&self) -> sp_std::result::Result { + Ok(()) + } + fn weight(&self) -> Weight { + Weight::zero() + } +} + +impl TransactionExtension for () { + type Val = (); + type Pre = (); + fn validate( + &self, + origin: ::RuntimeOrigin, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> Result< + (ValidTransaction, (), ::RuntimeOrigin), + TransactionValidityError, + > { + Ok((ValidTransaction::default(), (), origin)) + } + fn prepare( + self, + _val: (), + _origin: &::RuntimeOrigin, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + _context: &Context, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } +} diff --git a/substrate/primitives/runtime/src/transaction_validity.rs b/substrate/primitives/runtime/src/transaction_validity.rs index 836948493823cb4d137ce90721788e9a78a8ac99..24124128083c0e48ef0b7cd6cf590ecf1c6bb7cb 100644 --- a/substrate/primitives/runtime/src/transaction_validity.rs +++ b/substrate/primitives/runtime/src/transaction_validity.rs @@ -82,6 +82,8 @@ pub enum InvalidTransaction { MandatoryValidation, /// The sending address is disabled or known to be invalid. BadSigner, + /// The implicit data was unable to be calculated. + IndeterminateImplicit, } impl InvalidTransaction { @@ -113,6 +115,8 @@ 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", } } } @@ -338,7 +342,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/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index e1ab87bef0999d89a6b496f8acef640e15de36f1..21346fbaca5383554d1285ceeaba43815b81857a 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"], optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index c2ac5ae004b1b7621341020e614a9c769e27d2dd..f5b4a1ed63fb3da2e9d69f51f8bc10355dbd0730 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -150,6 +150,9 @@ pub trait OnStakingUpdate { _slashed_total: Balance, ) { } + + /// Fired when a portion of a staker's balance has been withdrawn. + fn on_withdraw(_stash: &AccountId, _amount: Balance) {} } /// A generic representation of a staking implementation. diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index b63d5685a331a88d659e13ea9d15b9f17becc402..09994f1ae91e1c9a7dba2faf169870f08a640b22 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -19,11 +19,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } hash-db = { version = "0.16.0", default-features = false } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8.5", optional = true } smallvec = "1.11.0" -thiserror = { version = "1.0.48", optional = true } +thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } sp-core = { path = "../core", default-features = false } sp-externalities = { path = "../externalities", default-features = false } diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 14af57a7b419b5a5db29065106a8853a6a9bf493..652ab3ef13aa695f13c9b9c0a525b3f90dff8f0c 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -26,7 +26,7 @@ sp-api = { path = "../api", default-features = false } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-runtime-interface = { path = "../runtime-interface", default-features = false } sp-externalities = { path = "../externalities", default-features = false } -thiserror = { version = "1.0", optional = true } +thiserror = { optional = true, workspace = true } # ECIES dependencies ed25519-dalek = { version = "2.1", optional = true } diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index 4c2f7cadefeb5a4100006f73fa595854fffa539e..d3ade87ea47f848e8036ce0a4d374fa4d77184b2 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", optional = true, default-features = false } ref-cast = "1.0.0" -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"], optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index 3649217cf74e136f88860d0c69466d3de9ef5a06..f310216dd58d737be7cde512d3fbdf27f4fbda25 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["derive"], optional = true } +serde = { features = ["derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 914c1e7865e972eb5f8acdba7d4cc9103ceb18f6..9e2b802bfb15e2e89169923d2e6f4274d2cdf1f2 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.74", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.48", optional = true } +thiserror = { optional = true, workspace = true } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index f871f462d363375ac85cbceb2c1687b0a5daacc6..16d3ca19a179ce97bbc2c5c42023ceb54bf8b32b 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -30,7 +30,7 @@ nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.48", optional = true } +thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.28.0", default-features = false } trie-root = { version = "0.18.0", default-features = false } diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 7de762d71e9948d8a36b93a21ef2acf7c3b459f8..a94e2322430b421d24b438b2899b67feec9dd059 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -21,8 +21,8 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, features = ["alloc", "derive"], optional = true } -thiserror = { version = "1.0.48", optional = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } +thiserror = { optional = true, workspace = true } sp-crypto-hashing-proc-macro = { path = "../crypto/hashing/proc-macro" } sp-runtime = { path = "../runtime", default-features = false } sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 9e90940825d5f12b76ca2e46e0593da65f6d1036..f7abf88c9a67b7e3102d44254b520a9bbeb7a8a8 100644 --- a/substrate/primitives/version/proc-macro/Cargo.toml +++ b/substrate/primitives/version/proc-macro/Cargo.toml @@ -21,8 +21,8 @@ proc-macro = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } proc-macro2 = "1.0.56" -quote = "1.0.28" -syn = { version = "2.0.48", features = ["extra-traits", "fold", "full", "visit"] } +quote = { workspace = true } +syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } [dev-dependencies] sp-version = { path = ".." } diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index ccd2a3043c5c9f319681ae9306c82ad0336f9a2b..f7d1038903eab6954374e6dac141b74683315a25 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" -log = { version = "0.4.17", optional = true } +log = { optional = true, workspace = true, default-features = true } wasmtime = { version = "8.0.1", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index 3a57720b964e4bffd9929547d3f519453ea0b8b7..a7d61de001b5525af1a43148a6c7f6f284c4e51f 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] bounded-collections = { version = "0.2.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.195", default-features = false, optional = true, features = ["alloc", "derive"] } +serde = { optional = true, features = ["alloc", "derive"], workspace = true } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } diff --git a/substrate/primitives/weights/src/lib.rs b/substrate/primitives/weights/src/lib.rs index aede9473535a361325f64c177dd9f1861664ca40..b2c956266e2c3a346ca32c7b74ceb7f4c5cc2c0c 100644 --- a/substrate/primitives/weights/src/lib.rs +++ b/substrate/primitives/weights/src/lib.rs @@ -18,9 +18,6 @@ //! # Primitives for transaction weighting. #![cfg_attr(not(feature = "std"), no_std)] -// TODO remove once `OldWeight` is gone. I dont know why this is needed, maybe by one of the macros -// of `OldWeight`. -#![allow(deprecated)] extern crate self as sp_weights; @@ -28,7 +25,7 @@ mod weight_meter; mod weight_v2; use bounded_collections::Get; -use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -52,28 +49,6 @@ pub mod constants { pub const WEIGHT_PROOF_SIZE_PER_KB: u64 = 1024; } -/// The old weight type. -/// -/// NOTE: This type exists purely for compatibility purposes! Use [`weight_v2::Weight`] in all other -/// cases. -#[derive( - Decode, - Encode, - CompactAs, - PartialEq, - Eq, - Clone, - Copy, - RuntimeDebug, - Default, - MaxEncodedLen, - TypeInfo, -)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(transparent))] -#[deprecated(note = "Will be removed soon; use `Weight` instead.")] -pub struct OldWeight(pub u64); - /// The weight of database operations that the runtime can invoke. /// /// NOTE: This is currently only measured in computational time, and will probably diff --git a/substrate/primitives/weights/src/weight_meter.rs b/substrate/primitives/weights/src/weight_meter.rs index 584d22304c3ae33ece669bc69927a2568fb9b288..cfe8396ae6d67ed36d038f6afc2a7700c56b815a 100644 --- a/substrate/primitives/weights/src/weight_meter.rs +++ b/substrate/primitives/weights/src/weight_meter.rs @@ -118,13 +118,6 @@ impl WeightMeter { debug_assert!(self.consumed.all_lte(self.limit), "Weight counter overflow"); } - /// Consume the given weight after checking that it can be consumed and return `true`. Otherwise - /// do nothing and return `false`. - #[deprecated(note = "Use `try_consume` instead. Will be removed after December 2023.")] - pub fn check_accrue(&mut self, w: Weight) -> bool { - self.try_consume(w).is_ok() - } - /// Consume the given weight after checking that it can be consumed. /// /// Returns `Ok` if the weight can be consumed or otherwise an `Err`. @@ -139,16 +132,15 @@ impl WeightMeter { }) } - /// Check if the given weight can be consumed. - #[deprecated(note = "Use `can_consume` instead. Will be removed after December 2023.")] - pub fn can_accrue(&self, w: Weight) -> bool { - self.can_consume(w) - } - /// Check if the given weight can be consumed. pub fn can_consume(&self, w: Weight) -> bool { self.consumed.checked_add(&w).map_or(false, |t| t.all_lte(self.limit)) } + + /// Reclaim the given weight. + pub fn reclaim_proof_size(&mut self, s: u64) { + self.consumed.saturating_reduce(Weight::from_parts(0, s)); + } } #[cfg(test)] @@ -160,80 +152,80 @@ mod tests { fn weight_meter_remaining_works() { let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 20)); - assert!(meter.check_accrue(Weight::from_parts(5, 0))); + assert_eq!(meter.try_consume(Weight::from_parts(5, 0)), Ok(())); assert_eq!(meter.consumed, Weight::from_parts(5, 0)); assert_eq!(meter.remaining(), Weight::from_parts(5, 20)); - assert!(meter.check_accrue(Weight::from_parts(2, 10))); + assert_eq!(meter.try_consume(Weight::from_parts(2, 10)), Ok(())); assert_eq!(meter.consumed, Weight::from_parts(7, 10)); assert_eq!(meter.remaining(), Weight::from_parts(3, 10)); - assert!(meter.check_accrue(Weight::from_parts(3, 10))); + assert_eq!(meter.try_consume(Weight::from_parts(3, 10)), Ok(())); assert_eq!(meter.consumed, Weight::from_parts(10, 20)); assert_eq!(meter.remaining(), Weight::from_parts(0, 0)); } #[test] - fn weight_meter_can_accrue_works() { + fn weight_meter_can_consume_works() { let meter = WeightMeter::with_limit(Weight::from_parts(1, 1)); - assert!(meter.can_accrue(Weight::from_parts(0, 0))); - assert!(meter.can_accrue(Weight::from_parts(1, 1))); - assert!(!meter.can_accrue(Weight::from_parts(0, 2))); - assert!(!meter.can_accrue(Weight::from_parts(2, 0))); - assert!(!meter.can_accrue(Weight::from_parts(2, 2))); + assert!(meter.can_consume(Weight::from_parts(0, 0))); + assert!(meter.can_consume(Weight::from_parts(1, 1))); + assert!(!meter.can_consume(Weight::from_parts(0, 2))); + assert!(!meter.can_consume(Weight::from_parts(2, 0))); + assert!(!meter.can_consume(Weight::from_parts(2, 2))); } #[test] - fn weight_meter_check_accrue_works() { + fn weight_meter_try_consume_works() { let mut meter = WeightMeter::with_limit(Weight::from_parts(2, 2)); - assert!(meter.check_accrue(Weight::from_parts(0, 0))); - assert!(meter.check_accrue(Weight::from_parts(1, 1))); - assert!(!meter.check_accrue(Weight::from_parts(0, 2))); - assert!(!meter.check_accrue(Weight::from_parts(2, 0))); - assert!(!meter.check_accrue(Weight::from_parts(2, 2))); - assert!(meter.check_accrue(Weight::from_parts(0, 1))); - assert!(meter.check_accrue(Weight::from_parts(1, 0))); + assert_eq!(meter.try_consume(Weight::from_parts(0, 0)), Ok(())); + assert_eq!(meter.try_consume(Weight::from_parts(1, 1)), Ok(())); + assert_eq!(meter.try_consume(Weight::from_parts(0, 2)), Err(())); + assert_eq!(meter.try_consume(Weight::from_parts(2, 0)), Err(())); + assert_eq!(meter.try_consume(Weight::from_parts(2, 2)), Err(())); + assert_eq!(meter.try_consume(Weight::from_parts(0, 1)), Ok(())); + assert_eq!(meter.try_consume(Weight::from_parts(1, 0)), Ok(())); } #[test] - fn weight_meter_check_and_can_accrue_works() { + fn weight_meter_check_and_can_consume_works() { let mut meter = WeightMeter::new(); - assert!(meter.can_accrue(Weight::from_parts(u64::MAX, 0))); - assert!(meter.check_accrue(Weight::from_parts(u64::MAX, 0))); + assert!(meter.can_consume(Weight::from_parts(u64::MAX, 0))); + assert_eq!(meter.try_consume(Weight::from_parts(u64::MAX, 0)), Ok(())); - assert!(meter.can_accrue(Weight::from_parts(0, u64::MAX))); - assert!(meter.check_accrue(Weight::from_parts(0, u64::MAX))); + assert!(meter.can_consume(Weight::from_parts(0, u64::MAX))); + assert_eq!(meter.try_consume(Weight::from_parts(0, u64::MAX)), Ok(())); - assert!(!meter.can_accrue(Weight::from_parts(0, 1))); - assert!(!meter.check_accrue(Weight::from_parts(0, 1))); + assert!(!meter.can_consume(Weight::from_parts(0, 1))); + assert_eq!(meter.try_consume(Weight::from_parts(0, 1)), Err(())); - assert!(!meter.can_accrue(Weight::from_parts(1, 0))); - assert!(!meter.check_accrue(Weight::from_parts(1, 0))); + assert!(!meter.can_consume(Weight::from_parts(1, 0))); + assert_eq!(meter.try_consume(Weight::from_parts(1, 0)), Err(())); - assert!(meter.can_accrue(Weight::zero())); - assert!(meter.check_accrue(Weight::zero())); + assert!(meter.can_consume(Weight::zero())); + assert_eq!(meter.try_consume(Weight::zero()), Ok(())); } #[test] fn consumed_ratio_works() { let mut meter = WeightMeter::with_limit(Weight::from_parts(10, 20)); - assert!(meter.check_accrue(Weight::from_parts(5, 0))); + assert_eq!(meter.try_consume(Weight::from_parts(5, 0)), Ok(())); assert_eq!(meter.consumed_ratio(), Perbill::from_percent(50)); - assert!(meter.check_accrue(Weight::from_parts(0, 12))); + assert_eq!(meter.try_consume(Weight::from_parts(0, 12)), Ok(())); assert_eq!(meter.consumed_ratio(), Perbill::from_percent(60)); - assert!(meter.check_accrue(Weight::from_parts(2, 0))); + assert_eq!(meter.try_consume(Weight::from_parts(2, 0)), Ok(())); assert_eq!(meter.consumed_ratio(), Perbill::from_percent(70)); - assert!(meter.check_accrue(Weight::from_parts(0, 4))); + assert_eq!(meter.try_consume(Weight::from_parts(0, 4)), Ok(())); assert_eq!(meter.consumed_ratio(), Perbill::from_percent(80)); - assert!(meter.check_accrue(Weight::from_parts(3, 0))); + assert_eq!(meter.try_consume(Weight::from_parts(3, 0)), Ok(())); assert_eq!(meter.consumed_ratio(), Perbill::from_percent(100)); - assert!(meter.check_accrue(Weight::from_parts(0, 4))); + assert_eq!(meter.try_consume(Weight::from_parts(0, 4)), Ok(())); assert_eq!(meter.consumed_ratio(), Perbill::from_percent(100)); } @@ -277,6 +269,21 @@ mod tests { assert_eq!(meter.consumed(), Weight::from_parts(5, 10)); } + #[test] + #[cfg(debug_assertions)] + fn reclaim_works() { + let mut meter = WeightMeter::with_limit(Weight::from_parts(5, 10)); + + meter.consume(Weight::from_parts(5, 10)); + assert_eq!(meter.consumed(), Weight::from_parts(5, 10)); + + meter.reclaim_proof_size(3); + assert_eq!(meter.consumed(), Weight::from_parts(5, 7)); + + meter.reclaim_proof_size(10); + assert_eq!(meter.consumed(), Weight::from_parts(5, 0)); + } + #[test] #[cfg(debug_assertions)] #[should_panic(expected = "Weight counter overflow")] diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index a0b93184546288b1c326e1f2584545dc12a0c7d6..cc60d0a4510132c543162c3bcf9964e35644b24e 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -14,7 +14,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/scripts/ci/node-template-release/src/main.rs b/substrate/scripts/ci/node-template-release/src/main.rs index fc8089f3051fe14a7608bcfad1418069d3bfcff9..2bcda2944fc90e62ed947af54c7be680c1038f38 100644 --- a/substrate/scripts/ci/node-template-release/src/main.rs +++ b/substrate/scripts/ci/node-template-release/src/main.rs @@ -18,6 +18,7 @@ use std::{ collections::HashMap, + ffi::OsString, fs::{self, File, OpenOptions}, path::{Path, PathBuf}, process::Command, @@ -56,9 +57,24 @@ struct Options { } /// Copy the `node-template` to the given path. -fn copy_node_template(node_template: &Path, dest_path: &Path) { +fn copy_node_template(node_template: &Path, node_template_folder: &OsString, dest_path: &Path) { let options = CopyOptions::new(); dir::copy(node_template, dest_path, &options).expect("Copies node-template to tmp dir"); + + let dest_path = dest_path.join(node_template_folder); + + dir::get_dir_content(dest_path.join("env-setup")) + .expect("`env-setup` directory should exist") + .files + .iter() + .for_each(|f| { + fs::copy( + f, + dest_path.join(PathBuf::from(f).file_name().expect("File has a file name.")), + ) + .expect("Copying from `env-setup` directory works"); + }); + dir::remove(dest_path.join("env-setup")).expect("Deleting `env-setup works`"); } /// Find all `Cargo.toml` files in the given path. @@ -195,6 +211,9 @@ fn update_root_cargo_toml( commit_id: &str, ) { let mut workspace = Table::new(); + + workspace.insert("resolver", value("2")); + workspace.insert("members", value(Array::from_iter(members.iter()))); let mut workspace_dependencies = Table::new(); deps.values() @@ -216,6 +235,8 @@ fn update_root_cargo_toml( workspace.insert("package", Item::Table(package)); workspace.insert("dependencies", Item::Table(workspace_dependencies)); + + workspace.insert("lints", Item::Table(Table::new())); cargo_toml.insert("workspace", Item::Table(workspace)); let mut panic_unwind = Table::new(); @@ -294,7 +315,7 @@ fn main() { .file_name() .expect("Node template folder is last element of path") .to_owned(); - copy_node_template(&options.node_template, build_dir.path()); + copy_node_template(&options.node_template, &node_template_folder, build_dir.path()); // The path to the node-template in the build dir. let node_template_path = build_dir.path().join(node_template_folder); @@ -429,6 +450,7 @@ frame-system = { workspace = true } ); let expected_toml = r#"[workspace] +resolver = "2" members = ["node", "pallets/template", "runtime"] [workspace.package] @@ -438,6 +460,8 @@ edition = "2021" frame-system = { version = "4.0.0-dev", default-features = true, git = "https://github.com/paritytech/polkadot-sdk.git", rev = "commit_id" } sp-io = { version = "7.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "commit_id" } +[workspace.lints] + [profile] [profile.release] diff --git a/substrate/scripts/run_all_benchmarks.sh b/substrate/scripts/run_all_benchmarks.sh index 83848100a7e5189f312411fb42eae7d4eb6a43c4..fe5f89a5b56ea109cee20274ce7c1454b72b7009 100755 --- a/substrate/scripts/run_all_benchmarks.sh +++ b/substrate/scripts/run_all_benchmarks.sh @@ -59,11 +59,12 @@ done if [ "$skip_build" != true ] then echo "[+] Compiling Substrate benchmarks..." - cargo build --profile=production --locked --features=runtime-benchmarks --bin substrate + cargo build --profile=production --locked --features=runtime-benchmarks --bin substrate-node fi # The executable to use. -SUBSTRATE=./target/production/substrate +# Parent directory because of the monorepo structure. +SUBSTRATE=../target/production/substrate-node # Manually exclude some pallets. EXCLUDED_PALLETS=( @@ -80,11 +81,7 @@ EXCLUDED_PALLETS=( # Load all pallet names in an array. ALL_PALLETS=($( - $SUBSTRATE benchmark pallet --list --chain=dev |\ - tail -n+2 |\ - cut -d',' -f1 |\ - sort |\ - uniq + $SUBSTRATE benchmark pallet --list=pallets --no-csv-header --chain=dev )) # Filter out the excluded pallets by concatenating the arrays and discarding duplicates. @@ -110,6 +107,19 @@ for PALLET in "${PALLETS[@]}"; do FOLDER="$(echo "${PALLET#*_}" | tr '_' '-')"; WEIGHT_FILE="./frame/${FOLDER}/src/weights.rs" + + # 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" + fi + echo "[+] Benchmarking $PALLET with weight file $WEIGHT_FILE"; OUTPUT=$( diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 14f55f6454659efb6abf4d0eabf4f37dc53212c9..349b04d32d7baff5c24323e171ebe373730f464f 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -20,8 +20,8 @@ array-bytes = "6.1" async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" -serde = "1.0.195" -serde_json = "1.0.111" +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sc-client-api = { path = "../../client/api" } sc-client-db = { path = "../../client/db", default-features = false, features = [ "test-helpers", diff --git a/substrate/test-utils/client/src/lib.rs b/substrate/test-utils/client/src/lib.rs index e3f06e27563581b100f489072d939b02d99a3247..d283b24f286aed743ba613f095f2cd319caba263 100644 --- a/substrate/test-utils/client/src/lib.rs +++ b/substrate/test-utils/client/src/lib.rs @@ -72,6 +72,7 @@ pub struct TestClientBuilder, bad_blocks: BadBlocks, enable_offchain_indexing_api: bool, + enable_import_proof_recording: bool, no_genesis: bool, } @@ -120,6 +121,7 @@ impl bad_blocks: None, enable_offchain_indexing_api: false, no_genesis: false, + enable_import_proof_recording: false, } } @@ -165,6 +167,12 @@ impl self } + /// Enable proof recording on import. + pub fn enable_import_proof_recording(mut self) -> Self { + self.enable_import_proof_recording = true; + self + } + /// Disable writing genesis. pub fn set_no_genesis(mut self) -> Self { self.no_genesis = true; @@ -202,6 +210,7 @@ impl }; let client_config = ClientConfig { + enable_import_proof_recording: self.enable_import_proof_recording, offchain_indexing_api: self.enable_offchain_indexing_api, no_genesis: self.no_genesis, ..Default::default() diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 589686c1229432acbbeac9885213a019531174a9..b6e6346e8017641dacd0f1bad4083db73be3fce8 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -24,9 +24,9 @@ sp-block-builder = { path = "../../primitives/block-builder", default-features = codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-inherents = { path = "../../primitives/inherents", default-features = false } -sp-keyring = { path = "../../primitives/keyring", optional = true } +sp-keyring = { path = "../../primitives/keyring", default-features = false } sp-offchain = { path = "../../primitives/offchain", default-features = false } -sp-core = { path = "../../primitives/core", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } sp-crypto-hashing = { path = "../../primitives/crypto/hashing", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } @@ -51,7 +51,7 @@ sp-externalities = { path = "../../primitives/externalities", default-features = # 3rd party array-bytes = { version = "6.1", optional = true } -log = { version = "0.4.17", default-features = false } +log = { workspace = true } [dev-dependencies] futures = "0.3.21" @@ -62,8 +62,8 @@ sc-executor-common = { path = "../../client/executor/common" } sp-consensus = { path = "../../primitives/consensus/common" } substrate-test-runtime-client = { path = "client" } sp-tracing = { path = "../../primitives/tracing" } -serde = { version = "1.0.195", features = ["alloc", "derive"], default-features = false } -serde_json = { version = "1.0.111", default-features = false, features = ["alloc"] } +serde = { features = ["alloc", "derive"], workspace = true } +serde_json = { features = ["alloc"], workspace = true } [build-dependencies] substrate-wasm-builder = { path = "../../utils/wasm-builder", optional = true } @@ -99,7 +99,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", - "sp-keyring", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", diff --git a/substrate/test-utils/runtime/src/extrinsic.rs b/substrate/test-utils/runtime/src/extrinsic.rs index 05ffb7db5d5b95d6d6dbadf5f48da563c04a4c59..7eb1839e97b68be8c36015bc8c7d3ef9b9620515 100644 --- a/substrate/test-utils/runtime/src/extrinsic.rs +++ b/substrate/test-utils/runtime/src/extrinsic.rs @@ -25,7 +25,7 @@ use codec::Encode; use frame_system::{CheckNonce, CheckWeight}; use sp_core::crypto::Pair as TraitPair; use sp_keyring::AccountKeyring; -use sp_runtime::{transaction_validity::TransactionPriority, Perbill}; +use sp_runtime::{generic::Preamble, transaction_validity::TransactionPriority, Perbill}; use sp_std::prelude::*; /// Transfer used in test substrate pallet. Extrinsic is created and signed using this data. @@ -66,11 +66,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(()), } @@ -190,18 +190,17 @@ 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 {}, ); let raw_payload = - SignedPayload::from_raw(self.function.clone(), extra.clone(), ((), (), ())); + SignedPayload::from_raw(self.function.clone(), tx_ext.clone(), (((), ()), ())); 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/genesismap.rs b/substrate/test-utils/runtime/src/genesismap.rs index 5ed9c8a645886f741611bc9fdc5d4eae01ae2704..9e972886b3771469284a7ee66e5f823623a75b07 100644 --- a/substrate/test-utils/runtime/src/genesismap.rs +++ b/substrate/test-utils/runtime/src/genesismap.rs @@ -124,7 +124,6 @@ impl GenesisStorageBuilder { .into_iter() .map(|x| (x.into(), 1)) .collect(), - epoch_config: Some(crate::TEST_RUNTIME_BABE_EPOCH_CONFIGURATION), ..Default::default() }, substrate_test: substrate_test_pallet::GenesisConfig { diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 8bc6f72a82ec2d0690c24565e841931bada92f05..7ec5f6722c4dde6a6aa943154ac5aa9fb9062bd1 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -58,10 +58,12 @@ use sp_api::{decl_runtime_apis, impl_runtime_apis}; pub use sp_core::hash::H256; 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}, - ApplyExtrinsicResult, Perbill, + create_runtime_str, 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))] use sp_version::NativeVersion; @@ -142,13 +144,14 @@ 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, CheckSubstrateCall); +// TODO: Remove after the Checks are migrated to TxExtension. +/// The extension to the basic transaction logic. +pub type TxExtension = ((CheckNonce, CheckWeight), CheckSubstrateCall); /// 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; @@ -243,7 +246,7 @@ impl sp_runtime::traits::Printable for CheckSubstrateCall { } impl sp_runtime::traits::Dispatchable for CheckSubstrateCall { - type RuntimeOrigin = CheckSubstrateCall; + type RuntimeOrigin = RuntimeOrigin; type Config = CheckSubstrateCall; type Info = CheckSubstrateCall; type PostInfo = CheckSubstrateCall; @@ -256,42 +259,37 @@ 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::TransactionExtensionBase for CheckSubstrateCall { const IDENTIFIER: &'static str = "CheckSubstrateCall"; - - fn additional_signed( - &self, - ) -> sp_std::result::Result { - Ok(()) - } + type Implicit = (); +} +impl sp_runtime::traits::TransactionExtension + for CheckSubstrateCall +{ + type Pre = (); + type Val = (); + impl_tx_ext_default!(RuntimeCall; Context; prepare); fn validate( &self, - _who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { + _context: &mut Context, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> 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)) } } @@ -364,6 +362,7 @@ impl frame_system::pallet::Config for Runtime { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); + type ExtensionsWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); type MaxConsumers = ConstU32<16>; @@ -480,9 +479,9 @@ impl_runtime_apis! { Executive::execute_block(block); } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> ExtrinsicInclusionMode { log::trace!(target: LOG_TARGET, "initialize_block: {header:#?}"); - Executive::initialize_block(header); + Executive::initialize_block(header) } } @@ -672,7 +671,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()) @@ -1025,7 +1024,7 @@ mod tests { use sp_core::{storage::well_known_keys::HEAP_PAGES, traits::CallContext}; use sp_keyring::AccountKeyring; use sp_runtime::{ - traits::{Hash as _, SignedExtension}, + traits::{DispatchTransaction, Hash as _}, transaction_validity::{InvalidTransaction, ValidTransaction}, }; use substrate_test_runtime_client::{ @@ -1174,31 +1173,33 @@ mod tests { fn check_substrate_check_signed_extension_works() { sp_tracing::try_init_simple(); new_test_ext().execute_with(|| { - let x = sp_keyring::AccountKeyring::Alice.into(); + let x: AccountId = sp_keyring::AccountKeyring::Alice.into(); let info = DispatchInfo::default(); 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, ) .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, ) .unwrap() + .0 .propagate, false ); @@ -1291,7 +1292,7 @@ mod tests { let r = Vec::::decode(&mut &r[..]).unwrap(); let json = String::from_utf8(r.into()).expect("returned value is json. qed."); - let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; + let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":{"c":[1,4],"allowed_slots":"PrimaryAndSecondaryVRFSlots"}},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; assert_eq!(expected.to_string(), json); } diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index b52a897438b6854a066a95e51ba49bd0eddd7f84..33e56e8e55e7a7479fb1c783af818f3120e1b7f4 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" parking_lot = "0.12.1" -thiserror = "1.0" +thiserror = { workspace = true } sc-transaction-pool = { path = "../../../client/transaction-pool" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/test-utils/runtime/transaction-pool/src/lib.rs b/substrate/test-utils/runtime/transaction-pool/src/lib.rs index 8c8345b06bd32e4efbe2f721ddebe2cc2f2f9c4e..5202e6e65154d62085a0656cc780cc39452e0ed9 100644 --- a/substrate/test-utils/runtime/transaction-pool/src/lib.rs +++ b/substrate/test-utils/runtime/transaction-pool/src/lib.rs @@ -81,6 +81,7 @@ pub struct ChainState { pub block_by_hash: HashMap, pub nonces: HashMap, pub invalid_hashes: HashSet, + pub priorities: HashMap, } /// Test Api for transaction pool. @@ -214,6 +215,22 @@ impl TestApi { self.chain.write().invalid_hashes.insert(Self::hash_and_length_inner(xts).0); } + /// Remove a transaction that was previously declared as invalid via `[Self::add_invalid]`. + /// + /// Next time transaction pool will try to validate this + /// extrinsic, api will succeed. + pub fn remove_invalid(&self, xts: &Extrinsic) { + self.chain.write().invalid_hashes.remove(&Self::hash_and_length_inner(xts).0); + } + + /// Set a transaction priority. + pub fn set_priority(&self, xts: &Extrinsic, priority: u64) { + self.chain + .write() + .priorities + .insert(Self::hash_and_length_inner(xts).0, priority); + } + /// Query validation requests received. pub fn validation_requests(&self) -> Vec { self.validation_requests.read().clone() @@ -300,8 +317,14 @@ impl ChainApi for TestApi { return ready(Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))))) } - let mut validity = - ValidTransaction { priority: 1, requires, provides, longevity: 64, propagate: true }; + let priority = self.chain.read().priorities.get(&self.hash_and_length(&uxt).0).cloned(); + let mut validity = ValidTransaction { + priority: priority.unwrap_or(1), + requires, + provides, + longevity: 64, + propagate: true, + }; (self.valid_modifier.read())(&mut validity); diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index b0b870823fbf42b1dc3790978f460c66dac1e8f5..6ba515afee175751840edadfb7e6fc2ab01c5e46 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] array-bytes = { version = "6.1", optional = true } -log = { version = "0.4", default-features = false, optional = true } +log = { optional = true, workspace = true } hash-db = { version = "0.16.0", default-features = false } [dev-dependencies] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 0314e3035c027ea34aa26a1b259ceb5ea8451d89..a25ab3a8f5b159f600cdc088365ca8f970aa6a7f 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -18,20 +18,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4" -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } comfy-table = { version = "7.1.0", default-features = false } -handlebars = "4.2.2" +handlebars = "5.1.0" Inflector = "0.11.4" itertools = "0.10.3" lazy_static = "1.4.0" linked-hash-map = "0.5.4" -log = "0.4.17" +log = { workspace = true, default-features = true } rand = { version = "0.8.5", features = ["small_rng"] } rand_pcg = "0.3.1" -serde = "1.0.195" -serde_json = "1.0.111" -thiserror = "1.0.48" +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } thousands = "0.2.0" frame-benchmarking = { path = "../../../frame/benchmarking" } frame-support = { path = "../../../frame/support" } diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 5c76ca68e85f5708cbccde38c5f35cb4046033c5..c6ba282401672335a6a72e698533a4af35670523 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::{writer, PalletCmd}; +use super::{writer, ListOutput, PalletCmd}; use codec::{Decode, Encode}; use frame_benchmarking::{ Analysis, BenchmarkBatch, BenchmarkBatchSplitResults, BenchmarkList, BenchmarkParameter, @@ -37,9 +37,15 @@ use sp_core::{ }; use sp_externalities::Extensions; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use sp_runtime::traits::Hash; use sp_state_machine::StateMachine; -use std::{collections::HashMap, fmt::Debug, fs, str::FromStr, time}; +use std::{ + collections::{BTreeMap, BTreeSet, HashMap}, + fmt::Debug, + fs, + str::FromStr, + time, +}; /// Logging target const LOG_TARGET: &'static str = "frame::benchmark::pallet"; @@ -140,11 +146,10 @@ This could mean that you either did not build the node correctly with the \ not created by a node that was compiled with the flag"; impl PalletCmd { - /// Runs the command and benchmarks the chain. - pub fn run(&self, config: Configuration) -> Result<()> + /// Runs the command and benchmarks a pallet. + pub fn run(&self, config: Configuration) -> Result<()> where - BB: BlockT + Debug, - <<::Header as HeaderT>::Number as std::str::FromStr>::Err: std::fmt::Debug, + Hasher: Hash, ExtraHostFunctions: sp_wasm_interface::HostFunctions, { let _d = self.execution.as_ref().map(|exec| { @@ -192,6 +197,7 @@ impl PalletCmd { let spec = config.chain_spec; 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(); @@ -199,7 +205,7 @@ impl PalletCmd { let genesis_storage = spec.build_storage()?; let mut changes = Default::default(); let cache_size = Some(self.database_cache_size as usize); - let state_with_tracking = BenchmarkingState::::new( + let state_with_tracking = BenchmarkingState::::new( genesis_storage.clone(), cache_size, // Record proof size @@ -207,7 +213,7 @@ impl PalletCmd { // Enable storage tracking true, )?; - let state_without_tracking = BenchmarkingState::::new( + let state_without_tracking = BenchmarkingState::::new( genesis_storage, cache_size, // Do not record proof size @@ -292,16 +298,23 @@ impl PalletCmd { // Convert `Vec` to `String` for better readability. let benchmarks_to_run: Vec<_> = benchmarks_to_run .into_iter() - .map(|b| { + .map(|(pallet, extrinsic, components, pov_modes)| { + let pallet_name = + String::from_utf8(pallet.clone()).expect("Encoded from String; qed"); + let extrinsic_name = + String::from_utf8(extrinsic.clone()).expect("Encoded from String; qed"); ( - b.0, - b.1, - b.2, - b.3.into_iter() + pallet, + extrinsic, + components, + pov_modes + .into_iter() .map(|(p, s)| { (String::from_utf8(p).unwrap(), String::from_utf8(s).unwrap()) }) .collect(), + pallet_name, + extrinsic_name, ) }) .collect(); @@ -310,9 +323,8 @@ impl PalletCmd { return Err("No benchmarks found which match your input.".into()) } - if self.list { - // List benchmarks instead of running them - list_benchmark(benchmarks_to_run); + if let Some(list_output) = self.list { + list_benchmark(benchmarks_to_run, list_output, self.no_csv_header); return Ok(()) } @@ -324,12 +336,12 @@ impl PalletCmd { let mut component_ranges = HashMap::<(Vec, Vec), Vec>::new(); let pov_modes = Self::parse_pov_modes(&benchmarks_to_run)?; - for (pallet, extrinsic, components, _) in benchmarks_to_run.clone() { + for (pallet, extrinsic, components, _, pallet_name, extrinsic_name) in + benchmarks_to_run.clone() + { log::info!( target: LOG_TARGET, - "Starting benchmark: {}::{}", - String::from_utf8(pallet.clone()).expect("Encoded from String; qed"), - String::from_utf8(extrinsic.clone()).expect("Encoded from String; qed"), + "Starting benchmark: {pallet_name}::{extrinsic_name}" ); let all_components = if components.is_empty() { vec![Default::default()] @@ -410,12 +422,7 @@ impl PalletCmd { ) .map_err(|e| format!("Failed to decode benchmark results: {:?}", e))? .map_err(|e| { - format!( - "Benchmark {}::{} failed: {}", - String::from_utf8_lossy(&pallet), - String::from_utf8_lossy(&extrinsic), - e - ) + format!("Benchmark {pallet_name}::{extrinsic_name} failed: {e}",) })?; } // Do one loop of DB tracking. @@ -489,11 +496,7 @@ impl PalletCmd { log::info!( target: LOG_TARGET, - "Running benchmark: {}.{}({} args) {}/{} {}/{}", - String::from_utf8(pallet.clone()) - .expect("Encoded from String; qed"), - String::from_utf8(extrinsic.clone()) - .expect("Encoded from String; qed"), + "Running benchmark: {pallet_name}::{extrinsic_name}({} args) {}/{} {}/{}", components.len(), s + 1, // s starts at 0. all_components.len(), @@ -702,12 +705,14 @@ impl PalletCmd { Vec, Vec<(BenchmarkParameter, u32, u32)>, Vec<(String, String)>, + String, + String, )>, ) -> Result { use std::collections::hash_map::Entry; let mut parsed = PovModesMap::new(); - for (pallet, call, _components, pov_modes) in benchmarks { + for (pallet, call, _components, pov_modes, _, _) in benchmarks { for (pallet_storage, mode) in pov_modes { let mode = PovEstimationMode::from_str(&mode)?; let splits = pallet_storage.split("::").collect::>(); @@ -756,19 +761,45 @@ impl CliConfiguration for PalletCmd { /// List the benchmarks available in the runtime, in a CSV friendly format. fn list_benchmark( - mut benchmarks_to_run: Vec<( + benchmarks_to_run: Vec<( Vec, Vec, Vec<(BenchmarkParameter, u32, u32)>, Vec<(String, String)>, + String, + String, )>, + list_output: ListOutput, + no_csv_header: bool, ) { - // Sort and de-dub by pallet and function name. - benchmarks_to_run.sort_by(|(pa, sa, _, _), (pb, sb, _, _)| (pa, sa).cmp(&(pb, sb))); - benchmarks_to_run.dedup_by(|(pa, sa, _, _), (pb, sb, _, _)| (pa, sa) == (pb, sb)); + let mut benchmarks = BTreeMap::new(); - println!("pallet, benchmark"); - for (pallet, extrinsic, _, _) in benchmarks_to_run { - println!("{}, {}", String::from_utf8_lossy(&pallet), String::from_utf8_lossy(&extrinsic)); + // Sort and de-dub by pallet and function name. + benchmarks_to_run.iter().for_each(|(_, _, _, _, pallet_name, extrinsic_name)| { + benchmarks + .entry(pallet_name) + .or_insert_with(BTreeSet::new) + .insert(extrinsic_name); + }); + + match list_output { + ListOutput::All => { + if !no_csv_header { + println!("pallet,extrinsic"); + } + for (pallet, extrinsics) in benchmarks { + for extrinsic in extrinsics { + println!("{pallet},{extrinsic}"); + } + } + }, + ListOutput::Pallets => { + if !no_csv_header { + println!("pallet"); + }; + for pallet in benchmarks.keys() { + println!("{pallet}"); + } + }, } } diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs index c69ce1765fc9dc490f1e0f40966ca07948b6b523..6dc56c0724eaffde1d70d25ef1161b29e01df0c4 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -19,6 +19,7 @@ mod command; mod writer; use crate::shared::HostInfoParams; +use clap::ValueEnum; use sc_cli::{ WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, @@ -31,17 +32,32 @@ fn parse_pallet_name(pallet: &str) -> std::result::Result { Ok(pallet.replace("-", "_")) } +/// List options for available benchmarks. +#[derive(Debug, Clone, Copy, ValueEnum)] +pub enum ListOutput { + /// List all available pallets and extrinsics. + All, + /// List all available pallets only. + Pallets, +} + /// Benchmark the extrinsic weight of FRAME Pallets. #[derive(Debug, clap::Parser)] pub struct PalletCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). - #[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input"])] + #[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))] pub pallet: Option, /// Select an extrinsic inside the pallet to benchmark, or `*` for all. - #[arg(short, long, required_unless_present_any = ["list", "json_input"])] + #[arg(short, long, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))] pub extrinsic: Option, + /// Run benchmarks for all pallets and extrinsics. + /// + /// This is equivalent to running `--pallet * --extrinsic *`. + #[arg(long)] + pub all: bool, + /// Select how many samples we should take across the variable components. #[arg(short, long, default_value_t = 50)] pub steps: u32, @@ -158,11 +174,15 @@ pub struct PalletCmd { #[arg(long = "db-cache", value_name = "MiB", default_value_t = 1024)] pub database_cache_size: u32, - /// List the benchmarks that match your query rather than running them. + /// List and print available benchmarks in a csv-friendly format. /// - /// When nothing is provided, we list all benchmarks. - #[arg(long)] - pub list: bool, + /// NOTE: `num_args` and `require_equals` are required to allow `--list` + #[arg(long, value_enum, ignore_case = true, num_args = 0..=1, require_equals = true, default_missing_value("All"))] + pub list: Option, + + /// Don't include csv header when listing benchmarks. + #[arg(long, requires("list"))] + pub no_csv_header: bool, /// If enabled, the storage info is not displayed in the output next to the analysis. /// diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs b/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs index 1e5e294acba263aa4f3abf97e4249ce5917d9d42..a044049a0d614e42530f30badee173a63a28f0f5 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/writer.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs index 9493a693bbed321785bf0d23326d0f68b3efd534..bd4b65d8a2e378d543b54bebd8db4a1c3d378f98 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -153,8 +153,8 @@ fn map_results( continue } - let pallet_string = String::from_utf8(batch.pallet.clone()).unwrap(); - let instance_string = String::from_utf8(batch.instance.clone()).unwrap(); + let pallet_name = String::from_utf8(batch.pallet.clone()).unwrap(); + let instance_name = String::from_utf8(batch.instance.clone()).unwrap(); let benchmark_data = get_benchmark_data( batch, storage_info, @@ -166,7 +166,7 @@ fn map_results( worst_case_map_values, additional_trie_layers, ); - let pallet_benchmarks = all_benchmarks.entry((pallet_string, instance_string)).or_default(); + let pallet_benchmarks = all_benchmarks.entry((pallet_name, instance_name)).or_default(); pallet_benchmarks.push(benchmark_data); } Ok(all_benchmarks) @@ -571,19 +571,22 @@ pub(crate) fn process_storage_results( let mut prefix_result = result.clone(); let key_info = storage_info_map.get(&prefix); + let pallet_name = match key_info { + Some(k) => String::from_utf8(k.pallet_name.clone()).expect("encoded from string"), + None => "".to_string(), + }; + let storage_name = match key_info { + Some(k) => String::from_utf8(k.storage_name.clone()).expect("encoded from string"), + None => "".to_string(), + }; let max_size = key_info.and_then(|k| k.max_size); let override_pov_mode = match key_info { - Some(StorageInfo { pallet_name, storage_name, .. }) => { - let pallet_name = - String::from_utf8(pallet_name.clone()).expect("encoded from string"); - let storage_name = - String::from_utf8(storage_name.clone()).expect("encoded from string"); - + Some(_) => { // Is there an override for the storage key? - pov_modes.get(&(pallet_name.clone(), storage_name)).or( + pov_modes.get(&(pallet_name.clone(), storage_name.clone())).or( // .. or for the storage prefix? - pov_modes.get(&(pallet_name, "ALL".to_string())).or( + pov_modes.get(&(pallet_name.clone(), "ALL".to_string())).or( // .. or for the benchmark? pov_modes.get(&("ALL".to_string(), "ALL".to_string())), ), @@ -662,15 +665,10 @@ pub(crate) fn process_storage_results( // writes. if !is_prefix_identified { match key_info { - Some(key_info) => { + Some(_) => { let comment = format!( "Storage: `{}::{}` (r:{} w:{})", - String::from_utf8(key_info.pallet_name.clone()) - .expect("encoded from string"), - String::from_utf8(key_info.storage_name.clone()) - .expect("encoded from string"), - reads, - writes, + pallet_name, storage_name, reads, writes, ); comments.push(comment) }, @@ -698,11 +696,7 @@ pub(crate) fn process_storage_results( ) { Some(new_pov) => { let comment = format!( - "Proof: `{}::{}` (`max_values`: {:?}, `max_size`: {:?}, added: {}, mode: `{:?}`)", - String::from_utf8(key_info.pallet_name.clone()) - .expect("encoded from string"), - String::from_utf8(key_info.storage_name.clone()) - .expect("encoded from string"), + "Proof: `{pallet_name}::{storage_name}` (`max_values`: {:?}, `max_size`: {:?}, added: {}, mode: `{:?}`)", key_info.max_values, key_info.max_size, new_pov, @@ -711,13 +705,9 @@ pub(crate) fn process_storage_results( comments.push(comment) }, None => { - let pallet = String::from_utf8(key_info.pallet_name.clone()) - .expect("encoded from string"); - let item = String::from_utf8(key_info.storage_name.clone()) - .expect("encoded from string"); let comment = format!( "Proof: `{}::{}` (`max_values`: {:?}, `max_size`: {:?}, mode: `{:?}`)", - pallet, item, key_info.max_values, key_info.max_size, + pallet_name, storage_name, key_info.max_values, key_info.max_size, used_pov_mode, ); comments.push(comment); diff --git a/substrate/utils/frame/benchmarking-cli/src/storage/write.rs b/substrate/utils/frame/benchmarking-cli/src/storage/write.rs index 65941497bda41f94b1230f73d59b187895cee4d9..4fa56b6e818f8d90103eb080db2e071ba2a240eb 100644 --- a/substrate/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/substrate/utils/frame/benchmarking-cli/src/storage/write.rs @@ -57,7 +57,7 @@ impl StorageCmd { let best_hash = client.usage_info().chain.best_hash; let header = client.header(best_hash)?.ok_or("Header not found")?; let original_root = *header.state_root(); - let trie = DbStateBuilder::::new(storage.clone(), original_root).build(); + let trie = DbStateBuilder::>::new(storage.clone(), original_root).build(); info!("Preparing keys from block {}", best_hash); // Load all KV pairs and randomly shuffle them. @@ -189,7 +189,7 @@ fn convert_tx( /// if `child_info` exist then it means this is a child tree key fn measure_write( db: Arc>, - trie: &DbState, + trie: &DbState>, key: Vec, new_v: Vec, version: StateVersion, @@ -220,7 +220,7 @@ fn measure_write( /// if `child_info` exist then it means this is a child tree key fn check_new_value( db: Arc>, - trie: &DbState, + trie: &DbState>, key: &Vec, new_v: &Vec, version: StateVersion, diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 87e3a50753f734950791f617063e03f418ab4390..919016b2d8f09f4327ed34e4dc1a7d0fe9b3fe6b 100644 --- a/substrate/utils/frame/frame-utilities-cli/Cargo.toml +++ b/substrate/utils/frame/frame-utilities-cli/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" workspace = true [dependencies] -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } frame-support = { path = "../../../frame/support" } frame-system = { path = "../../../frame/system" } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index b35e06879df7ebb493ea09a9d4be2b32b3e6128c..68d4733614c1521c285109aa7d8e3c8e9b8ea188 100644 --- a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -17,4 +17,4 @@ kitchensink-runtime = { path = "../../../../bin/node/runtime" } generate-bags = { path = ".." } # third-party -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index ff0b7572d334ca219b0aa007277a06e7aec24824..61e0a861ee0ebd847a54c46280d5c3c10fce0ad2 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -15,10 +15,10 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["http-client"] } +jsonrpsee = { version = "0.22", features = ["http-client"] } codec = { package = "parity-scale-codec", version = "3.6.1" } -log = "0.4.17" -serde = "1.0.195" +log = { workspace = true, default-features = true } +serde = { workspace = true, default-features = true } sp-core = { path = "../../../primitives/core" } sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } sp-state-machine = { path = "../../../primitives/state-machine" } diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index 47c0508485cd367da4627bdbca446c52e5974f45..d49479d9cda955770dc32df4800c7bef70082816 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -1204,8 +1204,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::generic::UncheckedExtrinsic; + pub(crate) type Block = RawBlock; pub(crate) fn init_logger() { sp_tracing::try_init_simple(); @@ -1263,7 +1264,11 @@ mod tests { #[cfg(all(test, feature = "remote-test"))] mod remote_tests { use super::test_prelude::*; - use std::os::unix::fs::MetadataExt; + use std::{env, os::unix::fs::MetadataExt}; + + fn endpoint() -> String { + env::var("TEST_WS").unwrap_or_else(|_| DEFAULT_HTTP_ENDPOINT.to_string()) + } #[tokio::test] async fn state_version_is_kept_and_can_be_altered() { @@ -1273,6 +1278,7 @@ mod remote_tests { // first, build a snapshot. let ext = Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), pallets: vec!["Proxy".to_owned()], child_trie: false, state_snapshot: Some(SnapshotConfig::new(CACHE)), @@ -1314,6 +1320,7 @@ mod remote_tests { // first, build a snapshot. let ext = Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), pallets: vec!["Proxy".to_owned()], child_trie: false, state_snapshot: Some(SnapshotConfig::new(CACHE)), @@ -1341,6 +1348,7 @@ mod remote_tests { // create an ext with children keys let child_ext = Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), pallets: vec!["Proxy".to_owned()], child_trie: true, state_snapshot: Some(SnapshotConfig::new(CACHE)), @@ -1353,6 +1361,7 @@ mod remote_tests { // create an ext without children keys let ext = Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), pallets: vec!["Proxy".to_owned()], child_trie: false, state_snapshot: Some(SnapshotConfig::new(CACHE)), @@ -1378,6 +1387,7 @@ mod remote_tests { .mode(Mode::OfflineOrElseOnline( OfflineConfig { state_snapshot: SnapshotConfig::new(CACHE) }, OnlineConfig { + transport: endpoint().clone().into(), pallets: vec!["Proxy".to_owned()], child_trie: false, state_snapshot: Some(SnapshotConfig::new(CACHE)), @@ -1419,6 +1429,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), pallets: vec!["Proxy".to_owned()], child_trie: false, ..Default::default() @@ -1434,6 +1445,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), pallets: vec!["Proxy".to_owned(), "Multisig".to_owned()], child_trie: false, ..Default::default() @@ -1451,6 +1463,7 @@ mod remote_tests { Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), state_snapshot: Some(SnapshotConfig::new(CACHE)), pallets: vec!["Proxy".to_owned()], child_trie: false, @@ -1480,6 +1493,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), state_snapshot: Some(SnapshotConfig::new(CACHE)), pallets: vec!["Crowdloan".to_owned()], child_trie: true, @@ -1511,7 +1525,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - transport: std::option_env!("TEST_WS").unwrap().to_owned().into(), + transport: endpoint().clone().into(), pallets: vec!["Staking".to_owned()], child_trie: false, ..Default::default() @@ -1530,7 +1544,7 @@ mod remote_tests { init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - transport: std::option_env!("TEST_WS").unwrap().to_owned().into(), + transport: endpoint().clone().into(), ..Default::default() })) .build() @@ -1543,9 +1557,10 @@ mod remote_tests { async fn can_fetch_in_parallel() { init_logger(); - let uri = String::from("wss://kusama-bridge-hub-rpc.polkadot.io:443"); - let mut builder = Builder::::new() - .mode(Mode::Online(OnlineConfig { transport: uri.into(), ..Default::default() })); + let mut builder = Builder::::new().mode(Mode::Online(OnlineConfig { + transport: endpoint().clone().into(), + ..Default::default() + })); builder.init_remote_client().await.unwrap(); let at = builder.as_online().at.unwrap(); diff --git a/substrate/utils/frame/rpc/client/Cargo.toml b/substrate/utils/frame/rpc/client/Cargo.toml index a97bc77b00f531d9dd0fc816a04a59a4ea73142f..b51e3f44f4e6457ee2f9e12dedace27728b96ac4 100644 --- a/substrate/utils/frame/rpc/client/Cargo.toml +++ b/substrate/utils/frame/rpc/client/Cargo.toml @@ -15,12 +15,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.20.3", features = ["ws-client"] } +jsonrpsee = { version = "0.22", features = ["ws-client"] } sc-rpc-api = { path = "../../../../client/rpc-api" } async-trait = "0.1.74" -serde = "1" +serde = { workspace = true, default-features = true } sp-runtime = { path = "../../../../primitives/runtime" } -log = "0.4" +log = { workspace = true, default-features = true } [dev-dependencies] tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread", "sync"] } diff --git a/substrate/utils/frame/rpc/client/src/lib.rs b/substrate/utils/frame/rpc/client/src/lib.rs index 9349ee2d357b2b8c608e722ea0100b790c509991..4f4f4bbef56213f88ecfa6fe848e178d448d5560 100644 --- a/substrate/utils/frame/rpc/client/src/lib.rs +++ b/substrate/utils/frame/rpc/client/src/lib.rs @@ -44,9 +44,9 @@ use std::collections::VecDeque; pub use jsonrpsee::{ core::{ - client::{ClientT, Subscription, SubscriptionClientT}, + client::{ClientT, Error, Subscription, SubscriptionClientT}, params::BatchRequestBuilder, - Error, RpcResult, + RpcResult, }, rpc_params, ws_client::{WsClient, WsClientBuilder}, @@ -199,11 +199,15 @@ where #[cfg(test)] mod tests { use super::*; - use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header, H256}; + use sp_runtime::{ + generic::UncheckedExtrinsic, + testing::{Block as TBlock, Header, MockCallU64, H256}, + }; use std::sync::Arc; use tokio::sync::Mutex; - type Block = TBlock>; + type UncheckedXt = UncheckedExtrinsic; + type Block = TBlock; type BlockNumber = u64; type Hash = H256; diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 83afff94a8dc06defc2abb90c4626d9acb633af7..f9a45e21ce13d3690c1efe366e1d0f480f0f9b8f 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -17,13 +17,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -serde = { version = "1", features = ["derive"] } +serde = { features = ["derive"], workspace = true, default-features = true } sp-core = { path = "../../../../primitives/core" } sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = "0.28.0" -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } + +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } # Substrate Dependencies sc-client-api = { path = "../../../../client/api" } @@ -31,4 +32,4 @@ sc-rpc-api = { path = "../../../../client/rpc-api" } sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 3750e3272c90d56cc47b31b75a262477cf410360..2e4bb6a105784fafecd1344a909e69dbcbfa0e3f 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.20.3", features = ["jsonrpsee-types"] } -serde = "1" +jsonrpsee = { version = "0.22", features = ["jsonrpsee-types"] } +serde = { workspace = true, default-features = true } frame-support = { path = "../../../../frame/support" } sc-rpc-api = { path = "../../../../client/rpc-api" } sp-storage = { path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.10.0" -jsonrpsee = { version = "0.20.3", features = ["jsonrpsee-types", "ws-client"] } +jsonrpsee = { version = "0.22", features = ["jsonrpsee-types", "ws-client"] } tokio = "1.22.0" sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } diff --git a/substrate/utils/frame/rpc/support/src/lib.rs b/substrate/utils/frame/rpc/support/src/lib.rs index e3ccbd6965893ed81b9698e4ff0b4caebba3830c..8280c46aadf2629c1f2b1efccfa98d2c7a5f5bdf 100644 --- a/substrate/utils/frame/rpc/support/src/lib.rs +++ b/substrate/utils/frame/rpc/support/src/lib.rs @@ -23,7 +23,7 @@ use codec::{DecodeAll, FullCodec, FullEncode}; use core::marker::PhantomData; use frame_support::storage::generator::{StorageDoubleMap, StorageMap, StorageValue}; -use jsonrpsee::core::Error as RpcError; +use jsonrpsee::core::ClientError as RpcError; use sc_rpc_api::state::StateApiClient; use serde::{de::DeserializeOwned, Serialize}; use sp_storage::{StorageData, StorageKey}; @@ -31,7 +31,7 @@ use sp_storage::{StorageData, StorageKey}; /// A typed query on chain state usable from an RPC client. /// /// ```no_run -/// # use jsonrpsee::core::Error as RpcError; +/// # use jsonrpsee::core::ClientError as RpcError; /// # use jsonrpsee::ws_client::WsClientBuilder; /// # use codec::Encode; /// # use frame_support::{construct_runtime, derive_impl, traits::ConstU32}; diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index 3f06ffe2bc2ee4ce5e96cb8e1e25bb7affff1779..f9a84a01af82f9cf4746e003990e43cb2515a7bc 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } futures = "0.3.21" -log = "0.4.17" +log = { workspace = true, default-features = true } frame-system-rpc-runtime-api = { path = "../../../../frame/system/rpc/runtime-api" } sc-rpc-api = { path = "../../../../client/rpc-api" } sc-transaction-pool-api = { path = "../../../../client/transaction-pool/api" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 1550a2cec4b054a5d8b9dc3874855dc705cc5336..d123fc5f62dc5848dc560f1eca37523435ebb331 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -38,12 +38,12 @@ frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true } substrate-rpc-client = { path = "../../rpc/client" } async-trait = "0.1.74" -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"] } hex = { version = "0.4.3", default-features = false } -log = "0.4.17" +log = { workspace = true, default-features = true } parity-scale-codec = "3.6.1" -serde = "1.0.195" -serde_json = "1.0.111" +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } zstd = { version = "0.12.4", default-features = false } [dev-dependencies] diff --git a/substrate/utils/prometheus/Cargo.toml b/substrate/utils/prometheus/Cargo.toml index 5ce943fbc598faf21af32f86edb81d7abe187a91..36527ac6183bb921266023320345afb9f6a89246 100644 --- a/substrate/utils/prometheus/Cargo.toml +++ b/substrate/utils/prometheus/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] hyper = { version = "0.14.16", default-features = false, features = ["http1", "server", "tcp"] } -log = "0.4.17" +log = { workspace = true, default-features = true } prometheus = { version = "0.13.0", default-features = false } -thiserror = "1.0" +thiserror = { workspace = true } tokio = { version = "1.22.0", features = ["parking_lot"] } [dev-dependencies] diff --git a/substrate/utils/substrate-bip39/Cargo.toml b/substrate/utils/substrate-bip39/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..a46f81ee24d96d666495ee5cea5ca58b415a9cb0 --- /dev/null +++ b/substrate/utils/substrate-bip39/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "substrate-bip39" +version = "0.4.7" +license = "Apache-2.0" +description = "Converting BIP39 entropy to valid Substrate (sr25519) SecretKeys" +documentation = "https://docs.rs/substrate-bip39" +authors.workspace = true +edition.workspace = true +repository.workspace = true + +[dependencies] +hmac = "0.12.1" +pbkdf2 = { version = "0.12.2", default-features = false } +schnorrkel = { version = "0.11.4", default-features = false } +sha2 = { version = "0.10.7", default-features = false } +zeroize = { version = "1.4.3", default-features = false } + +[dev-dependencies] +bip39 = "2.0.0" +rustc-hex = "2.1.0" + +[features] +default = ["std"] +std = [ + "hmac/std", + "pbkdf2/std", + "schnorrkel/std", + "sha2/std", + "zeroize/alloc", + "zeroize/std", +] diff --git a/substrate/utils/substrate-bip39/README.md b/substrate/utils/substrate-bip39/README.md new file mode 100644 index 0000000000000000000000000000000000000000..368d18f406bb6cf36abad1daa4020882c1a2fe73 --- /dev/null +++ b/substrate/utils/substrate-bip39/README.md @@ -0,0 +1,55 @@ +# Substrate BIP39 + +This is a crate for deriving secret keys for Ristretto compressed Ed25519 (should be compatible with Ed25519 at this +time) from BIP39 phrases. + +## Why? + +The natural approach here would be to use the 64-byte seed generated from the BIP39 phrase, and use that to construct +the key. This approach, while reasonable and fairly straight forward to implement, also means we would have to inherit +all the characteristics of seed generation. Since we are breaking compatibility with both BIP32 and BIP44 anyway (which +we are free to do as we are no longer using the Secp256k1 curve), there is also no reason why we should adhere to BIP39 +seed generation from the mnemonic. + +BIP39 seed generation was designed to be compatible with user supplied brain wallet phrases as well as being extensible +to wallets providing their own dictionaries and checksum mechanism. Issues with those two points: + +1. Brain wallets are a horrible idea, simply because humans are bad entropy generators. It's next to impossible to + educate users on how to use that feature in a secure manner. The 2048 rounds of PBKDF2 is a mere inconvenience that + offers no real protection against dictionary attacks for anyone equipped with modern consumer hardware. Brain wallets + have given users false sense of security. _People have lost money_ this way and wallet providers today tend to stick + to CSPRNG supplied dictionary phrases. + +2. Providing own dictionaries felt into the _you ain't gonna need it_ anti-pattern category on day 1. Wallet providers + (be it hardware or software) typically want their products to be compatibile with other wallets so that users can + migrate to their product without having to migrate all their assets. + +To achieve the above phrases have to be precisely encoded in _The One True Canonical Encoding_, for which UTF-8 NFKD was +chosen. This is largely irrelevant (and even ignored) for English phrases, as they encode to basically just ASCII in +virtualy every character encoding known to mankind, but immedietly becomes a problem for dictionaries that do use +non-ASCII characters. Even if the right encoding is used and implemented correctly, there are still [other caveats +present for some non-english dictionaries](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md), +such as normalizing spaces to a canonical form, or making some latin based characters equivalent to their base in +dictionary lookups (eg. Spanish `ñ` and `n` are meant to be interchangeable). Thinking about all of this gives me a +headache, and opens doors for disagreements between buggy implementations, breaking compatibility. + +BIP39 does already provide a form of the mnemonic that is free from all of these issues: the entropy byte array. Since +veryfing the checksum requires that we recover the entropy from which the phrase was generated, no extra work is +actually needed here. Wallet implementators can encode the dictionaries in whatever encoding they find convenient (as +long as they are the standard BIP39 dictionaries), no harm in using UTF-16 string primitives that Java and JavaScript +provide. Since the dictionary is fixed and known, and the checksum is done on the entropy itself, the exact character +encoding used becomes irrelevant, as are the precise codepoints and amount of whitespace around the words. It is thus +much harder to create a buggy implementation. + +PBKDF2 was kept in place, along with the password. Using 24 words (with its 256 bits entropy) makes the extra hashing +redundant (if you could brute force 256 bit entropy, you can also just brute force secret keys), however some users +might be still using 12 word phrases from other applications. There is no good reason to prohibit users from recovering +their old wallets using 12 words that I can see, in which case the extra hashing does provide _some_ protection. +Passwords are also a feature that some power users find useful - particularly for creating a decoy address with a small +balance with empty password, while the funds proper are stored on an address that requires a password to be entered. + +## Why not ditch BIP39 altogether? + +Because there are hardware wallets that use a single phrase for the entire device, and operate multiple accounts on +multiple networks using that. A completely different wordlist would make their life much harder when it comes to +providing future Substrate support. diff --git a/substrate/utils/substrate-bip39/src/lib.rs b/substrate/utils/substrate-bip39/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..3673d20faed68e8897b97040c66d726a8877fd7a --- /dev/null +++ b/substrate/utils/substrate-bip39/src/lib.rs @@ -0,0 +1,232 @@ +// 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_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::string::String; + +use hmac::Hmac; +use pbkdf2::pbkdf2; +use schnorrkel::keys::MiniSecretKey; +use sha2::Sha512; +use zeroize::Zeroize; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Error { + InvalidEntropy, +} + +/// `entropy` should be a byte array from a correctly recovered and checksumed BIP39. +/// +/// This function accepts slices of different length for different word lengths: +/// +/// + 16 bytes for 12 words. +/// + 20 bytes for 15 words. +/// + 24 bytes for 18 words. +/// + 28 bytes for 21 words. +/// + 32 bytes for 24 words. +/// +/// Any other length will return an error. +/// +/// `password` is analog to BIP39 seed generation itself, with an empty string being defalt. +pub fn mini_secret_from_entropy(entropy: &[u8], password: &str) -> Result { + let seed = seed_from_entropy(entropy, password)?; + Ok(MiniSecretKey::from_bytes(&seed[..32]).expect("Length is always correct; qed")) +} + +/// Similar to `mini_secret_from_entropy`, except that it provides the 64-byte seed directly. +pub fn seed_from_entropy(entropy: &[u8], password: &str) -> Result<[u8; 64], Error> { + if entropy.len() < 16 || entropy.len() > 32 || entropy.len() % 4 != 0 { + return Err(Error::InvalidEntropy); + } + + let mut salt = String::with_capacity(8 + password.len()); + salt.push_str("mnemonic"); + salt.push_str(password); + + let mut seed = [0u8; 64]; + + pbkdf2::>(entropy, salt.as_bytes(), 2048, &mut seed) + .map_err(|_| Error::InvalidEntropy)?; + + salt.zeroize(); + + Ok(seed) +} + +#[cfg(test)] +mod test { + use super::*; + + #[cfg(not(feature = "std"))] + use alloc::vec::Vec; + + use bip39::{Language, Mnemonic}; + use rustc_hex::FromHex; + + // phrase, entropy, seed, expanded secret_key + // + // ALL SEEDS GENERATED USING "Substrate" PASSWORD! + static VECTORS: &[[&str; 3]] = &[ + [ + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "00000000000000000000000000000000", + "44e9d125f037ac1d51f0a7d3649689d422c2af8b1ec8e00d71db4d7bf6d127e33f50c3d5c84fa3e5399c72d6cbbbbc4a49bf76f76d952f479d74655a2ef2d453", + ], + [ + "legal winner thank year wave sausage worth useful legal winner thank yellow", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b780416850f1e26c1f4b8d88ece681cb058ab66d6182bc2ce5a03181f7b74c27576b5c8bf", + ], + [ + "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", + "80808080808080808080808080808080", + "27f3eb595928c60d5bc91a4d747da40ed236328183046892ed6cd5aa9ae38122acd1183adf09a89839acb1e6eaa7fb563cc958a3f9161248d5a036e0d0af533d", + ], + [ + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "ffffffffffffffffffffffffffffffff", + "227d6256fd4f9ccaf06c45eaa4b2345969640462bbb00c5f51f43cb43418c7a753265f9b1e0c0822c155a9cabc769413ecc14553e135fe140fc50b6722c6b9df", + ], + [ + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "000000000000000000000000000000000000000000000000", + "44e9d125f037ac1d51f0a7d3649689d422c2af8b1ec8e00d71db4d7bf6d127e33f50c3d5c84fa3e5399c72d6cbbbbc4a49bf76f76d952f479d74655a2ef2d453", + ], + [ + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "cb1d50e14101024a88905a098feb1553d4306d072d7460e167a60ccb3439a6817a0afc59060f45d999ddebc05308714733c9e1e84f30feccddd4ad6f95c8a445", + ], + [ + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "808080808080808080808080808080808080808080808080", + "9ddecf32ce6bee77f867f3c4bb842d1f0151826a145cb4489598fe71ac29e3551b724f01052d1bc3f6d9514d6df6aa6d0291cfdf997a5afdb7b6a614c88ab36a", + ], + [ + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "8971cb290e7117c64b63379c97ed3b5c6da488841bd9f95cdc2a5651ac89571e2c64d391d46e2475e8b043911885457cd23e99a28b5a18535fe53294dc8e1693", + ], + [ + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "0000000000000000000000000000000000000000000000000000000000000000", + "44e9d125f037ac1d51f0a7d3649689d422c2af8b1ec8e00d71db4d7bf6d127e33f50c3d5c84fa3e5399c72d6cbbbbc4a49bf76f76d952f479d74655a2ef2d453", + ], + [ + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "3037276a5d05fcd7edf51869eb841bdde27c574dae01ac8cfb1ea476f6bea6ef57ab9afe14aea1df8a48f97ae25b37d7c8326e49289efb25af92ba5a25d09ed3", + ], + [ + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "8080808080808080808080808080808080808080808080808080808080808080", + "2c9c6144a06ae5a855453d98c3dea470e2a8ffb78179c2e9eb15208ccca7d831c97ddafe844ab933131e6eb895f675ede2f4e39837bb5769d4e2bc11df58ac42", + ], + [ + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "047e89ef7739cbfe30da0ad32eb1720d8f62441dd4f139b981b8e2d0bd412ed4eb14b89b5098c49db2301d4e7df4e89c21e53f345138e56a5e7d63fae21c5939", + ], + [ + "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic", + "9e885d952ad362caeb4efe34a8e91bd2", + "f4956be6960bc145cdab782e649a5056598fd07cd3f32ceb73421c3da27833241324dc2c8b0a4d847eee457e6d4c5429f5e625ece22abaa6a976e82f1ec5531d", + ], + [ + "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog", + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "fbcc5229ade0c0ff018cb7a329c5459f91876e4dde2a97ddf03c832eab7f26124366a543f1485479c31a9db0d421bda82d7e1fe562e57f3533cb1733b001d84d", + ], + [ + "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length", + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "7c60c555126c297deddddd59f8cdcdc9e3608944455824dd604897984b5cc369cad749803bb36eb8b786b570c9cdc8db275dbe841486676a6adf389f3be3f076", + ], + [ + "scheme spot photo card baby mountain device kick cradle pact join borrow", + "c0ba5a8e914111210f2bd131f3d5e08d", + "c12157bf2506526c4bd1b79a056453b071361538e9e2c19c28ba2cfa39b5f23034b974e0164a1e8acd30f5b4c4de7d424fdb52c0116bfc6a965ba8205e6cc121", + ], + [ + "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave", + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "23766723e970e6b79dec4d5e4fdd627fd27d1ee026eb898feb9f653af01ad22080c6f306d1061656d01c4fe9a14c05f991d2c7d8af8730780de4f94cd99bd819", + ], + [ + "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside", + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "f4c83c86617cb014d35cd87d38b5ef1c5d5c3d58a73ab779114438a7b358f457e0462c92bddab5a406fe0e6b97c71905cf19f925f356bc673ceb0e49792f4340", + ], + [ + "cat swing flag economy stadium alone churn speed unique patch report train", + "23db8160a31d3e0dca3688ed941adbf3", + "719d4d4de0638a1705bf5237262458983da76933e718b2d64eb592c470f3c5d222e345cc795337bb3da393b94375ff4a56cfcd68d5ea25b577ee9384d35f4246", + ], + [ + "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access", + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "7ae1291db32d16457c248567f2b101e62c5549d2a64cd2b7605d503ec876d58707a8d663641e99663bc4f6cc9746f4852e75e7e54de5bc1bd3c299c9a113409e", + ], + [ + "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform", + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "a911a5f4db0940b17ecb79c4dcf9392bf47dd18acaebdd4ef48799909ebb49672947cc15f4ef7e8ef47103a1a91a6732b821bda2c667e5b1d491c54788c69391", + ], + [ + "vessel ladder alter error federal sibling chat ability sun glass valve picture", + "f30f8c1da665478f49b001d94c5fc452", + "4e2314ca7d9eebac6fe5a05a5a8d3546bc891785414d82207ac987926380411e559c885190d641ff7e686ace8c57db6f6e4333c1081e3d88d7141a74cf339c8f", + ], + [ + "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump", + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "7a83851102849edc5d2a3ca9d8044d0d4f00e5c4a292753ed3952e40808593251b0af1dd3c9ed9932d46e8608eb0b928216a6160bd4fc775a6e6fbd493d7c6b2", + ], + [ + "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold", + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "938ba18c3f521f19bd4a399c8425b02c716844325b1a65106b9d1593fbafe5e0b85448f523f91c48e331995ff24ae406757cff47d11f240847352b348ff436ed", + ] + ]; + + #[test] + fn vectors_are_correct() { + for vector in VECTORS { + let phrase = vector[0]; + + let expected_entropy: Vec = vector[1].from_hex().unwrap(); + let expected_seed: Vec = vector[2].from_hex().unwrap(); + + let mnemonic = Mnemonic::parse_in(Language::English, phrase).unwrap(); + let seed = seed_from_entropy(&mnemonic.to_entropy(), "Substrate").unwrap(); + let secret = mini_secret_from_entropy(&mnemonic.to_entropy(), "Substrate") + .unwrap() + .to_bytes(); + + assert_eq!( + mnemonic.to_entropy(), + &expected_entropy[..], + "Entropy is incorrect for {}", + phrase + ); + assert_eq!(&seed[..], &expected_seed[..], "Seed is incorrect for {}", phrase); + assert_eq!(&secret[..], &expected_seed[..32], "Secret is incorrect for {}", phrase); + } + } +} diff --git a/substrate/utils/wasm-builder/src/prerequisites.rs b/substrate/utils/wasm-builder/src/prerequisites.rs index a601e3210dd0c2b89beffa1d5d6b788cb35fd6a3..22caf8950637960310c62eb98c5358de55c1662d 100644 --- a/substrate/utils/wasm-builder/src/prerequisites.rs +++ b/substrate/utils/wasm-builder/src/prerequisites.rs @@ -149,6 +149,14 @@ impl<'a> DummyCrate<'a> { sysroot_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok()) } + fn get_toolchain(&self) -> Option { + let sysroot = self.get_sysroot()?; + Path::new(sysroot.trim()) + .file_name() + .and_then(|s| s.to_str()) + .map(|s| s.to_string()) + } + fn try_build(&self) -> Result<(), Option> { let Ok(result) = self.prepare_command("build").output() else { return Err(None) }; if !result.status.success() { @@ -164,14 +172,15 @@ fn check_wasm_toolchain_installed( let dummy_crate = DummyCrate::new(&cargo_command, RuntimeTarget::Wasm); if let Err(error) = dummy_crate.try_build() { + let toolchain = dummy_crate.get_toolchain().unwrap_or("".to_string()); let basic_error_message = colorize_error_message( - "Rust WASM toolchain is not properly installed; please install it!", + &format!("Rust WASM target for toolchain {toolchain} is not properly installed; please install it!") ); return match error { None => Err(basic_error_message), Some(error) if error.contains("the `wasm32-unknown-unknown` target may not be installed") => { - Err(colorize_error_message("Cannot compile the WASM runtime: the `wasm32-unknown-unknown` target is not installed!\n\ - You can install it with `rustup target add wasm32-unknown-unknown` if you're using `rustup`.")) + Err(colorize_error_message(&format!("Cannot compile the WASM runtime: the `wasm32-unknown-unknown` target is not installed!\n\ + You can install it with `rustup target add wasm32-unknown-unknown --toolchain {toolchain}` if you're using `rustup`."))) }, // Apparently this can happen when we're running on a non Tier 1 platform. Some(ref error) if error.contains("linker `rust-lld` not found") => @@ -193,9 +202,10 @@ fn check_wasm_toolchain_installed( let src_path = Path::new(sysroot.trim()).join("lib").join("rustlib").join("src").join("rust"); if !src_path.exists() { + let toolchain = dummy_crate.get_toolchain().unwrap_or("".to_string()); return Err(colorize_error_message( - "Cannot compile the WASM runtime: no standard library sources found!\n\ - You can install them with `rustup component add rust-src` if you're using `rustup`.", + &format!("Cannot compile the WASM runtime: no standard library sources found at {}!\n\ + You can install them with `rustup component add rust-src --toolchain {toolchain}` if you're using `rustup`.", src_path.display()), )) } } diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index bc8c9b3b4b3999da9be5e1fb18a8c73444c1867b..13db9fce43103dabf94346b2a75b64cfeaca22e5 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -855,7 +855,7 @@ fn build_bloaty_blob( println!("{} {}", colorize_info_message("Using rustc version:"), cargo_cmd.rustc_version()); // Use `process::exit(1)` to have a clean error output. - if build_cmd.status().map(|s| s.success()).is_err() { + if !build_cmd.status().map_or(false, |s| s.success()) { process::exit(1); } @@ -877,7 +877,7 @@ fn build_bloaty_blob( if polkavm_path .metadata() .map(|polkavm_metadata| { - polkavm_metadata.modified().unwrap() >= elf_metadata.modified().unwrap() + polkavm_metadata.modified().unwrap() < elf_metadata.modified().unwrap() }) .unwrap_or(true) { 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 ea0f15e5d8ace1315e231c6db2e01399e0ce44f3..b68bce508c008396d699e67e08b98cdf74ba5138 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 @@ -34,8 +34,8 @@ 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 60 seconds -bob: reports substrate_beefy_best_block is greater than {{DB_BLOCK_HEIGHT}} within 60 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 bob: count of log lines containing "verification failed" is 0 within 10 seconds diff --git a/templates/minimal/README.md b/templates/minimal/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..410cfc9f6c34844a2c6edb5390c6e16c50cc4406 --- /dev/null +++ b/templates/minimal/node/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "minimal-template-node" +description = "A miniaml Substrate-based Substrate node, ready for hacking." +version = "0.0.0" +license = "MIT-0" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true +publish = false +build = "build.rs" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +clap = { version = "4.5.1", features = ["derive"] } +futures = { version = "0.3.21", features = ["thread-pool"] } +futures-timer = "3.0.1" +jsonrpsee = { version = "0.22", features = ["server"] } +serde_json = { workspace = true, default-features = true } + +sc-cli = { path = "../../../substrate/client/cli" } +sc-executor = { path = "../../../substrate/client/executor" } +sc-network = { path = "../../../substrate/client/network" } +sc-service = { path = "../../../substrate/client/service" } +sc-telemetry = { path = "../../../substrate/client/telemetry" } +sc-transaction-pool = { path = "../../../substrate/client/transaction-pool" } +sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } +sc-consensus = { path = "../../../substrate/client/consensus/common" } +sc-consensus-manual-seal = { path = "../../../substrate/client/consensus/manual-seal" } +sc-rpc-api = { path = "../../../substrate/client/rpc-api" } +sc-basic-authorship = { path = "../../../substrate/client/basic-authorship" } +sc-offchain = { path = "../../../substrate/client/offchain" } +sc-client-api = { path = "../../../substrate/client/api" } + +sp-timestamp = { path = "../../../substrate/primitives/timestamp" } +sp-keyring = { path = "../../../substrate/primitives/keyring" } +sp-api = { path = "../../../substrate/primitives/api" } +sp-blockchain = { path = "../../../substrate/primitives/blockchain" } +sp-block-builder = { path = "../../../substrate/primitives/block-builder" } +sp-io = { path = "../../../substrate/primitives/io" } +sp-runtime = { path = "../../../substrate/primitives/runtime" } + +substrate-frame-rpc-system = { path = "../../../substrate/utils/frame/rpc/system" } + +# Once the native runtime is gone, there should be little to no dependency on FRAME here, and +# certainly no dependency on the runtime. +frame = { path = "../../../substrate/frame", features = [ + "experimental", + "runtime", +] } +runtime = { package = "minimal-template-runtime", path = "../runtime" } + +[build-dependencies] +substrate-build-script-utils = { path = "../../../substrate/utils/build-script-utils" } + +[features] +default = [] diff --git a/substrate/bin/minimal/node/build.rs b/templates/minimal/node/build.rs similarity index 100% rename from substrate/bin/minimal/node/build.rs rename to templates/minimal/node/build.rs diff --git a/substrate/bin/minimal/node/src/chain_spec.rs b/templates/minimal/node/src/chain_spec.rs similarity index 100% rename from substrate/bin/minimal/node/src/chain_spec.rs rename to templates/minimal/node/src/chain_spec.rs diff --git a/substrate/bin/minimal/node/src/cli.rs b/templates/minimal/node/src/cli.rs similarity index 100% rename from substrate/bin/minimal/node/src/cli.rs rename to templates/minimal/node/src/cli.rs diff --git a/substrate/bin/minimal/node/src/command.rs b/templates/minimal/node/src/command.rs similarity index 100% rename from substrate/bin/minimal/node/src/command.rs rename to templates/minimal/node/src/command.rs diff --git a/substrate/bin/minimal/node/src/lib.rs b/templates/minimal/node/src/lib.rs similarity index 94% rename from substrate/bin/minimal/node/src/lib.rs rename to templates/minimal/node/src/lib.rs index c2065def736aeeb3b1102bade04063532128f3cd..cb8ed3bd209dd24d1bfa9d53b904d411acbea02e 100644 --- a/substrate/bin/minimal/node/src/lib.rs +++ b/templates/minimal/node/src/lib.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot Sdk. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/substrate/bin/minimal/node/src/main.rs b/templates/minimal/node/src/main.rs similarity index 100% rename from substrate/bin/minimal/node/src/main.rs rename to templates/minimal/node/src/main.rs diff --git a/substrate/bin/minimal/node/src/rpc.rs b/templates/minimal/node/src/rpc.rs similarity index 100% rename from substrate/bin/minimal/node/src/rpc.rs rename to templates/minimal/node/src/rpc.rs diff --git a/substrate/bin/minimal/node/src/service.rs b/templates/minimal/node/src/service.rs similarity index 100% rename from substrate/bin/minimal/node/src/service.rs rename to templates/minimal/node/src/service.rs diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9982e5ea53bc3eff28fb0331cfb14ad41a15eec7 --- /dev/null +++ b/templates/minimal/pallets/template/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "pallet-minimal-template" +description = "A minimal pallet built with FRAME, part of Polkadot Sdk." +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 = { package = "parity-scale-codec", version = "3.0.0", features = [ + "derive", +], default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } +frame = { path = "../../../../substrate/frame", default-features = false, features = [ + "experimental", + "runtime", +] } + + +[features] +default = ["std"] +std = ["codec/std", "frame/std", "scale-info/std"] diff --git a/templates/minimal/pallets/template/src/lib.rs b/templates/minimal/pallets/template/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..713f014bbe61fc9fa7df5019c00afddebf02bbc6 --- /dev/null +++ b/templates/minimal/pallets/template/src/lib.rs @@ -0,0 +1,19 @@ +//! A shell pallet built with [`frame`]. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame::prelude::*; + +// Re-export all pallet parts, this is needed to properly import the pallet into the runtime. +pub use pallet::*; + +#[frame::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); +} diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..20ffb706eb4992b71a7b34d638b7c4cdc70237fd --- /dev/null +++ b/templates/minimal/runtime/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "minimal-template-runtime" +description = "A solochain runtime template built with Substrate, part of Polkadot Sdk." +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] +parity-scale-codec = { version = "3.0.0", default-features = false } +scale-info = { version = "2.6.0", default-features = false } + +# this is a frame-based runtime, thus importing `frame` with runtime feature enabled. +frame = { path = "../../../substrate/frame", default-features = false, features = [ + "experimental", + "runtime", +] } + +# pallets that we want to use +pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } +pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } + +# genesis builder that allows us to interacto with runtime genesis config +sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } + +# local pallet templates +pallet-minimal-template = { path = "../pallets/template", default-features = false } + +[build-dependencies] +substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "scale-info/std", + + "frame/std", + + "pallet-balances/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + + "pallet-minimal-template/std", + + "sp-genesis-builder/std", + "substrate-wasm-builder", +] diff --git a/substrate/bin/minimal/runtime/build.rs b/templates/minimal/runtime/build.rs similarity index 100% rename from substrate/bin/minimal/runtime/build.rs rename to templates/minimal/runtime/build.rs diff --git a/substrate/bin/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs similarity index 92% rename from substrate/bin/minimal/runtime/src/lib.rs rename to templates/minimal/runtime/src/lib.rs index 610289693d91b778295b3e48569fc887f805a204..6920511e2765cd8c62f9049b5d06e960885b371f 100644 --- a/substrate/bin/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -22,21 +22,24 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use frame::{ - deps::frame_support::weights::{FixedFee, NoFee}, + deps::frame_support::{ + genesis_builder_helper::{build_config, create_default_config}, + weights::{FixedFee, NoFee}, + }, prelude::*, runtime::{ apis::{ - self, impl_runtime_apis, ApplyExtrinsicResult, CheckInherentsResult, OpaqueMetadata, + self, impl_runtime_apis, ApplyExtrinsicResult, CheckInherentsResult, + ExtrinsicInclusionMode, OpaqueMetadata, }, prelude::*, }, }; -use frame_support::genesis_builder_helper::{build_config, create_default_config}; #[runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("minimal-runtime"), - impl_name: create_runtime_str!("minimal-runtime"), + spec_name: create_runtime_str!("minimal-template-runtime"), + impl_name: create_runtime_str!("minimal-template-runtime"), authoring_version: 1, spec_version: 0, impl_version: 1, @@ -51,7 +54,7 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -type SignedExtra = ( +type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -70,6 +73,9 @@ construct_runtime!( Balances: pallet_balances, Sudo: pallet_sudo, TransactionPayment: pallet_transaction_payment, + + // our local pallet + Template: pallet_minimal_template, } ); @@ -103,7 +109,9 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = FixedFee<1, ::Balance>; } -type Block = frame::runtime::types_common::BlockOf; +impl pallet_minimal_template::Config for Runtime {} + +type Block = frame::runtime::types_common::BlockOf; type Header = HeaderFor; type RuntimeExecutive = @@ -121,7 +129,7 @@ impl_runtime_apis! { RuntimeExecutive::execute_block(block) } - fn initialize_block(header: &Header) { + fn initialize_block(header: &Header) -> ExtrinsicInclusionMode { RuntimeExecutive::initialize_block(header) } } diff --git a/cumulus/parachain-template/LICENSE b/templates/parachain/LICENSE similarity index 100% rename from cumulus/parachain-template/LICENSE rename to templates/parachain/LICENSE diff --git a/cumulus/parachain-template/README.md b/templates/parachain/README.md similarity index 100% rename from cumulus/parachain-template/README.md rename to templates/parachain/README.md diff --git a/cumulus/parachain-template/node/Cargo.toml b/templates/parachain/node/Cargo.toml similarity index 72% rename from cumulus/parachain-template/node/Cargo.toml rename to templates/parachain/node/Cargo.toml index c66c96056b956f8ebb4cecff39f2ecf0269dc12c..b4f3a504a4d9d7aebef6262d5677e6ff9967b8c2 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/templates/parachain/node/Cargo.toml @@ -1,26 +1,29 @@ [package] name = "parachain-template-node" -version = "0.1.0" -authors = ["Anonymous"] -description = "A new Cumulus FRAME-based Substrate Node, ready for hacking together a parachain." -license = "Unlicense" -homepage = "https://substrate.io" +description = "A parachain node template built with Substrate and Cumulus, part of Polkadot Sdk." +version = "0.0.0" +license = "MIT-0" +authors.workspace = true +homepage.workspace = true repository.workspace = true edition.workspace = true -build = "build.rs" publish = false +build = "build.rs" [lints] workspace = true +# [[bin]] +# name = "parachain-template-node" + [dependencies] -clap = { version = "4.4.18", features = ["derive"] } -log = "0.4.20" +clap = { version = "4.5.1", features = ["derive"] } +log = { workspace = true, default-features = true } codec = { package = "parity-scale-codec", version = "3.0.0" } -serde = { version = "1.0.195", features = ["derive"] } -jsonrpsee = { version = "0.20.3", features = ["server"] } +serde = { features = ["derive"], workspace = true, default-features = true } +jsonrpsee = { version = "0.22", features = ["server"] } futures = "0.3.28" -serde_json = "1.0.111" +serde_json = { workspace = true, default-features = true } # Local parachain-template-runtime = { path = "../runtime" } @@ -63,15 +66,15 @@ polkadot-primitives = { path = "../../../polkadot/primitives" } xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } # Cumulus -cumulus-client-cli = { path = "../../client/cli" } -cumulus-client-collator = { path = "../../client/collator" } -cumulus-client-consensus-aura = { path = "../../client/consensus/aura" } -cumulus-client-consensus-common = { path = "../../client/consensus/common" } -cumulus-client-consensus-proposer = { path = "../../client/consensus/proposer" } -cumulus-client-service = { path = "../../client/service" } -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } -cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface" } +cumulus-client-cli = { path = "../../../cumulus/client/cli" } +cumulus-client-collator = { path = "../../../cumulus/client/collator" } +cumulus-client-consensus-aura = { path = "../../../cumulus/client/consensus/aura" } +cumulus-client-consensus-common = { path = "../../../cumulus/client/consensus/common" } +cumulus-client-consensus-proposer = { path = "../../../cumulus/client/consensus/proposer" } +cumulus-client-service = { path = "../../../cumulus/client/service" } +cumulus-primitives-core = { path = "../../../cumulus/primitives/core" } +cumulus-primitives-parachain-inherent = { path = "../../../cumulus/primitives/parachain-inherent" } +cumulus-relay-chain-interface = { path = "../../../cumulus/client/relay-chain-interface" } color-print = "0.3.4" [build-dependencies] diff --git a/cumulus/parachain-template/node/build.rs b/templates/parachain/node/build.rs similarity index 100% rename from cumulus/parachain-template/node/build.rs rename to templates/parachain/node/build.rs diff --git a/cumulus/parachain-template/node/src/chain_spec.rs b/templates/parachain/node/src/chain_spec.rs similarity index 93% rename from cumulus/parachain-template/node/src/chain_spec.rs rename to templates/parachain/node/src/chain_spec.rs index a79c78699c07102aca27ed06c73f93ccf86ed3ce..16c91865cdb4aa9ae3c5882652100f5ef56a988c 100644 --- a/cumulus/parachain-template/node/src/chain_spec.rs +++ b/templates/parachain/node/src/chain_spec.rs @@ -1,5 +1,6 @@ use cumulus_primitives_core::ParaId; -use parachain_template_runtime::{AccountId, AuraId, Signature, EXISTENTIAL_DEPOSIT}; +use parachain_template_runtime as runtime; +use runtime::{AccountId, AuraId, Signature, EXISTENTIAL_DEPOSIT}; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; @@ -56,8 +57,8 @@ where /// Generate the session keys from individual elements. /// /// The input must be a tuple of individual keys (a single arg for now since we have just one key). -pub fn template_session_keys(keys: AuraId) -> parachain_template_runtime::SessionKeys { - parachain_template_runtime::SessionKeys { aura: keys } +pub fn template_session_keys(keys: AuraId) -> runtime::SessionKeys { + runtime::SessionKeys { aura: keys } } pub fn development_config() -> ChainSpec { @@ -68,8 +69,7 @@ pub fn development_config() -> ChainSpec { properties.insert("ss58Format".into(), 42.into()); ChainSpec::builder( - parachain_template_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), + runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! @@ -120,8 +120,7 @@ pub fn local_testnet_config() -> ChainSpec { #[allow(deprecated)] ChainSpec::builder( - parachain_template_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), + runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! diff --git a/cumulus/parachain-template/node/src/cli.rs b/templates/parachain/node/src/cli.rs similarity index 99% rename from cumulus/parachain-template/node/src/cli.rs rename to templates/parachain/node/src/cli.rs index 73ef996b7504114b3578604a8d2c37661c9261fc..a5c55b8118a89d3dede620099a7447e3ab5dda6d 100644 --- a/cumulus/parachain-template/node/src/cli.rs +++ b/templates/parachain/node/src/cli.rs @@ -40,7 +40,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone /// [CLI](). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, } diff --git a/cumulus/parachain-template/node/src/command.rs b/templates/parachain/node/src/command.rs similarity index 98% rename from cumulus/parachain-template/node/src/command.rs rename to templates/parachain/node/src/command.rs index 6ddb68a359a786be617e384b16d7292c3db45a88..82624ae0be59e3159477b6f35b95f86177a35754 100644 --- a/cumulus/parachain-template/node/src/command.rs +++ b/templates/parachain/node/src/command.rs @@ -1,5 +1,6 @@ use std::net::SocketAddr; +use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; @@ -183,7 +184,7 @@ pub fn run() -> Result<()> { match cmd { BenchmarkCmd::Pallet(cmd) => if cfg!(feature = "runtime-benchmarks") { - runner.sync_run(|config| cmd.run::(config)) + runner.sync_run(|config| cmd.run::, ReclaimHostFunctions>(config)) } else { Err("Benchmarking wasn't enabled when building the node. \ You can enable it with `--features runtime-benchmarks`." diff --git a/cumulus/parachain-template/node/src/main.rs b/templates/parachain/node/src/main.rs similarity index 100% rename from cumulus/parachain-template/node/src/main.rs rename to templates/parachain/node/src/main.rs diff --git a/cumulus/parachain-template/node/src/rpc.rs b/templates/parachain/node/src/rpc.rs similarity index 100% rename from cumulus/parachain-template/node/src/rpc.rs rename to templates/parachain/node/src/rpc.rs diff --git a/cumulus/parachain-template/node/src/service.rs b/templates/parachain/node/src/service.rs similarity index 98% rename from cumulus/parachain-template/node/src/service.rs rename to templates/parachain/node/src/service.rs index 830b6e82f969190b69425bd59a939c49372bf9f3..4dd24803e9b124d386d4912236ae1abd42229802 100644 --- a/cumulus/parachain-template/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -40,7 +40,10 @@ use substrate_prometheus_endpoint::Registry; pub struct ParachainNativeExecutor; impl sc_executor::NativeExecutionDispatch for ParachainNativeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + type ExtendHostFunctions = ( + cumulus_client_service::storage_proof_size::HostFunctions, + frame_benchmarking::benchmarking::HostFunctions, + ); fn dispatch(method: &str, data: &[u8]) -> Option> { parachain_template_runtime::api::dispatch(method, data) @@ -100,10 +103,11 @@ pub fn new_partial(config: &Configuration) -> Result let executor = ParachainExecutor::new_with_wasm_executor(wasm); let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts::( + sc_service::new_full_parts_record_import::( config, telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), executor, + true, )?; let client = Arc::new(client); diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/templates/parachain/pallets/template/Cargo.toml similarity index 69% rename from cumulus/parachain-template/pallets/template/Cargo.toml rename to templates/parachain/pallets/template/Cargo.toml index 2318375fec9c8d338e9e83ba12fa7b65449c41a9..89eb9d5171630459e2e313ad94cee53e97921cac 100644 --- a/cumulus/parachain-template/pallets/template/Cargo.toml +++ b/templates/parachain/pallets/template/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "pallet-parachain-template" -authors = ["Anonymous"] description = "FRAME pallet template for defining custom runtime logic." -version = "0.7.0" -license = "Unlicense" -homepage = "https://substrate.io" +version = "0.0.0" +license = "MIT-0" +authors.workspace = true +homepage.workspace = true repository.workspace = true edition.workspace = true +publish = false [lints] workspace = true @@ -15,21 +16,22 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } -# Substrate +# frame deps frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system", default-features = false } [dev-dependencies] -serde = { version = "1.0.195" } - -# Substrate -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../../substrate/primitives/io", default-features = false } -sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +sp-core = { path = "../../../../substrate/primitives/core" } +sp-io = { path = "../../../../substrate/primitives/io" } +sp-runtime = { path = "../../../../substrate/primitives/runtime" } [features] default = ["std"] @@ -41,7 +43,7 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/substrate/bin/node-template/pallets/template/README.md b/templates/parachain/pallets/template/README.md similarity index 100% rename from substrate/bin/node-template/pallets/template/README.md rename to templates/parachain/pallets/template/README.md diff --git a/substrate/bin/node-template/pallets/template/src/benchmarking.rs b/templates/parachain/pallets/template/src/benchmarking.rs similarity index 100% rename from substrate/bin/node-template/pallets/template/src/benchmarking.rs rename to templates/parachain/pallets/template/src/benchmarking.rs diff --git a/cumulus/parachain-template/pallets/template/src/lib.rs b/templates/parachain/pallets/template/src/lib.rs similarity index 96% rename from cumulus/parachain-template/pallets/template/src/lib.rs rename to templates/parachain/pallets/template/src/lib.rs index 5f3252bfc3a70aa731bf572493a3797bfef574bb..11587d1df426f485139eab9e333b292768c6c571 100644 --- a/cumulus/parachain-template/pallets/template/src/lib.rs +++ b/templates/parachain/pallets/template/src/lib.rs @@ -11,6 +11,8 @@ mod mock; #[cfg(test)] mod tests; +pub mod weights; + #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -24,6 +26,8 @@ pub mod pallet { 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. + type WeightInfo: crate::weights::WeightInfo; } #[pallet::pallet] @@ -32,7 +36,6 @@ pub mod pallet { // The pallet's runtime storage items. // https://docs.substrate.io/v3/runtime/storage #[pallet::storage] - #[pallet::getter(fn something)] // Learn more about declaring storage items: // https://docs.substrate.io/v3/runtime/storage#declaring-storage-items pub type Something = StorageValue<_, u32>; diff --git a/cumulus/parachain-template/pallets/template/src/mock.rs b/templates/parachain/pallets/template/src/mock.rs similarity index 98% rename from cumulus/parachain-template/pallets/template/src/mock.rs rename to templates/parachain/pallets/template/src/mock.rs index 411a16b116c8f94757c29a686022842e159e6924..f510a8b773acf398ef2442254de25e75f867fcbb 100644 --- a/cumulus/parachain-template/pallets/template/src/mock.rs +++ b/templates/parachain/pallets/template/src/mock.rs @@ -51,6 +51,7 @@ impl system::Config for Test { impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } // Build genesis storage according to the mock runtime. diff --git a/cumulus/parachain-template/pallets/template/src/tests.rs b/templates/parachain/pallets/template/src/tests.rs similarity index 86% rename from cumulus/parachain-template/pallets/template/src/tests.rs rename to templates/parachain/pallets/template/src/tests.rs index 527aec8ed00c058e5a9329a50d60267d7f9d1851..9ad3076be2cc9927063e1b50c293cafadf8f3361 100644 --- a/cumulus/parachain-template/pallets/template/src/tests.rs +++ b/templates/parachain/pallets/template/src/tests.rs @@ -1,4 +1,4 @@ -use crate::{mock::*, Error}; +use crate::{mock::*, Error, Something}; use frame_support::{assert_noop, assert_ok}; #[test] @@ -7,7 +7,7 @@ fn it_works_for_default_value() { // Dispatch a signed extrinsic. assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); // Read pallet storage and assert an expected result. - assert_eq!(TemplateModule::something(), Some(42)); + assert_eq!(Something::::get(), Some(42)); }); } diff --git a/substrate/bin/node-template/pallets/template/src/weights.rs b/templates/parachain/pallets/template/src/weights.rs similarity index 100% rename from substrate/bin/node-template/pallets/template/src/weights.rs rename to templates/parachain/pallets/template/src/weights.rs diff --git a/cumulus/parachain-template/polkadot-launch/config.json b/templates/parachain/polkadot-launch/config.json similarity index 100% rename from cumulus/parachain-template/polkadot-launch/config.json rename to templates/parachain/polkadot-launch/config.json diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml similarity index 80% rename from cumulus/parachain-template/runtime/Cargo.toml rename to templates/parachain/runtime/Cargo.toml index e4575d196c799e82049ecc69cba03174c16e4a88..44e9341b568af1f4dd039f275121b5baa535c820 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "parachain-template-runtime" -version = "0.7.0" -authors = ["Anonymous"] -description = "A new Cumulus FRAME-based Substrate Runtime, ready for hacking together a parachain." -license = "Unlicense" -homepage = "https://substrate.io" +description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." +version = "0.0.0" +license = "MIT-0" +authors.workspace = true +homepage.workspace = true repository.workspace = true edition.workspace = true +publish = false [lints] workspace = true @@ -18,16 +19,20 @@ targets = ["x86_64-unknown-linux-gnu"] substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } hex-literal = { version = "0.4.1", optional = true } -log = { version = "0.4.20", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +log = { workspace = true } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } smallvec = "1.11.0" # Local pallet-parachain-template = { path = "../pallets/template", default-features = false } -# Substrate +# Substrate / FRAME frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-executive = { path = "../../../substrate/frame/executive", default-features = false } frame-support = { path = "../../../substrate/frame/support", default-features = false } @@ -35,6 +40,8 @@ frame-system = { path = "../../../substrate/frame/system", default-features = fa frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } + +# FRAME Pallets pallet-aura = { path = "../../../substrate/frame/aura", default-features = false } pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } @@ -44,6 +51,8 @@ pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } + +# Substrate Primitives sp-api = { path = "../../../substrate/primitives/api", default-features = false } sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false } sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false } @@ -66,16 +75,19 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/x xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } # Cumulus -cumulus-pallet-aura-ext = { path = "../../pallets/aura-ext", default-features = false } -cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook"] } -cumulus-pallet-session-benchmarking = { path = "../../pallets/session-benchmarking", default-features = false } -cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-features = false } -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } -cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } -pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } -parachains-common = { path = "../../parachains/common", default-features = false } -parachain-info = { package = "staging-parachain-info", path = "../../parachains/pallets/parachain-info", default-features = false } +cumulus-pallet-aura-ext = { path = "../../../cumulus/pallets/aura-ext", default-features = false } +cumulus-pallet-parachain-system = { path = "../../../cumulus/pallets/parachain-system", default-features = false, features = [ + "parameterized-consensus-hook", +] } +cumulus-pallet-session-benchmarking = { path = "../../../cumulus/pallets/session-benchmarking", default-features = false } +cumulus-pallet-xcm = { path = "../../../cumulus/pallets/xcm", default-features = false } +cumulus-pallet-xcmp-queue = { path = "../../../cumulus/pallets/xcmp-queue", default-features = false } +cumulus-primitives-core = { path = "../../../cumulus/primitives/core", default-features = false } +cumulus-primitives-utility = { path = "../../../cumulus/primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../cumulus/primitives/storage-weight-reclaim", default-features = false } +pallet-collator-selection = { path = "../../../cumulus/pallets/collator-selection", default-features = false } +parachains-common = { path = "../../../cumulus/parachains/common", default-features = false } +parachain-info = { package = "staging-parachain-info", path = "../../../cumulus/parachains/pallets/parachain-info", default-features = false } [features] default = ["std"] @@ -87,6 +99,7 @@ std = [ "cumulus-pallet-xcm/std", "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", @@ -136,6 +149,7 @@ runtime-benchmarks = [ "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", "cumulus-primitives-core/runtime-benchmarks", + "cumulus-primitives-storage-weight-reclaim/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -148,6 +162,7 @@ runtime-benchmarks = [ "pallet-parachain-template/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/parachain-template/runtime/build.rs b/templates/parachain/runtime/build.rs similarity index 100% rename from cumulus/parachain-template/runtime/build.rs rename to templates/parachain/runtime/build.rs diff --git a/cumulus/parachain-template/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs similarity index 97% rename from cumulus/parachain-template/runtime/src/lib.rs rename to templates/parachain/runtime/src/lib.rs index d9bc111fcef7f1932d4b52e3f0c9f42d0dccc6c0..74ecd751f672c77424cdae2d3e48c143681127ec 100644 --- a/cumulus/parachain-template/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -97,8 +97,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 extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -107,11 +107,12 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// 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< @@ -179,8 +180,8 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("template-parachain"), - impl_name: create_runtime_str!("template-parachain"), + spec_name: create_runtime_str!("parachain-template-runtime"), + impl_name: create_runtime_str!("parachain-template-runtime"), authoring_version: 1, spec_version: 1, impl_version: 0, @@ -352,6 +353,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 { @@ -488,6 +490,7 @@ impl pallet_collator_selection::Config for Runtime { /// Configure the pallet template in pallets/template. impl pallet_parachain_template::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -528,6 +531,7 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] @@ -559,7 +563,7 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -711,6 +715,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(); @@ -726,6 +731,7 @@ impl_runtime_apis! { use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; 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: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachain-template/runtime/src/weights/block_weights.rs b/templates/parachain/runtime/src/weights/block_weights.rs similarity index 100% rename from cumulus/parachain-template/runtime/src/weights/block_weights.rs rename to templates/parachain/runtime/src/weights/block_weights.rs diff --git a/cumulus/parachain-template/runtime/src/weights/extrinsic_weights.rs b/templates/parachain/runtime/src/weights/extrinsic_weights.rs similarity index 100% rename from cumulus/parachain-template/runtime/src/weights/extrinsic_weights.rs rename to templates/parachain/runtime/src/weights/extrinsic_weights.rs diff --git a/cumulus/parachain-template/runtime/src/weights/mod.rs b/templates/parachain/runtime/src/weights/mod.rs similarity index 100% rename from cumulus/parachain-template/runtime/src/weights/mod.rs rename to templates/parachain/runtime/src/weights/mod.rs diff --git a/cumulus/parachain-template/runtime/src/weights/paritydb_weights.rs b/templates/parachain/runtime/src/weights/paritydb_weights.rs similarity index 100% rename from cumulus/parachain-template/runtime/src/weights/paritydb_weights.rs rename to templates/parachain/runtime/src/weights/paritydb_weights.rs diff --git a/cumulus/parachain-template/runtime/src/weights/rocksdb_weights.rs b/templates/parachain/runtime/src/weights/rocksdb_weights.rs similarity index 100% rename from cumulus/parachain-template/runtime/src/weights/rocksdb_weights.rs rename to templates/parachain/runtime/src/weights/rocksdb_weights.rs diff --git a/cumulus/parachain-template/runtime/src/xcm_config.rs b/templates/parachain/runtime/src/xcm_config.rs similarity index 94% rename from cumulus/parachain-template/runtime/src/xcm_config.rs rename to templates/parachain/runtime/src/xcm_config.rs index 9dd08dc7f3ea570f796a43915d290b78fa070d3c..b1230ba1e5d4151f12776040c76437b29152b468 100644 --- a/cumulus/parachain-template/runtime/src/xcm_config.rs +++ b/templates/parachain/runtime/src/xcm_config.rs @@ -12,15 +12,13 @@ use pallet_xcm::XcmPassthrough; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; use xcm::latest::prelude::*; -#[allow(deprecated)] -use xcm_builder::CurrencyAdapter; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, + FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -44,8 +42,7 @@ pub type LocationToAccountId = ( ); /// Means for transacting assets on this chain. -#[allow(deprecated)] -pub type LocalAssetTransactor = CurrencyAdapter< +pub type LocalAssetTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: diff --git a/substrate/bin/node-template/LICENSE b/templates/solochain/LICENSE similarity index 100% rename from substrate/bin/node-template/LICENSE rename to templates/solochain/LICENSE diff --git a/substrate/bin/node-template/README.md b/templates/solochain/README.md similarity index 100% rename from substrate/bin/node-template/README.md rename to templates/solochain/README.md diff --git a/substrate/bin/node-template/docs/rust-setup.md b/templates/solochain/docs/rust-setup.md similarity index 100% rename from substrate/bin/node-template/docs/rust-setup.md rename to templates/solochain/docs/rust-setup.md diff --git a/templates/solochain/env-setup/README.md b/templates/solochain/env-setup/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a7955872d3ff2172bc1c818e597a5b165005bb62 --- /dev/null +++ b/templates/solochain/env-setup/README.md @@ -0,0 +1,9 @@ +# Env setup + +Special files for setting up an environment to work with the template: + +- `rust-toolchain.toml` when working with `rustup`. +- `flake.nix` when working with `nix`. + +These files will be copied by the installer script to the main directory. They are +put into this special directory to not interfere with the normal CI. diff --git a/substrate/bin/node-template/flake.lock b/templates/solochain/env-setup/flake.lock similarity index 100% rename from substrate/bin/node-template/flake.lock rename to templates/solochain/env-setup/flake.lock diff --git a/substrate/bin/node-template/flake.nix b/templates/solochain/env-setup/flake.nix similarity index 100% rename from substrate/bin/node-template/flake.nix rename to templates/solochain/env-setup/flake.nix diff --git a/substrate/bin/node-template/rust-toolchain.toml b/templates/solochain/env-setup/rust-toolchain.toml similarity index 90% rename from substrate/bin/node-template/rust-toolchain.toml rename to templates/solochain/env-setup/rust-toolchain.toml index 2a35c6ed07c1c2a667729d1fa558e3da0cd0457f..f81199a2249993fce8c98bc4a721d77c6c91d3d7 100644 --- a/substrate/bin/node-template/rust-toolchain.toml +++ b/templates/solochain/env-setup/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly" +channel = "stable" components = [ "cargo", "clippy", diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..5e50e6106c1dc43481627faf6803cc76e59c101b --- /dev/null +++ b/templates/solochain/node/Cargo.toml @@ -0,0 +1,92 @@ +[package] +name = "solochain-template-node" +description = "A solochain node template built with Substrate, part of Polkadot Sdk." +version = "0.0.0" +license = "MIT-0" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true +publish = false + +build = "build.rs" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +clap = { version = "4.5.1", features = ["derive"] } +futures = { version = "0.3.21", features = ["thread-pool"] } +serde_json = { workspace = true, default-features = true } +jsonrpsee = { version = "0.22", features = ["server"] } + +# substrate client +sc-cli = { path = "../../../substrate/client/cli" } +sp-core = { path = "../../../substrate/primitives/core" } +sc-executor = { path = "../../../substrate/client/executor" } +sc-network = { path = "../../../substrate/client/network" } +sc-service = { path = "../../../substrate/client/service" } +sc-telemetry = { path = "../../../substrate/client/telemetry" } +sc-transaction-pool = { path = "../../../substrate/client/transaction-pool" } +sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/api" } +sc-offchain = { path = "../../../substrate/client/offchain" } +sc-consensus-aura = { path = "../../../substrate/client/consensus/aura" } +sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura" } +sc-consensus = { path = "../../../substrate/client/consensus/common" } +sc-consensus-grandpa = { path = "../../../substrate/client/consensus/grandpa" } +sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa" } +sc-client-api = { path = "../../../substrate/client/api" } +sc-rpc-api = { path = "../../../substrate/client/rpc-api" } +sc-basic-authorship = { path = "../../../substrate/client/basic-authorship" } + +# substrate primitives +sp-runtime = { path = "../../../substrate/primitives/runtime" } +sp-io = { path = "../../../substrate/primitives/io" } +sp-timestamp = { path = "../../../substrate/primitives/timestamp" } +sp-inherents = { path = "../../../substrate/primitives/inherents" } +sp-keyring = { path = "../../../substrate/primitives/keyring" } +sp-api = { path = "../../../substrate/primitives/api" } +sp-blockchain = { path = "../../../substrate/primitives/blockchain" } +sp-block-builder = { path = "../../../substrate/primitives/block-builder" } + +# frame and pallets +frame-system = { path = "../../../substrate/frame/system" } +pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } +pallet-transaction-payment-rpc = { path = "../../../substrate/frame/transaction-payment/rpc" } +substrate-frame-rpc-system = { path = "../../../substrate/utils/frame/rpc/system" } + +# These dependencies are used for runtime benchmarking +frame-benchmarking-cli = { path = "../../../substrate/utils/frame/benchmarking-cli" } + +# Local Dependencies +solochain-template-runtime = { path = "../runtime" } + +# CLI-specific dependencies +try-runtime-cli = { path = "../../../substrate/utils/frame/try-runtime/cli", optional = true } + +[build-dependencies] +substrate-build-script-utils = { path = "../../../substrate/utils/build-script-utils" } + +[features] +default = [] +# Dependencies that are only required if runtime benchmarking should be build. +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", +] +# Enable features that allow the runtime to be tried and debugged. Name might be subject to change +# in the near future. +try-runtime = [ + "frame-system/try-runtime", + "pallet-transaction-payment/try-runtime", + "solochain-template-runtime/try-runtime", + "sp-runtime/try-runtime", + "try-runtime-cli/try-runtime", +] diff --git a/substrate/bin/node-template/node/build.rs b/templates/solochain/node/build.rs similarity index 100% rename from substrate/bin/node-template/node/build.rs rename to templates/solochain/node/build.rs diff --git a/substrate/bin/node-template/node/src/benchmarking.rs b/templates/solochain/node/src/benchmarking.rs similarity index 97% rename from substrate/bin/node-template/node/src/benchmarking.rs rename to templates/solochain/node/src/benchmarking.rs index 6e29ad1a123118d953c1fad654bad9343fd8ca53..8710f303e1f03bd8471b38b10c68217a45225d5a 100644 --- a/substrate/bin/node-template/node/src/benchmarking.rs +++ b/templates/solochain/node/src/benchmarking.rs @@ -4,10 +4,10 @@ use crate::service::FullClient; -use node_template_runtime as runtime; use runtime::{AccountId, Balance, BalancesCall, SystemCall}; use sc_cli::Result; use sc_client_api::BlockBackend; +use solochain_template_runtime as runtime; use sp_core::{Encode, Pair}; use sp_inherents::{InherentData, InherentDataProvider}; use sp_keyring::Sr25519Keyring; @@ -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(), @@ -121,11 +121,12 @@ pub fn create_benchmark_extrinsic( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), - ); + ) + .into(); let raw_payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -143,7 +144,7 @@ pub fn create_benchmark_extrinsic( call, sp_runtime::AccountId32::from(sender.public()).into(), runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) } diff --git a/substrate/bin/node-template/node/src/chain_spec.rs b/templates/solochain/node/src/chain_spec.rs similarity index 97% rename from substrate/bin/node-template/node/src/chain_spec.rs rename to templates/solochain/node/src/chain_spec.rs index 6e0d78f647a594d7e3c247041a7499691edaad1e..be49f2c1fc731ee4e5ece7841151068abf0f0790 100644 --- a/substrate/bin/node-template/node/src/chain_spec.rs +++ b/templates/solochain/node/src/chain_spec.rs @@ -1,5 +1,5 @@ -use node_template_runtime::{AccountId, RuntimeGenesisConfig, Signature, WASM_BINARY}; use sc_service::ChainType; +use solochain_template_runtime::{AccountId, RuntimeGenesisConfig, Signature, WASM_BINARY}; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{sr25519, Pair, Public}; diff --git a/substrate/bin/node-template/node/src/cli.rs b/templates/solochain/node/src/cli.rs similarity index 98% rename from substrate/bin/node-template/node/src/cli.rs rename to templates/solochain/node/src/cli.rs index 98037eb886a8ec04ee78bc8f0b21b2269872d0fc..7f1b67b3696e6844f48c91b742a9017bff267d82 100644 --- a/substrate/bin/node-template/node/src/cli.rs +++ b/templates/solochain/node/src/cli.rs @@ -43,7 +43,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone CLI /// (). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, /// Db meta columns information. diff --git a/substrate/bin/node-template/node/src/command.rs b/templates/solochain/node/src/command.rs similarity index 97% rename from substrate/bin/node-template/node/src/command.rs rename to templates/solochain/node/src/command.rs index a25157693cd4392072703c28b14310f16dc01030..42d1477f22f18579d49fb48fdc91df39b10aaa2b 100644 --- a/substrate/bin/node-template/node/src/command.rs +++ b/templates/solochain/node/src/command.rs @@ -5,9 +5,9 @@ use crate::{ service, }; use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE}; -use node_template_runtime::{Block, EXISTENTIAL_DEPOSIT}; use sc_cli::SubstrateCli; use sc_service::PartialComponents; +use solochain_template_runtime::{Block, EXISTENTIAL_DEPOSIT}; use sp_keyring::Sr25519Keyring; impl SubstrateCli for Cli { @@ -117,7 +117,7 @@ pub fn run() -> sc_cli::Result<()> { ) } - cmd.run::(config) + cmd.run::, ()>(config) }, BenchmarkCmd::Block(cmd) => { let PartialComponents { client, .. } = service::new_partial(&config)?; diff --git a/substrate/bin/node-template/node/src/main.rs b/templates/solochain/node/src/main.rs similarity index 100% rename from substrate/bin/node-template/node/src/main.rs rename to templates/solochain/node/src/main.rs diff --git a/substrate/bin/node-template/node/src/rpc.rs b/templates/solochain/node/src/rpc.rs similarity index 96% rename from substrate/bin/node-template/node/src/rpc.rs rename to templates/solochain/node/src/rpc.rs index 246391adcbbe88a03b6cf9cf9043d82b8de18b60..fe2b6ca72ede5c8d9f8d878db88efa2da5c5ac97 100644 --- a/substrate/bin/node-template/node/src/rpc.rs +++ b/templates/solochain/node/src/rpc.rs @@ -8,8 +8,8 @@ use std::sync::Arc; use jsonrpsee::RpcModule; -use node_template_runtime::{opaque::Block, AccountId, Balance, Nonce}; use sc_transaction_pool_api::TransactionPool; +use solochain_template_runtime::{opaque::Block, AccountId, Balance, Nonce}; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; diff --git a/substrate/bin/node-template/node/src/service.rs b/templates/solochain/node/src/service.rs similarity index 94% rename from substrate/bin/node-template/node/src/service.rs rename to templates/solochain/node/src/service.rs index 25cd651178411c6338a2b0d1e7836804a3a5b676..dc25f7579129fe3ea86d0686732be5e6baec40ba 100644 --- a/substrate/bin/node-template/node/src/service.rs +++ b/templates/solochain/node/src/service.rs @@ -1,13 +1,13 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. use futures::FutureExt; -use node_template_runtime::{self, opaque::Block, RuntimeApi}; use sc_client_api::{Backend, BlockBackend}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; use sc_consensus_grandpa::SharedVoterState; use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use solochain_template_runtime::{self, opaque::Block, RuntimeApi}; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; use std::{sync::Arc, time::Duration}; @@ -80,23 +80,29 @@ pub fn new_partial(config: &Configuration) -> Result { telemetry.as_ref().map(|x| x.handle()), )?; - let slot_duration = sc_consensus_aura::slot_duration(&*client)?; - + let cidp_client = client.clone(); let import_queue = sc_consensus_aura::import_queue::(ImportQueueParams { block_import: grandpa_block_import.clone(), justification_import: Some(Box::new(grandpa_block_import.clone())), client: client.clone(), - create_inherent_data_providers: move |_, ()| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = cidp_client.clone(); + async move { + let slot_duration = sc_consensus_aura::standalone::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); - Ok((slot, timestamp)) + Ok((slot, timestamp)) + } }, spawner: &task_manager.spawn_essential_handle(), registry: config.prometheus_registry(), diff --git a/substrate/bin/node-template/pallets/template/Cargo.toml b/templates/solochain/pallets/template/Cargo.toml similarity index 55% rename from substrate/bin/node-template/pallets/template/Cargo.toml rename to templates/solochain/pallets/template/Cargo.toml index 51410a71c7bcee0267f36bbfcf20c616a5537ce3..bd2347151989df8950dc4dd96f039c74241d28a5 100644 --- a/substrate/bin/node-template/pallets/template/Cargo.toml +++ b/templates/solochain/pallets/template/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "pallet-template" -version = "4.0.0-dev" description = "FRAME pallet template for defining custom runtime logic." -authors = ["Substrate DevHub "] -homepage = "https://substrate.io" -edition.workspace = true +version = "0.0.0" license = "MIT-0" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true publish = false -repository = "https://github.com/substrate-developer-hub/substrate-node-template/" [lints] workspace = true @@ -19,16 +19,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../../../frame/benchmarking", default-features = false, optional = true } -frame-support = { path = "../../../../frame/support", default-features = false } -frame-system = { path = "../../../../frame/system", default-features = false } -sp-std = { path = "../../../../primitives/std", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } + +# frame deps +frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-support = { path = "../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../substrate/frame/system", default-features = false } [dev-dependencies] -sp-core = { path = "../../../../primitives/core" } -sp-io = { path = "../../../../primitives/io" } -sp-runtime = { path = "../../../../primitives/runtime" } +sp-core = { path = "../../../../substrate/primitives/core" } +sp-io = { path = "../../../../substrate/primitives/io" } +sp-runtime = { path = "../../../../substrate/primitives/runtime" } [features] default = ["std"] @@ -41,7 +44,6 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-std/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/templates/solochain/pallets/template/README.md b/templates/solochain/pallets/template/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9e4dc55267d69c47fff971cb0427bcb2e0ff871c --- /dev/null +++ b/templates/solochain/pallets/template/README.md @@ -0,0 +1 @@ +License: MIT-0 diff --git a/templates/solochain/pallets/template/src/benchmarking.rs b/templates/solochain/pallets/template/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..5a262417629c579c6ecf5ada30ae803217623766 --- /dev/null +++ b/templates/solochain/pallets/template/src/benchmarking.rs @@ -0,0 +1,35 @@ +//! Benchmarking setup for pallet-template +#![cfg(feature = "runtime-benchmarks")] +use super::*; + +#[allow(unused)] +use crate::Pallet as Template; +use frame_benchmarking::v2::*; +use frame_system::RawOrigin; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn do_something() { + let value = 100u32.into(); + let caller: T::AccountId = whitelisted_caller(); + #[extrinsic_call] + do_something(RawOrigin::Signed(caller), value); + + assert_eq!(Something::::get(), Some(value)); + } + + #[benchmark] + fn cause_error() { + Something::::put(100u32); + let caller: T::AccountId = whitelisted_caller(); + #[extrinsic_call] + cause_error(RawOrigin::Signed(caller)); + + assert_eq!(Something::::get(), Some(101u32)); + } + + impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/substrate/bin/node-template/pallets/template/src/lib.rs b/templates/solochain/pallets/template/src/lib.rs similarity index 98% rename from substrate/bin/node-template/pallets/template/src/lib.rs rename to templates/solochain/pallets/template/src/lib.rs index 4a2e53baa774ee5ca333602024d458aa078f9c10..90dfe370145856cc08483cdbce2bbc542b21b2b9 100644 --- a/substrate/bin/node-template/pallets/template/src/lib.rs +++ b/templates/solochain/pallets/template/src/lib.rs @@ -90,9 +90,7 @@ pub mod pallet { /// /// In this template, we are declaring a storage item called `Something` that stores a single /// `u32` value. Learn more about runtime storage here: - /// The [`getter`] macro generates a function to conveniently retrieve the value from storage. #[pallet::storage] - #[pallet::getter(fn something)] pub type Something = StorageValue<_, u32>; /// Events that functions in this pallet can emit. @@ -187,7 +185,7 @@ pub mod pallet { let _who = ensure_signed(origin)?; // Read a value from storage. - match Pallet::::something() { + match Something::::get() { // Return an error if the value has not been set. None => Err(Error::::NoneValue.into()), Some(old) => { diff --git a/substrate/bin/node-template/pallets/template/src/mock.rs b/templates/solochain/pallets/template/src/mock.rs similarity index 100% rename from substrate/bin/node-template/pallets/template/src/mock.rs rename to templates/solochain/pallets/template/src/mock.rs diff --git a/substrate/bin/node-template/pallets/template/src/tests.rs b/templates/solochain/pallets/template/src/tests.rs similarity index 88% rename from substrate/bin/node-template/pallets/template/src/tests.rs rename to templates/solochain/pallets/template/src/tests.rs index 7c2b853ee4dc56fdf526a17557fe37281a50e803..83e4bea7377b348d8ac1d389813a788f79b81970 100644 --- a/substrate/bin/node-template/pallets/template/src/tests.rs +++ b/templates/solochain/pallets/template/src/tests.rs @@ -1,4 +1,4 @@ -use crate::{mock::*, Error, Event}; +use crate::{mock::*, Error, Event, Something}; use frame_support::{assert_noop, assert_ok}; #[test] @@ -9,7 +9,7 @@ fn it_works_for_default_value() { // Dispatch a signed extrinsic. assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); // Read pallet storage and assert an expected result. - assert_eq!(TemplateModule::something(), Some(42)); + assert_eq!(Something::::get(), Some(42)); // Assert that the correct event was deposited System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into()); }); diff --git a/templates/solochain/pallets/template/src/weights.rs b/templates/solochain/pallets/template/src/weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..7c42936e09f292de831d28460a3bc39436c3323f --- /dev/null +++ b/templates/solochain/pallets/template/src/weights.rs @@ -0,0 +1,90 @@ + +//! Autogenerated weights for pallet_template +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Alexs-MacBook-Pro-2.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ../../target/release/node-template +// benchmark +// pallet +// --chain +// dev +// --pallet +// pallet_template +// --extrinsic +// * +// --steps=50 +// --repeat=20 +// --wasm-execution=compiled +// --output +// pallets/template/src/weights.rs +// --template +// ../../.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for pallet_template. +pub trait WeightInfo { + fn do_something() -> Weight; + fn cause_error() -> Weight; +} + +/// Weights for pallet_template using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn do_something() -> 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(T::DbWeight::get().writes(1_u64)) + } + /// Storage: TemplateModule Something (r:1 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn cause_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1489` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_000, 1489) + .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: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn do_something() -> 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(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: TemplateModule Something (r:1 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn cause_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1489` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_000, 1489) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..706ea863d0f1b79f99eeae69c12121abc165afc5 --- /dev/null +++ b/templates/solochain/runtime/Cargo.toml @@ -0,0 +1,152 @@ +[package] +name = "solochain-template-runtime" +description = "A solochain runtime template built with Substrate, part of Polkadot Sdk." +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 = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", + "serde", +] } + +# frame +frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["experimental"] } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } +frame-executive = { path = "../../../substrate/frame/executive", default-features = false } + +# frame pallets +pallet-aura = { path = "../../../substrate/frame/aura", default-features = false } +pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } +pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } +pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } +pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } +pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } + +# primitives +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false } +sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false, features = [ + "serde", +] } +sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa", default-features = false, features = [ + "serde", +] } +sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = [ + "serde", +] } +sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } +sp-offchain = { path = "../../../substrate/primitives/offchain", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false, features = [ + "serde", +] } +sp-session = { path = "../../../substrate/primitives/session", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-storage = { path = "../../../substrate/primitives/storage", default-features = false } +sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", default-features = false } +sp-version = { path = "../../../substrate/primitives/version", default-features = false, features = [ + "serde", +] } +sp-genesis-builder = { default-features = false, path = "../../../substrate/primitives/genesis-builder" } + +# RPC related +frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } + +# Used for runtime benchmarking +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } + +# The pallet in this template. +pallet-template = { path = "../pallets/template", default-features = false } + +[build-dependencies] +substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + + "frame-executive/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", + "pallet-sudo/std", + "pallet-template/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-consensus-grandpa/std", + "sp-core/std", + "sp-genesis-builder/std", + "sp-inherents/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-storage/std", + "sp-transaction-pool/std", + "sp-version/std", + + "substrate-wasm-builder", +] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-grandpa/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-template/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] + +try-runtime = [ + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-aura/try-runtime", + "pallet-balances/try-runtime", + "pallet-grandpa/try-runtime", + "pallet-sudo/try-runtime", + "pallet-template/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "sp-runtime/try-runtime", +] + +experimental = ["pallet-aura/experimental"] diff --git a/substrate/bin/node-template/runtime/build.rs b/templates/solochain/runtime/build.rs similarity index 100% rename from substrate/bin/node-template/runtime/build.rs rename to templates/solochain/runtime/build.rs diff --git a/substrate/bin/node-template/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs similarity index 91% rename from substrate/bin/node-template/runtime/src/lib.rs rename to templates/solochain/runtime/src/lib.rs index 3b6a74be2512c6214b2fadada68bb22d746f07a9..303122da564c0cdeaf1e5f402b37c721b130a27e 100644 --- a/substrate/bin/node-template/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -1,8 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] -// Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); @@ -22,7 +19,6 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use frame_support::genesis_builder_helper::{build_config, create_default_config}; -// A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{ @@ -95,8 +91,8 @@ pub mod opaque { // https://docs.substrate.io/main-docs/build/upgrade#runtime-versioning #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("node-template"), - impl_name: create_runtime_str!("node-template"), + spec_name: create_runtime_str!("solochain-template-runtime"), + impl_name: create_runtime_str!("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`, @@ -241,6 +237,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 { @@ -256,19 +253,47 @@ impl pallet_template::Config for Runtime { } // Create the runtime by composing the FRAME pallets that were previously configured. -construct_runtime!( - pub enum Runtime { - System: frame_system, - Timestamp: pallet_timestamp, - Aura: pallet_aura, - Grandpa: pallet_grandpa, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - Sudo: pallet_sudo, - // Include the custom logic from the pallet-template in the runtime. - TemplateModule: pallet_template, - } -); +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + + #[runtime::pallet_index(1)] + pub type Timestamp = pallet_timestamp; + + #[runtime::pallet_index(2)] + pub type Aura = pallet_aura; + + #[runtime::pallet_index(3)] + pub type Grandpa = pallet_grandpa; + + #[runtime::pallet_index(4)] + pub type Balances = pallet_balances; + + #[runtime::pallet_index(5)] + pub type TransactionPayment = pallet_transaction_payment; + + #[runtime::pallet_index(6)] + pub type Sudo = pallet_sudo; + + // Include the custom logic from the pallet-template in the runtime. + #[runtime::pallet_index(7)] + pub type TemplateModule = pallet_template; +} /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; @@ -276,8 +301,8 @@ pub type Address = sp_runtime::MultiAddress; pub type Header = generic::Header; /// Block type as expected by this runtime. pub type Block = generic::Block; -/// 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, @@ -296,9 +321,9 @@ type Migrations = (); /// 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; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -314,6 +339,7 @@ mod benches { frame_benchmarking::define_benchmarks!( [frame_benchmarking, BaselineBench::] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_timestamp, Timestamp] [pallet_sudo, Sudo] @@ -331,7 +357,7 @@ impl_runtime_apis! { Executive::execute_block(block); } - fn initialize_block(header: &::Header) { + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } @@ -498,6 +524,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; let mut list = Vec::::new(); @@ -514,6 +541,7 @@ impl_runtime_apis! { 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; impl frame_system_benchmarking::Config for Runtime {}